unity 基于光线步进的 舞台灯效果

样例 1:

 

样例 2:

 

 

 

参考了网上一个大神的体积光shader, 增加了光线的线性衰减和地面接受光源。

Light :

Shader "Hidden/VertexVolumetricLight"
{
    Properties
    {
    }
    SubShader
    {
        Tags { "RenderType" = "Transparent" "Queue" = "Transparent" "IgnoreProjector"="true" }
        LOD 100

        Pass
        {
            zwrite off
            blend srcalpha one
            
            colormask rgb
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #pragma multi_compile_fog
            #pragma multi_compile __ USE_COOKIE
            
            #include "UnityCG.cginc"
            #include "Lighting.cginc"
            #include "AutoLight.cginc"

            #define RAY_STEP 8
            
            uniform float4x4 _VolumetricLightProjector;
            uniform float4 _WorldLightPos;
            uniform float4 _VolumetricProjectionParams;

#ifdef USE_COOKIE
            uniform sampler2D _LightCookie;
#endif

            struct appdata
            {
                float4 vertex : POSITION;
                float3 color : COLOR;
            };

            struct v2f
            {
                UNITY_FOG_COORDS(0)
                float4 vertex : SV_POSITION;
                float3 viewPos : TEXCOORD1;
                float3 viewCamPos : TEXCOORD2;
                float3 vcol : COLOR;
            };

            float LinearLightEyeDepth(float z)
            {
                return 1.0 / (_VolumetricProjectionParams.y * z + _VolumetricProjectionParams.z);
            }
            
            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                UNITY_TRANSFER_FOG(o, o.vertex);

                o.viewCamPos = mul(unity_WorldToObject, float4(_WorldSpaceCameraPos.xyz, 1)).xyz;
                o.viewCamPos.z *= -1;

                o.viewPos = v.vertex.xyz;
                o.viewPos.z *= -1;
                o.vcol = v.color;
            
                return o;
            }
            
            float4 frag (v2f i) : SV_Target
            {
                float delta = 1.0 / RAY_STEP;
                float4 col = 0;

                float4 beginPjPos = mul(_VolumetricLightProjector, float4(i.viewPos, 1));
                beginPjPos /= beginPjPos.w;
                float4 pjCamPos = mul(_VolumetricLightProjector, float4(i.viewCamPos, 1));
                pjCamPos /= pjCamPos.w;

                float3 pjViewDir = normalize(beginPjPos.xyz - pjCamPos.xyz);
                pjViewDir -= 2 * pjViewDir * step(0, i.viewCamPos.z) * _WorldLightPos.w;

                for (float k = 0; k < RAY_STEP; k++) 
                {
                    float4 curpos = beginPjPos;
                    float3 vdir = pjViewDir.xyz*k*delta;
                    curpos.xyz += vdir;

                    float boardFac = step(-1, curpos.x)*step(-1, curpos.y)*step(-1, curpos.z)*step(curpos.x, 1)*step(curpos.y, 1)*step(curpos.z, 1);
                    curpos = ComputeScreenPos(curpos);
                    half2 pjuv = curpos.xy / curpos.w;
#if UNITY_UV_STARTS_AT_TOP
                    pjuv.y = 1 - pjuv.y;
#endif

#ifdef USE_COOKIE
                    fixed4 cookie = tex2D(_LightCookie, pjuv);
                    fixed3 cookiecol = cookie.rgb * cookie.a;
#else
                    half2 toCent = pjuv - half2(0.5, 0.5);
                    half l = 1 - saturate((length(toCent) - 0.3) / (0.5 - 0.3));
                    fixed3 cookiecol = fixed3(l, l, l);
#endif

                    col.rgb += cookiecol * i.vcol.rgb * delta * boardFac;
                }

                col.a = 1;

                UNITY_APPLY_FOG(i.fogCoord, col);

                // 线性衰减
                float z = LinearLightEyeDepth(-beginPjPos.z);
                col.rgb *= 1 - z * _VolumetricProjectionParams.w;
                return col;
            }
            ENDCG
        }
    }
}
// Upgrade NOTE: replaced '_Object2World' with 'unity_ObjectToWorld'

// Upgrade NOTE: replaced '_Object2World' with 'unity_ObjectToWorld'


// Upgrade NOTE: replaced 'PositionFog()' with transforming position into clip space.
// Upgrade NOTE: replaced 'V2F_POS_FOG' with 'float4 pos : SV_POSITION'

Shader "VLight/VolumetricCaster"
{
    Properties 
    {
        _Color ("Main Color", Color) = (1,1,1,1)
        _MainTex ("Base (RGB)", 2D) = "white" {}
    }


    SubShader
    {
        Tags { "Queue" = "Geometry" }
        LOD 100

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"

            #define VLNR_MAX 2

            struct v2f
            {
                float4 pos : SV_POSITION;
                float2    uv : TEXCOORD0;
                float3 worldPos : TEXCOORD1;
            };

            uniform float4 _MainTex_ST;
            uniform sampler2D _MainTex;
            half4 _Color;

            uniform int       _VLightCount;
            uniform float4x4  _VLightWorldToLocal[VLNR_MAX];
            uniform float4x4  _VLightProjector[VLNR_MAX];
            uniform float4    _VLightPos[VLNR_MAX];
            uniform sampler2D _VLightTex;

            float3 CalculateVLight(int index, float3 worldPos)
            {
                //  世界坐标转模型坐标!!!
                float3 pos = mul(_VLightWorldToLocal[index], float4(worldPos, 1.0)).xyz;
                pos.z *= -1;

                float4 pjPos = mul(_VLightProjector[index], float4(pos, 1));
                pjPos /= pjPos.w;

                float boardFac = step(-1, pjPos.x) * step(-1, pjPos.y) * step(-1, pjPos.z) * step(pjPos.x, 1) * step(pjPos.y, 1) * step(pjPos.z, 1);
                pjPos = ComputeScreenPos(pjPos);
                half2 pjuv = pjPos.xy / pjPos.w;

#if UNITY_UV_STARTS_AT_TOP
                pjuv.y = 1 - pjuv.y;
#endif
                fixed4 cookie = tex2D(_VLightTex, pjuv);

                return cookie.rgb * cookie.a * 1.0 / _VLightCount * boardFac;
            }

            v2f vert(appdata_base v)
            {
                v2f o;
                o.pos = UnityObjectToClipPos(v.vertex);
                o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
                o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
                return o;
            }

            float4 frag(v2f input) : SV_Target
            {
                half4 texcol = tex2D(_MainTex, input.uv);

                float3 col = 0;
                for (int i = 0; i < _VLightCount; i++)
                {
                    float3 worldPos = input.worldPos;
                    col += CalculateVLight(i, worldPos);
                }

                return texcol * _Color + float4(col, 1.0);
            }

            ENDCG
        }
    }

}

 

posted @ 2020-05-19 12:29  liuchong9123  阅读(939)  评论(0编辑  收藏  举报