Unity_CSMAndSimpleShadow

https://github.com/DreamChaseAndVera/Unity_CSMAndSimpleShadow.git

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

public class CascadedShadowMapping : MonoBehaviour
{
    public Light dirLight;
    Camera dirLightCamera;

    public int shadowResolution = 1;
    public Shader shadowCaster = null;

    private Matrix4x4 biasMatrix = Matrix4x4.identity;

    List<Matrix4x4> world2ShadowMats = new List<Matrix4x4>(4);
    GameObject[] dirLightCameraSplits = new GameObject[4];
    RenderTexture[] depthTextures = new RenderTexture[4];

    void OnDestroy()
    {
        dirLightCamera = null;

        for (int i = 0; i < 4; i++)
        {
            if (depthTextures[i])
            {
                DestroyImmediate(depthTextures[i]);
            }
        }
    }

    void Awake()
    {
        biasMatrix.SetRow(0, new Vector4(0.5f, 0, 0, 0.5f));
        biasMatrix.SetRow(1, new Vector4(0, 0.5f, 0, 0.5f));
        biasMatrix.SetRow(2, new Vector4(0, 0, 0.5f, 0.5f));
        biasMatrix.SetRow(3, new Vector4(0, 0, 0, 1f));

        InitFrustumCorners();
    }

    // Use this for initialization
    void Start()
    {
    }

    private void CreateRenderTexture()
    {
        RenderTextureFormat rtFormat = RenderTextureFormat.Default;
        if (!SystemInfo.SupportsRenderTextureFormat(rtFormat))
            rtFormat = RenderTextureFormat.Default;

        for (int i = 0; i < 4; i++)
        {
            depthTextures[i] = new RenderTexture(1024, 1024, 24, rtFormat);
            Shader.SetGlobalTexture("_gShadowMapTexture" + i, depthTextures[i]);
        }
    }

    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.enabled = false;

        for (int i = 0; i < 4; i++)
        {
            dirLightCameraSplits[i] = new GameObject("dirLightCameraSplits" + i);
        }

