【Shader】实验09——模板测试实现神奇的转转乐

这个还是挺久之前做的,都快忘了。上篇总结后处理的时候在乱七八糟的工程里突然找到,就也来写一篇。

效果还是挺有意思的,我觉得放在人物选择界面这种会很棒。

神奇的转转乐
unity的渲染管线的逐片元操作阶段有三项测试,通过三项测试的片元(fragment)才能成为像素(pixel)。
虽然这个阶段是不可编程的,但是却是高度可配置的。

三项测试按顺序分别是:

透明度测试(Alpha Test)

低于给定透明度的片元会被舍弃,默认是关闭的。

模板测试(Stencil Test)。

如果开启该测试,会在模板测试阶段读取片元的模板值,并与给定的参考值进行比较,再决定是否舍弃该片元。

一般用来限制渲染区域,可用来渲染轮廓、阴影等用法。

默认是关闭的。

深度测试(Depth Test)

读取片元的深度值,并与深度缓冲区已存在的深度值进行比较。

如果片元深度值大于缓冲器深度值,则说明该片元在场景中已有物体之后,则舍弃该片元;反之则说明该片元在场景已有物体之前,则保留该片元,并把缓冲区深度值更新为该片元深度值。

默认开启,可配置深度测试和深度写入的开启与否来渲染半透明物体(要很小心渲染顺序)。

源码

模板测试可以做出很多很有意思的东西,比如上面那个转转乐。具体的模板测试各种操作配置可以见这篇博文

转转乐的具体思路是在方框的四个侧面分别放四个plane当做mask,在外部写入模板值,并设置只有相同模板值才能渲染。

虽然写了阴影的模板测试,但是不知道为啥会出现比较诡异的阴影情况,模板配置改了很多遍也没法正常,只能关掉阴影投射和接收,希望以后哪一天我搞定了再回来改掉。

mask和几何体的shader源码如下:

StencilMask源码

Shader "Unlit/StencilMask"
{
	Properties
	{ 
		_StencilMask("Stencil Mask", Int) = 0 
	} 
	SubShader
	{ 
		Tags{ "RenderType" = "Opaque" "Queue" = "Geometry" } 

		ColorMask 0 //不输出任何颜色
		ZWrite off //关闭深度写入

		Stencil
		{ 
			Ref[_StencilMask] 
			Comp Always
			Pass Replace 
		} 

		Pass
		{ 
			CGPROGRAM 
			#pragma vertex vert 
			#pragma fragment frag 

			struct appdata 
			{ 
				float4 vertex : POSITION; 
			}; 
			struct v2f 
			{ 
				float4 pos : SV_POSITION; 
			};

			v2f vert(appdata v) 
			{ 
				v2f o; 
				o.pos = UnityObjectToClipPos(v.vertex); 
				return o; 
			} 

			half4 frag(v2f i) : COLOR
			{ 
				return half4(1,1,1,1); 
			} 
			ENDCG 
		} 
	} 
}

StencilGeometry源码

Shader "Unlit/StencilGeometry"
{
	Properties
	{
		_StencilMask("Stencil Mask", Int) = 0
		_Color("Color", Color) = (1,1,1,1)
	}

	SubShader
	{
		Tags{ "RenderType" = "Opaque" "Queue" = "Geometry+1" }

		Pass
		{
			Stencil
			{
				Ref[_StencilMask]
				Comp equal  //只有与模板缓冲区里的值相等才通过模板测试
				Pass Keep
			}

			Tags {"LightMode" = "ForwardBase"}

			CGPROGRAM
			#pragma vertex vert 
			#pragma fragment frag 


			#pragma multi_compile_fwdbase
			#include "UnityCG.cginc"
			#include "AutoLight.cginc"
			#include "Lighting.cginc"

			fixed4 _Color;

			struct v2f
			{
				float4 pos : SV_POSITION;
				float4 worldPos : TEXCOORD0;
				float3 worldNormal : TEXCOORD1;
				SHADOW_COORDS(2)
			};
			
			v2f vert(appdata_base v)
			{
				v2f o;
				o.pos = UnityObjectToClipPos(v.vertex);
				o.worldPos = mul(unity_ObjectToWorld, v.vertex);
				o.worldNormal = UnityObjectToWorldNormal(v.normal);
				TRANSFER_SHADOW(o);

				return o;
			}

			fixed4 frag(v2f i) : SV_Target
			{
				fixed3 worldNormal = normalize(i.worldNormal);
				fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));

				fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * _Color.rgb;
				fixed3 diffuse = _LightColor0.rgb * _Color.rgb * saturate(dot(worldNormal, worldLightDir));
				UNITY_LIGHT_ATTENUATION(atten, i, i.worldPos);

				return fixed4(diffuse * atten + ambient, 1.0);
			}

			ENDCG
		}

		Pass
		{
			Stencil
			{
				Ref 0
				Comp equal
				Pass Keep
			}

			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;
			}

			fixed4 frag(v2f i) : SV_Target
			{
				SHADOW_CASTER_FRAGMENT(i);
			}

			ENDCG 
		}		
	} 
	FallBack "Diffuse" 
} 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值