ShadowMap 实时阴影

ShadowMap的原理就是在灯光空间渲染出一张RenderTexture 记录物体顶点在灯光空间中的深度值,在渲染地面的时候 使用顶点计算在灯光空间中的深度 ,再与深度图中的值进行比较>则是阴影

1、渲染深度图使用的shader——一定要放在Resources

Shader "ZLY/DeapthTextureShader"
{
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 100

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

            struct appdata
            {
                float4 vertex : POSITION;
            };

            struct v2f
            {
                float4 vertex : SV_POSITION;
                float2 depth:TEXCOORD1;
            };

            sampler2D _MainTex;
            float4 _MainTex_ST;

            float4x4 zly_ProjectionMatrix;


            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);//模型空间转裁剪空间
                 //o.depth=o.vertex.zw; 坐标空间转换后会产生深度误差 所以使用相同的深度转换方式
    zly_ProjectionMatrix = mul(zly_ProjectionMatrix, unity_ObjectToWorld);	
	o.depth = mul(zly_ProjectionMatrix,v.vertex).zw;
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                float depth =i.depth.x/i.depth.y;
#if defined(UNITY_REVERSED_Z)
    depth = 1.0f - depth;//转成齐次空间坐标 [1,0]变成[0,1]
#endif
				fixed4 col = EncodeFloatRGBA(depth);// float四个字节 存RGB
				return col;
            }
            ENDCG
        }
    }
}

2、顶点深度比较  放在要渲染的物体上


Shader "ZLY/ShadowOnShader"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
    }
    SubShader
    {
       Pass
		{
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag

			#include "UnityCG.cginc"

			sampler2D _MainTex;
			float4 _MainTex_ST;

		
			// sampler2D unity_Lightmap;//若开启光照贴图,系统默认填值
			// float4 unity_LightmapST;//与上unity_Lightmap同理

			struct v2f {
				float4 pos:SV_POSITION;
				float2 uv:TEXCOORD0;
				float2 uv2:TEXCOORD1;				
				float4 proj : TEXCOORD3;
			};


			float4x4 zly_ProjectionMatrix;//世界空间转灯关空间矩阵
			sampler2D zly_DepthTexture;//深度图

			v2f vert(appdata_full v)
			{
				v2f o;
				o.pos = UnityObjectToClipPos(v.vertex);

				//动态阴影
				zly_ProjectionMatrix = mul(zly_ProjectionMatrix, unity_ObjectToWorld);//模型空间转世界空间转灯关空间
				o.proj = mul(zly_ProjectionMatrix, v.vertex);
	
				//--------------------------------------------------
				o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);//偏移压缩后的像素取点位置
				o.uv2 = v.texcoord1.xy * unity_LightmapST.xy + unity_LightmapST.zw;	

				return o;
			}

			fixed4 frag(v2f v) : COLOR
			{
				//解密光照贴图计算公式
				float3 lightmapColor = DecodeLightmap(UNITY_SAMPLE_TEX2D(unity_Lightmap,v.uv2));
				fixed4 col = tex2D(_MainTex, v.uv);

				col.rgb *= lightmapColor;

				

				float depth = v.proj.z/v.proj.w;//齐次坐标深度值
#if defined(UNITY_REVERSED_Z)
    depth = 1.0f - depth;//转成齐次空间坐标 [1,0]变成[0,1]
#endif
				fixed4 dcol = tex2Dproj(zly_DepthTexture, v.proj);//转齐次坐标后uv
				float d = DecodeFloatRGBA(dcol);//RGB转float
				float shadowScale = 1;
				if(depth > d)
				{
					shadowScale = 0.55;
				}
				return col*shadowScale;
			}
			ENDCG
		}
    }
}

3、调用Shader的脚本

using UnityEngine;
using System.Collections;

/// <summary>
/// 创建depth相机
/// by lijia
/// </summary>
public class DepthTextureCamera : MonoBehaviour
{
    private static DepthTextureCamera _inst;
    public static DepthTextureCamera Instance() { return _inst; }