        return LightCamera;
    }

    private void Update()
    {
        CalcMainCameraSplitsFrustumCorners();
        CalcLightCameraSplitsFrustum();

        if (dirLight)
        {
            if (!dirLightCamera)
            {
                dirLightCamera = CreateDirLightCamera();

                CreateRenderTexture();
            }

            Shader.SetGlobalFloat("_gShadowBias", 0.005f);
            Shader.SetGlobalFloat("_gShadowStrength", 0.5f);

            world2ShadowMats.Clear();
            for (int i = 0; i < 4; i++)
            {
                ConstructLightCameraSplits(i);

                dirLightCamera.targetTexture = depthTextures[i];
                dirLightCamera.RenderWithShader(shadowCaster, "");

                Matrix4x4 projectionMatrix = GL.GetGPUProjectionMatrix(dirLightCamera.projectionMatrix, false);
                world2ShadowMats.Add(projectionMatrix * dirLightCamera.worldToCameraMatrix);
            }

            Shader.SetGlobalMatrixArray("_gWorld2Shadow", world2ShadowMats);
        }
    }

    float[] _LightSplitsNear;
    float[] _LightSplitsFar;

    struct FrustumCorners
    {
        public Vector3[] nearCorners;
        public Vector3[] farCorners;
    }

    FrustumCorners[] mainCamera_Splits_fcs;
    FrustumCorners[] lightCamera_Splits_fcs;

    void InitFrustumCorners()
    {
        mainCamera_Splits_fcs = new FrustumCorners[4];
        lightCamera_Splits_fcs = new FrustumCorners[4];
        for (int i = 0; i < 4; i++)
        {
            mainCamera_Splits_fcs[i].nearCorners = new Vector3[4];
            mainCamera_Splits_fcs[i].farCorners = new Vector3[4];

            lightCamera_Splits_fcs[i].nearCorners = new Vector3[4];
            lightCamera_Splits_fcs[i].farCorners = new Vector3[4];
        }
    }

    void CalcMainCameraSplitsFrustumCorners()
    {
        float near = Camera.main.nearClipPlane;
        float far = Camera.main.farClipPlane;

        float[] nears = { near,
            far * 0.067f + near,
            far * 0.133f + far * 0.067f + near,
            far * 0.267f + far * 0.133f + far * 0.067f + near
        };
        float[] fars = { far * 0.067f + near, far * 0.133f + far * 0.067f + near, far * 0.267f + far * 0.133f + far * 0.067f + near, far };

        _LightSplitsNear = nears;
        _LightSplitsFar = fars;

        Shader.SetGlobalVector("_gLightSplitsNear", new Vector4(_LightSplitsNear[0], _LightSplitsNear[1], _LightSplitsNear[2], _LightSplitsNear[3]));
        Shader.SetGlobalVector("_gLightSplitsFar", new Vector4(_LightSplitsFar[0], _LightSplitsFar[1], _LightSplitsFar[2], _LightSplitsFar[3]));

        for (int k = 0; k < 4; k++)
        {
            Camera.main.CalculateFrustumCorners(new Rect(0, 0, 1, 1), _LightSplitsNear[k], Camera.MonoOrStereoscopicEye.Mono, mainCamera_Splits_fcs[k].nearCorners);
            for (int i = 0; i < 4; i++)
            {
                mainCamera_Splits_fcs[k].nearCorners[i] = Camera.main.transform.TransformPoint(mainCamera_Splits_fcs[k].nearCorners[i]);
            }

            Camera.main.CalculateFrustumCorners(new Rect(0, 0, 1, 1), _LightSplitsFar[k], Camera.MonoOrStereoscopicEye.Mono, mainCamera_Splits_fcs[k].farCorners);
            for (int i = 0; i < 4; i++)
            {
                mainCamera_Splits_fcs[k].farCorners[i] = Camera.main.transform.TransformPoint(mainCamera_Splits_fcs[k].farCorners[i]);
            }
        }
    }

    void CalcLightCameraSplitsFrustum()
    {
        if (dirLightCamera == null)
            return;

        for (int k = 0; k < 4; k++)
        {
            for (int i = 0; i < 4; i++)
            {
                lightCamera_Splits_fcs[k].nearCorners[i] = dirLightCameraSplits[k].transform.InverseTransformPoint(mainCamera_Splits_fcs[k].nearCorners[i]);
                lightCamera_Splits_fcs[k].farCorners[i] = dirLightCameraSplits[k].transform.InverseTransformPoint(mainCamera_Splits_fcs[k].farCorners[i]);
            }

            float[] xs = { lightCamera_Splits_fcs[k].nearCorners[0].x, lightCamera_Splits_fcs[k].nearCorners[1].x, lightCamera_Splits_fcs[k].nearCorners[2].x, lightCamera_Splits_fcs[k].nearCorners[3].x,
                       lightCamera_Splits_fcs[k].farCorners[0].x, lightCamera_Splits_fcs[k].farCorners[1].x, lightCamera_Splits_fcs[k].farCorners[2].x, lightCamera_Splits_fcs[k].farCorners[3].x };

            float[] ys = { lightCamera_Splits_fcs[k].nearCorners[0].y, lightCamera_Splits_fcs[k].nearCorners[1].y, lightCamera_Splits_fcs[k].nearCorners[2].y, lightCamera_Splits_fcs[k].nearCorners[3].y,
                       lightCamera_Splits_fcs[k].farCorners[0].y, lightCamera_Splits_fcs[k].farCorners[1].y, lightCamera_Splits_fcs[k].farCorners[2].y, lightCamera_Splits_fcs[k].farCorners[3].y };

            float[] zs = { lightCamera_Splits_fcs[k].nearCorners[0].z, lightCamera_Splits_fcs[k].nearCorners[1].z, lightCamera_Splits_fcs[k].nearCorners[2].z, lightCamera_Splits_fcs[k].nearCorners[3].z,
                       lightCamera_Splits_fcs[k].farCorners[0].z, lightCamera_Splits_fcs[k].farCorners[1].z, lightCamera_Splits_fcs[k].farCorners[2].z, lightCamera_Splits_fcs[k].farCorners[3].z };

            float minX = Mathf.Min(xs);
            float maxX = Mathf.Max(xs);

            float minY = Mathf.Min(ys);
            float maxY = Mathf.Max(ys);

            float minZ = Mathf.Min(zs);
            float maxZ = Mathf.Max(zs);

            lightCamera_Splits_fcs[k].nearCorners[0] = new Vector3(minX, minY, minZ);
            lightCamera_Splits_fcs[k].nearCorners[1] = new Vector3(maxX, minY, minZ);
            lightCamera_Splits_fcs[k].nearCorners[2] = new Vector3(maxX, maxY, minZ);
            lightCamera_Splits_fcs[k].nearCorners[3] = new Vector3(minX, maxY, minZ);

            lightCamera_Splits_fcs[k].farCorners[0] = new Vector3(minX, minY, maxZ);
            lightCamera_Splits_fcs[k].farCorners[1] = new Vector3(maxX, minY, maxZ);
            lightCamera_Splits_fcs[k].farCorners[2] = new Vector3(maxX, maxY, maxZ);
            lightCamera_Splits_fcs[k].farCorners[3] = new Vector3(minX, maxY, maxZ);

            Vector3 pos = lightCamera_Splits_fcs[k].nearCorners[0] + (lightCamera_Splits_fcs[k].nearCorners[2] - lightCamera_Splits_fcs[k].nearCorners[0]) * 0.5f;


            dirLightCameraSplits[k].transform.position = dirLightCameraSplits[k].transform.TransformPoint(pos);
            dirLightCameraSplits[k].transform.rotation = dirLight.transform.rotation;

        }
    }

    void ConstructLightCameraSplits(int k)
    {
        dirLightCamera.transform.position = dirLightCameraSplits[k].transform.position;
        dirLightCamera.transform.rotation = dirLightCameraSplits[k].transform.rotation;

        dirLightCamera.nearClipPlane = lightCamera_Splits_fcs[k].nearCorners[0].z;
        dirLightCamera.farClipPlane = lightCamera_Splits_fcs[k].farCorners[0].z;

        dirLightCamera.aspect = Vector3.Magnitude(lightCamera_Splits_fcs[k].nearCorners[0] - lightCamera_Splits_fcs[k].nearCorners[1]) / Vector3.Magnitude(lightCamera_Splits_fcs[k].nearCorners[1] - lightCamera_Splits_fcs[k].nearCorners[2]);
        dirLightCamera.orthographicSize = Vector3.Magnitude(lightCamera_Splits_fcs[k].nearCorners[1] - lightCamera_Splits_fcs[k].nearCorners[2]) * 0.5f;
    }

    void CalcWorldToShadows()
    {

    }

    void OnDrawGizmos()
    {
        if (dirLightCamera == null)
            return;

        /*
        Gizmos.color = Color.blue;
        for (int i = 0; i < 4; i++)
        {
            Gizmos.DrawSphere(mainCamera_fcs.nearCorners[i], 0.1f);
            Gizmos.DrawSphere(mainCamera_fcs.farCorners[i], 0.1f);
        }

        Gizmos.color = Color.red;
        for (int i = 0; i < 4; i++)
        {
            Gizmos.DrawSphere(lightCamera_fcs.nearCorners[i], 0.1f);
            Gizmos.DrawSphere(lightCamera_fcs.farCorners[i], 0.1f);
        }

        Gizmos.color = Color.red;
        Gizmos.DrawLine(lightCamera_fcs.nearCorners[0], lightCamera_fcs.nearCorners[1]);
        Gizmos.DrawLine(lightCamera_fcs.nearCorners[1], lightCamera_fcs.nearCorners[2]);
        Gizmos.DrawLine(lightCamera_fcs.nearCorners[2], lightCamera_fcs.nearCorners[3]);
        Gizmos.DrawLine(lightCamera_fcs.nearCorners[3], lightCamera_fcs.nearCorners[0]);

        Gizmos.color = Color.green;
        Gizmos.DrawLine(lightCamera_fcs.farCorners[0], lightCamera_fcs.farCorners[1]);
        Gizmos.DrawLine(lightCamera_fcs.farCorners[1], lightCamera_fcs.farCorners[2]);
        Gizmos.DrawLine(lightCamera_fcs.farCorners[2], lightCamera_fcs.farCorners[3]);
        Gizmos.DrawLine(lightCamera_fcs.farCorners[3], lightCamera_fcs.farCorners[0]);

        Gizmos.DrawLine(lightCamera_fcs.nearCorners[0], lightCamera_fcs.farCorners[0]);
        Gizmos.DrawLine(lightCamera_fcs.nearCorners[1], lightCamera_fcs.farCorners[1]);
        Gizmos.DrawLine(lightCamera_fcs.nearCorners[2], lightCamera_fcs.farCorners[2]);
        Gizmos.DrawLine(lightCamera_fcs.nearCorners[3], lightCamera_fcs.farCorners[3]);
        */

        FrustumCorners[] fcs = new FrustumCorners[4];
        for (int k = 0; k < 4; k++)
        {
            Gizmos.color = Color.white;
            Gizmos.DrawLine(mainCamera_Splits_fcs[k].nearCorners[1], mainCamera_Splits_fcs[k].nearCorners[2]);

            fcs[k].nearCorners = new Vector3[4];
            fcs[k].farCorners = new Vector3[4];

            for (int i = 0; i < 4; i++)
            {
                fcs[k].nearCorners[i] = dirLightCameraSplits[k].transform.TransformPoint(lightCamera_Splits_fcs[k].nearCorners[i]);
                fcs[k].farCorners[i] = dirLightCameraSplits[k].transform.TransformPoint(lightCamera_Splits_fcs[k].farCorners[i]);
            }

            Gizmos.color = Color.red;
            Gizmos.DrawLine(fcs[k].nearCorners[0], fcs[k].nearCorners[1]);
            Gizmos.DrawLine(fcs[k].nearCorners[1], fcs[k].nearCorners[2]);
            Gizmos.DrawLine(fcs[k].nearCorners[2], fcs[k].nearCorners[3]);
            Gizmos.DrawLine(fcs[k].nearCorners[3], fcs[k].nearCorners[0]);

            Gizmos.color = Color.green;
            Gizmos.DrawLine(fcs[k].farCorners[0], fcs[k].farCorners[1]);
            Gizmos.DrawLine(fcs[k].farCorners[1], fcs[k].farCorners[2]);
            Gizmos.DrawLine(fcs[k].farCorners[2], fcs[k].farCorners[3]);
            Gizmos.DrawLine(fcs[k].farCorners[3], fcs[k].farCorners[0]);

            Gizmos.DrawLine(fcs[k].nearCorners[0], fcs[k].farCorners[0]);
            Gizmos.DrawLine(fcs[k].nearCorners[1], fcs[k].farCorners[1]);
            Gizmos.DrawLine(fcs[k].nearCorners[2], fcs[k].farCorners[2]);
            Gizmos.DrawLine(fcs[k].nearCorners[3], fcs[k].farCorners[3]);
        }
    }
}

// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'

///
// author     : chen yong
// create time: 2015/8/5
// modify time: 
// description: Generate a depth texture from the projector
///

Shader "Kingsoft/CustomShadow/Caster" 
{
	SubShader {
		Tags { 			
		    "RenderType" = "Opaque"
		}

		CGINCLUDE
		#include "UnityCG.cginc"	
		struct v2f {
			float4 pos : SV_POSITION;
			float2 depth:TEXCOORD0;
		};

		uniform float _gShadowBias;
		v2f vert (appdata_full v)
		{
			v2f o;
			o.pos = UnityObjectToClipPos(v.vertex);
			o.pos.z += _gShadowBias;
			o.depth = o.pos.zw;
			return o;
		}
		
		fixed4 frag (v2f i) : COLOR
		{
			float depth = i.depth.x/i.depth.y;

		#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

			//return EncodeFloatRGBA(depth);
			return depth;
		}
		ENDCG 

		Pass {
			Fog { Mode Off }
			Cull front
			
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag	
			ENDCG
		}	
	}
}

// Upgrade NOTE: replaced '_World2Shadow' with 'unity_WorldToShadow[0]'

// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'
// Upgrade NOTE: replaced '_Object2World' with 'unity_ObjectToWorld'

///
// author     : chen yong
// create time: 2017/7/5
// modify time: 
// description: 
///

