Search Unity

Custom Multi-Light Blend Mode for hacky Frag Shader??

Discussion in 'Shaders' started by transporter_gate_studios, Apr 27, 2020.

  1. transporter_gate_studios

    transporter_gate_studios

    Joined:
    Oct 17, 2016
    Posts:
    219
    I'm new to vert/frag shaders. So, I've written this shader (code at the end of this post) which is a demo shader that i've heavily modified to get this special coloring effect from scene lights. It supports normal maps, and multiple scene lights. However, the transitions between lights that get out of range are harsh, sudden cutovers as you can see from the screenshot. I imagine that I would have to to blend the Forward-Adds a certain way based on light distance but I can't figure out how to do that.



    and here is the code:

    Code (CSharp):
    1. // Upgrade NOTE: replaced '_Object2World' with 'unity_ObjectToWorld'
    2. // Upgrade NOTE: replaced '_World2Object' with 'unity_WorldToObject'
    3. // Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'
    4.  
    5. Shader "Super Paint"
    6. {
    7.     Properties {
    8.         _Color ( "Color Tint", Color ) = ( 1.0, 1.0, 1.0, 1.0 )
    9.         _MainTex ("Diffuse Texture", 2D) = "white" {}
    10.         _BumpMap ("Normal Texture", 2D) = "bump" {}
    11.         _BumpDepth ("Bump Depth", Range( -2.0, 2.0 )) = 1
    12.         _Shininess( "Shininess", float ) = 10
    13.     }
    14.     SubShader
    15.     {
    16.         Pass
    17.         {
    18.             Tags { "LightMode" = "ForwardBase" }
    19.             CGPROGRAM
    20.             #pragma vertex vert
    21.             #pragma fragment frag
    22.             #pragma exclude_renderers flash
    23.             #include "UnityCG.cginc"
    24.             #include "UnityLightingCommon.cginc"
    25.            
    26.             // User Defined Variables
    27.             uniform float4 _Color;
    28.             uniform sampler2D _MainTex;
    29.             uniform float4 _MainTex_ST;
    30.             uniform sampler2D _BumpMap;
    31.             uniform float4 _BumpMap_ST;
    32.             uniform float _BumpDepth;
    33.             uniform float _Shininess;
    34.            
    35.            
    36.             // Base Input Structs
    37.             struct vertexInput
    38.             {
    39.                 float4 vertex: POSITION;
    40.                 float3 normal: NORMAL;
    41.                 float4 texcoord: TEXCOORD0;
    42.                 float4 tangent: TANGENT;
    43.             };
    44.             struct vertexOutput
    45.             {
    46.                 float4 pos: SV_POSITION;
    47.                 float4 tex: TEXCOORD0;
    48.                 float4 posWorld: TEXCOORD1;
    49.                 float3 normalWorld: TEXCOORD2;
    50.                 float3 tangentWorld: TEXCOORD3;
    51.                 float3 binormalWorld: TEXCOORD4;
    52.             };
    53.            
    54.             // Vertex Function
    55.             vertexOutput vert( vertexInput v )
    56.             {
    57.                 vertexOutput o;
    58.                
    59.                 o.normalWorld = normalize( mul( float4( v.normal, 0.0 ), unity_WorldToObject ).xyz );      
    60.                 o.tangentWorld = normalize( mul( unity_ObjectToWorld, v.tangent ).xyz );
    61.                 o.binormalWorld = normalize( cross( o.normalWorld, o.tangentWorld ) );
    62.                        
    63.                 o.posWorld = mul( unity_ObjectToWorld, v.vertex );
    64.                 o.pos = UnityObjectToClipPos( v.vertex );
    65.                 o.tex = v.texcoord;
    66.                
    67.                 return o;
    68.             }
    69.            
    70.             // Fragment Function
    71.             float4 frag( vertexOutput i ): COLOR
    72.             {
    73.                 float3 viewDirection = normalize( _WorldSpaceCameraPos.xyz - i.posWorld.xyz );
    74.                 float3 lightDirection;
    75.                 float atten;
    76.                
    77.                 if ( _WorldSpaceLightPos0.w == 0.0 )
    78.                 { // Directional Light
    79.                     atten = 1.0;
    80.                     lightDirection = normalize( _WorldSpaceLightPos0.xyz );
    81.                 }
    82.                 else
    83.                 {
    84.                     float3 fragmentToLightSource = _WorldSpaceLightPos0.xyz - i.posWorld.xyz;
    85.                     float distance = length( fragmentToLightSource );
    86.                     float atten = 1 / distance;
    87.                     lightDirection = normalize( fragmentToLightSource );
    88.                 }
    89.                
    90.                 // Texture Maps
    91.                 float4 tex = tex2D( _MainTex, i.tex);
    92.                 float4 texN = tex2D( _BumpMap, i.tex);
    93.                
    94.                 // unpackNormal Function
    95.                 float3 localCoords = float3(2.0 * texN.ag - float2(1.0,1.0), 0.0);
    96.                 //localCoords.z = 1.0 - 0.5 * dot( localCoords, localCoords );
    97.                 //localCoords.z = 1.0;
    98.                 localCoords.z = _BumpDepth;
    99.                
    100.                 // Normal Transpose Matrix
    101.                 float3x3 local2WorldTranspose = float3x3
    102.                 (
    103.                     i.tangentWorld,
    104.                     i.binormalWorld,
    105.                     i.normalWorld
    106.                 );
    107.                
    108.                 // Calculate Normal Direction
    109.                 float3 normalDirection = normalize( mul( localCoords, local2WorldTranspose ) );
    110.                
    111.                 // Lighting
    112.                 float3 diff = atten * _LightColor0.rgb * saturate( dot( normalDirection, lightDirection ) );
    113.                 float3 specularReflection = diff * tex.rgb * pow( saturate( dot( reflect( -lightDirection, normalDirection ), viewDirection ) ), _Shininess);
    114.                
    115.                
    116.  
    117.                 float3 lightFinal = diff + specularReflection;
    118.  
    119.                 //Painter
    120.                
    121.                 fixed4 shiftlightcol = float4(1.0 - _LightColor0.r, 1.0 - _LightColor0.g, 1.0 - _LightColor0.b, 1.0);
    122.  
    123.                 shiftlightcol = (shiftlightcol * Luminance(_LightColor0) - 0.1) * smoothstep( 0.0 , 0.6 ,Luminance(tex.rgb));
    124.  
    125.                 fixed4 outcol;
    126.  
    127.                 fixed4 texmixcol = float4(lerp(shiftlightcol.rgb, tex.rgb, length(diff * 4)), 1.0);
    128.                
    129.  
    130.                 fixed4 BrightSide = float4(_LightColor0.rgb * smoothstep( 0.0 , 0.3 ,Luminance(tex.rgb)), 1.0);
    131.  
    132.                 fixed4 lampmixcol = float4
    133.                                         (
    134.                                             lerp
    135.                                             (
    136.                                                 texmixcol.rgb,
    137.                                                  BrightSide.rgb,
    138.                                                   length(diff)
    139.                                             )
    140.                                         , 1.0);
    141.  
    142.                 fixed4 AnaLight = float4(_LightColor0.r - 0.35, _LightColor0.g, _LightColor0.b + 0.35, 1.0);
    143.                
    144.                 fixed4 AnaGradient = lerp(Luminance(tex.rgb) * AnaLight, Luminance(tex.rgb) * (_LightColor0 + _LightColor0), length(diff) * 2.5);
    145.                
    146.                 lampmixcol = lerp(lampmixcol, AnaGradient, length(diff * 2));
    147.  
    148.                 lampmixcol = lerp(lampmixcol, Luminance(lampmixcol) * tex, smoothstep( 0.4 , 0.6 , -length(diff)));
    149.  
    150.                 //implement fog - update pass
    151.  
    152.                 fixed LtSat = ( max(_LightColor0.r, max(_LightColor0.g, _LightColor0.b)) - min(_LightColor0.r, min(_LightColor0.g, _LightColor0.b)) )
    153.                                     / (1.0 - (2 * (Luminance(_LightColor0) - 1.0)));
    154.  
    155.                 lampmixcol = lerp(lerp((tex + float4(0.0,0.0,0.3,0.0)) * 0.5, tex + float4(0.3,0.0,0.0,0.0), length(diff)), lampmixcol, smoothstep(0.1, 0.2, LtSat));
    156.  
    157.                 return lampmixcol;
    158.             }
    159.            
    160.             ENDCG
    161.         }
    162.  
    163.         Pass
    164.         {
    165.             Tags { "LightMode" = "ForwardAdd" }
    166.  
    167.             Blend OneMinusDstColor One
    168.             CGPROGRAM
    169.             #pragma vertex vert
    170.             #pragma fragment frag
    171.             #pragma exclude_renderers flash
    172.             #include "UnityCG.cginc"
    173.             #include "UnityLightingCommon.cginc"
    174.            
    175.             // User Defined Variables
    176.             uniform float4 _Color;
    177.             uniform sampler2D _MainTex;
    178.             uniform float4 _MainTex_ST;
    179.             uniform sampler2D _BumpMap;
    180.             uniform float4 _BumpMap_ST;
    181.             uniform float _BumpDepth;
    182.             uniform float _Shininess;
    183.            
    184.            
    185.             // Base Input Structs
    186.             struct vertexInput
    187.             {
    188.                 float4 vertex: POSITION;
    189.                 float3 normal: NORMAL;
    190.                 float4 texcoord: TEXCOORD0;
    191.                 float4 tangent: TANGENT;
    192.             };
    193.             struct vertexOutput
    194.             {
    195.                 float4 pos: SV_POSITION;
    196.                 float4 tex: TEXCOORD0;
    197.                 float4 posWorld: TEXCOORD1;
    198.                 float3 normalWorld: TEXCOORD2;
    199.                 float3 tangentWorld: TEXCOORD3;
    200.                 float3 binormalWorld: TEXCOORD4;
    201.             };
    202.            
    203.             // Vertex Function
    204.             vertexOutput vert( vertexInput v )
    205.             {
    206.                 vertexOutput o;
    207.                
    208.                 o.normalWorld = normalize( mul( float4( v.normal, 0.0 ), unity_WorldToObject ).xyz );      
    209.                 o.tangentWorld = normalize( mul( unity_ObjectToWorld, v.tangent ).xyz );
    210.                 o.binormalWorld = normalize( cross( o.normalWorld, o.tangentWorld ) );
    211.                        
    212.                 o.posWorld = mul( unity_ObjectToWorld, v.vertex );
    213.                 o.pos = UnityObjectToClipPos( v.vertex );
    214.                 o.tex = v.texcoord;
    215.                
    216.                 return o;
    217.             }
    218.            
    219.             // Fragment Function
    220.             float4 frag( vertexOutput i ): COLOR
    221.             {
    222.                 float3 viewDirection = normalize( _WorldSpaceCameraPos.xyz - i.posWorld.xyz );
    223.                 float3 lightDirection;
    224.                 float atten;
    225.                
    226.                 if ( _WorldSpaceLightPos0.w == 0.0 )
    227.                 { // Directional Light
    228.                     atten = 1.0;
    229.                     lightDirection = normalize( _WorldSpaceLightPos0.xyz );
    230.                 }
    231.                 else
    232.                 {
    233.                     float3 fragmentToLightSource = _WorldSpaceLightPos0.xyz - i.posWorld.xyz;
    234.                     float distance = length( fragmentToLightSource );
    235.                     float atten = 1 / distance;
    236.                     lightDirection = normalize( fragmentToLightSource );
    237.                 }
    238.                
    239.                 // Texture Maps
    240.                 float4 tex = tex2D( _MainTex, i.tex);
    241.                 float4 texN = tex2D( _BumpMap, i.tex);
    242.                
    243.                 // unpackNormal Function
    244.                 float3 localCoords = float3(2.0 * texN.ag - float2(1.0,1.0), 0.0);
    245.                 //localCoords.z = 1.0 - 0.5 * dot( localCoords, localCoords );
    246.                 //localCoords.z = 1.0;
    247.                 localCoords.z = _BumpDepth;
    248.                
    249.                 // Normal Transpose Matrix
    250.                 float3x3 local2WorldTranspose = float3x3
    251.                 (
    252.                     i.tangentWorld,
    253.                     i.binormalWorld,
    254.                     i.normalWorld
    255.                 );
    256.                
    257.                 // Calculate Normal Direction
    258.                 float3 normalDirection = normalize( mul( localCoords, local2WorldTranspose ) );
    259.                
    260.                 // Lighting
    261.                 float3 diff = atten * _LightColor0.rgb * saturate( dot( normalDirection, lightDirection ) );
    262.                 float3 specularReflection = diff * tex.rgb * pow( saturate( dot( reflect( -lightDirection, normalDirection ), viewDirection ) ), _Shininess);
    263.                
    264.                
    265.  
    266.                 float3 lightFinal = diff + specularReflection;
    267.  
    268.                 //Painter
    269.                
    270.                 fixed4 shiftlightcol = float4(1.0 - _LightColor0.r, 1.0 - _LightColor0.g, 1.0 - _LightColor0.b, 1.0);
    271.  
    272.                 shiftlightcol = (shiftlightcol * Luminance(_LightColor0) - 0.1) * smoothstep( 0.0 , 0.6 ,Luminance(tex.rgb));
    273.  
    274.                 fixed4 outcol;
    275.  
    276.                 fixed4 texmixcol = float4(lerp(shiftlightcol.rgb, tex.rgb, length(diff * 4)), 1.0);
    277.                
    278.  
    279.                 fixed4 BrightSide = float4(_LightColor0.rgb * smoothstep( 0.0 , 0.3 ,Luminance(tex.rgb)), 1.0);
    280.  
    281.                 fixed4 lampmixcol = float4
    282.                                         (
    283.                                             lerp
    284.                                             (
    285.                                                 texmixcol.rgb,
    286.                                                  BrightSide.rgb,
    287.                                                   length(diff)
    288.                                             )
    289.                                         , 1.0);
    290.  
    291.                 fixed4 AnaLight = float4(_LightColor0.r - 0.35, _LightColor0.g, _LightColor0.b + 0.35, 1.0);
    292.                
    293.                 fixed4 AnaGradient = lerp(Luminance(tex.rgb) * AnaLight, Luminance(tex.rgb) * (_LightColor0 + _LightColor0), length(diff) * 2.5);
    294.                
    295.                 lampmixcol = lerp(lampmixcol, AnaGradient, length(diff * 2));
    296.  
    297.                 lampmixcol = lerp(lampmixcol, Luminance(lampmixcol) * tex, smoothstep( 0.4 , 0.6 , -length(diff)));
    298.  
    299.                 //implement fog - update pass
    300.  
    301.                 fixed LtSat = ( max(_LightColor0.r, max(_LightColor0.g, _LightColor0.b)) - min(_LightColor0.r, min(_LightColor0.g, _LightColor0.b)) )
    302.                                     / (1.0 - (2 * (Luminance(_LightColor0) - 1.0)));
    303.  
    304.                 lampmixcol = lerp(lerp((tex + float4(0.0,0.0,0.3,0.0)) * 0.5, tex + float4(0.3,0.0,0.0,0.0), length(diff)), lampmixcol, smoothstep(0.1, 0.2, LtSat));
    305.  
    306.                 return lampmixcol;
    307.             }
    308.            
    309.             ENDCG
    310.         }
    311.        
    312.     }
    313.     //FallBack "Specular"
    314. }
     
  2. transporter_gate_studios

    transporter_gate_studios

    Joined:
    Oct 17, 2016
    Posts:
    219