    private Transform _target;
    public Camera _camera;
    private RenderTexture _rt;
    /// <summary>
    /// 光照的角度
    /// </summary>
    //public Transform lightTrans;

    Matrix4x4 sm = new Matrix4x4();


    private float _xOffset = 0f;
    private float _yOffset = 20f;
    private float _zOffset = 20f;

    void Awake()
    {
        _inst = this;
    }
    void Start()
    {
        //_camera = new GameObject().AddComponent<Camera>();
        //_camera.name = "DepthCamera";
        //_camera.depth = 0;
        //_camera.clearFlags = CameraClearFlags.SolidColor;
        //_camera.backgroundColor = new Color(1, 1, 1, 0);

        //_camera.cullingMask = LayerMask.GetMask("Player");
        //_camera.aspect = 1;
        //_camera.transform.parent = lightTrans.transform;
        //_camera.transform.localPosition = Vector3.left * 15;
        //_camera.transform.localEulerAngles = Vector3.up*30;

        //_camera.orthographic = true;
        //_camera.orthographicSize = 10;

        sm.m00 = 0.5f;
        sm.m11 = 0.5f;
        sm.m22 = 0.5f;
        sm.m03 = 0.5f;
        sm.m13 = 0.5f;
        sm.m23 = 0.5f;
        sm.m33 = 1;

        _rt = new RenderTexture(2048, 2048, 0);
        _rt.wrapMode = TextureWrapMode.Clamp;
        _camera.targetTexture = _rt;
        _camera.SetReplacementShader(Shader.Find("ZLY/DeapthTextureShader"), "RenderType");

    }  

    void Update()
    {
        if(_target==null)
        {
            return;
        }
        HELPER_VEC.Set(_target.position.x + _xOffset, _target.position.y + _yOffset,
                _target.position.z + _zOffset);
        this.transform.position = HELPER_VEC;
        //transform.LookAt(_target.position);
        //世界顶点坐标转换到_camera裁剪空间坐标矩阵  sm[-1,1]转换到[0,1]转换矩阵
        Matrix4x4 tm = GL.GetGPUProjectionMatrix(_camera.projectionMatrix, false) * _camera.worldToCameraMatrix;
        tm = sm * tm;
        Shader.SetGlobalMatrix("zly_ProjectionMatrix", tm);
    }
    private static Vector3 HELPER_VEC = new Vector3();
  
    public void SetTarget(Transform target,ushort mapID) 
    { 
        _target = target;

        HELPER_VEC.Set(60, -123, 0);//设置光照方向       
        
        transform.position = _target.position;
        transform.eulerAngles = HELPER_VEC;
        transform.position -= transform.forward * 40;
        _xOffset = transform.position.x - _target.position.x;
        _yOffset = transform.position.y - _target.position.y;
        _zOffset = transform.position.z - _target.position.z;
        Matrix4x4 tm = GL.GetGPUProjectionMatrix(_camera.projectionMatrix, false) * _camera.worldToCameraMatrix;
        tm = sm * tm;
        Shader.SetGlobalMatrix("zly_ProjectionMatrix", tm);
        Shader.SetGlobalTexture("zly_DepthTexture", _rt);
        Shader.SetGlobalFloat("zly_Shadow", 1);

    }
}

在顶点坐标从模型空间转换到灯光空间时,深度会发生偏移,不同的相机旋转角度offset不同 

 使用:

o.vertex = UnityObjectToClipPos(v.vertex);
                //o.depth=o.vertex.zw;

改为使用:——此方法会产生偏移

//世界顶点坐标转换到_camera裁剪空间坐标矩阵  sm[-1,1]转换到[0,1]转换矩阵
        Matrix4x4 tm = GL.GetGPUProjectionMatrix(_camera.projectionMatrix, false) * _camera.worldToCameraMatrix;
        tm = sm * tm;
        Shader.SetGlobalMatrix("zly_ProjectionMatrix", tm);
    zly_ProjectionMatrix = mul(zly_ProjectionMatrix, unity_ObjectToWorld);    
    o.depth = mul(zly_ProjectionMatrix,v.vertex).zw;

是为了使比较的depth使用相同的空间转换方式 产生相同的差值

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值