Search Unity

Problems with popular grass shader tutorial...!

Discussion in 'Shaders' started by Reverend-Speed, Sep 15, 2019.

  1. Reverend-Speed

    Reverend-Speed

    Joined:
    Mar 28, 2011
    Posts:
    284
    Hey folks,

    I'm trying to follow this tutorial, but I'm running into problems.. can anybody suggest a solution?

    I'm supposed to be getting a response like this...

    ...but instead, my model is showing up as this:


    I assume this is to do with the relative positions of the origins on the respective models. Presuming this is to do with world origins... but trying to subtract -5 from the normalised values seems to do very little.
    My code is as follows...

    Code (CSharp):
    1. Shader "RS/LRGrass"
    2. {
    3.     Properties
    4.     {
    5.         _Color        ("Color", Color)            = (1,1,1,1)
    6.         _MainTex    ("Albedo (RGB)", 2D)        = "white" {}
    7.         _Glossiness ("Smoothness", Range(0,1))    = 0.5
    8.         _Metallic    ("Metallic", Range(0,1))    = 0.0
    9.  
    10.         _WindTex ("Wind Texture", 2D) = "white" {}
    11.         _WorldSize    ("World Size", vector)        = (1,1,1,1)
    12.         _WindSpeed ("Wind Speed", vector)        = (1,1,1,1)
    13.     }
    14.     SubShader
    15.     {
    16.         Tags { "RenderType"="Opaque" }
    17.         LOD 200
    18.  
    19.         Pass
    20.         {
    21.             CGPROGRAM
    22.  
    23.             #pragma vertex vert
    24.             #pragma fragment frag
    25.            
    26.             struct vertexInput
    27.             {
    28.                 float4 vertex : POSITION;
    29.                 float3 normal : NORMAL;
    30.             };
    31.  
    32.             struct vertexOutput
    33.             {
    34.                 float4 pos : SV_POSITION;
    35.                 float3 normal : NORMAL;
    36.                 float2 sp : TEXCOORD0; //Test sample position
    37.             };
    38.  
    39.             sampler2D    _WindTex;
    40.             vector        _WorldSize;
    41.             vector        _WindSpeed;
    42.  
    43.             vertexOutput vert(vertexInput input)
    44.             {
    45.                 vertexOutput output;
    46.  
    47.                 // convert input to clip and world space
    48.                 output.pos        = UnityObjectToClipPos(input.vertex);
    49.                 float4 normal4    = float4(input.normal, 0.0f);
    50.                 output.normal    = normalize(mul(normal4, unity_WorldToObject).xyz);
    51.  
    52.                 // get vertex world position
    53.                 float4 worldPos = mul(input.vertex, unity_ObjectToWorld);
    54.                 // normalize position based on world Size
    55.                 float2 samplePos = worldPos.xz / _WorldSize.xz;
    56.  
    57.                 // scroll sample position based on time
    58.                 // samplePos += _Time.x * _WindSpeed.xy;
    59.  
    60.                 // Sample wind texture
    61.                 //float windSample = tex2Dlod (_WindTex, float4(samplePos, 0, 0));
    62.  
    63.                 output.sp = samplePos; // Test sample position.
    64.  
    65.                
    66.  
    67.                 return output;
    68.             };
    69.            
    70.             float4 frag (vertexOutput input) : COLOR
    71.             {
    72.                 return float4(input.sp.x, 0, 0, 1); // Temporary measure!
    73.             };
    74.  
    75.             ENDCG
    76.         }
    77.  
    78.         /*
    79.         CGPROGRAM
    80.         // Physically based Standard lighting model, and enable shadows on all light types
    81.         #pragma surface surf Standard fullforwardshadows
    82.        
    83.         // Use shader model 3.0 target, to get nicer looking lighting
    84.         #pragma target 3.0
    85.  
    86.         sampler2D _MainTex;
    87.  
    88.         struct Input
    89.         {
    90.             float2 uv_MainTex;
    91.         };
    92.  
    93.         half _Glossiness;
    94.         half _Metallic;
    95.         fixed4 _Color;
    96.  
    97.         // Add instancing support for this shader. You need to check 'Enable Instancing' on materials that use the shader.
    98.         // See https://docs.unity3d.com/Manual/GPUInstancing.html for more information about instancing.
    99.         // #pragma instancing_options assumeuniformscaling
    100.         UNITY_INSTANCING_BUFFER_START(Props)
    101.             // put more per-instance properties here
    102.         UNITY_INSTANCING_BUFFER_END(Props)
    103.  
    104.         void surf (Input IN, inout SurfaceOutputStandard o)
    105.         {
    106.             // Albedo comes from a texture tinted by color
    107.             fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
    108.             o.Albedo = c.rgb;
    109.             // Metallic and smoothness come from slider variables
    110.             o.Metallic = _Metallic;
    111.             o.Smoothness = _Glossiness;
    112.             o.Alpha = c.a;
    113.         }
    114.         ENDCG
    115.         */
    116.     }
    117.     FallBack "Diffuse"
    118. }
    119.  
    Can anybody help me out with this? Really confused here and I'd like to have it sorted soon...!
     
  2. gamedevbill

    gamedevbill

    Joined:
    May 25, 2018
    Posts:
    43
    From my tests, the matrix and vertex need to switch order in the multiply, to this:

    mul(unity_ObjectToWorld, input.vertex);

    Perhaps Linden's graphics settings are different, or it's a typo.

    Also note that in his image, all his grass starts at a positive coordinate. The scale multiply only adjusts for size of scene, does not fix things being negative.

    Good luck
    gdb
    gamedevbill.com
     
    Last edited: Nov 16, 2019
  3. DrDust265

    DrDust265

    Joined:
    Apr 5, 2013
    Posts:
    3
  4. Reverend-Speed

    Reverend-Speed

    Joined:
    Mar 28, 2011
    Posts:
    284
    Hey folks, I'm aware that it's almost a month after my initial posts, but I figured I'd post the solution we went with for our project - just in case anybody else is looking for resources on this topic (it was a pain in the ass for me!). Credit goes to our awesome guest programmer, who I'll mention properly if I get permission.

    It's a bit of a mess, but our shader code was as follows...
    Code (CSharp):
    1. // Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'
    2.  
    3. Shader "RS/WindGrassRS"
    4. {
    5.     Properties
    6.     {
    7.         // Surface shader parameters
    8.         _Color                ("Color", Color)                    = (1,1,1,1)
    9.         _EmColor            ("Emission Color", Color)            = (1,1,1,1)
    10.         // _MainTex            ("Albedo (RGB)", 2D)                = "white" {}
    11.         _Glossiness            ("Smoothness", Range(0,1))            = 0.5
    12.         _Metallic            ("Metallic", Range(0,1))            = 0.0
    13.         // Wind effect parameters
    14.         _WindDirection        ("Wind Direction", vector)            = (1,0, 1,0)
    15.  
    16.         _WindTex            ("Wind Texture", 2D)                = "white" {}
    17.         _WorldSize            ("World Size", vector)                = (1,1,1,1)
    18.         _WindSpeed            ("Wind Speed", vector)                = (1,1,1,1)
    19.  
    20.         _OverallBillowEffect("Overall Billow Effect", Range(0,1))= 0.0
    21.  
    22.         //--- TRIPLANAR STUFF ---//
    23.  
    24.         _Texture1            ("Texture 1", 2D)                    = "white" {}
    25.         _Texture2            ("Texture 2", 2D)                    = "white" {}
    26.         _Texture3            ("Texture 3", 2D)                    = "white" {}
    27.         _Scale                ("Scale", Range(0.001, 0.2))        = 0.1
    28.  
    29.         //--- OUTLINE STUFF ---//
    30.         //_Outline            ("_Outline", Range(0,0.1))            = 0
    31.         //_OutlineColor        ("Outline Color", Color)                    = (1, 1, 1, 1)
    32.  
    33.         //--- DISSOLVE STUFF ---//
    34.         _SliceGuide            ("Slice Guide (RGB)", 2D)            = "white" {}
    35.         _SliceAmount        ("Slice Amount", Range(0.0, 1.0))    = 0.5
    36.  
    37.         _PercentSeaweed     ("Percentage Seaweed", float)       = 1
    38.         _PercentStormy      ("Percentage Stormy", float)        = 0
    39.         _PercentBreathing   ("Percentage Breathing", float)     = 0
    40.     }
    41.  
    42.  
    43.     SubShader
    44.     {
    45.         Tags {"RenderType" = "Opaque"}
    46.      
    47.         //Cull Front
    48.         //Cull Off // DISSOLVE STUFF!
    49.  
    50.         LOD 200
    51.         CGPROGRAM
    52. /*
    53.         Pass {
    54.             Tags { "RenderType"="Opaque" }
    55.             Cull Front
    56.  
    57.             CGPROGRAM
    58.             #pragma vertex vert
    59.             #pragma fragment frag
    60.             #include "UnityCG.cginc"
    61.             struct v2f {
    62.                 float4 pos : SV_POSITION;
    63.             };
    64.             float _Outline;
    65.             float4 _OutlineColor;
    66.             float4 vert(appdata_base v) : SV_POSITION {
    67.                 v2f o;
    68.                 o.pos = UnityObjectToClipPos(v.vertex);
    69.                 float3 normal = mul((float3x3) UNITY_MATRIX_MV, v.normal);
    70.                 normal.x *= UNITY_MATRIX_P[0][0];
    71.                 normal.y *= UNITY_MATRIX_P[1][1];
    72.                 o.pos.xy += normal.xy * _Outline;
    73.                 return o.pos;
    74.             }
    75.             half4 frag(v2f i) : COLOR {
    76.                 return _OutlineColor;
    77.             }
    78.             ENDCG
    79.         }
    80.         */
    81.  
    82.         #pragma surface surf Standard vertex:vert
    83.        
    84.         struct Input
    85.         {
    86.             // float2 uv_MainTex;
    87.  
    88.             //--- TRIPLANAR STUFF ---//
    89.  
    90.             float3 worldNormal;
    91.             float3 worldPos;
    92.  
    93.             //--- DISSOLVE STUFF ---//
    94.             //float2 uv_SliceGuide;
    95.             //float _SliceAmount;
    96.  
    97.             //--- VAINS ---//
    98.             float3 localPos; // Local position of vertex
    99.             float electricalOffset;
    100.         };
    101.         //sampler2D    _MainTex;
    102.         half        _Glossiness;
    103.         half        _Metallic;
    104.         fixed4        _Color;
    105.         fixed4        _EmissionColor;
    106.         float3        _WindDirection;
    107.  
    108.         sampler2D    _WindTex;
    109.         float4      _WorldSize;
    110.         float4        _WindSpeed;
    111.  
    112.         float        _OverallBillowEffect;
    113.  
    114.         //--- TRIPLANAR STUFF ---//
    115.         sampler2D    _Texture1;
    116.         sampler2D    _Texture2;
    117.         sampler2D    _Texture3;
    118.         float        _Scale;
    119.  
    120.         //--- DISSOLVE STUFF ---//
    121.         sampler2D    _SliceGuide;
    122.         float        _SliceAmount;
    123.  
    124.         float       _PercentSeaweed;
    125.         float       _PercentStormy;
    126.         float       _PercentBreathing;
    127.  
    128.         // our vert modification function
    129.         void vert(inout appdata_full v, out Input o) // TODO: Add in out Input o...
    130.         {
    131.             UNITY_INITIALIZE_OUTPUT(Input, o);
    132.             o.localPos = v.vertex.xyz;
    133.  
    134.             float4 localSpaceVertex = v.vertex;
    135.             // Takes the mesh's verts and turns it into a point in world space
    136.             // this is the equivalent of Transform.TransformPoint on the scripting side
    137.             float4 worldSpaceVertex = mul( unity_ObjectToWorld, localSpaceVertex );
    138.             // normalize position based on world Size
    139.             float2 samplePos = ((worldSpaceVertex.xz + _WorldSize.xz/2) / _WorldSize.xz);
    140.  
    141.             // scroll sample position based on time
    142.             samplePos += _Time.x * _WindSpeed.xy;
    143.  
    144.             // Sample wind texture
    145.             const float da = 0.05;
    146.             float windSample = tex2Dlod(_WindTex, float4(samplePos, 0, 0));
    147.             windSample += tex2Dlod(_WindTex, float4(samplePos.x + da, samplePos.y, 0, 0));
    148.             windSample += tex2Dlod(_WindTex, float4(samplePos.x, samplePos.y + da, 0, 0));
    149.             windSample += tex2Dlod(_WindTex, float4(samplePos.x - da, samplePos.y, 0, 0));
    150.             windSample += tex2Dlod(_WindTex, float4(samplePos.x, samplePos.y - da, 0, 0));
    151.             windSample /= 5;
    152.  
    153.  
    154.             // windSample = sin(_Time.x * 10); // TESTING: Shows that it is the windsample that's screwing it up :c.
    155.          
    156.             worldSpaceVertex.x += (windSample * _WindDirection.x * v.color) * _OverallBillowEffect;
    157.             worldSpaceVertex.z += (windSample * _WindDirection.z * v.color) * _OverallBillowEffect;
    158.             // takes the new modified position of the vert in world space and then puts it back in local space
    159.             v.vertex = mul( unity_WorldToObject, worldSpaceVertex );
    160.  
    161.             // Stuff for vains
    162.  
    163.             float2 samplePos2 = ((worldSpaceVertex.xz + _WorldSize.xz / 2) / _WorldSize.xz);
    164.             o.electricalOffset = tex2Dlod(_WindTex, float4(samplePos2, 0, 0));
    165.          
    166.  
    167.             //float2 modelPos = mul(float4(0, 0, 0, 1), unity_ObjectToWorld).xz / _WorldSize.xz;
    168.             //o.electricalOffset = (tex2Dlod(_WindTex, float4(modelPos, 0, 0)) + _Time.x)  % 1;
    169.         }
    170.  
    171.         float getLightVal(float3 p1, float3 p2, Input IN) {
    172.             // Unpacking vects
    173.             float offsetMult = p1.x, freq = p1.y, timePercOutside = p1.z;
    174.             float numWaves = p2.x;
    175.             float sinMult = p2.y, sinAdd = p2.z;
    176.  
    177.             // Parametric func
    178.             float off = (IN.electricalOffset*offsetMult + _Time.x * freq / timePercOutside) * timePercOutside;
    179.             float t = -IN.localPos.y*numWaves + off;
    180.             return clamp(sin(t) * sinMult + sinAdd, 0, 1);
    181.         }
    182.         void surf(Input IN, inout SurfaceOutputStandard o)
    183.         {
    184.  
    185.  
    186.             //--- TRIPLANAR STUFF ---//
    187.             //fixed4 col1 = tex2D(_Texture2, IN.worldPos.yz * _Scale);// * _Color;
    188.             //fixed4 col2 = tex2D(_Texture1, IN.worldPos.xz * _Scale);// * _Color;
    189.             //fixed4 col3 = tex2D(_Texture3, IN.worldPos.xy * _Scale);// * _Color;
    190.  
    191.             fixed4 col1 = tex2D(_Texture2, IN.worldPos.yz * _Scale);// * _Color;
    192.             fixed4 col2 = tex2D(_Texture1, IN.worldPos.xz * _Scale);// * _Color;
    193.             fixed4 col3 = tex2D(_Texture3, IN.worldPos.xy * _Scale);// * _Color;
    194.  
    195.  
    196.             float3 vec = abs(IN.worldNormal);
    197.             vec /= vec.x + vec.y + vec.z + 0.001f;
    198.             fixed4 col = vec.x * col1 + vec.y * col2 + vec.z * col3;
    199.  
    200.             /*
    201.                        fixed4 slice1 = tex2D(_SliceGuide, IN.worldPos.yz * _Scale);
    202.                        fixed4 slice2 = tex2D(_SliceGuide, IN.worldPos.xz * _Scale);
    203.                        fixed4 slice3 = tex2D(_SliceGuide, IN.worldPos.xy * _Scale);
    204.  
    205.                        fixed4 sliceAll = vec.x * slice1 + vec.y * slice2 + vec.z * slice3;
    206.  
    207.                        clip (sliceAll.rgb - _SliceAmount);
    208.                        */
    209.             o.Albedo = col;
    210.             //o.Emission = col + _EmissionColor;
    211.  
    212.             // Metallic and smoothness come from slider variables
    213.             o.Metallic = _Metallic;
    214.             o.Smoothness = _Glossiness;
    215.             o.Alpha = col.a;
    216.  
    217.             // TEMP: Testing for veins - Base version w/ ~2 waves per tree
    218.  
    219.  
    220.             // Sharper waves, visable best from the side. (STORMY)
    221.             //o.Albedo = col / 2;
    222.             //float off = (IN.electricalOffset*3.14 + _Time.x * 3) * 4;
    223.             //float t = -IN.localPos.y / 3.14 + off;
    224.             //o.Emission = col * clamp(sin(t) * 50 - 48.7, 0, 1);
    225.  
    226.  
    227.             // Stormy (kinda)
    228.             //o.Albedo = col / 2;
    229.             //float off = (IN.electricalOffset*3.14 + _Time.x * 7) * 3;  // More 'breathing'
    230.             //float t = -IN.localPos.y /1.5 + off;
    231.             //o.Emission = col * clamp(sin(t) * 2 - 0.8, 0, 1);
    232.  
    233.  
    234.             // SEAWEED
    235.             //o.Albedo = col / 2;
    236.             //float off = (IN.electricalOffset + _Time.x * 40);
    237.             //o.Emission = 0.05 + col * (0.2 + 0.5*sin(-IN.localPos.y*2.3 + off));
    238.  
    239.  
    240.             // SEAWEED (parametric)
    241.             //float offsetMult = 1, freq = 40, timePercOutside = 1;
    242.             //float numWaves = 2.3;
    243.             //float sinMult = 0.5, sinAdd = 0.2;
    244.             const float3 p1W = float3(1, 40, 1);
    245.             const float3 p2W = float3(2.3, 0.5, 0.2);
    246.             float sw = getLightVal(p1W, p2W, IN);
    247.              
    248.             // Stormy (kinda/breathing) (parametric)
    249.             //float offsetMult = 3.14, freq = 21, timePercOutside = 3;
    250.             //float numWaves = 1/1.5;
    251.             //float sinMult = 2, sinAdd = -0.8;
    252.             const float3 p1STB = float3(3.14, 21, 3);
    253.             const float3 p2STB = float3(1 / 1.5, 2, -0.8);
    254.             float stb = getLightVal(p1STB, p2STB, IN);
    255.  
    256.  
    257.             // Stormy (parametric)
    258.             //float offsetMult = 3.14, freq = 12, timePercOutside = 3;
    259.             //float numWaves = 1 / 3.14;
    260.             //float sinMult = 50, sinAdd = -48.7;
    261.             const float3 p1ST = float3(3.14, 12, 3);
    262.             const float3 p2ST = float3(1 / 3.14, 50, -48.7);
    263.             float st = getLightVal(p1ST, p2ST, IN);
    264.  
    265.  
    266.             // Interpolate
    267.             //const float3 p1 = _PercentSeaweed * p1W + _PercentStormy * p1ST + _PercentBreathing * p1STB;
    268.             //const float3 p2 = _PercentSeaweed * p2W + _PercentStormy * p2ST + _PercentBreathing * p2STB;
    269.  
    270.             float brightness = _PercentSeaweed * sw + _PercentStormy * st + _PercentBreathing * stb;
    271.          
    272.          
    273.             // Shader vals...
    274.             o.Albedo = col / 2;
    275.             o.Emission = col * brightness;
    276.         }
    277.         ENDCG
    278.     }
    279.     FallBack "Diffuse"
    280. }
    @gamedevbill - Many thanks for the advice, man! I'm going to sit down and study that now at my leisure!

    @DrDust265 - Really appreciate that, man! That tutorial drove me a little crazy, and I'd appreciate the chance to sit down and really study a fully-working version of the shader.
     
    gamedevbill likes this.