UnityShader开发之阴影

1.原理

阴影映射相机:放置于会产生阴影的光源处的相机,用于生成阴影映射纹理
光源阴影映射纹理:记录了从某个光源的位置出发,能看到的场景中距离光源最近的表面的位置(深度信息)的深度图。
主相机:用来 渲染 主要可视场景的相机

1.1 传统阴影映射技术

将阴影映射相机放置到产生阴影的光源处,然后生成一张阴影映射纹理。
流程上是

1)当光源投射阴影时,将阴影映射相机放到光源位置上
2)调用LightMode标签为ShadowCaster的Pass,这个Pass主要用来更新光源阴影映射纹理
3) 这个通道通过对顶点的变化得到光源空间下的位置,并将深度信息写入光源阴影映射纹理中
4)使用顶点的xy分量对光源阴影映射纹理进行采样,得到光源阴影映射纹理中该位置的深度信息
5)如果获得的深度值小于该顶点的深度值,则该点位于阴影中(即该顶点的位置在光源阴影映射纹理中存储的表面后面)

1.2 屏幕空间的阴影映射(ScreenspaceShadowMap)

1)当光源投射阴影时,将阴影映射相机放到光源位置上
2)调用LightMode标签为ShadowCaster的Pass,获得光源阴影映射纹理以及主相机的深度纹理
3)如果主相机的深度纹理的深度转换到光源空间中大于阴影映射纹理上的深度,则是处于阴影中的

1.3 对比

类型描述
传统
屏幕空间

我们可以看出,传统阴影映射与屏幕空间的阴影映射的主要区别其实就是前向渲染与延迟渲染的区别,这是因为一开始屏幕阴影映射是延迟渲染中产生阴影的方法。

2.使用

2.1 光源配置

在这里插入图片描述

2.2 被投影物体配置

在这里插入图片描述

2.2.1 Shader宏定义:

阴影shader中相关的宏定义在AutoLight.cginc中


// ---- Screen space direction light shadows helpers (any version)
#if defined (SHADOWS_SCREEN)

    #if defined(UNITY_NO_SCREENSPACE_SHADOWS)
        UNITY_DECLARE_SHADOWMAP(_ShadowMapTexture);
        #define TRANSFER_SHADOW(a) a._ShadowCoord = mul( unity_WorldToShadow[0], mul( unity_ObjectToWorld, v.vertex ) );
        inline fixed unitySampleShadow (unityShadowCoord4 shadowCoord)
        {
            #if defined(SHADOWS_NATIVE)
                fixed shadow = UNITY_SAMPLE_SHADOW(_ShadowMapTexture, shadowCoord.xyz);
                shadow = _LightShadowData.r + shadow * (1-_LightShadowData.r);
                return shadow;
            #else
                unityShadowCoord dist = SAMPLE_DEPTH_TEXTURE(_ShadowMapTexture, shadowCoord.xy);
                // tegra is confused if we use _LightShadowData.x directly
                // with "ambiguous overloaded function reference max(mediump float, float)"
                unityShadowCoord lightShadowDataX = _LightShadowData.x;
                unityShadowCoord threshold = shadowCoord.z;
                return max(dist > threshold, lightShadowDataX);
            #endif
        }

    #else // UNITY_NO_SCREENSPACE_SHADOWS
        UNITY_DECLARE_SCREENSPACE_SHADOWMAP(_ShadowMapTexture);
        #define TRANSFER_SHADOW(a) a._ShadowCoord = ComputeScreenPos(a.pos);
        inline fixed unitySampleShadow (unityShadowCoord4 shadowCoord)
        {
            fixed shadow = UNITY_SAMPLE_SCREEN_SHADOW(_ShadowMapTexture, shadowCoord);
            return shadow;
        }

    #endif

    #define SHADOW_COORDS(idx1) unityShadowCoord4 _ShadowCoord : TEXCOORD##idx1;
    #define SHADOW_ATTENUATION(a) unitySampleShadow(a._ShadowCoord)
#endif
2.2.1 宏定义 TRANSFER_SHADOW(a)

(1)支持屏幕阴影技术

	a._ShadowCoord = ComputeScreenPos(a.pos);

(2)不支持屏幕阴影技术

	a._ShadowCoord = mul( unity_WorldToShadow[0], mul( unity_ObjectToWorld, v.vertex ) );

将本地坐标转换为阴影空间的坐标

2.2.2 宏定义 SHADOW_COORDS(idx1)
	unityShadowCoord4 _ShadowCoord : TEXCOORD##idx1;

定义一个数据

2.2.3 宏定义 SHADOW_ATTENUATION(a)

在这里插入图片描述

2.2.2 具体Shader代码:

Shader "Custom/Shadow" {
	Properties {
		_Color ("Color", Color) = (1,1,1,1)
	}
	SubShader {

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

			CGPROGRAM

			#pragma multi_compile_fwdbase	

			#pragma vertex vert
			#pragma fragment frag
			
			#include "UnityCG.cginc"
			#include "AutoLight.cginc"

			struct a2v
			{
				float4 vertex : POSITION;
				float3 normal : NORMAL;
			};

			struct v2f
			{
				float4 pos : SV_POSITION;
				float3 worldNormal:TEXCOORD0;
				float3 worldPos:TEXCOORD1;
				SHADOW_COORDS(2)
				
			};

			fixed4 _Color;
			
			v2f vert (a2v v)
			{
				v2f o;
				o.pos = UnityObjectToClipPos(v.vertex);
				o.worldNormal = UnityObjectToWorldNormal(v.normal);
				o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
				
				TRANSFER_SHADOW(o);
				return o;
			}
			
			fixed4 frag (v2f i) : SV_Target
			{
				fixed4 col = _Color;
				fixed shadow = SHADOW_ATTENUATION(i);
				return fixed4(col.xyz*shadow,col.a);
			}
			ENDCG
		}

		Pass
		{
			Name "ShadowCaster"
			Tags{"LightMode"="ShadowCaster"}

			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			#pragma multi_compile_shadowcaster
			#include "UnityCG.cginc"
			
			struct v2f{
				V2F_SHADOW_CASTER;
			};

			v2f vert(appdata_base v)
			{
				v2f o;
				TRANSFER_SHADOW_CASTER_NORMALOFFSET(o)
				return o;
			}

			float4 frag(v2f i):SV_Target
			{
				SHADOW_CASTER_FRAGMENT(i)
			}

			ENDCG
		}
		
	}
	// FallBack "Specular"
}

效果
在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值