美文网首页
GLSL in Unity 系列文章(六):实时阴影实现——Sh

GLSL in Unity 系列文章(六):实时阴影实现——Sh

作者: 雄关漫道从头越 | 来源:发表于2020-12-04 20:44 被阅读0次

    Unity实时阴影实现——Shadow Mapping
    Unity的实时阴影-ShadowMap实现原理

    今天用GLSL实现一下Shadow Mapping,Shadow Mapping原理也比较简单,先在灯光的位置生成一个相机,平行光就使用正交模式,本篇使用的就是平行光,并且相机的朝向与灯光朝向一致,渲染出一张深度图,也就是生成了Shadow Mapping图,接收阴影时通过uv去采样深度图,比较深度即可,大于深度则说明被遮挡了,反之则没有,更详情的可以参考文章顶部的链接。
    以下是效果:


    Shadow Soft Shadow

    生成深度图

    Shader "GLSL/ShadowMapping/Caster" 
    {
        SubShader {
            Tags {          
                "RenderType" = "Opaque"
            }
            Pass {
                Fog { Mode Off }
                Cull front//设置Cull front可解决面向光源的acne问题
                GLSLPROGRAM
                //gl_Vertex 顶点
                //gl_Position 裁剪空间坐标输出到片元着色器
                //gl_FragColor 输出颜色
                #include "UnityCG.glslinc"
                #include "lib/Custom.glslinc"
                
                uniform float _gShadowBias;
    
                struct v2f {
                    vec4 pos;//其实没用到,为了展示如何使用glsl结构体
                    vec2 depth;
                };
    
                #ifdef VERTEX
                out v2f v;
                void main()
                {            
                    gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
                    gl_Position.z += _gShadowBias;
                    v.depth = gl_Position.zw;
                }
                #endif
                #ifdef FRAGMENT
                in v2f v;
                void main()
                {
                    float depth = v.depth.x / v.depth.y;
    
                #if defined (SHADER_TARGET_GLSL) 
                    depth = depth* 0.5 + 0.5; //(-1, 1)-->(0, 1)
                #elif defined (UNITY_REVERSED_Z) //如果是使用的reverzed-z,需要处理一下
                    depth = 1.0 - depth;       //(1, 0)-->(0, 1)
                #endif
    
                    gl_FragColor = EncodeFloatRGBA(depth);
                }
                #endif
                ENDGLSL  
            }
        }
    }
    

    接收阴影

    Shader "GLSL/ShadowMapping/Receiver" {
        SubShader{
            Tags { "RenderType" = "Opaque" }
            LOD 300
    
            Pass {
                Name "FORWARD"
                Tags{ "LightMode" = "ForwardBase" }
    
                GLSLPROGRAM
                //gl_Vertex 顶点
                //gl_Position 裁剪空间坐标输出到片元着色器
                //gl_FragColor 输出颜色
                #include "UnityCG.glslinc"
                #include "lib/Custom.glslinc"
    
                uniform mat4 _gWorldToShadow;
                uniform sampler2D _gShadowMapTexture;
                /*{TextureName}_TexelSize - a float4 property contains texture size information :
                x contains 1.0 / width
                y contains 1.0 / height
                z contains width
                w contains height*/
                uniform vec4 _gShadowMapTexture_TexelSize;
                uniform float _gShadowStrength;
    
                //3x3的PCF Soft Shadow
                float PCFSample(float depth, vec2 uv)
                {
                    float shadow = 0.0;
                    for (int x = -1; x <= 1; ++x)
                    {
                        for (int y = -1; y <= 1; ++y)
                        {
                            vec4 col = texture(_gShadowMapTexture, uv + vec2(x, y) * _gShadowMapTexture_TexelSize.xy);
                            float sampleDepth = DecodeFloatRGBA(col);
                            shadow += sampleDepth < depth ? _gShadowStrength : 1.0;//接受物体片元的深度与深度图的值比较,大于则表示被挡住灯光,显示为阴影,否则显示自己的颜色(这里显示白色)
                        }
                    }
                    return shadow /= 9.0;
                }
    
                #ifdef VERTEX
                out vec4 shadowCoord;
                void main()
                {            
                    gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
                    vec4 worldPos = unity_ObjectToWorld * gl_Vertex;
                    shadowCoord = _gWorldToShadow * worldPos;
                }
                #endif
                #ifdef FRAGMENT
                in vec4 shadowCoord;
                void main()
                {
                    // shadow
                    vec2 uv = shadowCoord.xy / shadowCoord.w;
                    uv = uv * 0.5 + 0.5; //(-1, 1)-->(0, 1)
    
                    float depth = shadowCoord.z / shadowCoord.w;
                #if defined (SHADER_TARGET_GLSL)
                    depth = depth * 0.5 + 0.5; //(-1, 1)-->(0, 1)
                #elif defined (UNITY_REVERSED_Z)
                    depth = 1 - depth;       //(1, 0)-->(0, 1)
                #endif
                    // PCFSample
                    // float shadow = PCFSample(depth, uv);
                    // gl_FragColor = vec4(shadow, shadow, shadow, shadow);
    
                    // sample depth texture
                    vec4 col = texture(_gShadowMapTexture, uv);//310以后texture2D过期了,使用texture函数
                    float sampleDepth = DecodeFloatRGBA(col);
                    float shadow = sampleDepth < depth ? _gShadowStrength : 1.0;//接受物体片元的深度与深度图的值比较,大于则表示被挡住灯光,显示为阴影,否则显示自己的颜色(这里显示白色)
                    gl_FragColor = vec4(shadow, shadow, shadow, shadow);
                }
                #endif
                ENDGLSL
            }
        }
    }
    

    C#设置全局变量

    using UnityEngine;
    
    public class ShadowMapping : MonoBehaviour
    {
        public Light dirLight;
        Camera dirLightCamera;
    
        public int shadowResolution = 1;
        public Shader shadowCaster = null;
        private RenderTexture rt_2d;
    
        void OnDestroy()
        {
            dirLightCamera = null;
            DestroyImmediate(rt_2d);
        }
        
        //创建rt
        private RenderTexture CreateRenderTexture()
        {
            RenderTextureFormat rtFormat = RenderTextureFormat.Default;
            if (!SystemInfo.SupportsRenderTextureFormat(rtFormat))
                rtFormat = RenderTextureFormat.Default;
    
            rt_2d = new RenderTexture(512 * shadowResolution, 512 * shadowResolution, 24, rtFormat);
            rt_2d.hideFlags = HideFlags.DontSave;
    
            Shader.SetGlobalTexture("_gShadowMapTexture", rt_2d);
    
            return rt_2d;
        }
        
        //创建正交相机
        public Camera CreateDirLightCamera()
        {
            GameObject goLightCamera = new GameObject("Directional Light Camera");
            Camera LightCamera = goLightCamera.AddComponent<Camera>();
    
            LightCamera.cullingMask = 1 << LayerMask.NameToLayer("Caster");
            LightCamera.backgroundColor = Color.white;
            LightCamera.clearFlags = CameraClearFlags.SolidColor;
    
            LightCamera.orthographic = true;
            LightCamera.orthographicSize = 10f;
            LightCamera.nearClipPlane = 0.3f;
            LightCamera.farClipPlane = 100;
            LightCamera.transform.rotation = dirLight.transform.rotation;
            LightCamera.transform.position = dirLight.transform.position;
            //LightCamera.enabled = false;
            return LightCamera;
        }
    
        private void Update()
        {
            if (dirLight)
            {
                if (!dirLightCamera)
                {
                    dirLightCamera = CreateDirLightCamera();
                    dirLightCamera.targetTexture = CreateRenderTexture();
                }
                //dirLightCamera.RenderWithShader(shadowCaster, "");//没用
                dirLightCamera.SetReplacementShader(shadowCaster, "RenderType");
                Shader.SetGlobalFloat("_gShadowBias", 0.005f);
                Shader.SetGlobalFloat("_gShadowStrength", 0.5f);
                Matrix4x4 projectionMatrix = GL.GetGPUProjectionMatrix(dirLightCamera.projectionMatrix, false);
                Shader.SetGlobalMatrix("_gWorldToShadow", projectionMatrix * dirLightCamera.worldToCameraMatrix);
            }
        }
    }
    

    好了,下次可以实现一下CSM(Cascaded Shadow Mapping),一起期待吧。

    github:https://github.com/eangulee/GLSLInUnity.git

    相关文章

      网友评论

          本文标题:GLSL in Unity 系列文章(六):实时阴影实现——Sh

          本文链接:https://www.haomeiwen.com/subject/okniwktx.html