实践篇:简单阴影处理

前言:本篇博客只是一个简单的实现方向光和点光源产生阴影功能的例子,主要是当做笔记使用。

核心要点
1.光源(方向光或者点光源等)必须设置阴影类型,否则将不会产生对应光源的阴影。如下图所示:
在这里插入图片描述
2.阴影投射物体上面必须开启投射阴影功能,否则将不会传递光源产生的阴影。如下图所示:
在这里插入图片描述
3.阴影接收物体上面必须开启接收阴影功能,否则将不会显示光源产生的阴影。如下图所示:
在这里插入图片描述
4.可以写一个LightMode为ShadowCaster的pass来投射方向光阴影,也可以使用FallBack指定shader文件中的投射阴影类型。

5.接收光源阴影时,可以使用AutoLight.cginc文件中针对unity 4.0以及5.0或者更高版本的光照处理宏。如4.0中使用LIGHTING_COORDS宏定义阴影相关变量,在顶点着色器中使用TRANSFER_VERTEX_TO_FRAGMENT宏来赋值阴影相关变量,在片段着色器中使用LIGHT_ATTENUATION宏来使用阴影相关变量得到一个阴影强度值。然后使用该阴影强度值和获取的最终颜色值相乘,从而获取阴影处理后的颜色值。

6.在Forward渲染路径中,光照模型为ForwardBase时,可以使用#pragma multi_compile_fwdbase编译指令接收方向光阴影。光照模型为ForwardAdd时,可以使用#pragma multi_compile_fwdadd_fullshadows编译指令接收点光源阴影。具体的接收宏接口参见第5点。同时由于AutoLight.cginc文件中关于阴影处理相关宏实现部分使用v结构体成员,所以在着色器输入参数中需要将包含该成员的结构体参数名设定为v。

7.在多个pass处理不同光源阴影时,需要使用blend one one来混合每个pass的颜色值,从而保证pass处理的颜色值有效。

核心代码:如下所示:

Shader "Custom/MyShadow" {
	Properties {
		_MainColor ("MainColor", Color) = (1,1,1,1)
	}

	SubShader {
		//pass {
		//	// 投射方向光阴影
		//	Tags { "LightMode"="ShadowCaster" }
		//}

		pass {
			Tags { "LightMode"="ForwardBase" }
			
			CGPROGRAM
			#pragma vertex vert 
			#pragma fragment frag 
			#include "unitycg.cginc"
			#include "lighting.cginc"
			#include "autolight.cginc"
			#pragma multi_compile_fwdbase

			struct v2f {
				float4 pos:POSITION0;
				fixed3 normal:POSITION1;
				float4 vertex:POSITION2;
				// 定义阴影相关的变量
				LIGHTING_COORDS(0, 1)
			};

			fixed4 _MainColor;

			v2f vert(appdata_base v)
			{
				v2f o;
				o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
				o.normal = v.normal;
				o.vertex = v.vertex;
				// 对阴影相关变量赋值
				TRANSFER_VERTEX_TO_FRAGMENT(o)

				return o;
			}

			fixed4 frag(v2f v):COLOR0
			{
				// 获取世界空间中不受模型缩放影响的归一化法向量:模型到世界的转逆矩阵对模型顶点坐标进行变换
				float3 N = UnityObjectToWorldNormal(v.normal);
				// 获取世界空间中归一化的光照向量
				float3 L = normalize(WorldSpaceLightDir(v.vertex));
				// 获取光照强度:取法向量和光照向量点积值,值越大,夹角越小,光照强度越大。值为负数时光照在平面背面,可以不做光照处理
				float ndotl = saturate(dot(N, L));
				// 获取漫反射颜色
				fixed4 diffuseCol = _MainColor * _LightColor0 * ndotl;
				// 获取环境光颜色
				fixed4 ambientCol = UNITY_LIGHTMODEL_AMBIENT;
				// 使用阴影相关变量来获取阴影强度
				float atten = LIGHT_ATTENUATION(v);
				// 获取兰伯特模型光照颜色:漫反射颜色+环境光颜色
				fixed4 col = diffuseCol + ambientCol;
				col.rgb *= atten;

				return col;
			}

			ENDCG
		}

		pass {
			Tags { "LightMode"="ForwardAdd" }
			blend one one
			
			CGPROGRAM
			#pragma vertex vert 
			#pragma fragment frag 
			#include "unitycg.cginc"
			#include "lighting.cginc"
			#include "autolight.cginc"
			#pragma multi_compile_fwdadd_fullshadows

			struct v2f {
				float4 pos:POSITION0;
				fixed3 normal:POSITION1;
				float4 vertex:POSITION2;
				// 定义阴影相关的变量
				LIGHTING_COORDS(0, 1)
			};

			fixed4 _MainColor;

			v2f vert(appdata_base v)
			{
				v2f o;
				o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
				o.normal = v.normal;
				o.vertex = v.vertex;
				// 对阴影相关变量赋值
				TRANSFER_VERTEX_TO_FRAGMENT(o)

				return o;
			}

			fixed4 frag(v2f i):COLOR0
			{
				// 获取世界空间中不受模型缩放影响的归一化法向量:模型到世界的转逆矩阵对模型顶点坐标进行变换
				float3 N = UnityObjectToWorldNormal(i.normal);
				// 获取世界空间中归一化的光照向量
				float3 L = normalize(WorldSpaceLightDir(i.vertex));
				// 获取光照强度:取法向量和光照向量点积值,值越大,夹角越小,光照强度越大。值为负数时光照在平面背面,可以不做光照处理
				float ndotl = saturate(dot(N, L));
				// 获取漫反射颜色
				fixed4 diffuseCol = _MainColor * _LightColor0 * ndotl;
				// 获取环境光颜色
				fixed4 ambientCol = UNITY_LIGHTMODEL_AMBIENT;
				// 使用阴影相关变量来获取阴影强度
				float atten = LIGHT_ATTENUATION(i);
				// 获取兰伯特模型光照颜色:漫反射颜色+环境光颜色,由于上面pass已经加了环境光,这里就不加了
				fixed4 col = diffuseCol;
				col.rgb *= atten;

				return col;
			}

			ENDCG
		}
	}

	// 没有的部分从Diffuse着色器中去获取。比如:阴影
	FallBack "Diffuse"
}

运行效果:如下图所示:
在这里插入图片描述

发布了81 篇原创文章 · 获赞 39 · 访问量 10万+

猜你喜欢

转载自blog.csdn.net/zjz520yy/article/details/88829482