Search Unity

Vertex Shaders Custom Lighting

Discussion in 'Shaders' started by looytroop, Nov 7, 2019.

  1. looytroop

    looytroop

    Joined:
    Jun 22, 2017
    Posts:
    70
    Hello, I am trying to write grass shader and I would like to take in information about the directional light, as well as spot lights and point lights. However, I cannot seem to figure out how each light effects the pass.

    I have this statement.


    Code (CSharp):
    1. if (_WorldSpaceLightPos0.w == 0)
    2.             {
    3.                 //Set multiplier to Directional
    4.             }
    5.             else
    6.             {
    7.                 //Calculate distance to the light source and then based on it's range, use an inverse square falloff.
    8.             }
    The only lights in my scene are the directional light, and the player's flashlight. However, when I look around, it seems that the lighting switches between the two conditions based on the direction I am looking and where I am standing. If anyone could help me better understand this process, please let me know.
     
  2. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,336
    Unity’s forward renderer uses a multi-pass lighting system which is split into a base, and multiple optional additive passes. The base pass, denoted by the tag
    “LightMode” = “ForwardBase”
    , renders the ambient lighting, the main directional light, light maps, and any per vertex lights (those set to non-important). The add passes, denoted by
    “LightMode” = “ForwardAdd”
    , renders all other lights one by one, rerunning that same pass several times with different settings.

    If your shader pass doesn’t have a
    “LightMode”
    tag, it’s just using whatever the lighting values were for the previous lit object that was rendered, which might explain why the value you’re seeing keeps changing as you move the camera.
     
    Last edited: Nov 13, 2019
    looytroop likes this.
  3. looytroop

    looytroop

    Joined:
    Jun 22, 2017
    Posts:
    70
    @bgolus Thank you for your response. I did not have "LightMode" tag set. I have now set the LightMode tag to "ForwardAdd" as I would like to have grass lit up from my flashlight, and I would also like it to be lit up by other lights in the world.

    However, I am now running into a new problem, it seems that when I add this tag, some grass nolonger renders at all, and it will only light up the two different lights based on my position. I am seeing a weird square of unlit grass as in the images attached.

    I have attached three images, one that has the forwardAdd tag, this shows the odd rendering of a square, and that the grass around me is unlit. The NoLightModeTag shows what the shader looks like when I remove the tag, this is similar to what it should look like, although, the flashlight is not lighting anything. Finally, the last image shows no tag, and when I disable the fire pointlight, this is to show what the flashlight lighting should look like. Basically, I just want the ability to combine these last two.

    EDIT: It seems that this square is coming from my spotlight angle. Is this only rendering the grass that is being hit by a light? In this case, how would I render grass that is not currently being hit?

    Also, I am assuming that the reason everything looks black is because I am setting the lighting values in the shader, if it is not being hit, it sets the lighting value to 0, I imagine that currently, the grass is taking the lighting value from the light that is getting ran last, and all other verts are set to a 0 lighting value. Is there a way I can have these passes add on top of one another as opposed to replace the old lighting values?

    In case this is useful, here is the shader currently:


    Code (CSharp):
    1. // Based upon the example at: http://www.battlemaze.com/?p=153
    2. // Also: https://developer.nvidia.com/gpugems/GPUGems/gpugems_ch07.html
    3.  
    4. Shader "Custom/Grass Geo Shader" {
    5.     Properties{
    6.         _MainTex("Albedo (RGB)", 2D) = "white" {}
    7.         _SpecularColor("Specular Material Color", Color) = (1,1,1,1)
    8.         _Shininess("Shininess", Float) = 1.0
    9.         _Cutoff("Cutoff", Range(0,1)) = 0.25
    10.         _GrassHeight("Grass Height", Float) = 0.25
    11.         _GrassTopWidth("Grass Width at Top", Float) = 0.25
    12.         _GrassBotWidth("Grass Width at Bottom", Float) = 0.25
    13.         _WindSpeed("Wind Speed", Float) = 100
    14.         _WindStength("Wind Strength", Float) = 0.05
    15.     }
    16.         SubShader{
    17.         Tags{ "Queue" = "AlphaTest" "IgnoreProjector" = "True" "RenderType" = "TransparentCutout"  "LightMode" = "ForwardAdd" }
    18.         LOD 200
    19.  
    20.         Pass
    21.     {
    22.             CULL OFF
    23.  
    24.             CGPROGRAM
    25.             #pragma target 5.0
    26.             #pragma vertex vert
    27.             #pragma fragment frag
    28.             #pragma geometry geom
    29.             #include "UnityCG.cginc"
    30.  
    31.             sampler2D _MainTex;
    32.             uniform float4 _SpecularColor;
    33.             uniform float _Shininess;
    34.             uniform float3 _LightColor0;
    35.             half _GrassHeight;
    36.             half _GrassTopWidth;
    37.             half _GrassBotWidth;
    38.             uniform half _Cutoff;
    39.             half _WindStength;
    40.             half _WindSpeed;
    41.             float _FlashLightRange;
    42.  
    43.             struct v2g
    44.             {
    45.             float4 pos : SV_POSITION;
    46.             float3 normal : NORMAL;
    47.             float2 uv : TEXCOORD0;
    48.             float3 color : TEXCOORD1;
    49.             };
    50.  
    51.             struct g2f
    52.             {
    53.             float4 pos : SV_POSITION;
    54.             float2 uv : TEXCOORD0;
    55.             float3 specularColor : TEXCOORD2;
    56.             };
    57.  
    58.             float GetSpecularReflection(float multiplier, float attenuation, float viewDirection, float normalDirection)
    59.             {
    60.                 return multiplier * attenuation * _LightColor0.rgb * _SpecularColor.rgb * _Shininess;
    61.                 /*return multiplier * attenuation * _LightColor0.rgb * _SpecularColor.rgb * pow(max(0.0, max(dot(
    62.                     reflect(viewDirection, -normalDirection), reflect(viewDirection, normalDirection)),
    63.                     viewDirection)), _Shininess);*/
    64.             }
    65.  
    66.             v2g vert(appdata_full v)
    67.             {
    68.  
    69.             v2g OUT;
    70.             OUT.pos = v.vertex;
    71.             OUT.normal = v.normal;
    72.             OUT.uv = v.texcoord;
    73.             OUT.color = tex2Dlod(_MainTex, v.texcoord).rgb;
    74.             return OUT;
    75.             }
    76.  
    77.             [maxvertexcount(24)]
    78.             void geom(point v2g IN[1], inout TriangleStream<g2f> triStream)
    79.             {
    80.  
    81.             float3 perpendicularAngle = float3(0, 0, 1);
    82.             float3 faceNormal = cross(perpendicularAngle, IN[0].normal);
    83.             float3 normalDirection;
    84.             normalDirection = normalize(mul(float4(IN[0].normal, 0.0), unity_WorldToObject).xyz);
    85.  
    86.             float3 v0 = IN[0].pos.xyz;
    87.             float3 v1 = IN[0].pos.xyz + IN[0].normal * _GrassHeight;
    88.  
    89.             float3 centerPos = (v0 + v1) / 2.0;
    90.  
    91.             float3 lightDirection = normalize(_WorldSpaceLightPos0.xyz);
    92.             float3 viewDirection = normalize(_WorldSpaceCameraPos - mul(unity_ObjectToWorld, float4(centerPos, 0.0)).xyz);
    93.             float attenuation = 1.0;
    94.  
    95.             float3 ambientLighting = UNITY_LIGHTMODEL_AMBIENT.rgb * IN[0].color.rgb;
    96.             float3 specularReflection;
    97.  
    98.             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,
    99.             cos(_Time.x * _WindSpeed + v0.x * 2) + cos(_Time.x * _WindSpeed + v0.z));
    100.             v1 += wind * _WindStength;
    101.  
    102.             float3 color = (IN[0].color);
    103.  
    104.             float sin30 = 0.5;
    105.             float sin60 = 0.866f;
    106.             float cos30 = sin60;
    107.             float cos60 = sin30;
    108.  
    109.             g2f OUT;
    110.  
    111.             // QUAD1
    112.             float4 q1_0 = UnityObjectToClipPos(v0 + perpendicularAngle * _GrassBotWidth);
    113.  
    114.  
    115.            
    116.             float multiplier = 1;
    117.  
    118.             if (_WorldSpaceLightPos0.w == 0)
    119.             {
    120.                 multiplier = 0;
    121.             }
    122.             else
    123.             {
    124.                 float3 dV = mul(IN[0].pos, unity_WorldToObject).xyz;
    125.                 float distance = sqrt(pow(_WorldSpaceLightPos0.x - dV.x, 2) + pow(_WorldSpaceLightPos0.y - dV.y, 2) + pow(_WorldSpaceLightPos0.z - dV.z, 2));
    126.  
    127.                 if (distance < _FlashLightRange)
    128.                 {
    129.                     float fallOff = 2 / max(2, (pow(distance, 2.25)));
    130.                     multiplier = fallOff;
    131.                 }
    132.                 else
    133.                 {
    134.                     multiplier = 0;
    135.                 }
    136.             }
    137.  
    138.  
    139.             float3 q1 = normalize(cross(v1 - v0, q1_0 - v0));
    140.             normalDirection = normalize(mul(float4(q1, 0.0), unity_ObjectToWorld).xyz);
    141.             centerPos = (v0 + v1) / 2.0;
    142.             specularReflection = GetSpecularReflection(multiplier, attenuation, viewDirection, normalDirection);
    143.  
    144.             OUT.pos = q1_0;
    145.             OUT.specularColor = ambientLighting + specularReflection;
    146.             OUT.uv = float2(1, 0);
    147.             triStream.Append(OUT);
    148.  
    149.             OUT.pos = UnityObjectToClipPos(v1 + perpendicularAngle * _GrassTopWidth);
    150.             OUT.specularColor = ambientLighting + specularReflection;
    151.             OUT.uv = float2(1, 1);
    152.             triStream.Append(OUT);
    153.  
    154.             OUT.pos = UnityObjectToClipPos(v0);
    155.             OUT.specularColor = ambientLighting + specularReflection;
    156.             OUT.uv = float2(0.5, 0);
    157.             triStream.Append(OUT);
    158.  
    159.             OUT.pos = UnityObjectToClipPos(v1);
    160.             OUT.specularColor = ambientLighting + specularReflection;
    161.             OUT.uv = float2(0.5, 1);
    162.             triStream.Append(OUT);
    163.  
    164.             OUT.pos = UnityObjectToClipPos(v1 - perpendicularAngle * _GrassTopWidth);
    165.             OUT.specularColor = specularReflection;
    166.             OUT.uv = float2(0, 1);
    167.             triStream.Append(OUT);
    168.  
    169.             OUT.pos = UnityObjectToClipPos(v0 - perpendicularAngle *_GrassBotWidth);
    170.             OUT.specularColor = specularReflection;
    171.             OUT.uv = float2(0, 0);
    172.             triStream.Append(OUT);
    173.  
    174.  
    175.             OUT.pos = UnityObjectToClipPos(v0);
    176.             OUT.specularColor = ambientLighting + specularReflection;
    177.             OUT.uv = float2(0.5, 0);
    178.             triStream.Append(OUT);
    179.  
    180.             OUT.pos = UnityObjectToClipPos(v1);
    181.             OUT.specularColor = ambientLighting + specularReflection;
    182.             OUT.uv = float2(0.5, 1);
    183.             triStream.Append(OUT);
    184.  
    185.             // Quad 2
    186.  
    187.             float4 q2_0 = UnityObjectToClipPos(v0 + float3(sin60, 0, -cos60) * _GrassBotWidth);
    188.  
    189.             float3 q2 = normalize(cross(v1 - v0, q2_0 - v0));
    190.             normalDirection = normalize(mul(float4(q2, 0.0), unity_WorldToObject).xyz);
    191.  
    192.  
    193.             specularReflection = GetSpecularReflection(multiplier, attenuation, viewDirection, normalDirection);
    194.  
    195.  
    196.  
    197.             OUT.pos = q2_0;
    198.             OUT.specularColor = ambientLighting + specularReflection;
    199.             OUT.uv = float2(1, 0);
    200.             triStream.Append(OUT);
    201.  
    202.             OUT.pos = UnityObjectToClipPos(v1 + float3(sin60, 0, -cos60)* _GrassTopWidth);
    203.             OUT.specularColor = ambientLighting + specularReflection;
    204.             OUT.uv = float2(1, 1);
    205.             triStream.Append(OUT);
    206.  
    207.             OUT.pos = UnityObjectToClipPos(v0);
    208.             OUT.specularColor = ambientLighting + specularReflection;
    209.             OUT.uv = float2(0.5, 0);
    210.             triStream.Append(OUT);
    211.  
    212.             OUT.pos = UnityObjectToClipPos(v1);
    213.             OUT.specularColor = ambientLighting + specularReflection;
    214.             OUT.uv = float2(0.5, 1);
    215.             triStream.Append(OUT);
    216.  
    217.             OUT.pos = UnityObjectToClipPos(v0 - float3(sin60, 0, -cos60) * _GrassBotWidth);
    218.             OUT.specularColor = ambientLighting + specularReflection;
    219.             OUT.uv = float2(0, 0);
    220.             triStream.Append(OUT);
    221.  
    222.             OUT.pos = UnityObjectToClipPos(v1 - float3(sin60, 0, -cos60) * _GrassTopWidth);
    223.             OUT.specularColor = ambientLighting + specularReflection;
    224.             OUT.uv = float2(0, 1);
    225.             triStream.Append(OUT);
    226.  
    227.             OUT.pos = UnityObjectToClipPos(v0);
    228.             OUT.specularColor = ambientLighting + specularReflection;
    229.             OUT.uv = float2(0.5, 0);
    230.             triStream.Append(OUT);
    231.  
    232.             OUT.pos = UnityObjectToClipPos(v1);
    233.             OUT.specularColor = ambientLighting + specularReflection;
    234.             OUT.uv = float2(0.5, 1);
    235.             triStream.Append(OUT);
    236.  
    237.             // Quad 3 - Positive
    238.  
    239.  
    240.             float4 q3_0 = UnityObjectToClipPos(v0 + float3(sin60, 0, cos60) * _GrassBotWidth);
    241.  
    242.             float3 q3 = normalize(cross(v1 - v0, q3_0 - v0));
    243.             normalDirection = normalize(mul(float4(q3, 0.0), unity_WorldToObject).xyz);
    244.  
    245.  
    246.             specularReflection = GetSpecularReflection(multiplier, attenuation, viewDirection, normalDirection);
    247.  
    248.  
    249.             OUT.pos = q3_0;
    250.             OUT.specularColor = ambientLighting + specularReflection;
    251.             OUT.uv = float2(1, 0);
    252.             triStream.Append(OUT);
    253.  
    254.             OUT.pos = UnityObjectToClipPos(v1 + float3(sin60, 0, cos60)* _GrassTopWidth);
    255.             OUT.specularColor = ambientLighting + specularReflection;
    256.             OUT.uv = float2(1, 1);
    257.             triStream.Append(OUT);
    258.  
    259.             OUT.pos = UnityObjectToClipPos(v0);
    260.             OUT.specularColor = ambientLighting + specularReflection;
    261.             OUT.uv = float2(0.5, 0);
    262.             triStream.Append(OUT);
    263.  
    264.             OUT.pos = UnityObjectToClipPos(v1);
    265.             OUT.specularColor = ambientLighting + specularReflection;
    266.             OUT.uv = float2(0.5, 1);
    267.             triStream.Append(OUT);
    268.  
    269.             // Quad 3 - NEgative
    270.  
    271.             OUT.pos = UnityObjectToClipPos(v0 - float3(sin60, 0, cos60) * _GrassBotWidth);
    272.             OUT.specularColor = ambientLighting + specularReflection;
    273.             OUT.uv = float2(0, 0);
    274.             triStream.Append(OUT);
    275.  
    276.             OUT.pos = UnityObjectToClipPos(v1 - float3(sin60, 0, cos60) * _GrassTopWidth);
    277.             OUT.specularColor = ambientLighting + specularReflection;
    278.             OUT.uv = float2(0, 1);
    279.             triStream.Append(OUT);
    280.  
    281.             OUT.pos = UnityObjectToClipPos(v0);
    282.             OUT.specularColor = ambientLighting + specularReflection;
    283.             OUT.uv = float2(0.5, 0);
    284.             triStream.Append(OUT);
    285.  
    286.             OUT.pos = UnityObjectToClipPos(v1);
    287.             OUT.specularColor = ambientLighting + specularReflection;
    288.             OUT.uv = float2(0.5, 1);
    289.             triStream.Append(OUT);
    290.             }
    291.  
    292.             half4 frag(g2f IN) : COLOR
    293.             {
    294.                 fixed4 c = tex2D(_MainTex, IN.uv);
    295.                 c.rgb *= IN.specularColor;
    296.                 clip(c.a - _Cutoff);
    297.                 return c;
    298.             }
    299.             ENDCG
    300.         }
    301.     }
    302. }
     

    Attached Files:

    Last edited: Nov 13, 2019
  4. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,336
    looytroop likes this.
  5. looytroop

    looytroop

    Joined:
    Jun 22, 2017
    Posts:
    70
    @bgolus Thank you so much for your help, those articles are really useful, I have been looking all over for information just like this!

    I now am successfully able to combine my directional, spot and point lights, with one issue. I still cannot seem to get rid of the box surrounding the other light source. It seems as though it also scales with my distance from it, and the direction I am looking. I am not really sure where it is coming from.
     

    Attached Files:

  6. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,336
    When Unity draws the forward add pass, it clips the screen to a box the size of the light source. If your shader doesn’t limit the lighting to the range of the light in a similar fashion to Unity then you’ll see a box like that.
     
    looytroop likes this.
  7. looytroop

    looytroop

    Joined:
    Jun 22, 2017
    Posts:
    70
    Thanks, I will try and look into this, and continue reading through the materials you sent over. I will get this to work :)