Shader "Kingsoft/CustomShadow/Receiver" {

	SubShader {
		Tags { "RenderType"="Opaque"  }

		LOD 300 

		Pass {
			Name "FORWARD"
			Tags{ "LightMode" = "ForwardBase" }

			CGPROGRAM
			#include "UnityCG.cginc"

			struct v2f
			{
				float4 pos : SV_POSITION;
				float2 uv : TEXCOORD0;
				float4 shadowCoord : TEXCOORD1;
				float eyeZ : TEXCOORD2;
				float4 worldPos : TEXCOORD3;
			};

			uniform float4x4 _gWorldToShadow;
			uniform sampler2D _gShadowMapTexture;
			uniform float4 _gShadowMapTexture_TexelSize;

			uniform float4 _gLightSplitsNear;
			uniform float4 _gLightSplitsFar;
			uniform float4x4 _gWorld2Shadow[4];
			
			uniform sampler2D _gShadowMapTexture0;
			uniform sampler2D _gShadowMapTexture1;
			uniform sampler2D _gShadowMapTexture2;
			uniform sampler2D _gShadowMapTexture3;

			uniform float _gShadowStrength;

			v2f vert (appdata_full v) 
			{
				v2f o;
				o.pos = UnityObjectToClipPos (v.vertex);
				o.uv = v.texcoord.xy;
                o.worldPos = mul(unity_ObjectToWorld, v.vertex);
                o.shadowCoord = mul(_gWorldToShadow, o.worldPos);
				o.eyeZ = o.pos.w;
				return o; 
			}

			float PCFSample(float depth, float2 uv)
			{
				float shadow = 0.0;
				for (int x = -1; x <= 1; ++x)
				{
					for (int y = -1; y <= 1; ++y)
					{
						float4 col = tex2D(_gShadowMapTexture, uv + float2(x, y) * _gShadowMapTexture_TexelSize.xy);
						float sampleDepth = DecodeFloatRGBA(col);
						shadow += sampleDepth < depth ? _gShadowStrength : 1;
					}
				}
				return shadow /= 9;
			}

			fixed4 getCascadeWeights(float z)
			{
				fixed4 zNear = float4(z >= _gLightSplitsNear);
				fixed4 zFar = float4(z < _gLightSplitsFar);
				fixed4 weights = zNear * zFar;
				return weights;
			}

			float4 getShadowCoord(float4 wpos, fixed4 cascadeWeights)
			{
				float3 sc0 = mul(_gWorld2Shadow[0], wpos).xyz;
				float3 sc1 = mul(_gWorld2Shadow[1], wpos).xyz;
				float3 sc2 = mul(_gWorld2Shadow[2], wpos).xyz;
				float3 sc3 = mul(_gWorld2Shadow[3], wpos).xyz;
				return float4(sc0 * cascadeWeights[0] + sc1 * cascadeWeights[1] + sc2 * cascadeWeights[2] + sc3 * cascadeWeights[3], 1);
			}

			float4 SampleShadowTexture(float4 wPos, fixed4 cascadeWeights)
			{
				float4 shadowCoord0 = mul(_gWorld2Shadow[0], wPos);
				float4 shadowCoord1 = mul(_gWorld2Shadow[1], wPos);
				float4 shadowCoord2 = mul(_gWorld2Shadow[2], wPos);
				float4 shadowCoord3 = mul(_gWorld2Shadow[3], wPos);

				shadowCoord0.xy /= shadowCoord0.w;
				shadowCoord1.xy /= shadowCoord1.w;
				shadowCoord2.xy /= shadowCoord2.w;
				shadowCoord3.xy /= shadowCoord3.w;

				shadowCoord0.xy = shadowCoord0.xy*0.5 + 0.5;
				shadowCoord1.xy = shadowCoord1.xy*0.5 + 0.5;
				shadowCoord2.xy = shadowCoord2.xy*0.5 + 0.5;
				shadowCoord3.xy = shadowCoord3.xy*0.5 + 0.5;

				float4 sampleDepth0 = tex2D(_gShadowMapTexture0, shadowCoord0.xy);
				float4 sampleDepth1 = tex2D(_gShadowMapTexture1, shadowCoord1.xy);
				float4 sampleDepth2 = tex2D(_gShadowMapTexture2, shadowCoord2.xy);
				float4 sampleDepth3 = tex2D(_gShadowMapTexture3, shadowCoord3.xy);

				float depth0 = shadowCoord0.z / shadowCoord0.w;
				float depth1 = shadowCoord1.z / shadowCoord1.w;
				float depth2 = shadowCoord2.z / shadowCoord2.w;
				float depth3 = shadowCoord3.z / shadowCoord3.w;

				#if defined (SHADER_TARGET_GLSL)
					depth0 = depth0*0.5 + 0.5; //(-1, 1)-->(0, 1)
					depth1 = depth1*0.5 + 0.5;
					depth2 = depth2*0.5 + 0.5;
					depth3 = depth3*0.5 + 0.5;
				#elif defined (UNITY_REVERSED_Z)
					depth0 = 1 - depth0;       //(1, 0)-->(0, 1)
					depth1 = 1 - depth1;
					depth2 = 1 - depth2;
					depth3 = 1 - depth3;
				#endif

				float shadow0 = sampleDepth0 < depth0 ? _gShadowStrength : 1;
				float shadow1 = sampleDepth1 < depth1 ? _gShadowStrength : 1;
				float shadow2 = sampleDepth2 < depth2 ? _gShadowStrength : 1;
				float shadow3 = sampleDepth3 < depth3 ? _gShadowStrength : 1;

				//return col0;
				float shadow = shadow0*cascadeWeights[0] + shadow1*cascadeWeights[1] + shadow2*cascadeWeights[2] + shadow3*cascadeWeights[3];
				return shadow*cascadeWeights;
			}

			fixed4 frag (v2f i) : COLOR0 
			{			
				//return float4(i.eyeZ < _gLightSplitsFar);

				fixed4 weights = getCascadeWeights(i.eyeZ);
				fixed4 coord = getShadowCoord(i.worldPos, weights);

			

				//return i.shadowCoord;
				// shadow
				i.shadowCoord.xy = i.shadowCoord.xy/i.shadowCoord.w;
				float2 uv = i.shadowCoord.xy;
				uv = uv*0.5 + 0.5; //(-1, 1)-->(0, 1)
	
				float depth = i.shadowCoord.z / i.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

				// sample depth texture
				float4 col = SampleShadowTexture(i.worldPos, weights);
				return col;

				//return PCFSample(depth, uv);
			}	
		
			#pragma vertex vert
			#pragma fragment frag
			#pragma fragmentoption ARB_precision_hint_fastest 	
			ENDCG
		}
	}
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值