Search Unity

Detect obstacles on light sources

Discussion in 'Shaders' started by ogr021, Feb 20, 2017.

  1. ogr021

    ogr021

    Joined:
    Oct 9, 2015
    Posts:
    13
    Hi everyone.
    I am making a kind of toon shading style combining textures and normals (thanks to the Noob To Pro Writing Shaders from CGCOOKIE). I implemented the multiple light options by a second pass render, but my question is: How can I detect that there is an obstacle between the light source and my analized model?
    Here is the image that explain that:

    Between the lamp and the object there is a "wall", so in real life there will be parts that the light will not reach the object, but on shaders I don't know how to detect the "wall" that is inside the red box. If there is a defined variable that unity has for shaders that can detect other objects, is what I want to know.

    Thanks for your answers :)
     
  2. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,339
    You're taking about shadows. If you're using surface shaders you just need to add fullforwardshadows to the #pragma surface line.
    https://docs.unity3d.com/Manual/SL-SurfaceShaders.html

    If you're using vertex fragment shaders it's a bit more work, but not too bad. There's an example for the base pass in the official documentation.
    https://docs.unity3d.com/Manual/SL-VertexFragmentShaderExamples.html

    Adding shadows for the forward add pass is almost identical. You just need to include the same SHADOW lines and use multi_compile_fwdadd_fullshadows instead of multi_compile_fwdbase
    https://docs.unity3d.com/Manual/SL-MultipleProgramVariants.html
     
  3. ogr021

    ogr021

    Joined:
    Oct 9, 2015
    Posts:
    13
    Hi, thanks, the forwardbase shadows Works great but I am having problems with the forwardAdd shadows. I put in the second pass the multi_compile_fwdadd_fullshadows but I have an error message that says: "undeclared identifier UnityDecodeCobeShadowDepth at UnityShadowLibrary", I look for that variable and it says that is related to cubemaps o_o, How can it be configure this kind of shadows?
     
  4. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,339
    Shouldn't be anything you need to do particularly special in the shader code. Cube map shadows are used by point lights, and all the special handling should be done by those shadow macros (the lines all in caps). Best guess is this is problem caused by having missing #include lines.
     
  5. ogr021

    ogr021

    Joined:
    Oct 9, 2015
    Posts:
    13
    Oh!, so I cannot use point lights on this?, because the light you see on the image is a point light.
     
  6. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,339
    No, you can use pointlights ... once you fix the shader so it compiles properly. Post the whole shader here (inline in a code block, not as an attachment) and we can look at it, otherwise I can't really say what's wrong for sure.
     
  7. ogr021

    ogr021

    Joined:
    Oct 9, 2015
    Posts:
    13
    Ok, it is too long but I am still learning how to optimize this, so here it is :):
    Code (CSharp):
    1. Shader "UnityCookie/NoobToProTut/Intermediate/10 - Toon Map"
    2. {
    3.     Properties
    4.     {
    5.         _Color ("Lit Color", Color) = (1.0,1.0,1.0,1.0)
    6.         _UnlitColor ("Unlit Color", Color) = (0.5,0.5,0.5,1.0)
    7.         _MainTex ("Diffuse Texture", 2D) = "white" {}
    8.         _BumpMap ("Normal Texture", 2D) = "bump" {}
    9.         _BumpDepth ("Bump Depth", Range(0.0, 1.0)) = 1.0
    10.         _DiffuseThreshold ("Lighting Threshold", Range(0.0, 1.0)) = 0.1        // Control the line transition between both colors
    11.         _Diffusion ("Diffusion", Range(0.0, 1.0)) = 0.0                            // Control the blurry the line transition it is
    12.         _SpecColor ("Specular Color", Color) = (1.0,1.0,1.0,1.0)
    13.         _Shininess ("Shininess", Range(0.5, 1)) = 1
    14.         _SpecDiffusion ("Specular Diffusion", Range(0, 0.99)) = 0.0                // Controls the blurry border line of the specular light
    15.         _OutlineColor ("Outline Color", Color) = (0.0,0.0,0.0,1.0)
    16.         _OutlineThickness ("Outline Thickness", Range(0.0, 1.0)) = 0.1
    17.         _OutlineDiffusion ("Outline Diffusion", Range(0.0, 1.0)) = 0
    18.     }
    19.     SubShader
    20.     {
    21.         // FIRST RENDERER PASS
    22.         Pass {
    23.             Tags {"LightMode" = "ForwardBase"}
    24.             CGPROGRAM
    25.             #pragma vertex vert
    26.             #pragma fragment frag
    27.  
    28.             // compile shader into multiple variants, with and without shadows
    29.             // (we don't care about any lightmaps yet, so skip these variants)
    30.             #pragma multi_compile_fwdbase nolightmap nodirlightmap nodynlightmap novertexlight
    31.             // shadow helper functions and macros
    32.             #include "AutoLight.cginc"
    33.             #include "UnityCG.cginc"
    34.  
    35.             //user defined variables
    36.             uniform fixed4 _Color;
    37.             uniform fixed4 _UnlitColor;
    38.             uniform sampler2D _MainTex;
    39.             uniform half4 _MainTex_ST;
    40.             uniform sampler2D _BumpMap;
    41.             uniform half4 _BumpMap_ST;
    42.             uniform fixed _BumpDepth;
    43.             uniform fixed _DiffuseThreshold;
    44.             uniform fixed _Diffusion;
    45.             uniform fixed4 _SpecColor;
    46.             uniform fixed _Shininess;
    47.             uniform fixed _SpecDiffusion;
    48.             uniform fixed4 _OutlineColor;
    49.             uniform fixed _OutlineThickness;
    50.             uniform fixed _OutlineDiffusion;
    51.  
    52.             //unity defined variables
    53.             uniform half4 _LightColor0;
    54.  
    55.             //base input structs
    56.             struct vertexInput
    57.             {
    58.                 half4 vertex : POSITION;
    59.                 half3 normal : NORMAL;
    60.                 half4 texcoord : TEXCOORD0;        // Gets the UV map from the texture on the object
    61.                 half4 tangent : TANGENT;        // Gets the tangent direction of the normals
    62.             };
    63.             struct vertexOutput
    64.             {
    65.                 half4 pos : SV_POSITION;
    66.                 half4 tex : TEXCOORD0;
    67.                 SHADOW_COORDS(1) // put shadows data into TEXCOORD1          
    68.                 fixed3 normalDir : TEXCOORD2;
    69.                 fixed4 lightDir : TEXCOORD3;
    70.                 fixed3 viewDir : TEXCOORD4;
    71.                 fixed3 tangentDir : TEXCOORD5;    // Store the tangent direction of the normals
    72.                 fixed3 binomialDir : TEXCOORD6;    // Store the perpendicular direction between the normal and tangent
    73.             };
    74.            
    75.             //vertex Function
    76.             vertexOutput vert(vertexInput v)
    77.             {
    78.                 vertexOutput o;
    79.                
    80.                 //normalDirection
    81.                 o.normalDir = normalize( mul( half4( v.normal, 0.0 ), unity_WorldToObject ).xyz );
    82.  
    83.                 // calculate directions for bump map
    84.                 o.tangentDir = normalize( mul( unity_ObjectToWorld, v.tangent).xyz);
    85.                 o.binomialDir = normalize( cross( o.normalDir, o.tangentDir) * v.tangent.w);
    86.  
    87.                 // Store texture coordinates
    88.                 o.tex = v.texcoord;
    89.  
    90.                 //unity transform position
    91.                 o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
    92.                
    93.                 //world position
    94.                 half4 posWorld = mul(unity_ObjectToWorld, v.vertex);
    95.                 //view direction
    96.                 o.viewDir = normalize( _WorldSpaceCameraPos.xyz - posWorld.xyz );
    97.                 //light direction
    98.                 half3 vertexToLightSource = _WorldSpaceLightPos0.xyz - posWorld.xyz;
    99.                 o.lightDir = fixed4(
    100.                     normalize( lerp(_WorldSpaceLightPos0.xyz , vertexToLightSource, _WorldSpaceLightPos0.w) ),
    101.                     lerp(1.0 , 1.0/length(vertexToLightSource), _WorldSpaceLightPos0.w)
    102.                 );
    103.  
    104.                 // compute shadows data
    105.                 TRANSFER_SHADOW(o)
    106.  
    107.                 return o;
    108.             }
    109.            
    110.             //fragment function
    111.             fixed4 frag(vertexOutput i) : SV_TARGET
    112.             {
    113.                 // Texture and Bump Maps
    114.                 fixed4 tex = tex2D(_MainTex, i.tex.xy * _MainTex_ST.xy + _MainTex_ST.zw);
    115.                 fixed4 texN = tex2D(_BumpMap, i.tex.xy * _BumpMap_ST.xy + _BumpMap_ST.zw);
    116.  
    117.                 // Unpack Normal function
    118.                 fixed3 localCoords = fixed3( 2.0 * texN.ag - float2( 1.0, 1.0), _BumpDepth);
    119.  
    120.                 // Normal transpose matrix
    121.                 fixed3x3 local2WorldTranspose = fixed3x3(
    122.                     i.tangentDir,
    123.                     i.binomialDir,
    124.                     i.normalDir
    125.                 );
    126.  
    127.                 // Calculate Bump Direction
    128.                 fixed3 bumpDirection = normalize( mul( localCoords, local2WorldTranspose));
    129.  
    130.                 // compute shadow attenuation (1.0 = fully lit, 0.0 = fully shadowed)
    131.                 fixed shadow = smoothstep(0.0, 1.0, SHADOW_ATTENUATION(i));
    132.  
    133.                 // Transition Masks
    134.                 fixed diffuseCutoff = saturate( smoothstep( _DiffuseThreshold, 1.0, i.lightDir.w * dot(bumpDirection, i.lightDir.xyz) * shadow) * pow( (2 - _Diffusion), 10));
    135.                 fixed specularCutoff = saturate( smoothstep( _Shininess, 1.0, i.lightDir.w * dot( reflect( -i.lightDir.xyz, bumpDirection), i.viewDir)) * shadow * pow( ( 2 - _SpecDiffusion), 10));
    136.  
    137.                 // Calculate outlines
    138.                 fixed outlineStrenth = saturate( ( dot( i.normalDir, i.viewDir) - _OutlineThickness) * pow( ( 2 - _OutlineDiffusion), 10) + _OutlineThickness);
    139.                 fixed3 outlineOverlay = (_OutlineColor.xyz * _LightColor0.xyz * ( 1 - outlineStrenth)) + outlineStrenth;
    140.  
    141.                 // Lighting
    142.                 fixed3 ambientLight = tex.xyz * ( 1 - diffuseCutoff) * _UnlitColor.xyz * (_LightColor0.xyz + UNITY_LIGHTMODEL_AMBIENT.xyz);
    143.                 fixed3 diffuseReflection = tex.xyz * (1 - specularCutoff) * _Color.xyz * _LightColor0.xyz * diffuseCutoff;
    144.                 fixed3 specularReflection = specularCutoff * _SpecColor.xyz * tex.a;
    145.  
    146.                 fixed3 lightFinal = (ambientLight + diffuseReflection) * outlineOverlay + specularReflection;
    147.                
    148.                 return fixed4(lightFinal, 1.0);
    149.             }
    150.            
    151.             ENDCG      
    152.         }
    153.  
    154.         // SECOND RENDERER PASS
    155.         Pass {
    156.             Tags {"LightMode" = "ForwardAdd"}
    157.             Blend SrcAlpha OneMinusSrcColor
    158.             CGPROGRAM
    159.             #pragma vertex vert
    160.             #pragma fragment frag
    161.             #pragma multi_compile_fwdadd_fullshadows
    162.             #include "AutoLight.cginc"
    163.             #include "UnityCG.cginc"
    164.  
    165.             //user defined variables
    166.             uniform fixed4 _Color;
    167.             uniform fixed4 _UnlitColor;
    168.             uniform sampler2D _MainTex;
    169.             uniform half4 _MainTex_ST;
    170.             uniform sampler2D _BumpMap;
    171.             uniform half4 _BumpMap_ST;
    172.             uniform fixed _BumpDepth;
    173.             uniform fixed _DiffuseThreshold;
    174.             uniform fixed _Diffusion;
    175.             uniform fixed4 _SpecColor;
    176.             uniform fixed _Shininess;
    177.             uniform fixed _SpecDiffusion;
    178.             uniform fixed4 _OutlineColor;
    179.             uniform fixed _OutlineThickness;
    180.             uniform fixed _OutlineDiffusion;
    181.  
    182.             //unity defined variables
    183.             uniform half4 _LightColor0;
    184.  
    185.             //base input structs
    186.             struct vertexInput
    187.             {
    188.                 half4 vertex : POSITION;
    189.                 half3 normal : NORMAL;
    190.                 half4 texcoord : TEXCOORD0;      
    191.                 half4 tangent : TANGENT;      
    192.             };
    193.             struct vertexOutput
    194.             {
    195.                 half4 pos : SV_POSITION;
    196.                 half4 tex : TEXCOORD0;          
    197.                 SHADOW_COORDS(1)      
    198.                 fixed3 normalDir : TEXCOORD2;
    199.                 fixed4 lightDir : TEXCOORD3;
    200.                 fixed3 viewDir : TEXCOORD4;
    201.                 fixed3 tangentDir : TEXCOORD5;
    202.                 fixed3 binomialDir : TEXCOORD6;
    203.             };
    204.            
    205.             //vertex Function
    206.             vertexOutput vert(vertexInput v)
    207.             {
    208.                 vertexOutput o;
    209.                
    210.                 //normalDirection
    211.                 o.normalDir = normalize( mul( half4( v.normal, 0.0 ), unity_WorldToObject ).xyz );
    212.  
    213.                 // calculate directions for bump map
    214.                 o.tangentDir = normalize( mul( unity_ObjectToWorld, v.tangent).xyz);
    215.                 o.binomialDir = normalize( cross( o.normalDir, o.tangentDir) * v.tangent.w);
    216.  
    217.                 // Store texture coordinates
    218.                 o.tex = v.texcoord;
    219.  
    220.                 //unity transform position
    221.                 o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
    222.                
    223.                 //world position
    224.                 half4 posWorld = mul(unity_ObjectToWorld, v.vertex);
    225.                 //view direction
    226.                 o.viewDir = normalize( _WorldSpaceCameraPos.xyz - posWorld.xyz );
    227.                 //light direction
    228.                 half3 vertexToLightSource = _WorldSpaceLightPos0.xyz - posWorld.xyz;
    229.                 o.lightDir = fixed4(
    230.                     normalize( lerp(_WorldSpaceLightPos0.xyz , vertexToLightSource, _WorldSpaceLightPos0.w) ),
    231.                     lerp(1.0 , 1.0/length(vertexToLightSource), _WorldSpaceLightPos0.w)
    232.                 );
    233.  
    234.                 // compute shadows data
    235.                 TRANSFER_SHADOW(o)
    236.                
    237.                 return o;
    238.             }
    239.            
    240.             //fragment function
    241.             fixed4 frag(vertexOutput i) : SV_TARGET
    242.             {
    243.                 // Texture and Bump Maps
    244.                 fixed4 tex = tex2D(_MainTex, i.tex.xy * _MainTex_ST.xy + _MainTex_ST.zw);
    245.                 fixed4 texN = tex2D(_BumpMap, i.tex.xy * _BumpMap_ST.xy + _BumpMap_ST.zw);
    246.  
    247.                 // Unpack Normal function
    248.                 fixed3 localCoords = fixed3( 2.0 * texN.ag - float2( 1.0, 1.0), _BumpDepth);
    249.  
    250.                 // Normal transpose matrix
    251.                 fixed3x3 local2WorldTranspose = fixed3x3(
    252.                     i.tangentDir,
    253.                     i.binomialDir,
    254.                     i.normalDir
    255.                 );
    256.  
    257.                 // Calculate Bump Direction
    258.                 fixed3 bumpDirection = normalize( mul( localCoords, local2WorldTranspose));
    259.  
    260.                 // compute shadow attenuation (1.0 = fully lit, 0.0 = fully shadowed)
    261.                 fixed shadow = smoothstep(0.0, 1.0, SHADOW_ATTENUATION(i));
    262.  
    263.                 // Transition Masks
    264.                 fixed diffuseCutoff = saturate( smoothstep( _DiffuseThreshold, 1.0, i.lightDir.w * shadow * dot(bumpDirection, i.lightDir.xyz)) * pow( (2 - _Diffusion), 10));
    265.                 fixed specularCutoff = saturate( smoothstep( _Shininess, 1.0, i.lightDir.w * dot( reflect( -i.lightDir.xyz, bumpDirection), i.viewDir)) * shadow * pow( ( 2 - _SpecDiffusion), 10));
    266.  
    267.                 // Calculate outlines
    268.                 fixed outlineStrenth = saturate( ( dot( i.normalDir, i.viewDir) - _OutlineThickness) * pow( ( 2 - _OutlineDiffusion), 10) + _OutlineThickness);
    269.                 fixed3 outlineOverlay = (_OutlineColor.xyz * ( 1 - outlineStrenth)) + outlineStrenth;
    270.  
    271.                 // Lighting
    272.                 fixed3 ambientLight = tex.xyz * ( 1 - diffuseCutoff) * _UnlitColor.xyz;
    273.                 fixed3 diffuseReflection = tex.xyz * (1 - specularCutoff) * _Color.xyz * _LightColor0.xyz * diffuseCutoff;
    274.                 fixed3 specularReflection = specularCutoff * _SpecColor.xyz * _LightColor0.xyz * tex.a;
    275.  
    276.                 fixed3 lightFinal = (ambientLight + diffuseReflection) * outlineOverlay + specularReflection;
    277.                
    278.                 return fixed4(lightFinal, 1.0);
    279.             }
    280.            
    281.             ENDCG      
    282.         }
    283.  
    284.         // SHADOW CASTER RENDERING PASS
    285.         Pass
    286.         {
    287.             Tags {"LightMode" = "ShadowCaster"}
    288.  
    289.             CGPROGRAM
    290.             #pragma vertex vert
    291.             #pragma fragment frag
    292.             #pragma multi_compile_shadowcaster
    293.             #include "UnityCG.cginc"
    294.  
    295.             //base input structs
    296.             struct v2f
    297.             {
    298.                 V2F_SHADOW_CASTER;
    299.             };
    300.  
    301.             v2f vert (appdata_base v)
    302.             {
    303.                 v2f o;
    304.                 TRANSFER_SHADOW_CASTER_NORMALOFFSET(o)
    305.                 return o;
    306.             }
    307.  
    308.             half4 frag(v2f i) : SV_Target
    309.             {
    310.                 SHADOW_CASTER_FRAGMENT(i)
    311.             }
    312.  
    313.             ENDCG
    314.         }
    315.  
    316.     }
    317.     //Fallback "Specular"
    318. }
     
  8. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,339
    The order of #include lines can matter! Try swapping them so the #include "UnityCG.cginc" is before the #include "AutoLight.cginc" line in the add pass specifically, though it wouldn't hurt to do it for both.
     
  9. ogr021

    ogr021

    Joined:
    Oct 9, 2015
    Posts:
    13
    Oh yeah, it Works, Thanks!!!. Besides it is a little complicate for me to understand this kind of programming. I noticed some other details, when the object recieves a shadow I notice that this shadow is a little sharpy, different what I have on the lighting threshold transition. As you can see on the code, I try to put a smoothstep function on the "shadow" variable, but the recieve shadow still seems sharpy, and the bump map doesn't follow the shadow at all. How can I change the shadow variable to work as the "diffuseCutoff" that has that smooth chagne between the shadow and the light?
     
  10. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,339
    Not really, no.

    You should read up on shadow maps. Cat like coding has a decent tutorial delving deep into shadow maps in Unity. You can try turning on soft shadows on your light to help some, however Unity's point light shadows in particular are kind of terrible and always a little harsh. There are some assets out there that soften the shadows at the cost of performance and / or noise.