zoukankan      html  css  js  c++  java
  • 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
            }
        }
    
    }
  • 相关阅读:
    慎用静态类static class
    20170617
    学习笔记之工厂模式-2017年1月11日23:00:53
    链表翻转
    面试被虐
    tips
    依赖注入那些事儿
    浅谈算法和数据结构(1):栈和队列
    猫都能学会的Unity3D Shader入门指南(一)
    SerializeField等Unity内的小用法
  • 原文地址:https://www.cnblogs.com/liucUP/p/12916242.html
Copyright © 2011-2022 走看看