Advertisement
Guest User

MeshDistanceField

a guest
Jun 13th, 2018
142
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. Shader "Unlit/MeshDistanceField"
  2. {
  3.     Properties
  4.     {
  5.         _MeshDistanceField ("Mesh Distance Field", 3D) = "white" {}
  6.         _CutoutField ("Cutout Distance Field", 3D) = "white" {}
  7.         _MainTex("Main Texture", 2D) = "white" {}
  8.         _NormalMap("Normal Map", 2D) = "blue" {}
  9.         _Tiling("Main Texture Tiling", Float) = 1
  10.         _NormalStrength("Normal Map Influence", Range(0,1)) = 0.5
  11.         _CutOff ("Distance Field Collision", Range(0,0.1)) = 0.1
  12.         _Gloss ("Gloss", Range(1,64)) = 4
  13.         _ReflectionInfluence("Reflection Influence", Range(0,1)) = 0.5
  14.         _AmbientInfluence("Ambient Influence", Range(0,1)) = 0.5
  15.         _SpecularIntensity("Specular Intensity", Range(0,1)) = 0.5
  16.     }
  17.     SubShader
  18.     {
  19.         Tags
  20.         {
  21.             "RenderType"="Opaque"
  22.             "LightMode"="ForwardBase"
  23.         }
  24.         LOD 100
  25.         ZTest Always
  26.        
  27.         Pass
  28.         {
  29.             CGPROGRAM
  30.             #pragma vertex vert
  31.             #pragma fragment frag
  32.            
  33.             #include "UnityCG.cginc"
  34.             #include "UnityLightingCommon.cginc" // for _LightColor0
  35.  
  36.             struct appdata
  37.             {
  38.                 float4 vertex : POSITION;
  39.             };
  40.  
  41.             struct v2f
  42.             {
  43.                 float4 vertex : SV_POSITION;
  44.                 float4 objectPosition : TEXCOORD0;
  45.                 float3 worldPosition : TEXCOORD1;
  46.             };
  47.  
  48.             sampler3D _MeshDistanceField;
  49.             sampler3D _CutoutField;
  50.             float _CutOff;
  51.             float _Tiling;
  52.             float _NormalStrength;
  53.             float _Gloss;
  54.             float _AmbientInfluence;
  55.             float _ReflectionInfluence;
  56.             float _SpecularIntensity;
  57.  
  58.             sampler2D _MainTex;
  59.             sampler2D _NormalMap;
  60.  
  61.             v2f vert (appdata v)
  62.             {
  63.                 v2f o;
  64.                 o.vertex = UnityObjectToClipPos(v.vertex);
  65.                 o.objectPosition = v.vertex;
  66.                 o.worldPosition = mul(unity_ObjectToWorld, v.vertex);
  67.                 return o;
  68.             }
  69.  
  70.             float opU( float d1, float d2 )
  71.             {
  72.                 return min(d1,d2);
  73.             }
  74.  
  75.             float opS( float d1, float d2 )
  76.             {
  77.                 return max(-d1,d2);
  78.             }
  79.  
  80.             float map( in float3 pos ) {
  81.                 float d1 = tex3D(_MeshDistanceField, pos ).a;
  82.                 //float d2 = tex3D(_CutoutField, pos ).a * 2 - 1;
  83.                 return d1;//opS(d1,d2);
  84.             }
  85.  
  86.             float3 calcNormal(in float3 pos)
  87.             {
  88.                 // epsilon - used to approximate dx when taking the derivative
  89.                 const float2 eps = float2(0.1, 0.0);
  90.  
  91.                 // The idea here is to find the "gradient" of the distance field at pos
  92.                 // Remember, the distance field is not boolean - even if you are inside an object
  93.                 // the number is negative, so this calculation still works.
  94.                 // Essentially you are approximating the derivative of the distance field at this point.
  95.                 float3 nor = float3(
  96.                     map(pos + eps.xyy) - map(pos - eps.xyy),
  97.                     map(pos + eps.yxy) - map(pos - eps.yxy),
  98.                     map(pos + eps.yyx) - map(pos - eps.yyx));
  99.                 return normalize(nor);
  100.             }
  101.  
  102.             fixed4 calcPixelColor(float3 nop, float3 rayOrigin, float3 viewDir) {
  103.                         //get normal by sampling at various points around and integrating
  104.                         //Stole this from the Raymarching Unity tutorial, but had to significantly "fudge" (increase) the step offset
  105.                         // which I think is because analytical distance fields yield good results at small deltas, but mesh distance fields really don't
  106.                         float3 localNormal = calcNormal( nop * 1.75 - .375 );
  107.                         //convert to a "smooth" worldNormal
  108.                         float3 worldNormal = normalize(mul(unity_ObjectToWorld, localNormal).xyz);
  109.                        
  110.                         //triplanar normal map, based on smooth worldNormal
  111.                         fixed4 x = tex2D(_NormalMap, rayOrigin.yz * _Tiling);
  112.                         fixed4 y = tex2D(_NormalMap, rayOrigin.xz * _Tiling);
  113.                         fixed4 z = tex2D(_NormalMap, rayOrigin.xy * _Tiling);
  114.  
  115.                         float3 blend = abs(worldNormal);
  116.                         blend *= blend;
  117.                         float3 normTex = UnpackNormal( blend.x * x + blend.y * y + blend.z * z );
  118.  
  119.                         //apply normal distortion to object-space normal, then convert to world space for "final" (perturbed) normal
  120.                         localNormal.rg += normTex.rg * _NormalStrength;
  121.                         float3 finalNormal = normalize(mul(unity_ObjectToWorld, normalize(localNormal)));
  122.  
  123.                         //get world position of pixel, make sure to use float4 object position, otherwise translation is ignored
  124.                         float4 worldPixel = mul(unity_ObjectToWorld, float4(rayOrigin,1));
  125.  
  126.                         //for directional lights, this is the light dir
  127.                         float3 lightDir = _WorldSpaceLightPos0;
  128.                         float lighting = ( dot(finalNormal, lightDir ) * .5 + .5 ) * _LightColor0;  //smooth lighting (Blinn?)
  129.  
  130.                         //triplanar map, re-using previous vars
  131.                         x = tex2D(_MainTex, rayOrigin.yz * _Tiling);
  132.                         y = tex2D(_MainTex, rayOrigin.xz * _Tiling);
  133.                         z = tex2D(_MainTex, rayOrigin.xy * _Tiling);
  134.  
  135.                         blend = abs(worldNormal);
  136.                         blend *= blend;
  137.  
  138.                         fixed4 tex = blend.x * x + blend.y * y + blend.z * z;
  139.                        
  140.                         //Specular
  141.                         //Stole this from a shader forge graph example, because the "half vector" thing wouldn't work properly...
  142.                         float3 viewRefl = reflect(viewDir, worldNormal);
  143.                         //Intensity of the specular light
  144.                         float NdotH = max(dot( lightDir, viewRefl),0);
  145.                         float specIntensity = pow( saturate( NdotH ), _Gloss );
  146.  
  147.                         //Stole this from the examples page
  148.                         // sample the default reflection cubemap, using the (world)reflection vector
  149.                         float3 worldRefl = reflect(viewDir, finalNormal);
  150.                         half4 skyData = UNITY_SAMPLE_TEXCUBE(unity_SpecCube0, worldRefl);
  151.                         // decode cubemap data into actual color
  152.                         half3 skyColor = DecodeHDR(skyData, unity_SpecCube0_HDR);
  153.  
  154.                         //start with lit diffuse
  155.                         half4 col = lighting * tex;
  156.                         //add ambient term (stole this from the Unity manual again)
  157.                         col.rgb += ShadeSH9(half4(finalNormal,1)) * _AmbientInfluence;
  158.  
  159.                         //reflectivity implemented as a lerp between diffuse and reflection
  160.                         fixed4 base = lerp(col, half4(skyColor,1), _ReflectionInfluence);
  161.                         //add specular afterwards, so even fully reflective objects retain their own specular
  162.                         base.rgb += specIntensity * _SpecularIntensity * tex.rgb;
  163.  
  164.                         return base;
  165.             }
  166.            
  167.             fixed4 frag (v2f i) : SV_Target
  168.             {
  169.                 //TODO
  170.                 //1. determine the ray starting position from pixel object position & normal
  171.                 //object position determines volume pixel to read from (at starting edge)
  172.                 float3 nop = ( i.objectPosition.xyz + 1 ) * .5;
  173.                
  174.                 //2. get starting "closest distance" value from outer edge of mesh distance field
  175.                 float minDist = map( nop * 1.75 - .375 );
  176.                 float3 rayOrigin = i.objectPosition.xyz;
  177.                 float3 viewDir = normalize( i.worldPosition -  _WorldSpaceCameraPos.xyz );
  178.                 float3 rayDir = normalize( mul( unity_WorldToObject, viewDir  ) );
  179.  
  180.                 //ray march
  181.                 //3. raymarch into the mesh distance field from ( origin - viewDir ), until output < ..., or we leave bounds of object
  182.                 for( int step = 0; step < 64; ++step ) {
  183.                     rayOrigin += rayDir * minDist;
  184.                     nop = ( mul( unity_WorldToObject, rayOrigin) + 1 ) * .5;
  185.  
  186.                     //out of bounds condition
  187.                     if ( min( min(nop.x, nop.y), nop.z) < 0 ) discard;
  188.                     if ( max( max(nop.x, nop.y), nop.z) > 1 ) discard;
  189.  
  190.                     minDist = map(nop * 1.75 - .375);
  191.  
  192.                     //4. output color based on distance of ray (calculate normal direction & light it?)
  193.                     if ( minDist < _CutOff ) {
  194.                         return calcPixelColor(nop, rayOrigin, viewDir);
  195.                     }
  196.                 }
  197.  
  198.                 discard;
  199.                 return 0;
  200.             }
  201.             ENDCG
  202.         }
  203.     }
  204. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement