Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Shader shadows on multiple base passes.

Discussion in 'Shaders' started by AlphaSilverback, Nov 26, 2021.

  1. AlphaSilverback

    AlphaSilverback

    Joined:
    Aug 18, 2016
    Posts:
    10
    Hello.

    Preamble: I'm making a shader for a isosurface/voxel generated mesh, where I want the verts with grass ID's to render grass. I'd like the shader to have two passes:
    1) The base pass that can render the raw mesh, and include shadows.
    2) A tessellated mesh pass that can render grass quads, and receive shadows.

    I achieved this rather quickly, mostly thanks to the absolute GOD, "bgolus", who apparently is a guru and has a brain meant for building hyperdrives and wormhole generators.

    Problem: I'm trying to create a shadow caster pass that includes both meshes, but it's producing some very weird artifacts. Take a look at this:

    or see it here: VIDEO


    It's really hard to see, but the base mesh is actually rendering. The shades (but not the mesh) of the grass on the opposite side of the mesh is just showing through.

    I can achieve my goal by making two different materials with their separate shadow caster passes (the base mesh just has a fallback set to diffuse):
    upload_2021-11-26_22-51-39.png
    upload_2021-11-26_22-52-39.png

    As you can see, by using 2 materials in the renderers, both "passes" receives and cast shadow.

    Question: I guess my question is: Is there a way to add shadows with two normal passes? Am I missing something like a shadow collector, some keywords. Can someone point me to documents on how the unity shadows work with forward rendering in more detail, or even better, explain it to me? I am normally well versed with shaders, but I don't seem to fully understand how these passes are implemented. Is using 2 materials per renderer my only option? I would like to keep it in one shader, but I am not even sure it's more performant. Usually I would assume so, because the old built-in pipeline used to batch per material, meaning less draw calls, but does it matter when I'm smacking in extra passes?

    Any help, guidance, banter, or pointers are much appreciated!

    Here's the shader where I'm attempting to drawing everything from 1 shader:

    Code (CSharp):
    1. Shader "Tessellation with Geometry"
    2. {
    3.     Properties
    4.     {
    5.         _MainTex("Texture 1", 2D) = "white" {}
    6.         _SecondaryTex("Texture 2", 2D) = "white" {}
    7.         _TertiaryTex("Texture 3", 2D) = "white" {}
    8.         _QuadiaryTex("Texture 4", 2D) = "white" {}
    9.         _GrassTex("Grass Texture", 2D) = "black"{}
    10.         _WaveBump("Wind map", 2D) = "bump"{}
    11.         _GrassColor("GrassColor", Color) = (1,1,1,1)
    12.         _WaveColor("Wave Color", Color) = (1,1,1,1)
    13.         _TessellationFactor("Tessellation Factor", Range(0, 64)) = 16
    14.         _MaxDist("Maximum distance", Float) = 50
    15.         _GrassWidth("Grass Width", Float) = 0.2
    16.         _GrassHeight("Grass Height", Float) = 0.5
    17.         _LightAtBottom("Light at bottom", Range(0,1)) = 0.1
    18.         _Color("Color", Color) = (1,1,1,1)
    19.        
    20.     }
    21.     SubShader
    22.     {
    23.  
    24.         Pass // Base Mesh
    25.         {
    26.             Name "BaseMesh"
    27.             Tags
    28.             {
    29.                 "LightMode" = "ForwardBase"
    30.                 "RenderType" = "Opaque"
    31.                 //"IgnoreProjector" = "True"
    32.                 //"DisableBatching" = "True"
    33.         }
    34.         LOD 200
    35.         ZWrite On
    36.  
    37.  
    38.         CGPROGRAM
    39.         #pragma vertex vert
    40.         #pragma fragment frag
    41.             // make fog work
    42.             #pragma multi_compile_fog
    43.             #pragma target 5.0
    44.             //#pragma multi_compile_fwdadd_fullshadows
    45.             #pragma multi_compile_fwdbase
    46.             #include "UnityCG.cginc"
    47.             #include "AutoLight.cginc"
    48.             #include "UnityLightingCommon.cginc"
    49.             //#include "LightingUtils.cginc"
    50.  
    51.             struct appdata
    52.             {
    53.                 float4 vertex : POSITION;
    54.                 float2 uv : TEXCOORD0;
    55.                 float4 color : COLOR0;
    56.                 float3 normal : NORMAL;
    57.                 float4 tangent : TANGENT;
    58.                 float2 specialData1 : TEXCOORD6;
    59.                 float2 specialData2 : TEXCOORD7;
    60.             };
    61.  
    62.             struct v2f
    63.             {
    64.                 UNITY_FOG_COORDS(4)
    65.                 LIGHTING_COORDS(2, 3)
    66.                 float2 uv : TEXCOORD0;
    67.                 float4 pos : SV_POSITION;
    68.                 float3 worldPos : POSITION1;
    69.                 float3 normal : NORMAL;
    70.                 float4 specialData : BINORMAL1;
    71.             };
    72.  
    73.             sampler2D _MainTex;
    74.             float4 _MainTex_ST;
    75.             sampler2D _SecondaryTex;
    76.             sampler2D _TertiaryTex;
    77.             sampler2D _QuadiaryTex;
    78.  
    79.             float2 CalculateUV(float3 position, float3 normal)
    80.             {
    81.                 float2 newUV = float2(0, 0);
    82.                 float angleX = abs(dot(normal, float3(1, 0, 0)));
    83.                 float angleY = abs(dot(normal, float3(0, 1, 0)));
    84.                 float angleZ = abs(dot(normal, float3(0, 0, 1)));
    85.  
    86.                 float2 uvx = float2(position.y, position.z);
    87.                 float2 uvy = float2(position.x, position.z);
    88.                 float2 uvz = float2(position.x, position.y);
    89.  
    90.                 newUV = ((uvx * angleX) + (uvy * angleY) + (uvz * angleZ)) / 3;
    91.                 //newUV = uvy;
    92.                 return newUV;
    93.             }
    94.  
    95.             v2f vert(appdata v)
    96.             {
    97.                 v2f o;
    98.                 o.pos = UnityObjectToClipPos(v.vertex);
    99.                 o.normal = mul(unity_ObjectToWorld, v.normal);
    100.                 o.worldPos = mul(unity_ObjectToWorld, v.vertex);
    101.                 v.uv = CalculateUV(v.vertex, v.normal);
    102.                 o.uv = TRANSFORM_TEX(v.uv, _MainTex);
    103.                 o.specialData = float4(v.specialData1, v.specialData2);
    104.                 UNITY_TRANSFER_FOG(o, o.pos);
    105.                 TRANSFER_VERTEX_TO_FRAGMENT(o);
    106.                 return o;
    107.             }
    108.  
    109.  
    110.             float4 CalculateLighting(v2f i, float4 colorIn)
    111.             {
    112.                 float shadingMultiplier = clamp(dot(float4(i.normal, 1), _WorldSpaceLightPos0),0,1);
    113.                 float4 shadedColor = colorIn * shadingMultiplier * _LightColor0;
    114.  
    115.                 fixed atten = LIGHT_ATTENUATION(i);
    116.                 shadedColor *= atten;
    117.  
    118.                 shadedColor = lerp(colorIn, shadedColor, 0.9);
    119.  
    120.                 return shadedColor;
    121.             }
    122.  
    123.             fixed4 frag(v2f i) : SV_Target
    124.             {
    125.                 // 1) Find the correct Colors from the correct textures
    126.                 int mat1 = round(i.specialData.x) - 1;
    127.                 int mat2 = round(i.specialData.y) - 1;
    128.                 float blendWeight = i.specialData.z;
    129.  
    130.  
    131.                 // sample the texture
    132.                 float4 col1 = tex2D(_MainTex,       i.uv);
    133.                 float4 col2 = tex2D(_SecondaryTex,  i.uv);
    134.                 float4 col3 = tex2D(_TertiaryTex,   i.uv);
    135.                 float4 col4 = tex2D(_QuadiaryTex,   i.uv);
    136.  
    137.                 float4 colors[4] = { col1,col2,col3,col4 };
    138.  
    139.                 float4 selectedColor1 = colors[mat1];
    140.                 float4 selectedColor2 = colors[mat2];
    141.  
    142.                 fixed4 col = lerp(selectedColor1, selectedColor2, blendWeight);
    143.  
    144.                 // 2) Apply Shades:
    145.                 col = CalculateLighting(i, col);
    146.  
    147.                 // apply fog
    148.                 UNITY_APPLY_FOG(i.fogCoord, col);
    149.                 return col;
    150.             }
    151.             ENDCG
    152.         }
    153.  
    154.         Pass // Foliage/Grass
    155.         {
    156.             Name "Foliage"
    157.             Tags
    158.             {
    159.                 "LightMode" = "ForwardBase"
    160.             }
    161.             LOD 300
    162.             Cull Off
    163.  
    164.             CGPROGRAM
    165.  
    166.             #pragma vertex Vert
    167.             #pragma hull Hull
    168.             #pragma domain Domain
    169.             #pragma require geometry
    170.             #pragma geometry Geom
    171.             #pragma fragment PSMain
    172.             #pragma target 5.0
    173.  
    174.             #pragma multi_compile_fog
    175.             #include "UnityCG.cginc"
    176.             #pragma multi_compile_fwdbase
    177.             #include "AutoLight.cginc"
    178.             //#include "Lighting.cginc"
    179.             #include "UnityLightingCommon.cginc"
    180.  
    181.             //#pragma multi_compile _ _MAIN_LIGHT_SHADOWS
    182.             //#pragma multi_compile _ _MAIN_LIGHT_SHADOWS_CASCADE
    183.             //#pragma multi_compile _ _SHADOWS_SOFT
    184.  
    185.             // ------------       Helper functions     ---------------------//
    186.  
    187.             float Random(float3 st)
    188.             {
    189.                 return frac(sin(dot(st,float3(12.9898,78.233, 453.174))) * 43758.5453123);
    190.             }
    191.  
    192.             float PI = 3.1415926535897932384626433832795;
    193.  
    194.             float4 setAxisAngle(float3 axis, float rad)
    195.             {
    196.                 rad = rad * 0.5;
    197.                 float s = sin(rad);
    198.                 return float4(s * axis[0], s * axis[1], s * axis[2], cos(rad));
    199.             }
    200.  
    201.             float3 xUnitVec3 = float3(1.0, 0.0, 0.0);
    202.             float3 yUnitVec3 = float3(0.0, 1.0, 0.0);
    203.  
    204.             float4 rotationTo(float3 a, float3 b)
    205.             {
    206.                 float vecDot = dot(a, b);
    207.                 float3 tmpvec3 = float3(0, 0, 0);
    208.                 if (vecDot < -0.999999)
    209.                 {
    210.                     tmpvec3 = cross(xUnitVec3, a);
    211.                     if (length(tmpvec3) < 0.000001)
    212.                     {
    213.                         tmpvec3 = cross(yUnitVec3, a);
    214.                     }
    215.                     tmpvec3 = normalize(tmpvec3);
    216.                     return setAxisAngle(tmpvec3, PI);
    217.                 }
    218.                 else if (vecDot > 0.999999)
    219.                 {
    220.                     return float4(0,0,0,1);
    221.                 }
    222.                 else
    223.                 {
    224.                     tmpvec3 = cross(a, b);
    225.                     float4 _out = float4(tmpvec3[0], tmpvec3[1], tmpvec3[2], 1.0 + vecDot);
    226.                     return normalize(_out);
    227.                 }
    228.             }
    229.  
    230.             float4 multQuat(float4 q1, float4 q2)
    231.             {
    232.               return float4(
    233.                 q1.w * q2.x + q1.x * q2.w + q1.z * q2.y - q1.y * q2.z,
    234.                 q1.w * q2.y + q1.y * q2.w + q1.x * q2.z - q1.z * q2.x,
    235.                 q1.w * q2.z + q1.z * q2.w + q1.y * q2.x - q1.x * q2.y,
    236.                 q1.w * q2.w - q1.x * q2.x - q1.y * q2.y - q1.z * q2.z
    237.               );
    238.             }
    239.  
    240.             float3 rotateVector(float4 quat, float3 vec)
    241.             {
    242.                 // https://twistedpairdevelopment.wordpress.com/2013/02/11/rotating-a-vector-by-a-quaternion-in-glsl/
    243.                 float4 qv = multQuat(quat, float4(vec, 0.0));
    244.                 return multQuat(qv, float4(-quat.x, -quat.y, -quat.z, quat.w)).xyz;
    245.             }
    246.  
    247.             //--------------------------------------------------------------
    248.  
    249.  
    250.             struct Appdata
    251.             {
    252.                 float4 vertex : POSITION;
    253.                 float2 uv : TEXCOORD0;
    254.                 float4 color : COLOR0;
    255.                 float3 normal : NORMAL;
    256.                 float4 tangent : TANGENT;
    257.             };
    258.  
    259.             struct V2G
    260.             {
    261.                 LIGHTING_COORDS(2, 3)
    262.                 UNITY_FOG_COORDS(1)
    263.                 float4 pos : POSITION;
    264.                 float2 uv : TEXCOORD0;
    265.                 float3 normal : NORMAL;
    266.                 float4 color : COLOR0;
    267.             };
    268.  
    269.             struct G2P
    270.             {
    271.                 LIGHTING_COORDS(2, 3)
    272.                 UNITY_FOG_COORDS(1)
    273.                 float4 pos : SV_POSITION;
    274.                 float2 uv : TEXCOORD0;
    275.                 float4 color : COLOR0;
    276.                 float3 worldPos : COLOR1;
    277.                 float3 normal : NORMAL;
    278.                 float layerHeight : BLENDWEIGHT0;
    279.                 float windEffect : BLENDWEIGHT1;
    280.             };
    281.  
    282.             V2G Vert(Appdata i)
    283.             {
    284.                 V2G o;
    285.                 o.pos = i.vertex;
    286.                 o.uv = i.uv;
    287.                 o.normal = i.normal;
    288.                 o.color = i.color;
    289.                 TRANSFER_VERTEX_TO_FRAGMENT(o);
    290.                 UNITY_TRANSFER_FOG(o, o.pos);
    291.                 return o;
    292.             }
    293.  
    294.             float _TessellationFactor;
    295.             float _QuadSize;
    296.             float _MaxDist;
    297.             float _GrassWidth, _GrassHeight;
    298.             float _LightAtBottom;
    299.  
    300.             void constantsHS(InputPatch<V2G,3> V, out float edge[3]:SV_TessFactor, out float inside : SV_InsideTessFactor)
    301.             {
    302.                 float4 localCameraPos = mul(unity_WorldToObject, float4(_WorldSpaceCameraPos,1));
    303.                 //edge[0] = edge[1] = edge[2] = _TessellationFactor;
    304.                 edge[0] = (1 - saturate(distance(localCameraPos, V[0].pos)/_MaxDist)) * _TessellationFactor;
    305.                 edge[1] = (1 - saturate(distance(localCameraPos, V[1].pos)/_MaxDist)) * _TessellationFactor;
    306.                 edge[2] = (1 - saturate(distance(localCameraPos, V[2].pos)/_MaxDist)) * _TessellationFactor;
    307.                 float4 center = (V[0].pos + V[1].pos + V[2].pos) / 3;
    308.                 inside = (1 - saturate(distance(mul(unity_WorldToObject,center),_WorldSpaceCameraPos) / _MaxDist)) * _TessellationFactor;//_TessellationFactor;
    309.             }
    310.  
    311.             [domain("tri")]
    312.             [partitioning("integer")]
    313.             [outputtopology("triangle_cw")]
    314.             [patchconstantfunc("constantsHS")]
    315.             [outputcontrolpoints(3)]
    316.             V2G Hull(InputPatch<V2G,3> V, uint ID : SV_OutputControlPointID)
    317.             {
    318.                 return V[ID];
    319.             }
    320.  
    321.             [domain("tri")]
    322.             V2G Domain(float edge[3]:SV_TessFactor, float inside : SV_InsideTessFactor, const OutputPatch<V2G,3> P, float3 K : SV_DomainLocation)
    323.             {
    324.                 V2G o;
    325.                 o.pos = float4(P[0].pos.xyz * K.x + P[1].pos.xyz * K.y + P[2].pos.xyz * K.z, 1.0);
    326.                 o.uv = float2((P[0].uv * K.x + P[1].uv * K.y + P[2].uv * K.z) / 3);
    327.                 o.normal = float3(P[0].normal * K.x + P[1].normal * K.y + P[2].normal * K.z);
    328.                 o.color = float4(P[0].color.xyz * K.x + P[1].color.xyz * K.y + P[2].color.xyz * K.z, 1.0);
    329.                 UNITY_TRANSFER_FOG(o, o.pos);
    330.                 TRANSFER_VERTEX_TO_FRAGMENT(o);
    331.                 return o;
    332.             }
    333.  
    334.             sampler2D _WaveBump;
    335.             float4 _WaveBump_ST;
    336.  
    337.             float3 CalculateWind(float3 center, float3 waveNormal, float percent, float windEffectMultiplier)
    338.             {
    339.                 float3 movement = waveNormal * percent * percent;
    340.                 float3 movedCenter = center + (movement * windEffectMultiplier);
    341.                 return movedCenter;
    342.             }
    343.  
    344.             [maxvertexcount(32)]
    345.             void Geom(triangle V2G IN[3], inout TriangleStream<G2P> stream)
    346.             {
    347.                 G2P Out;
    348.  
    349.                 //float3 delta = float3 (_QuadSize, 0.00, 0.00);
    350.                 float3 center = float3((IN[0].pos.xyz + IN[1].pos.xyz + IN[2].pos.xyz) / 3);
    351.                 float3 normal = float3((IN[0].normal + IN[1].normal + IN[2].normal) / 3);
    352.                 float2 uv = float2((IN[0].uv + IN[1].uv + IN[2].uv) / 3);
    353.                 float4 color = float4((IN[0].color + IN[1].color + IN[2].color) / 3);
    354.  
    355.                 //float4 localCameraPos = mul(unity_WorldToObject, float4(_WorldSpaceCameraPos, 1));
    356.                 float distToCam = distance(_WorldSpaceCameraPos, mul(unity_ObjectToWorld,center));
    357.                 float grassWidth = _GrassWidth + (saturate(distToCam / _MaxDist) * _GrassWidth);
    358.  
    359.                 float3 up = float3(0, 1, 0);
    360.                 float3 right = float3(1, 0, 0);
    361.  
    362.                 float randomRotAngle = Random(center) * 360;
    363.                 right = rotateVector( setAxisAngle(up, radians(randomRotAngle)), right);
    364.  
    365.                 // First point :
    366.                 float3 rightSide = (right * grassWidth * 0.5);
    367.                 float3 upPoint = (up * _GrassHeight);
    368.  
    369.                 float2 uvWind = TRANSFORM_TEX(uv, _WaveBump);
    370.  
    371.                 // Get the direction from the Normal map
    372.                 uvWind.x += _Time.y * 1 / 10;
    373.                 uvWind.y += _Time.y * 0.5 / 10;
    374.                 fixed4 n = tex2Dlod(_WaveBump, float4(uvWind, 0, 1));
    375.                 float3 waveNormal = UnpackNormal(n); //unpacks from dxt5nm to rgb
    376.                 float windEffectMultiplier = 1;
    377.  
    378.                 int layers = 4;
    379.                 [unroll]
    380.                 for(int i = 0; i < layers; i++)
    381.                 {
    382.                     float percent = (float)i / layers;
    383.  
    384.                     float3 movement = waveNormal * percent * percent;
    385.                     float3 movedCenter = center + (movement * windEffectMultiplier);
    386.  
    387.                     float3 p1 = movedCenter - rightSide + (upPoint * percent);
    388.                     float3 p2 = movedCenter + rightSide + (upPoint * percent);
    389.                     float3 movedCenter2 = CalculateWind(center, waveNormal, ((float)(i + 1) / layers), windEffectMultiplier);
    390.                     float3 p3 = movedCenter2 - rightSide + (upPoint * ((float)(i+1) / layers));
    391.                     float3 p4 = movedCenter2 + rightSide + (upPoint * ((float)(i+1) / layers));
    392.  
    393.                     Out.pos = UnityObjectToClipPos(p1);
    394.                     Out.uv = float2(0, percent);
    395.                     Out.layerHeight = percent;
    396.                     Out.windEffect = saturate(pow(length(float2(waveNormal.x,waveNormal.z)),2));
    397.                     Out.normal = normalize(normal + waveNormal * 0.2);// cross(normalize(p3 - p1), normalize(p2 - p1));
    398.                     Out.color = color;
    399.                     TRANSFER_SHADOW(Out);
    400.                     UNITY_TRANSFER_FOG(Out, Out.pos);
    401.                     TRANSFER_VERTEX_TO_FRAGMENT(Out);
    402.                     Out.worldPos = mul(unity_ObjectToWorld, p1).xyz;
    403.                     stream.Append(Out);
    404.  
    405.                     Out.pos = UnityObjectToClipPos(p2);
    406.                     Out.uv = float2(1, percent);
    407.                     TRANSFER_SHADOW(Out);
    408.                     UNITY_TRANSFER_FOG(Out, Out.pos);
    409.                     TRANSFER_VERTEX_TO_FRAGMENT(Out);
    410.                     Out.worldPos = mul(unity_ObjectToWorld, p2).xyz;
    411.                     stream.Append(Out);
    412.  
    413.                     percent = ((float)i+1) / layers;
    414.                     movement = waveNormal * percent * percent;
    415.                     movedCenter = center + (movement * windEffectMultiplier);
    416.  
    417.                     Out.pos= UnityObjectToClipPos(p3);
    418.                     Out.layerHeight = percent;
    419.                     TRANSFER_SHADOW(Out);
    420.                     UNITY_TRANSFER_FOG(Out, Out.pos);
    421.                     TRANSFER_VERTEX_TO_FRAGMENT(Out);
    422.                     Out.uv = float2(0, percent);
    423.                     Out.worldPos = mul(unity_ObjectToWorld, p3).xyz;
    424.                     stream.Append(Out);
    425.                    
    426.                     Out.pos = UnityObjectToClipPos(p4);
    427.                     Out.uv = float2(1, percent);
    428.                     TRANSFER_SHADOW(Out);
    429.                     UNITY_TRANSFER_FOG(Out, Out.pos);
    430.                     TRANSFER_VERTEX_TO_FRAGMENT(Out);
    431.                     Out.worldPos = mul(unity_ObjectToWorld, p4).xyz;
    432.                     stream.Append(Out);
    433.  
    434.                     stream.RestartStrip();
    435.                 }
    436.  
    437.  
    438.             }
    439.  
    440.             sampler2D _GrassTex;
    441.             float4 _GrassTex_ST;
    442.  
    443.             float4 _GrassColor;
    444.             float4 _WaveColor;
    445.  
    446.             float4 CalculateLighting(G2P i, float4 colorIn)
    447.             {
    448.                 float shadingMultiplier = clamp(dot(float4(i.normal, 1), _WorldSpaceLightPos0), 0, 1);
    449.                 float4 shadedColor = colorIn * shadingMultiplier * _LightColor0;
    450.                
    451.  
    452.                 fixed atten = LIGHT_ATTENUATION(i);
    453.                 shadedColor *= atten;
    454.  
    455.                 /*half shadow = SHADOW_ATTENUATION(i);
    456.                 shadedColor *= shadow;*/
    457.  
    458.                 //_WorldSpaceLightPos0
    459.                 shadedColor = lerp(colorIn, shadedColor, 0.9);
    460.                
    461.  
    462.                 return shadedColor;
    463.             }
    464.  
    465.             float4 PSMain(G2P i) : SV_Target
    466.             {
    467.                
    468.                 fixed4 col = tex2D(_GrassTex, i.uv);
    469.                 clip(col.a - 0.5);
    470.                 float greyLevel = length(col.xyz);
    471.                 col.xyz = greyLevel;
    472.  
    473.                 col = lerp(_GrassColor, _WaveColor, saturate(i.windEffect - 0.5));
    474.                 col *= lerp(_LightAtBottom, 1, i.layerHeight);
    475.  
    476.                 col = CalculateLighting(i, col);
    477.  
    478.  
    479.                 UNITY_APPLY_FOG(i.fogCoord, col);
    480.  
    481.                 return col;
    482.             }
    483.             ENDCG
    484.         }
    485.  
    486.         Pass // Shadow Caster
    487.         {
    488.             Name "ShadowCaster"
    489.             Tags
    490.             {
    491.                 "LightMode" = "ShadowCaster"
    492.             }
    493.             LOD 50
    494.             Cull Off
    495.             ZWrite On
    496.             ZTest LEqual
    497.  
    498.             CGPROGRAM
    499.  
    500.             #pragma vertex Vert
    501.             #pragma hull Hull
    502.             #pragma domain Domain
    503.             #pragma require geometry
    504.             #pragma geometry Geom
    505.             #pragma fragment PSMain
    506.             #pragma target 5.0
    507.  
    508.             #pragma multi_compile_fog
    509.             #include "UnityCG.cginc"
    510.             #pragma multi_compile_fwdbase
    511.             #include "AutoLight.cginc"
    512.             #include "Lighting.cginc"
    513.             #include "UnityLightingCommon.cginc"
    514.             #pragma multi_compile_shadowcaster
    515.             #pragma multi_compile _ _MAIN_LIGHT_SHADOWS
    516.             #pragma multi_compile _ _MAIN_LIGHT_SHADOWS_CASCADE
    517.             #pragma multi_compile _ _SHADOWS_SOFT
    518.  
    519.             //------------       Helper functions     ---------------------//
    520.  
    521.             float Random(float3 st)
    522.             {
    523.                 return frac(sin(dot(st,float3(12.9898,78.233, 453.174))) * 43758.5453123);
    524.             }
    525.  
    526.             float PI = 3.1415926535897932384626433832795;
    527.  
    528.             float4 setAxisAngle(float3 axis, float rad)
    529.             {
    530.                 rad = rad * 0.5;
    531.                 float s = sin(rad);
    532.                 return float4(s * axis[0], s * axis[1], s * axis[2], cos(rad));
    533.             }
    534.  
    535.             float3 xUnitVec3 = float3(1.0, 0.0, 0.0);
    536.             float3 yUnitVec3 = float3(0.0, 1.0, 0.0);
    537.  
    538.             float4 rotationTo(float3 a, float3 b)
    539.             {
    540.                 float vecDot = dot(a, b);
    541.                 float3 tmpvec3 = float3(0, 0, 0);
    542.                 if (vecDot < -0.999999)
    543.                 {
    544.                     tmpvec3 = cross(xUnitVec3, a);
    545.                     if (length(tmpvec3) < 0.000001)
    546.                     {
    547.                         tmpvec3 = cross(yUnitVec3, a);
    548.                     }
    549.                     tmpvec3 = normalize(tmpvec3);
    550.                     return setAxisAngle(tmpvec3, PI);
    551.                 }
    552.                 else if (vecDot > 0.999999)
    553.                 {
    554.                     return float4(0,0,0,1);
    555.                 }
    556.                 else
    557.                 {
    558.                     tmpvec3 = cross(a, b);
    559.                     float4 _out = float4(tmpvec3[0], tmpvec3[1], tmpvec3[2], 1.0 + vecDot);
    560.                     return normalize(_out);
    561.                 }
    562.             }
    563.  
    564.             float4 multQuat(float4 q1, float4 q2)
    565.             {
    566.               return float4(
    567.                 q1.w * q2.x + q1.x * q2.w + q1.z * q2.y - q1.y * q2.z,
    568.                 q1.w * q2.y + q1.y * q2.w + q1.x * q2.z - q1.z * q2.x,
    569.                 q1.w * q2.z + q1.z * q2.w + q1.y * q2.x - q1.x * q2.y,
    570.                 q1.w * q2.w - q1.x * q2.x - q1.y * q2.y - q1.z * q2.z
    571.               );
    572.             }
    573.  
    574.             float3 rotateVector(float4 quat, float3 vec)
    575.             {
    576.                 //https://twistedpairdevelopment.wordpress.com/2013/02/11/rotating-a-vector-by-a-quaternion-in-glsl/
    577.                 float4 qv = multQuat(quat, float4(vec, 0.0));
    578.                 return multQuat(qv, float4(-quat.x, -quat.y, -quat.z, quat.w)).xyz;
    579.             }
    580.  
    581.             //--------------------------------------------------------------
    582.  
    583.  
    584.             struct Appdata
    585.             {
    586.                 float4 vertex : POSITION;
    587.                 float2 uv : TEXCOORD0;
    588.                 float3 normal : NORMAL;
    589.                 float4 tangent : TANGENT;
    590.             };
    591.  
    592.             struct V2G
    593.             {
    594.                 float4 vertex : POSITION;
    595.                 float2 uv : TEXCOORD0;
    596.                 float3 normal : NORMAL;
    597.                 float4 color : COLOR0;
    598.             };
    599.  
    600.             struct G2P
    601.             {
    602.                 float4 pos : SV_POSITION;
    603.                 float2 uv : TEXCOORD0;
    604.                 float layerHeight : BLENDWEIGHT0;
    605.                 float windEffect : BLENDWEIGHT1;
    606.             };
    607.  
    608.             V2G Vert(Appdata i)
    609.             {
    610.                 V2G o;
    611.                 o.vertex = i.vertex;
    612.                 o.uv = i.uv;
    613.                 o.normal = i.normal;
    614.                 o.color = 0;
    615.                 return o;
    616.             }
    617.  
    618.             float _TessellationFactor;
    619.             float _QuadSize;
    620.             float _MaxDist;
    621.             float _GrassWidth, _GrassHeight;
    622.             float _LightAtBottom;
    623.  
    624.             void constantsHS(InputPatch<V2G,3> V, out float edge[3]:SV_TessFactor, out float inside : SV_InsideTessFactor)
    625.             {
    626.                 float4 localCameraPos = mul(unity_WorldToObject, float4(_WorldSpaceCameraPos,1));
    627.  
    628.                 edge[0] = (1 - saturate(distance(localCameraPos, V[0].vertex) / _MaxDist)) * _TessellationFactor;
    629.                 edge[1] = (1 - saturate(distance(localCameraPos, V[1].vertex) / _MaxDist)) * _TessellationFactor;
    630.                 edge[2] = (1 - saturate(distance(localCameraPos, V[2].vertex) / _MaxDist)) * _TessellationFactor;
    631.                 float4 center = (V[0].vertex + V[1].vertex + V[2].vertex) / 3;
    632.                 inside = (1 - saturate(distance(mul(unity_WorldToObject,center),_WorldSpaceCameraPos) / _MaxDist)) * _TessellationFactor;//_TessellationFactor;
    633.             }
    634.  
    635.             [domain("tri")]
    636.             [partitioning("integer")]
    637.             [outputtopology("triangle_cw")]
    638.             [patchconstantfunc("constantsHS")]
    639.             [outputcontrolpoints(3)]
    640.             V2G Hull(InputPatch<V2G,3> V, uint ID : SV_OutputControlPointID)
    641.             {
    642.                 return V[ID];
    643.             }
    644.  
    645.             [domain("tri")]
    646.             V2G Domain(float edge[3]:SV_TessFactor, float inside : SV_InsideTessFactor, const OutputPatch<V2G,3> P, float3 K : SV_DomainLocation)
    647.             {
    648.                 V2G o;
    649.                 o.vertex = float4(P[0].vertex.xyz * K.x + P[1].vertex.xyz * K.y + P[2].vertex.xyz * K.z, 1.0);
    650.                 o.uv = float2((P[0].uv * K.x + P[1].uv * K.y + P[2].uv * K.z) / 3);
    651.                 o.normal = float3(P[0].normal * K.x + P[1].normal * K.y + P[2].normal * K.z);
    652.                 o.color = float4(P[0].color.xyz * K.x + P[1].color.xyz * K.y + P[2].color.xyz * K.z, 1.0);
    653.                 return o;
    654.             }
    655.  
    656.             sampler2D _WaveBump;
    657.             float4 _WaveBump_ST;
    658.  
    659.             float3 CalculateWind(float3 center, float3 waveNormal, float percent, float windEffectMultiplier)
    660.             {
    661.                 float3 movement = waveNormal * percent * percent;
    662.                 float3 movedCenter = center + (movement * windEffectMultiplier);
    663.                 return movedCenter;
    664.             }
    665.  
    666.             [maxvertexcount(64)]
    667.             void Geom(triangle V2G IN[3], inout TriangleStream<G2P> stream)
    668.             {
    669.                 G2P Out;
    670.  
    671.                 //Add the normal first 3 verts as well in the shadow caster pass;
    672.                 int limit = 3;
    673.                 [unroll]
    674.                 for (int k = 3; k < limit; k++)
    675.                 {
    676.                     Out.pos = UnityObjectToClipPos(IN[k].vertex);
    677.                     Out.uv = IN[k].uv;
    678.                     Out.layerHeight = -10;
    679.                     Out.windEffect = 0;
    680.                     stream.Append(Out);
    681.                 }
    682.                 stream.RestartStrip();
    683.                 //return;
    684.  
    685.  
    686.                 float3 delta = float3 (_QuadSize, 0.00, 0.00);
    687.                 float3 center = float3((IN[0].vertex.xyz + IN[1].vertex.xyz + IN[2].vertex.xyz) / 3);
    688.                 float3 normal = float3((IN[0].normal + IN[1].normal + IN[2].normal) / 3);
    689.                 float2 uv = float2((IN[0].uv + IN[1].uv + IN[2].uv) / 3);
    690.                 float4 color = float4((IN[0].color + IN[1].color + IN[2].color) / 3);
    691.  
    692.                 float4 localCameraPos = mul(unity_WorldToObject, float4(_WorldSpaceCameraPos, 1));
    693.                 float distToCam = distance(_WorldSpaceCameraPos, mul(unity_ObjectToWorld,center));
    694.                 float grassWidth = _GrassWidth + (saturate(distToCam / _MaxDist) * _GrassWidth);
    695.  
    696.                 float3 up = float3(0, 1, 0);
    697.                 float3 right = float3(1, 0, 0);
    698.  
    699.                 float randomRotAngle = Random(center) * 360;
    700.                 right = rotateVector(setAxisAngle(up, radians(randomRotAngle)), right);
    701.  
    702.                 //First point :
    703.                 float3 rightSide = (right * grassWidth * 0.5);
    704.                 float3 upPoint = (up * _GrassHeight);
    705.  
    706.  
    707.                 float2 uvWind = TRANSFORM_TEX(uv, _WaveBump);
    708.  
    709.                 uvWind.x += _Time.y * 1 / 10;
    710.                 uvWind.y += _Time.y * 0.5 / 10;
    711.                 fixed4 n = tex2Dlod(_WaveBump, float4(uvWind, 0, 1));
    712.                 float3 waveNormal = UnpackNormal(n); //unpacks from dxt5nm to rgb
    713.                 float windEffectMultiplier = 1;
    714.  
    715.                 int layers = 4;
    716.                 [unroll]
    717.                 for (int i = 0; i < layers; i++)
    718.                 {
    719.                     float percent = (float)i / layers;
    720.  
    721.                     float3 movement = waveNormal * percent * percent;
    722.                     float3 movedCenter = center + (movement * windEffectMultiplier);
    723.  
    724.                     float3 p1 = movedCenter - rightSide + (upPoint * percent);
    725.                     float3 p2 = movedCenter + rightSide + (upPoint * percent);
    726.                     float3 movedCenter2 = CalculateWind(center, waveNormal, ((float)(i + 1) / layers), windEffectMultiplier);
    727.                     float3 p3 = movedCenter2 - rightSide + (upPoint * ((float)(i + 1) / layers));
    728.                     float3 p4 = movedCenter2 + rightSide + (upPoint * ((float)(i + 1) / layers));
    729.  
    730.                     Out.pos = UnityObjectToClipPos(p1);
    731.                     Out.uv = float2(0, percent);
    732.                     Out.layerHeight = percent;
    733.                     Out.windEffect = saturate(pow(length(float2(waveNormal.x,waveNormal.z)),2));
    734.                     stream.Append(Out);
    735.  
    736.                     Out.pos = UnityObjectToClipPos(p2);
    737.                     Out.uv = float2(1, percent);
    738.                     stream.Append(Out);
    739.  
    740.                     percent = ((float)i + 1) / layers;
    741.                     movement = waveNormal * percent * percent;
    742.                     movedCenter = center + (movement * windEffectMultiplier);
    743.  
    744.                     Out.pos = UnityObjectToClipPos(p3);
    745.                     Out.layerHeight = percent;
    746.  
    747.                     Out.uv = float2(0, percent);
    748.                     stream.Append(Out);
    749.  
    750.                     Out.pos = UnityObjectToClipPos(p4);
    751.                     Out.uv = float2(1, percent);
    752.                     stream.Append(Out);
    753.  
    754.                     stream.RestartStrip();
    755.                 }
    756.  
    757.  
    758.             }
    759.  
    760.             sampler2D _GrassTex;
    761.             float4 _GrassTex_ST;
    762.  
    763.             float4 PSMain(G2P i) : SV_Target
    764.             {
    765.                 if (i.layerHeight < 0)
    766.                 {
    767.                     return 1;
    768.                 }
    769.                 else
    770.                 {
    771.                     fixed4 col = tex2D(_GrassTex, i.uv);
    772.                     clip(col.a - 0.5);
    773.                 }
    774.  
    775.                 return 1;
    776.  
    777.             }
    778.             ENDCG
    779.         }
    780.  
    781.     }
    782.     Fallback "Diffuse"
    783. }
     
  2. AlphaSilverback

    AlphaSilverback

    Joined:
    Aug 18, 2016
    Posts:
    10
    I fixed it. I made a typo in the shadow casters geometry shader where the base mesh never gets sent to the fragment shader :oops:.

    For any other interested in this: It is as one would expect. You can have as many normal passes as you like, but the shadow caster pass must include all the geometry and data identical to the meshes you want to cast/receive shadows.

    Here is a working shader that utilize 2 forward base passes and a shadow caster pass.


    Code (CSharp):
    1. Shader "Pyremind Interactive/IsoSurface TessGeom Terrain Example"
    2. {
    3.     Properties
    4.     {
    5.         _MainTex("Texture 1", 2D) = "white" {}
    6.         _SecondaryTex("Texture 2", 2D) = "white" {}
    7.         _TertiaryTex("Texture 3", 2D) = "white" {}
    8.         _QuadiaryTex("Texture 4", 2D) = "white" {}
    9.         _GrassTex("Grass Texture", 2D) = "black"{}
    10.         _WaveBump("Wind map", 2D) = "bump"{}
    11.         _GrassColor("GrassColor", Color) = (1,1,1,1)
    12.         _WaveColor("Wave Color", Color) = (1,1,1,1)
    13.         _WaveSpeed("Wave speed", Float) = 1
    14.         _TessellationFactor("Tessellation Factor", Range(0, 10)) = 3
    15.         _MaxDist("Maximum distance", Float) = 50
    16.         _GrassWidth("Grass Width", Float) = 0.2
    17.         _GrassHeight("Grass Height", Float) = 0.5
    18.         _LightAtBottom("Light at bottom", Range(0,1)) = 0.1
    19.         _Color("Color", Color) = (1,1,1,1)
    20.         //[Header(Grass Variation)]
    21.         _VariationTex("Flower Sprite Sheet", 2D) = "black" {}
    22.         _Tiles("Sprite Sheet", Vector) = (1,1,1,1)
    23.         _VariationAmount("VariationAmount", Range(0,1)) = 0.02
    24.        
    25.     }
    26.     SubShader
    27.     {
    28.  
    29.         Pass // Base Mesh
    30.         {
    31.             Name "BaseMesh"
    32.             Tags
    33.             {
    34.                 "LightMode" = "ForwardBase"
    35.                 "RenderType" = "Opaque"
    36.                 "IgnoreProjector" = "True"
    37.                 //"DisableBatching" = "True"
    38.         }
    39.         LOD 200
    40.         ZWrite On
    41.        
    42.  
    43.  
    44.         CGPROGRAM
    45.         #pragma vertex vert
    46.         #pragma fragment frag
    47.             // make fog work
    48.             #pragma multi_compile_fog
    49.             #pragma target 5.0
    50.             //#pragma multi_compile_fwdadd_fullshadows
    51.             #pragma multi_compile_fwdbase
    52.             #include "UnityCG.cginc"
    53.             #include "AutoLight.cginc"
    54.             #include "UnityLightingCommon.cginc"
    55.             //#include "LightingUtils.cginc"
    56.  
    57.             struct appdata
    58.             {
    59.                 float4 vertex : POSITION;
    60.                 float2 uv : TEXCOORD0;
    61.                 float4 color : COLOR0;
    62.                 float3 normal : NORMAL;
    63.                 float4 tangent : TANGENT;
    64.                 float2 specialData1 : TEXCOORD6;
    65.                 float2 specialData2 : TEXCOORD7;
    66.             };
    67.  
    68.             struct v2f
    69.             {
    70.                 UNITY_FOG_COORDS(4)
    71.                 LIGHTING_COORDS(2, 3)
    72.                 float2 uv : TEXCOORD0;
    73.                 float4 pos : SV_POSITION;
    74.                 float3 worldPos : POSITION1;
    75.                 float3 normal : NORMAL;
    76.                 float4 specialData : BINORMAL1;
    77.             };
    78.  
    79.             sampler2D _MainTex;
    80.             float4 _MainTex_ST;
    81.             sampler2D _SecondaryTex;
    82.             sampler2D _TertiaryTex;
    83.             sampler2D _QuadiaryTex;
    84.  
    85.             float2 CalculateUV(float3 position, float3 normal)
    86.             {
    87.                 float2 newUV = float2(0, 0);
    88.                 float angleX = abs(dot(normal, float3(1, 0, 0)));
    89.                 float angleY = abs(dot(normal, float3(0, 1, 0)));
    90.                 float angleZ = abs(dot(normal, float3(0, 0, 1)));
    91.  
    92.                 float2 uvx = float2(position.y, position.z);
    93.                 float2 uvy = float2(position.x, position.z);
    94.                 float2 uvz = float2(position.x, position.y);
    95.  
    96.                 newUV = ((uvx * angleX) + (uvy * angleY) + (uvz * angleZ)) / 3;
    97.                 //newUV = uvy;
    98.                 return newUV;
    99.             }
    100.  
    101.             v2f vert(appdata v)
    102.             {
    103.                 v2f o;
    104.                 o.pos = UnityObjectToClipPos(v.vertex);
    105.                 o.normal = mul(unity_ObjectToWorld, v.normal);
    106.                 o.worldPos = mul(unity_ObjectToWorld, v.vertex);
    107.                 v.uv = CalculateUV(v.vertex, v.normal);
    108.                 o.uv = TRANSFORM_TEX(v.uv, _MainTex);
    109.                 o.specialData = float4(v.specialData1, v.specialData2);
    110.                 UNITY_TRANSFER_FOG(o, o.pos);
    111.                 TRANSFER_VERTEX_TO_FRAGMENT(o);
    112.                 return o;
    113.             }
    114.  
    115.  
    116.             float4 CalculateLighting(v2f i, float4 colorIn)
    117.             {
    118.                 float shadingMultiplier = clamp(dot(float4(i.normal, 1), _WorldSpaceLightPos0),0,1);
    119.                 float4 shadedColor = colorIn * shadingMultiplier * _LightColor0;
    120.  
    121.                 fixed atten = LIGHT_ATTENUATION(i);
    122.                 shadedColor *= atten;
    123.  
    124.                 shadedColor = lerp(colorIn, shadedColor, 0.9);
    125.  
    126.                 return shadedColor;
    127.             }
    128.  
    129.             fixed4 frag(v2f i) : SV_Target
    130.             {
    131.                 // 1) Find the correct Colors from the correct textures
    132.                 int mat1 = round(i.specialData.x) - 1;
    133.                 int mat2 = round(i.specialData.y) - 1;
    134.                 float blendWeight = i.specialData.z;
    135.  
    136.  
    137.                 // sample the texture
    138.                 float4 col1 = tex2D(_MainTex,       i.uv);
    139.                 float4 col2 = tex2D(_SecondaryTex,  i.uv);
    140.                 float4 col3 = tex2D(_TertiaryTex,   i.uv);
    141.                 float4 col4 = tex2D(_QuadiaryTex,   i.uv);
    142.  
    143.                 float4 colors[4] = { col1,col2,col3,col4 };
    144.  
    145.                 float4 selectedColor1 = colors[mat1];
    146.                 float4 selectedColor2 = colors[mat2];
    147.  
    148.                 fixed4 col = lerp(selectedColor1, selectedColor2, blendWeight);
    149.  
    150.                 // 2) Apply Shades:
    151.                 col = CalculateLighting(i, col);
    152.  
    153.                 // apply fog
    154.                 UNITY_APPLY_FOG(i.fogCoord, col);
    155.                 return col;
    156.             }
    157.             ENDCG
    158.         }
    159.  
    160.         Pass // Foliage/Grass
    161.         {
    162.             Name "Foliage"
    163.             Tags
    164.             {
    165.                 "LightMode" = "ForwardBase"
    166.             }
    167.             LOD 300
    168.             Cull Off
    169.             //Blend SrcAlpha OneMinusSrcAlpha
    170.  
    171.  
    172.             CGPROGRAM
    173.  
    174.             #pragma vertex Vert
    175.             #pragma hull Hull
    176.             #pragma domain Domain
    177.             #pragma require geometry
    178.             #pragma geometry Geom
    179.             #pragma fragment PSMain
    180.             #pragma target 5.0
    181.  
    182.             #pragma multi_compile_fog
    183.             #include "UnityCG.cginc"
    184.             #pragma multi_compile_fwdbase
    185.             #include "AutoLight.cginc"
    186.             #include "UnityLightingCommon.cginc"
    187.  
    188.             // ------------       Helper functions     ---------------------//
    189.  
    190.             float Random(float3 st)
    191.             {
    192.                 return frac(sin(dot(st,float3(2.9898,5.2332453, -3.17408954376))) * 5.94215 /*43758.5453123*/);
    193.             }
    194.  
    195.             float PI = 3.1415926535897932384626433832795;
    196.  
    197.             float4 setAxisAngle(float3 axis, float rad)
    198.             {
    199.                 rad = rad * 0.5;
    200.                 float s = sin(rad);
    201.                 return float4(s * axis[0], s * axis[1], s * axis[2], cos(rad));
    202.             }
    203.  
    204.             float3 xUnitVec3 = float3(1.0, 0.0, 0.0);
    205.             float3 yUnitVec3 = float3(0.0, 1.0, 0.0);
    206.  
    207.             float4 rotationTo(float3 a, float3 b)
    208.             {
    209.                 float vecDot = dot(a, b);
    210.                 float3 tmpvec3 = float3(0, 0, 0);
    211.                 if (vecDot < -0.999999)
    212.                 {
    213.                     tmpvec3 = cross(xUnitVec3, a);
    214.                     if (length(tmpvec3) < 0.000001)
    215.                     {
    216.                         tmpvec3 = cross(yUnitVec3, a);
    217.                     }
    218.                     tmpvec3 = normalize(tmpvec3);
    219.                     return setAxisAngle(tmpvec3, PI);
    220.                 }
    221.                 else if (vecDot > 0.999999)
    222.                 {
    223.                     return float4(0,0,0,1);
    224.                 }
    225.                 else
    226.                 {
    227.                     tmpvec3 = cross(a, b);
    228.                     float4 _out = float4(tmpvec3[0], tmpvec3[1], tmpvec3[2], 1.0 + vecDot);
    229.                     return normalize(_out);
    230.                 }
    231.             }
    232.  
    233.             float4 multQuat(float4 q1, float4 q2)
    234.             {
    235.               return float4(
    236.                 q1.w * q2.x + q1.x * q2.w + q1.z * q2.y - q1.y * q2.z,
    237.                 q1.w * q2.y + q1.y * q2.w + q1.x * q2.z - q1.z * q2.x,
    238.                 q1.w * q2.z + q1.z * q2.w + q1.y * q2.x - q1.x * q2.y,
    239.                 q1.w * q2.w - q1.x * q2.x - q1.y * q2.y - q1.z * q2.z
    240.               );
    241.             }
    242.  
    243.             float3 rotateVector(float4 quat, float3 vec)
    244.             {
    245.                 // https://twistedpairdevelopment.wordpress.com/2013/02/11/rotating-a-vector-by-a-quaternion-in-glsl/
    246.                 float4 qv = multQuat(quat, float4(vec, 0.0));
    247.                 return multQuat(qv, float4(-quat.x, -quat.y, -quat.z, quat.w)).xyz;
    248.             }
    249.  
    250.             float2 GetSpriteSheetUV(float2 uvIn, int tileTarget, int2 size)
    251.             {
    252.                 float sizeX = (1.0 / size.x);
    253.                 float sizeY = (1.0 / size.y);
    254.  
    255.                 uint indexX = tileTarget % (uint)size.x;
    256.                 uint indexY = tileTarget / (uint)size.y;
    257.  
    258.                 float x = (sizeX * uvIn.x) + (indexX * sizeX);
    259.                 float y = (sizeY * uvIn.y) + (indexY * sizeY);
    260.                 return float2(x, y);
    261.             }
    262.  
    263.             inline double snap(double original, int numerator, int denominator)
    264.             {
    265.                 return round(original * denominator / numerator) * numerator / denominator;
    266.             }
    267.             //--------------------------------------------------------------
    268.  
    269.  
    270.             struct Appdata
    271.             {
    272.                 float4 vertex : POSITION;
    273.                 float2 uv : TEXCOORD0;
    274.                 float4 color : COLOR0;
    275.                 float3 normal : NORMAL;
    276.                 float4 tangent : TANGENT;
    277.                 float2 specialData1 : TEXCOORD6;
    278.                 float2 specialData2 : TEXCOORD7;
    279.             };
    280.  
    281.             struct V2G
    282.             {
    283.                 LIGHTING_COORDS(2, 3)
    284.                 UNITY_FOG_COORDS(1)
    285.                 float4 pos : POSITION;
    286.                 float2 uv : TEXCOORD0;
    287.                 float3 normal : NORMAL;
    288.                 float4 color : COLOR0;
    289.                 float4 specialData : BINORMAL1;
    290.                 float4 originalCenter : COLOR1;
    291.             };
    292.  
    293.             struct G2P
    294.             {
    295.                 LIGHTING_COORDS(2, 3)
    296.                 UNITY_FOG_COORDS(1)
    297.                 float4 pos : SV_POSITION;
    298.                 float2 uv : TEXCOORD0;
    299.                 float4 color : COLOR0;
    300.                 float3 worldPos : COLOR1;
    301.                 float3 normal : NORMAL;
    302.                 float layerHeight : BLENDWEIGHT0;
    303.                 float windEffect : BLENDWEIGHT1;
    304.                 float4 originalCenter : COLOR2;
    305.                 //float transparency : BLENDWEIGHT2;
    306.             };
    307.  
    308.             V2G Vert(Appdata i)
    309.             {
    310.                 V2G o;
    311.                 o.pos = i.vertex;
    312.                 o.uv = i.uv;
    313.                 o.normal = i.normal;
    314.                 o.color = i.color;
    315.                 TRANSFER_VERTEX_TO_FRAGMENT(o);
    316.                 UNITY_TRANSFER_FOG(o, o.pos);
    317.                 o.specialData = float4(i.specialData1, i.specialData2);
    318.                 o.originalCenter = i.vertex;
    319.                 return o;
    320.             }
    321.  
    322.             float _WaveSpeed;
    323.             float _TessellationFactor;
    324.             float _QuadSize;
    325.             float _MaxDist;
    326.             float _GrassWidth, _GrassHeight;
    327.             float _LightAtBottom;
    328.  
    329.             void constantsHS(InputPatch<V2G,3> V, out float edge[3]:SV_TessFactor, out float inside : SV_InsideTessFactor)
    330.             {
    331.  
    332.                 edge[0] = (1 - saturate(distance(_WorldSpaceCameraPos, mul(unity_ObjectToWorld,V[0].pos).xyz)/_MaxDist)) * _TessellationFactor;
    333.                 edge[1] = (1 - saturate(distance(_WorldSpaceCameraPos, mul(unity_ObjectToWorld,V[1].pos).xyz)/_MaxDist)) * _TessellationFactor;
    334.                 edge[2] = (1 - saturate(distance(_WorldSpaceCameraPos, mul(unity_ObjectToWorld,V[2].pos).xyz)/_MaxDist)) * _TessellationFactor;
    335.                 float4 center = (V[0].pos + V[1].pos + V[2].pos) / 3;
    336.                 inside = (1 - saturate(distance(mul(unity_WorldToObject,center),_WorldSpaceCameraPos) / _MaxDist)) * _TessellationFactor;//_TessellationFactor;
    337.             }
    338.  
    339.             [domain("tri")]
    340.             //[partitioning("integer")]
    341.             [outputtopology("triangle_cw")]
    342.             [UNITY_partitioning("fractional_odd")]
    343.             [patchconstantfunc("constantsHS")]
    344.             [outputcontrolpoints(3)]
    345.             V2G Hull(InputPatch<V2G,3> V, uint ID : SV_OutputControlPointID)
    346.             {
    347.                 return V[ID];
    348.             }
    349.  
    350.             [domain("tri")]
    351.             V2G Domain(float edge[3]:SV_TessFactor, float inside : SV_InsideTessFactor, const OutputPatch<V2G,3> P, float3 K : SV_DomainLocation)
    352.             {
    353.                 V2G o;
    354.                 o.pos = float4(P[0].pos.xyz * K.x + P[1].pos.xyz * K.y + P[2].pos.xyz * K.z, 1.0);
    355.                 o.uv = float2((P[0].uv * K.x + P[1].uv * K.y + P[2].uv * K.z) / 3);
    356.                 o.normal = float3(P[0].normal * K.x + P[1].normal * K.y + P[2].normal * K.z);
    357.                 o.color = float4(P[0].color.xyz * K.x + P[1].color.xyz * K.y + P[2].color.xyz * K.z, 1.0);
    358.                 o.specialData = P[0].specialData;
    359.                 o.originalCenter = (P[0].pos + P[1].pos + P[2].pos) / 3;
    360.                 UNITY_TRANSFER_FOG(o, o.pos);
    361.                 TRANSFER_VERTEX_TO_FRAGMENT(o);
    362.                 return o;
    363.             }
    364.  
    365.             sampler2D _WaveBump;
    366.             float4 _WaveBump_ST;
    367.  
    368.             float3 CalculateWind(float3 center, float3 waveNormal, float percent, float windEffectMultiplier)
    369.             {
    370.                 float3 movement = waveNormal * pow(percent,2);
    371.                 float3 movedCenter = center + (movement * windEffectMultiplier);
    372.                 return movedCenter;
    373.             }
    374.  
    375.             [maxvertexcount(32)]
    376.             void Geom(triangle V2G IN[3], inout TriangleStream<G2P> stream)
    377.             {
    378.                 G2P Out;
    379.  
    380.                 if ((int)IN[0].specialData != 1 ||
    381.                     (int)IN[1].specialData != 1 ||
    382.                     (int)IN[2].specialData != 1)
    383.                     return;
    384.  
    385.                 float3 center =  float3((IN[0].pos.xyz + IN[1].pos.xyz + IN[2].pos.xyz) / 3);
    386.                 float3 normal = float3((IN[0].normal + IN[1].normal + IN[2].normal) / 3);
    387.                 float2 uv = float2((IN[0].uv + IN[1].uv + IN[2].uv) / 3);
    388.                 float4 color = float4((IN[0].color + IN[1].color + IN[2].color) / 3);
    389.  
    390.                 float distToCam = distance(_WorldSpaceCameraPos, mul(unity_ObjectToWorld,center));
    391.                 float grassWidth = _GrassWidth + ((distToCam / _MaxDist) * _GrassWidth * 3);
    392.  
    393.                 float3 up = float3(0, 1, 0);
    394.                 float3 right = float3(1, 0, 0);
    395.  
    396.                 float3 snappedCenter = float3(snap(center.x, 1, 10), snap(center.y, 1, 10), snap(center.z, 1, 10));
    397.  
    398.                 float randomRotAngle = Random(snappedCenter) * 360.0;
    399.                 right = rotateVector( setAxisAngle(up, radians(randomRotAngle)), right);
    400.  
    401.                 float grassHeight = Random(snappedCenter) * 2 * _GrassHeight;
    402.  
    403.                 // First point :
    404.                 float3 rightSide = (right * grassWidth * 0.5);
    405.                 float3 upPoint = (up * grassHeight);
    406.  
    407.                 float2 uvWind = TRANSFORM_TEX(uv, _WaveBump);
    408.  
    409.                 // Get the direction from the Normal map
    410.                 uvWind.x += _Time.y * _WaveSpeed / 10;
    411.                 uvWind.y += _Time.y * (0.5*_WaveSpeed) / 10;
    412.                 fixed4 n = tex2Dlod(_WaveBump, float4(uvWind, 0, 1));
    413.                 float3 waveNormal = UnpackNormal(n) - (float3(0.5,0,0.5)); //unpacks from dxt5nm to rgb
    414.                 float windEffectMultiplier = _WaveSpeed;
    415.  
    416.                 Out.worldPos = mul(unity_ObjectToWorld, center).xyz;
    417.                 Out.color = color;
    418.                 Out.originalCenter = IN[0].originalCenter;
    419.  
    420.                 // Build the straws:
    421.                 int layers = 4;
    422.                 [unroll]
    423.                 for(int i = 0; i < layers; i++)
    424.                 {
    425.                     float percent = (float)i / layers;
    426.  
    427.                     float3 movement = waveNormal * pow(percent,2);
    428.                     float3 movedCenter = center + (movement * windEffectMultiplier);
    429.  
    430.                     float3 p1 = movedCenter - rightSide + (upPoint * percent);
    431.                     float3 p2 = movedCenter + rightSide + (upPoint * percent);
    432.                     float3 movedCenter2 = CalculateWind(center, waveNormal, ((float)(i + 1) / layers), windEffectMultiplier);
    433.                     float3 p3 = movedCenter2 - rightSide + (upPoint * ((float)(i+1) / layers));
    434.                     float3 p4 = movedCenter2 + rightSide + (upPoint * ((float)(i+1) / layers));
    435.  
    436.                     Out.pos = UnityObjectToClipPos(p1);
    437.                     Out.uv = float2(0, percent);
    438.                     Out.layerHeight = percent;
    439.                     Out.windEffect = saturate(pow(length(float2(waveNormal.x,waveNormal.z)),2));
    440.                     Out.normal = normalize(normal + waveNormal * 0.2);
    441.                     TRANSFER_SHADOW(Out);
    442.                     UNITY_TRANSFER_FOG(Out, Out.pos);
    443.                     TRANSFER_VERTEX_TO_FRAGMENT(Out);
    444.                     stream.Append(Out);
    445.  
    446.                     Out.pos = UnityObjectToClipPos(p2);
    447.                     Out.uv = float2(1, percent);
    448.                     TRANSFER_SHADOW(Out);
    449.                     UNITY_TRANSFER_FOG(Out, Out.pos);
    450.                     TRANSFER_VERTEX_TO_FRAGMENT(Out);
    451.                     stream.Append(Out);
    452.  
    453.                     percent = ((float)i+1) / layers;
    454.                     movement = waveNormal * pow(percent, 2);
    455.                     movedCenter = center + (movement * windEffectMultiplier);
    456.  
    457.                     Out.pos= UnityObjectToClipPos(p3);
    458.                     Out.layerHeight = percent;
    459.                     TRANSFER_SHADOW(Out);
    460.                     UNITY_TRANSFER_FOG(Out, Out.pos);
    461.                     TRANSFER_VERTEX_TO_FRAGMENT(Out);
    462.                     Out.uv = float2(0, percent);
    463.                     stream.Append(Out);
    464.                    
    465.                     Out.pos = UnityObjectToClipPos(p4);
    466.                     Out.uv = float2(1, percent);
    467.                     TRANSFER_SHADOW(Out);
    468.                     UNITY_TRANSFER_FOG(Out, Out.pos);
    469.                     TRANSFER_VERTEX_TO_FRAGMENT(Out);
    470.                     stream.Append(Out);
    471.  
    472.                     stream.RestartStrip();
    473.                 }
    474.  
    475.  
    476.             }
    477.  
    478.             sampler2D _GrassTex;
    479.             float4 _GrassTex_ST;
    480.  
    481.             sampler2D _VariationTex;
    482.  
    483.             float4 _GrassColor;
    484.             float4 _WaveColor;
    485.             float4 _Tiles;
    486.             float _VariationAmount;
    487.  
    488.             float4 CalculateLighting(G2P i, float4 colorIn)
    489.             {
    490.                 float shadingMultiplier = clamp(dot(float4(i.normal, 1), _WorldSpaceLightPos0), 0, 1);
    491.                 float4 shadedColor = colorIn * shadingMultiplier * _LightColor0;
    492.                
    493.  
    494.                 fixed atten = LIGHT_ATTENUATION(i);
    495.                 shadedColor *= atten;
    496.  
    497.                 /*half shadow = SHADOW_ATTENUATION(i);
    498.                 shadedColor *= shadow;*/
    499.  
    500.                 //_WorldSpaceLightPos0
    501.                 shadedColor = lerp(colorIn, shadedColor, 0.9);
    502.                
    503.  
    504.                 return shadedColor;
    505.             }
    506.  
    507.             float4 PSMain(G2P i) : SV_Target
    508.             {
    509.                 fixed4 col = tex2D(_GrassTex, saturate(i.uv));
    510.                
    511.                 uint variation = floor(Random(i.originalCenter.xyz) * 18 ) - floor(Random(i.originalCenter.xyz + 1) * lerp(4000,9,_VariationAmount));
    512.                 float2 varUV = GetSpriteSheetUV(i.uv, variation, round(_Tiles.xy));
    513.                 if (variation > 0.3)
    514.                 {
    515.                     col = tex2D(_VariationTex, saturate(varUV));
    516.                 }
    517.  
    518.                 clip(col.a - 0.6);
    519.                 if (variation <= 0.3)
    520.                 {
    521.                     float greyLevel = length(col.xyz);
    522.                     col.xyz = greyLevel;
    523.                     col.xyz = lerp(_GrassColor, _WaveColor, saturate(i.windEffect - 0.5));
    524.                 }
    525.  
    526.                 //col.a = i.transparency;
    527.                 col.xyz *= lerp(_LightAtBottom, 1, i.layerHeight);
    528.                 col.xyz = CalculateLighting(i, col);
    529.                 UNITY_APPLY_FOG(i.fogCoord, col);
    530.  
    531.                 return col;
    532.             }
    533.             ENDCG
    534.         }
    535.         ///////////////////////////////////////////////////////////////////////////////////////////////////
    536.         Pass // Shadow Caster
    537.         {
    538.             Name "ShadowCaster"
    539.             Tags
    540.             {
    541.                 "LightMode" = "ShadowCaster"
    542.                 "IgnoreProjector" = "True"
    543.             }
    544.             LOD 50
    545.             Cull Off
    546.             ZWrite On
    547.             ZTest LEqual
    548.  
    549.             CGPROGRAM
    550.  
    551.             #pragma vertex Vert
    552.             #pragma hull Hull
    553.             #pragma domain Domain
    554.             #pragma require geometry
    555.             #pragma geometry Geom
    556.             #pragma fragment PSMain
    557.             #pragma target 5.0
    558.  
    559.             #pragma multi_compile_fog
    560.             #include "UnityCG.cginc"
    561.             #pragma multi_compile_fwdbase
    562.             #include "AutoLight.cginc"
    563.             #include "Lighting.cginc"
    564.             #include "UnityLightingCommon.cginc"
    565.             #pragma multi_compile_shadowcaster
    566.             #pragma multi_compile _ _MAIN_LIGHT_SHADOWS
    567.             #pragma multi_compile _ _MAIN_LIGHT_SHADOWS_CASCADE
    568.             #pragma multi_compile _ _SHADOWS_SOFT
    569.  
    570.             //------------       Helper functions     ---------------------//
    571.  
    572.             float Random(float3 st)
    573.             {
    574.                 return frac(sin(dot(st,float3(2.9898,5.2332453, -3.17408954376))) * 5.94215 /*43758.5453123*/);
    575.             }
    576.  
    577.             float PI = 3.1415926535897932384626433832795;
    578.  
    579.             float4 setAxisAngle(float3 axis, float rad)
    580.             {
    581.                 rad = rad * 0.5;
    582.                 float s = sin(rad);
    583.                 return float4(s * axis[0], s * axis[1], s * axis[2], cos(rad));
    584.             }
    585.  
    586.             float3 xUnitVec3 = float3(1.0, 0.0, 0.0);
    587.             float3 yUnitVec3 = float3(0.0, 1.0, 0.0);
    588.  
    589.             float4 rotationTo(float3 a, float3 b)
    590.             {
    591.                 float vecDot = dot(a, b);
    592.                 float3 tmpvec3 = float3(0, 0, 0);
    593.                 if (vecDot < -0.999999)
    594.                 {
    595.                     tmpvec3 = cross(xUnitVec3, a);
    596.                     if (length(tmpvec3) < 0.000001)
    597.                     {
    598.                         tmpvec3 = cross(yUnitVec3, a);
    599.                     }
    600.                     tmpvec3 = normalize(tmpvec3);
    601.                     return setAxisAngle(tmpvec3, PI);
    602.                 }
    603.                 else if (vecDot > 0.999999)
    604.                 {
    605.                     return float4(0,0,0,1);
    606.                 }
    607.                 else
    608.                 {
    609.                     tmpvec3 = cross(a, b);
    610.                     float4 _out = float4(tmpvec3[0], tmpvec3[1], tmpvec3[2], 1.0 + vecDot);
    611.                     return normalize(_out);
    612.                 }
    613.             }
    614.  
    615.             float4 multQuat(float4 q1, float4 q2)
    616.             {
    617.               return float4(
    618.                 q1.w * q2.x + q1.x * q2.w + q1.z * q2.y - q1.y * q2.z,
    619.                 q1.w * q2.y + q1.y * q2.w + q1.x * q2.z - q1.z * q2.x,
    620.                 q1.w * q2.z + q1.z * q2.w + q1.y * q2.x - q1.x * q2.y,
    621.                 q1.w * q2.w - q1.x * q2.x - q1.y * q2.y - q1.z * q2.z
    622.               );
    623.             }
    624.  
    625.             float3 rotateVector(float4 quat, float3 vec)
    626.             {
    627.                 //https://twistedpairdevelopment.wordpress.com/2013/02/11/rotating-a-vector-by-a-quaternion-in-glsl/
    628.                 float4 qv = multQuat(quat, float4(vec, 0.0));
    629.                 return multQuat(qv, float4(-quat.x, -quat.y, -quat.z, quat.w)).xyz;
    630.             }
    631.  
    632.             float2 GetSpriteSheetUV(float2 uvIn, int tileTarget, int2 size)
    633.             {
    634.                 float sizeX = (1.0 / size.x);
    635.                 float sizeY = (1.0 / size.y);
    636.  
    637.                 int indexX = tileTarget % size.x;
    638.                 int indexY = tileTarget / size.y;
    639.  
    640.                 float x = (sizeX * uvIn.x) + (indexX * sizeX);
    641.                 float y = (sizeY * uvIn.y) + (indexY * sizeY);
    642.                 return float2(x, y);
    643.             }
    644.  
    645.  
    646.             inline double snap(double original, int numerator, int denominator)
    647.             {
    648.                 return round(original * denominator / numerator) * numerator / denominator;
    649.             }
    650.             //--------------------------------------------------------------
    651.  
    652.  
    653.             struct Appdata
    654.             {
    655.                 float4 vertex : POSITION;
    656.                 float2 uv : TEXCOORD0;
    657.                 float3 normal : NORMAL;
    658.                 float4 tangent : TANGENT;
    659.                 float2 specialData1 : TEXCOORD6;
    660.                 float2 specialData2 : TEXCOORD7;
    661.             };
    662.  
    663.             struct V2G
    664.             {
    665.                 float4 vertex : POSITION;
    666.                 float2 uv : TEXCOORD0;
    667.                 float3 normal : NORMAL;
    668.                 float4 color : COLOR0;
    669.                 float4 specialData : BINORMAL1;
    670.                 float4 originalCenter : COLOR2;
    671.             };
    672.  
    673.             struct G2P
    674.             {
    675.                 float4 pos : SV_POSITION;
    676.                 float2 uv : TEXCOORD0;
    677.                 float layerHeight : BLENDWEIGHT0;
    678.                 float windEffect : BLENDWEIGHT1;
    679.                 float3 worldPos : COLOR0;
    680.                 float4 originalCenter : COLOR2;
    681.             };
    682.  
    683.             V2G Vert(Appdata i)
    684.             {
    685.                 V2G o;
    686.                 o.vertex = i.vertex;
    687.                 o.uv = i.uv;
    688.                 o.normal = i.normal;
    689.                 o.color = 0;
    690.                 o.specialData = float4(i.specialData1, i.specialData2);
    691.                 o.originalCenter = i.vertex;
    692.                 return o;
    693.             }
    694.  
    695.             float _TessellationFactor;
    696.             float _QuadSize;
    697.             float _MaxDist;
    698.             float _GrassWidth, _GrassHeight;
    699.             float _LightAtBottom;
    700.  
    701.             void constantsHS(InputPatch<V2G,3> V, out float edge[3]:SV_TessFactor, out float inside : SV_InsideTessFactor)
    702.             {
    703.                 float4 localCameraPos = mul(unity_WorldToObject, float4(_WorldSpaceCameraPos,1));
    704.  
    705.                 edge[0] = (1 - saturate(distance(localCameraPos, V[0].vertex) / _MaxDist)) * _TessellationFactor;
    706.                 edge[1] = (1 - saturate(distance(localCameraPos, V[1].vertex) / _MaxDist)) * _TessellationFactor;
    707.                 edge[2] = (1 - saturate(distance(localCameraPos, V[2].vertex) / _MaxDist)) * _TessellationFactor;
    708.                 float4 center = (V[0].vertex + V[1].vertex + V[2].vertex) / 3;
    709.                 inside = (1 - saturate(distance(mul(unity_WorldToObject,center),_WorldSpaceCameraPos) / _MaxDist)) * _TessellationFactor;//_TessellationFactor;
    710.             }
    711.  
    712.             [domain("tri")]
    713.             //[partitioning("integer")]
    714.             [outputtopology("triangle_cw")]
    715.             [UNITY_partitioning("fractional_odd")]
    716.             [patchconstantfunc("constantsHS")]
    717.             [outputcontrolpoints(3)]
    718.             V2G Hull(InputPatch<V2G,3> V, uint ID : SV_OutputControlPointID)
    719.             {
    720.                 return V[ID];
    721.             }
    722.  
    723.             [domain("tri")]
    724.             V2G Domain(float edge[3]:SV_TessFactor, float inside : SV_InsideTessFactor, const OutputPatch<V2G,3> P, float3 K : SV_DomainLocation)
    725.             {
    726.                 V2G o;
    727.                 o.vertex = float4(P[0].vertex.xyz * K.x + P[1].vertex.xyz * K.y + P[2].vertex.xyz * K.z, 1.0);
    728.                 o.uv = float2((P[0].uv * K.x + P[1].uv * K.y + P[2].uv * K.z) / 3);
    729.                 o.normal = float3(P[0].normal * K.x + P[1].normal * K.y + P[2].normal * K.z);
    730.                 o.color = float4(P[0].color.xyz * K.x + P[1].color.xyz * K.y + P[2].color.xyz * K.z, 1.0);
    731.                 o.specialData = P[0].specialData;
    732.                 o.originalCenter = (P[0].vertex + P[1].vertex + P[2].vertex) / 3;
    733.                 return o;
    734.             }
    735.  
    736.             sampler2D _WaveBump;
    737.             float4 _WaveBump_ST;
    738.  
    739.             float3 CalculateWind(float3 center, float3 waveNormal, float percent, float windEffectMultiplier)
    740.             {
    741.                 float3 movement = waveNormal * percent * percent;
    742.                 float3 movedCenter = center + (movement * windEffectMultiplier);
    743.                 return movedCenter;
    744.             }
    745.  
    746.             float _WaveSpeed;
    747.  
    748.             [maxvertexcount(64)]
    749.             void Geom(triangle V2G IN[3], inout TriangleStream<G2P> stream)
    750.             {
    751.                 G2P Out;
    752.  
    753.  
    754.                 Out.originalCenter = IN[0].originalCenter;
    755.  
    756.                 //Add the normal first 3 verts as well in the shadow caster pass;
    757.                 int limit = 3;
    758.                 [unroll]
    759.                 for (int k = 0; k < limit; k++)
    760.                 {
    761.                     Out.pos = UnityObjectToClipPos( IN[k].vertex);
    762.                     Out.uv =  IN[k].uv;
    763.  
    764.                     Out.worldPos = mul(unity_ObjectToWorld, IN[k].vertex).xyz;
    765.  
    766.                     Out.layerHeight = -10;
    767.                     Out.windEffect = 0;
    768.                     Out.originalCenter = IN[k].originalCenter;
    769.                     TRANSFER_SHADOW(Out);
    770.                     UNITY_TRANSFER_FOG(Out, Out.pos);
    771.                     TRANSFER_VERTEX_TO_FRAGMENT(Out);
    772.                     stream.Append(Out);
    773.                 }
    774.                 stream.RestartStrip();
    775.                 //return;
    776.  
    777.                 if ((int)IN[0].specialData != 1 ||
    778.                     (int)IN[1].specialData != 1 ||
    779.                     (int)IN[2].specialData != 1)
    780.                     return;
    781.  
    782.                 float3 center = float3((IN[0].vertex.xyz + IN[1].vertex.xyz + IN[2].vertex.xyz) / 3);
    783.                 float3 normal = float3((IN[0].normal + IN[1].normal + IN[2].normal) / 3);
    784.                 float2 uv = float2((IN[0].uv + IN[1].uv + IN[2].uv) / 3);
    785.                 float4 color = float4((IN[0].color + IN[1].color + IN[2].color) / 3);
    786.  
    787.                 float distToCam = distance(_WorldSpaceCameraPos, mul(unity_ObjectToWorld, center));
    788.                 float grassWidth = _GrassWidth + ((distToCam / _MaxDist) * _GrassWidth * 3);
    789.  
    790.                 float3 up = float3(0, 1, 0);
    791.                 float3 right = float3(1, 0, 0);
    792.  
    793.                 float3 snappedCenter = float3(snap(center.x, 1, 10), snap(center.y, 1, 10), snap(center.z, 1, 10));
    794.  
    795.                 float randomRotAngle = Random(snappedCenter) * 360.0;
    796.                 right = rotateVector(setAxisAngle(up, radians(randomRotAngle)), right);
    797.  
    798.                 float grassHeight = Random(snappedCenter) * 2 * _GrassHeight;
    799.  
    800.                 // First point :
    801.                 float3 rightSide = (right * grassWidth * 0.5);
    802.                 float3 upPoint = (up * grassHeight);
    803.  
    804.                 float2 uvWind = TRANSFORM_TEX(uv, _WaveBump);
    805.  
    806.                 // Get the direction from the Normal map
    807.                 uvWind.x += _Time.y * _WaveSpeed / 10;
    808.                 uvWind.y += _Time.y * (0.5 * _WaveSpeed) / 10;
    809.                 fixed4 n = tex2Dlod(_WaveBump, float4(uvWind, 0, 1));
    810.                 float3 waveNormal = UnpackNormal(n) - (float3(0.5, 0, 0.5)); //unpacks from dxt5nm to rgb
    811.                 float windEffectMultiplier = _WaveSpeed;
    812.  
    813.                 Out.worldPos = mul(unity_ObjectToWorld, center).xyz;
    814.  
    815.                 // Build the straws:
    816.                 int layers = 4;
    817.                 [unroll]
    818.                 for (int i = 0; i < layers; i++)
    819.                 {
    820.                     float percent = (float)i / layers;
    821.  
    822.                     float3 movement = waveNormal * pow(percent, 2);
    823.                     float3 movedCenter = center + (movement * windEffectMultiplier);
    824.  
    825.                     float3 p1 = movedCenter - rightSide + (upPoint * percent);
    826.                     float3 p2 = movedCenter + rightSide + (upPoint * percent);
    827.                     float3 movedCenter2 = CalculateWind(center, waveNormal, ((float)(i + 1) / layers), windEffectMultiplier);
    828.                     float3 p3 = movedCenter2 - rightSide + (upPoint * ((float)(i + 1) / layers));
    829.                     float3 p4 = movedCenter2 + rightSide + (upPoint * ((float)(i + 1) / layers));
    830.  
    831.                     Out.pos = UnityObjectToClipPos(p1);
    832.                     Out.uv = float2(0, percent);
    833.                     Out.layerHeight = percent;
    834.                     Out.windEffect = saturate(pow(length(float2(waveNormal.x, waveNormal.z)), 2));
    835.                     //Out.normal = normalize(normal + waveNormal * 0.2);
    836.                     TRANSFER_SHADOW(Out);
    837.                     UNITY_TRANSFER_FOG(Out, Out.pos);
    838.                     TRANSFER_VERTEX_TO_FRAGMENT(Out);
    839.                     stream.Append(Out);
    840.  
    841.                     Out.pos = UnityObjectToClipPos(p2);
    842.                     Out.uv = float2(1, percent);
    843.                     TRANSFER_SHADOW(Out);
    844.                     UNITY_TRANSFER_FOG(Out, Out.pos);
    845.                     TRANSFER_VERTEX_TO_FRAGMENT(Out);
    846.                     stream.Append(Out);
    847.  
    848.                     percent = ((float)i + 1) / layers;
    849.                     movement = waveNormal * pow(percent, 2);
    850.                     movedCenter = center + (movement * windEffectMultiplier);
    851.  
    852.                     Out.pos = UnityObjectToClipPos(p3);
    853.                     Out.layerHeight = percent;
    854.                     TRANSFER_SHADOW(Out);
    855.                     UNITY_TRANSFER_FOG(Out, Out.pos);
    856.                     TRANSFER_VERTEX_TO_FRAGMENT(Out);
    857.                     Out.uv = float2(0, percent);
    858.                     stream.Append(Out);
    859.  
    860.                     Out.pos = UnityObjectToClipPos(p4);
    861.                     Out.uv = float2(1, percent);
    862.                     TRANSFER_SHADOW(Out);
    863.                     UNITY_TRANSFER_FOG(Out, Out.pos);
    864.                     TRANSFER_VERTEX_TO_FRAGMENT(Out);
    865.                     stream.Append(Out);
    866.  
    867.                     stream.RestartStrip();
    868.                 }
    869.  
    870.  
    871.             }
    872.  
    873.             sampler2D _GrassTex;
    874.             float4 _GrassTex_ST;
    875.             sampler2D _VariationTex;
    876.             float4 _Tiles;
    877.             float _VariationAmount;
    878.  
    879.             float4 PSMain(G2P i) : SV_Target
    880.             {
    881.                
    882.                 if (i.layerHeight <= 0)
    883.                 {
    884.                     return 1;
    885.                 }
    886.                 else
    887.                 {
    888.                    
    889.                     fixed4 col = tex2D(_GrassTex, saturate(i.uv));
    890.  
    891.                     uint variation = floor(Random(i.originalCenter.xyz) * 18) - floor(Random(i.originalCenter.xyz + 1) * lerp(4000, 9, _VariationAmount));
    892.                     float2 varUV = GetSpriteSheetUV(i.uv, variation, round(_Tiles.xy));
    893.                     if (variation > 0.3)
    894.                     {
    895.                         col = tex2D(_VariationTex, saturate(varUV));
    896.                     }
    897.                     clip(col.a - 0.6);
    898.  
    899.                 }
    900.  
    901.                 return 1;
    902.  
    903.             }
    904.             ENDCG
    905.         }
    906.  
    907.     }
    908.     Fallback "Diffuse"
    909. }
    upload_2021-11-27_22-22-48.png