【Shader进阶】Pass块的Tags标签——LightMode之ForwardAdd

目录

简洁版

跳转---->更正文章部分


// Upgrade NOTE: replaced '_Object2World' with 'unity_ObjectToWorld'

Shader "Unlit/ForwardAdd"
{
	Properties
	{
		_MainTex("Texture", 2D) = "white" {}
		_DiffuseCol("DiffuseCol", Color) = (1,1,1,1)
		[Toggle(ENABLE_SHADOW)] _EnableShadow("EnableShadow", Float) = 0
	}
		SubShader
		{
			Tags { "RenderType" = "Opaque" }
			LOD 100

			Pass
			{
				Tags{
					"LightMode" = "ForwardBase" //定义该Pass在Unity的流水线中的角色 (只有定义它才能获取到一些Unity内置的光照变量如_LightColor0
				}

				CGPROGRAM
				#pragma vertex vert
				#pragma fragment frag
				#pragma multi_compile_fwdbase

				#include "UnityCG.cginc"
				#include "Lighting.cginc" //这个命名空间中包含_LightColor0
				#include "AutoLight.cginc"//阴影和光源衰减值等信息需要

				struct appdata
				{
					float4 vertex : POSITION;
					float2 uv : TEXCOORD0;
					float3 normal : NORMAL;
				};

				struct v2f
				{
					float2 uv : TEXCOORD0;
					float4 pos : SV_POSITION;
					float3 normal : NORMAL;
					float4 worldPos : TEXCOORD1;
					SHADOW_COORDS(2)
				};

				sampler2D _MainTex;
				float4 _MainTex_ST;
				fixed4 _DiffuseCol;

				//顶点着色器没有对任何逐顶点光源进行处理
				v2f vert(appdata v)
				{
					v2f o;
					o.pos = UnityObjectToClipPos(v.vertex);
					o.uv = TRANSFORM_TEX(v.uv, _MainTex);
					o.worldPos = mul(unity_ObjectToWorld, v.vertex);
					o.normal = UnityObjectToWorldNormal(v.normal);
					TRANSFER_SHADOW(o)
					return o;
				}

				fixed4 frag(v2f i) : SV_Target
				{
				fixed3 normal = normalize(i.normal);
	#ifdef USING_DIRECTIONAL_LIGHT
				fixed3 lightDir = normalize(_WorldSpaceLightPos0.xyz);
	#endif
				//注意这是宏不是if条件判断,所以判断是非平行光的逐像素光源会进行另一种计算衰减值方法(从光照贴图中获取)
				#ifdef USING_DIRECTIONAL_LIGHT
					fixed atten = 1.0;
				#endif
				fixed3 diffCol = _LightColor0.rgb * _DiffuseCol.rgb * saturate(dot(lightDir, normal));
				fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
				fixed shadow = SHADOW_ATTENUATION(i);
				return fixed4(ambient + diffCol * atten * shadow, 1); //考虑平行光和环境光、自发光影响,不考虑其他逐像素光源
				}
				ENDCG
			}


			Pass
			{
				Tags{
					"LightMode" = "ForwardAdd" //另一个前向渲染的光照模式,支持所有逐像素光源的计算
				}
				Blend One One
				CGPROGRAM
				#pragma vertex vert
				#pragma fragment frag
					//#pragma multi_compile_fwdadd //不考虑阴影的ForwardAdd模式
					#pragma multi_compile_fwdadd_fullshadows //考虑阴影影响

					#include "UnityCG.cginc"
					#include "Lighting.cginc" //这个命名空间中包含_LightColor0
					#include "AutoLight.cginc"//这个中包含世界转光源空间的空间转换矩阵unity_WorldToLight

					struct appdata
					{
						float4 vertex : POSITION;
						float2 uv : TEXCOORD0;
						float3 normal : NORMAL;
					};

					struct v2f
					{
						float2 uv : TEXCOORD0;
						float4 pos : SV_POSITION;
						float3 normal : NORMAL;
						float4 worldPos : TEXCOORD1;
						SHADOW_COORDS(2)
					};

					sampler2D _MainTex;
					float4 _MainTex_ST;
					fixed4 _DiffuseCol;

					//顶点着色器没有对任何逐顶点光源进行处理
					v2f vert(appdata v)
					{
						v2f o;
						o.pos = UnityObjectToClipPos(v.vertex);
						o.uv = TRANSFORM_TEX(v.uv, _MainTex);
						o.worldPos = mul(unity_ObjectToWorld, v.vertex);
						o.normal = UnityObjectToWorldNormal(v.normal);
						TRANSFER_SHADOW(o)
						return o;
					}

					fixed4 frag(v2f i) : SV_Target
					{
					fixed3 normal = normalize(i.normal);
		#ifdef USING_DIRECTIONAL_LIGHT
					fixed3 lightDir = normalize(_WorldSpaceLightPos0.xyz);
		#else
					fixed3 lightDir = normalize(_WorldSpaceLightPos0.xyz - i.worldPos.xyz);
		#endif
					//注意这是宏不是if条件判断,所以判断是非平行光的逐像素光源会进行另一种计算衰减值方法(从光照贴图中获取)
					#ifdef USING_DIRECTIONAL_LIGHT
						fixed atten = 1.0;
					#else					
						#ifdef POINT
							//针对Point光源(点光源)
							float3 lightCoord = mul(unity_WorldToLight, float4(i.worldPos.xyz, 1)).xyz; //世界空间转光源空间					
							//用上方获取到的坐标的长度平方作为纹理坐标值进行采样光照贴图,取其衰减值(其中一个分量)
							fixed atten = tex2D(_LightTexture0, dot(lightCoord, lightCoord).rr).UNITY_ATTEN_CHANNEL;
						#elif SPOT			
							//针对Spot光源(聚光灯)
							float4 lightCoord = mul(unity_WorldToLight, float4(i.worldPos.xyz, 1)); //世界空间转光源空间					
							fixed atten = (lightCoord.z > 0) * UnitySpotCookie(lightCoord) * UnitySpotAttenuate(lightCoord.xyz);
						#endif
					#endif				
					fixed3 diffCol = _LightColor0.rgb * saturate(dot(lightDir, normal));//只考虑逐像素光源
					fixed shadow = SHADOW_ATTENUATION(i);
					//为什么只需要考虑逐像素光源,而不考虑环境光、自发光的影响?博客有说明
					return fixed4(diffCol * atten * shadow,1);
				}
				ENDCG
			}
		}
}

