美文网首页
【Unity Shader入门精要学习】复杂的光照(四)

【Unity Shader入门精要学习】复杂的光照(四)

作者: 小王子称号发放NPC | 来源:发表于2019-10-21 15:08 被阅读0次

Unity的阴影——通用ShadowMap的实现

其实还有很多其他阴影的实现方式,详见其他文章。

一、不透明物体阴影

一般ShadowMap的实现方式分为三步:
1、获取ShadowMap(也就是某个光源下的深度图,即将某个摄像机放在光源下,并调整朝向与光源一致,所绘制出的图像),目前只使用自定义获取深度图。其实这一步就是对投射阴影的物体进行深度图绘制


深度图

2、将主摄像机绘制的物体装换到光源空间下,然后用转换之后的XY对ShadowMap采样,将采样得到的深度值S_Z与转换到光源空间之后的Z值进行比较,如果Z大于S_Z则说明此点处于阴影中。
3、绘制阴影


阴影

获取深度图Shader
所谓深度就是在裁剪坐标下的Z值,因为只有在裁剪坐标下才有深度比较才有意义,最终的深度值会除以W,变成NDC下的值,而NDC下的Z值才是真正的深度值

Shader "Unlit/DepthTexture"
{
    SubShader{
        Tags{"RenderType"="Opaque"}
        Pass{
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

            struct a2v
            {
                float4 vertex:POSITION;
            };

            struct v2f
            {
                float4 pos:SV_POSITION;
                float2 depth : TEXCOORD0;
            };

            v2f vert(a2v v)
            {
                v2f o;
                o.pos = UnityObjectToClipPos(v.vertex);
                o.depth = o.pos.zw;

                return o;
            }

            fixed4 frag(v2f i):SV_TARGET
            {
                float depth = i.depth.x/i.depth.y;
                fixed4 color = EncodeFloatRGBA(depth);

                return color;
            }

            ENDCG
        }
    }
}

获取某个摄像机深度图与转换到裁剪矩阵的CS

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class DepthCapture : MonoBehaviour
{
    // Start is called before the first frame update
    private Camera _childCamera;
    private RenderTexture _renderTexture;
    void Start()
    {
        CameraInit();
    }
    
    // Update is called once per frame
    void Update()
    { 
       SetLightDirection();
       CameraUpdate();
    }

    void CameraInit()
    {
        _childCamera = new GameObject().AddComponent<Camera>();
        _childCamera.name = "DepthCamera";
        _childCamera.depth = 2;
        _childCamera.clearFlags = CameraClearFlags.SolidColor;
        _childCamera.backgroundColor = new Color(1,1,1,0);
        _childCamera.aspect = 1;
        
        _childCamera.orthographic = true;
        _childCamera.orthographicSize = 10;
        
        _renderTexture = new RenderTexture(1024, 1024, 0);
        _renderTexture.wrapMode = TextureWrapMode.Clamp;
        _childCamera.targetTexture = _renderTexture;
        
        _childCamera.SetReplacementShader(Shader.Find("Unlit/DepthTexture"),"RenderType" );
        Shader.SetGlobalTexture("_CameraRT",_renderTexture);
    }

    void CameraUpdate()
    {
        Matrix4x4 lightClipProjectMatrix = GetLightProjectMatrix();
        Shader.SetGlobalMatrix("_LightProjection",lightClipProjectMatrix);
        
    }

    private Matrix4x4 GetLightProjectMatrix()
    {
        //这个矩阵其实是世界坐标系转换到相机坐标系的
        Matrix4x4 toCameraMatrix = _childCamera.worldToCameraMatrix;
        Matrix4x4 projectionMatrix = GL.GetGPUProjectionMatrix(_childCamera.projectionMatrix, false);
        Matrix4x4 lightClipMatrix = projectionMatrix * toCameraMatrix;

        return lightClipMatrix;
    }

    void SetLightDirection()
    {
        Vector3 dir = Vector3.zero - this.transform.position;
        this.transform.rotation = Quaternion.LookRotation(dir);
        
        _childCamera.transform.position = this.transform.position;
        _childCamera.transform.rotation = this.transform.rotation;
        _childCamera.transform.parent = this.transform;
    }
}

绘制阴影的Shader

Shader "Unlit/BaseShadow"
{
    Properties
    {
        _DepthTex ("Texture", 2D) = "white" {}
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 100

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

            struct a2v
            {
                float4 vertex : POSITION;
            };

            struct v2f
            {
                float4 pos:SV_POSITION;
                float4 worldPos:TEXCOORD0;
            };

            sampler2D _DepthTex;
            float4x4 _LightProjection;
            sampler2D _CameraRT;

            v2f vert (a2v v)
            {
                v2f o;
                o.pos = UnityObjectToClipPos(v.vertex);
                o.worldPos = mul(unity_ObjectToWorld,v.vertex);
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                float4 lightClipPos = mul(_LightProjection,i.worldPos);
                lightClipPos.xyz = lightClipPos.xyz/lightClipPos.w;

                float2 uv = lightClipPos * 0.5 + 0.5;

                fixed4 depthColor = tex2D(_CameraRT, uv);
                float depth = DecodeFloatRGBA(depthColor);

                if(depth < lightClipPos.z + 0.0005){
                    return fixed4(1,0,0,1);
                }
                else{
                    return fixed4(1,1,1,1);
                }
            }
            ENDCG
        }
    }
}

相关文章

网友评论

      本文标题:【Unity Shader入门精要学习】复杂的光照(四)

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