Search Unity

Creating a really good geometry grass shader!

Discussion in 'Shaders' started by markashburner, Mar 21, 2018.

  1. markashburner

    markashburner

    Joined:
    Aug 14, 2015
    Posts:
    212
    Hi

    So I have a fairly simple geometry grass shader that creates an X quad.




    It looks fairly mediocre, not great, I want it to look a lot more natural and realistic.

    I am sure it has something to do with creating an X quad from the grass geometry shader.

    So I have been looking on google on how to create natural looking grass where each individual blade is generated through a HLSL geometry shader.

    I have come across a few tutorials such as these:

    https://www.scribd.com/document/229699570/Nick-Vanheer-Grass-Geometry-Shader

    http://outerra.blogspot.com.au/2016/01/procedural-rendering-performance-test-1.html

    But the code he is using is so alien to the shader code used in Unity.

    So anyway, can anyone give me some tips on creating a natural realistic grass with a geometry shader?

    I don't paticularly like the X quads like this:



    I want it to look more natural like this grass shaders:

    This is from Outtera and I know they use geometry shaders for their grass.



    Can anyone give me any tips or point me in the right direction on how to get a result that's even somewhat remotley closer to the example above?

    Here is the current geometry shader code I am using:

    Code (CSharp):
    1. //------------MODIFIED------------//
    2. //Modified to work with spherical surfaces and added basic lighting
    3.  
    4. // Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'
    5.  
    6. // Upgrade NOTE: replaced '_Object2World' with 'unity_ObjectToWorld'
    7.  
    8. // Low Poly Shader developed as part of World of Zero: http://youtube.com/worldofzerodevelopment
    9. // Based upon the example at: http://www.battlemaze.com/?p=153
    10.  
    11. Shader "Planet/PlanetGrass" {
    12.     Properties{
    13.    
    14.         _MainTex("Albedo (RGB)", 2D) = "white" {}
    15.         _GrassColor ("Color", Color) = (1,1,1,1)
    16.         _Glossiness("Smoothness", Range(0,1)) = 0.5
    17.         _Metallic("Metallic", Range(0,1)) = 0.0
    18.         _Cutoff("Cutoff", Range(0,1)) = 0.25
    19.         _GrassHeight("Grass Height", Range(0,1)) = 0.25
    20.         _GrassWidth("Grass Width", Float) = 0.25
    21.         _WindSpeed("Wind Speed", Float) = 100
    22.         _WindStength("Wind Strength", Float) = 0.05
    23.     }
    24.         SubShader{
    25.         Tags{ "Queue" = "AlphaTest" "IgnoreProjector" = "True" "RenderType" = "TransparentCutout" }
    26.         LOD 200
    27.  
    28.         Pass
    29.     {
    30.  
    31.         CULL OFF
    32.  
    33.         CGPROGRAM
    34. #include "UnityCG.cginc"
    35. #pragma vertex vert
    36. #pragma fragment frag
    37. #pragma geometry geom
    38. //#pragma alphatest : _Cutoff
    39.  
    40.         // Use shader model 4.0 target, we need geometry shader support
    41. #pragma target 4.0
    42.  
    43.         sampler2D _MainTex;
    44.  
    45.     struct v2g
    46.     {
    47.         float4 pos : SV_POSITION;
    48.         float3 norm : NORMAL;
    49.         float2 uv : TEXCOORD0;
    50.         float3 color : TEXCOORD1;
    51.     };
    52.  
    53.     struct g2f
    54.     {
    55.         float4 pos : SV_POSITION;
    56.         float3 norm : NORMAL;
    57.         float2 uv : TEXCOORD0;
    58.         float diffuseLighting : TEXCOORD1;
    59.         //float diffuseLighting;
    60.         //float3 up;
    61.         //float3 specularColor : TEXCOORD2;
    62.     };
    63.  
    64.     half _Glossiness;
    65.     half _Metallic;
    66.  
    67.     fixed4 _GrassColor;
    68.     half _GrassHeight;
    69.     half _GrassWidth;
    70.     half _Cutoff;
    71.     half _WindStength;
    72.     half _WindSpeed;
    73.  
    74.     v2g vert(appdata_full v)
    75.     {
    76.         float3 v0 = v.vertex.xyz;
    77.  
    78.         v2g OUT;
    79.         OUT.pos = v.vertex;
    80.         OUT.norm = v.normal;
    81.         OUT.uv = v.texcoord;
    82.         OUT.color = tex2Dlod(_MainTex, v.texcoord).rgb;
    83.         return OUT;
    84.     }
    85.  
    86.     [maxvertexcount(24)]
    87.     void geom(point v2g IN[1], inout TriangleStream<g2f> triStream)
    88.     {
    89.         float sin30 = 0.5;
    90.         float sin60 = 0.866f;
    91.         float cos30 = sin60;
    92.         float cos60 = sin30;
    93.  
    94.         float3 lightPosition = _WorldSpaceLightPos0;
    95.         float3 perpendicularAngle = cross(IN[0].norm, normalize(float3(0, 1, 0)));
    96.         float3 faceNormal = cross(perpendicularAngle, IN[0].norm);
    97.    
    98.         float3 v0 = IN[0].pos.xyz;
    99.         float3 v1 = IN[0].pos.xyz + IN[0].norm * _GrassHeight;
    100.  
    101.         float3 wind = float3(sin(_Time.x * _WindSpeed + v0.x) + sin(_Time.x * _WindSpeed + v0.z * 2) + sin(_Time.x * _WindSpeed * 0.1 + v0.x), 0,
    102.             cos(_Time.x * _WindSpeed + v0.x * 2) + cos(_Time.x * _WindSpeed + v0.z));
    103.         v1 += wind * _WindStength;
    104.  
    105.         float diffuseLighting = dot(IN[0].norm, normalize(_WorldSpaceLightPos0.xyz));
    106.  
    107.         //float3 color = (IN[0].color * ndotl);
    108.  
    109.    
    110.  
    111.         g2f OUT;
    112.  
    113.         // Quad 1
    114.  
    115.         OUT.pos = UnityObjectToClipPos(v0 + perpendicularAngle * 0.5 * _GrassHeight);
    116.         OUT.norm = faceNormal;
    117.         OUT.diffuseLighting = diffuseLighting;
    118.         OUT.uv = float2(1, 0);
    119.         triStream.Append(OUT);
    120.  
    121.         OUT.pos = UnityObjectToClipPos(v1 + perpendicularAngle * 0.5 * _GrassHeight);
    122.         OUT.norm = faceNormal;
    123.         OUT.diffuseLighting = diffuseLighting;
    124.         OUT.uv = float2(1, 1);
    125.         triStream.Append(OUT);
    126.  
    127.         OUT.pos = UnityObjectToClipPos(v0);
    128.         OUT.norm = faceNormal;
    129.         OUT.diffuseLighting = diffuseLighting;
    130.         OUT.uv = float2(0.5, 0);
    131.         triStream.Append(OUT);
    132.  
    133.         OUT.pos = UnityObjectToClipPos(v0 + perpendicularAngle * 0.5 * _GrassHeight);
    134.         OUT.norm = faceNormal;
    135.         OUT.diffuseLighting = diffuseLighting;
    136.         OUT.uv = float2(0.5, 1);
    137.         triStream.Append(OUT);
    138.  
    139.         OUT.pos = UnityObjectToClipPos(v1 + perpendicularAngle * 0.5 * _GrassHeight);
    140.         OUT.norm = faceNormal;
    141.         OUT.diffuseLighting = diffuseLighting;
    142.         OUT.uv = float2(0, 1);
    143.         triStream.Append(OUT);
    144.  
    145.         OUT.pos = UnityObjectToClipPos(v0);
    146.         OUT.norm = faceNormal;
    147.         OUT.diffuseLighting = diffuseLighting;
    148.         OUT.uv = float2(0, 0);
    149.         triStream.Append(OUT);
    150.  
    151.    
    152.         OUT.pos = UnityObjectToClipPos(v0);
    153.         OUT.norm = faceNormal;
    154.         OUT.diffuseLighting = diffuseLighting;
    155.         OUT.uv = float2(0.5, 0);
    156.         triStream.Append(OUT);
    157.  
    158.         OUT.pos = UnityObjectToClipPos(v1);
    159.         OUT.norm = faceNormal;
    160.         OUT.diffuseLighting = diffuseLighting;
    161.         OUT.uv = float2(0.5, 1);
    162.         triStream.Append(OUT);
    163.  
    164.         perpendicularAngle = cross(IN[0].norm, normalize(float3(sin60, cos60, 0)));
    165.    
    166.         OUT.pos = UnityObjectToClipPos(v0 + perpendicularAngle * 0.5 * _GrassHeight);
    167.         OUT.norm = faceNormal;
    168.         OUT.diffuseLighting = diffuseLighting;
    169.         OUT.uv = float2(1, 0);
    170.         triStream.Append(OUT);
    171.  
    172.         OUT.pos = UnityObjectToClipPos(v1 + perpendicularAngle * 0.5 * _GrassHeight);
    173.         OUT.norm = faceNormal;
    174.         OUT.diffuseLighting = diffuseLighting;
    175.         OUT.uv = float2(1, 1);
    176.         triStream.Append(OUT);
    177.  
    178.         OUT.pos = UnityObjectToClipPos(v0);
    179.         OUT.norm = faceNormal;
    180.         OUT.diffuseLighting = diffuseLighting;
    181.         OUT.uv = float2(0.5, 0);
    182.         triStream.Append(OUT);
    183.  
    184.         OUT.pos = UnityObjectToClipPos(v1);
    185.         OUT.norm = faceNormal;
    186.         OUT.diffuseLighting = diffuseLighting;
    187.         OUT.uv = float2(0.5, 1);
    188.         triStream.Append(OUT);
    189.  
    190.         OUT.pos = UnityObjectToClipPos(v1 - perpendicularAngle * 0.5 * _GrassHeight);
    191.         OUT.norm = faceNormal;
    192.         OUT.diffuseLighting = diffuseLighting;
    193.         OUT.uv = float2(0, 1);
    194.         triStream.Append(OUT);
    195.  
    196.         OUT.pos = UnityObjectToClipPos(v0 - perpendicularAngle * 0.5 * _GrassHeight);
    197.         OUT.norm = faceNormal;
    198.         OUT.diffuseLighting = diffuseLighting;
    199.         OUT.uv = float2(0, 0);
    200.         triStream.Append(OUT);
    201.  
    202.         OUT.pos = UnityObjectToClipPos(v0);
    203.         OUT.norm = faceNormal;
    204.         OUT.diffuseLighting = diffuseLighting;
    205.         OUT.uv = float2(0.5, 0);
    206.         triStream.Append(OUT);
    207.  
    208.         OUT.pos = UnityObjectToClipPos(v1);
    209.         OUT.norm = faceNormal;
    210.         OUT.diffuseLighting = diffuseLighting;
    211.         OUT.uv = float2(0.5, 1);
    212.         triStream.Append(OUT);
    213.  
    214.         perpendicularAngle = cross(IN[0].norm, normalize(float3(-sin60, cos60, 0)));
    215.  
    216.         OUT.pos = UnityObjectToClipPos(v0 + perpendicularAngle * 0.5 * _GrassHeight);
    217.         OUT.norm = faceNormal;
    218.         OUT.diffuseLighting = diffuseLighting;
    219.         OUT.uv = float2(1, 0);
    220.         triStream.Append(OUT);
    221.  
    222.         OUT.pos = UnityObjectToClipPos(v1 + perpendicularAngle * 0.5 * _GrassHeight);
    223.         OUT.norm = faceNormal;
    224.         OUT.diffuseLighting = diffuseLighting;
    225.         OUT.uv = float2(1, 1);
    226.         triStream.Append(OUT);
    227.  
    228.         OUT.pos = UnityObjectToClipPos(v0);
    229.         OUT.norm = faceNormal;
    230.         OUT.diffuseLighting = diffuseLighting;
    231.         OUT.uv = float2(0.5, 0);
    232.         triStream.Append(OUT);
    233.  
    234.         OUT.pos = UnityObjectToClipPos(v1);
    235.         OUT.norm = faceNormal;
    236.         OUT.diffuseLighting = diffuseLighting;
    237.         OUT.uv = float2(0.5, 1);
    238.         triStream.Append(OUT);
    239.  
    240.         OUT.pos = UnityObjectToClipPos(v1 - perpendicularAngle * 0.5 * _GrassHeight);
    241.         OUT.norm = faceNormal;
    242.         OUT.diffuseLighting = diffuseLighting;
    243.         OUT.uv = float2(0, 1);
    244.         triStream.Append(OUT);
    245.  
    246.         OUT.pos = UnityObjectToClipPos(v0 - perpendicularAngle * 0.5 * _GrassHeight);
    247.         OUT.norm = faceNormal;
    248.         OUT.diffuseLighting = diffuseLighting;
    249.         OUT.uv = float2(0, 0);
    250.         triStream.Append(OUT);
    251.  
    252.         OUT.pos = UnityObjectToClipPos(v0);
    253.         OUT.norm = faceNormal;
    254.         OUT.diffuseLighting = diffuseLighting;
    255.         OUT.uv = float2(0.5, 0);
    256.         triStream.Append(OUT);
    257.  
    258.         OUT.pos = UnityObjectToClipPos(v1);
    259.         OUT.norm = faceNormal;
    260.         OUT.diffuseLighting = diffuseLighting;
    261.         OUT.uv = float2(0.5, 1);
    262.         triStream.Append(OUT);
    263.    
    264.     }
    265.  
    266.     half4 frag(g2f IN) : SV_Target
    267.     {
    268.         fixed4 c = tex2D(_MainTex, IN.uv) * _GrassColor;
    269.         clip(c.a - _Cutoff);
    270.  
    271.         return c * IN.diffuseLighting;
    272.     }
    273.         ENDCG
    274.  
    275.     }
    276.     }
    277. }
     
    Last edited: Mar 21, 2018
    Ignacii likes this.