简洁版

//计算阴影和衰减值的积存入atten变量(fixed类型),变量由宏来定义
UNITY_LIGHT_ATTENUATION(atten, i, i.worldPos)    //不要写分号

UNITY_LIGHT_ATTENUATION(fixed, v2f, v2f.世界坐标点)

//下面这句话是错误的,2020年4月21日23:30:36更正
***其中,注意v2f结构体的裁剪坐标(SV_POSITION语义修饰的变量)必须命名为"pos"
如果你没有命名为pos,那么将会报错。***错误!

//2020年4月21日23:30:44更正:
第三个参数世界坐标点 必须是float3类型的,即i.worldPos.xyz传入,如果传入的是float4则报错

这个报错就是因为v2f结构体的裁剪坐标命名没有写为"pos"的缘故,猜测是宏定义更深层的会使用到pos命名的裁剪坐标(坑爹玩意)

阴影三剑客还有其他约束,如:

SHADOW_COORDS(n)  不要写分号在后面,n代表第几个TEXCOORDn

TRANSFER_SHADOW(o) 不要写分号在后面,o代表v2f结构体,而且顶点着色器输入结构必须命名为"v",且输入结构体中包含有命名为"vertex"的模型空间顶点坐标(蛋疼)不过默认基本上是v 以及 vertex ,所以这里一般都不会出错。

SHADOW_ATTENUATION(i); 要写分号在后面, i代表v2f输入结构体,这里就没啥约束了

---------------------------------------------

使用UNITY_LIGHT_ATTENUATION(atten, i, i.worldPos);  要写分号在后面,且v2f结构体的裁剪坐标命名为"pos",其他要求暂时未发现。

跳转---->更正文章部分

-------------------2020年4月21日23:28:56----------------------更正

报错是由于传入的UNITY_LIGHT_ATTENUATION(atten, i, i.worldPos)的第三个参数,不是float4,是float3类型的!是float3类型的!wdnmd

--------------------2020年4月24日22:00:49---------------------------更新

LightMode为ForwardAdd的Pass,在没有任何非平行光的逐像素光源是不会进行渲染的!可自行试验测试(注意:测试时需要满足一个SubShader且它只有一个ForwardAdd的Pass,且没有FallBack)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值