Unity Shader入门学习(2):前向渲染与延迟渲染

本文介绍了Unity中的前向渲染和延迟渲染两种光照模型的Shader实现。前向渲染主要处理逐像素光照,包括BasePass和AdditionalPass,用于计算主要平行光和额外光源;延迟渲染则通过两个Pass,首先存储G缓冲区信息,然后进行光照计算。内容详细解释了Shader代码中的关键部分,如光照衰减、阴影处理和G缓冲区的使用。
摘要由CSDN通过智能技术生成

1.前向渲染

(1)

Shader "Unlit/001"
{
	Properties
	{
		_MainTex("Main Tex", 2D) = "white"{} // 纹理贴图
		_Diffuse("Diffuse",Color) = (1,1,1,1)
		_Specular("Specular", Color) = (1,1,1,1)
		_Gloss("Gloss", Range(8.0, 256)) = 20
	}


	//前向渲染路径原理:渲染对象的渲染图元,并计算两个缓冲区(深度与颜色缓冲区)。深度决定片元是否可见。可见则更新颜色缓冲区颜色值
	//对每个逐像素光照,都要进行一次上述的过程。若物体被多个逐像素光照影响,则物体执行多个pass,每个物体执行一次逐像素光照计算。
	//N个物体M个逐像素光照,N*M个pass

	//Base pass不仅可以处理逐像素光照,还可以处理其他。如逐顶点光照,球鞋函数。
	//前向渲染有两种pass。一个是BasePass,一个AdditionPass
	//BasePass计算最主要的平行光(最亮的,没有则不处理。只有这个光逐像素处理),环境光,自发光。逐顶点/SH光源和Lightmaps.默认支持阴影。	只会执行一次。
	//AdditionPass计算额外的逐像素光源,每个pass对应一个光源。这里的光源类型不定,但一定是逐像素。
	SubShader
	{
		Tags { "RenderType" = "Opaque" }
		LOD 100

        Pass {//前向渲染中Base Pass
            Tags{"LightMode" = "ForwardBase"}
            CGPROGRAM
			#pragma multi_compile_fwdbase
			//这个指令可以保证我们在shder中使用光照衰减等光照变量可以被正确赋值

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

			fixed4 _Diffuse;
			fixed4 _Specular;
			float _Gloss;
			sampler2D _MainTex;
			float4 _MainTex_ST;

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

            struct v2f
            {
                float4 vertex : SV_POSITION;
				float3 worldNormal : TEXCOORD0;
				float3 worldPos:TEXCOORD1;
				float2 uv : TEXCOORD2;

				float3 vertexLight : TEXCOORD3;//顶点光照与球鞋光照
            };

            v2f vert (a2v v)
            {
                v2f f;
                f.vertex = UnityObjectToClipPos(v.vertex);
				f.worldNormal = UnityObjectToWorldNormal(v.normal);
				f.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
				
				f.uv=TRANSFORM_TEX(v.texcoord,_MainTex);

				//下面是顶点光源与球鞋光源的计算
#ifdef LIGHTMAP_OFF 
// LIGHTMAP关闭才会计算球鞋,顶点光照
				float3 shLight = ShadeSH9(float4(v.normal,0.3));//球鞋光源。传入法线。
				f.vertexLight = shLight;

#ifdef VERTEXLIGHT_ON
//顶点光源开启时
				float3 vertexLight = Shade4PointLights(unity_4LightPosX0,unity_4LightPosY0,unity_4LightPosZ0,
				unity_LightColor[0].rgb,unity_LightColor[1].rgb,unity_LightColor[2].rgb,unity_LightColor[3].rgb,
				unity_4LightAtten0, f.worldPos, f.worldNormal);
				f.vertexLight += vertexLight;
#endif
#endif
                return f;
            }

            fixed4 frag (v2f i) : SV_Target
            {
				//然后在Base Pass中处理场景中的最重要的平行光
				//如果场景中包含了多个平行光,
				//Unity会选择最亮的平行光传递给Base Pass进行逐像素处理,
				//其他平行光会按照逐顶点或在Additional Pass中按逐像素的方式处理。
				//_LightColor0得到平行光强度

				fixed3 worldNormal = normalize(i.worldNormal);
				fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));

				fixed3 albedo =tex2D(_MainTex,i.uv).rgb* _Diffuse.rgb;
				fixed3 ambient=UNITY_LIGHTMODEL_AMBIENT*albedo;

				fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * max(0, dot(worldNormal,worldLightDir))*albedo;

				fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz - i.worldPos.xyz);
				//fixed3 viewDir = normalize(UnityWorldSpaceViewDir(f.WorldPos));
				fixed3 halfDir = normalize(worldLightDir + viewDir);
				fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(max(0,dot(worldNormal,halfDir)),_Gloss);

                return fixed4(ambient + diffuse + specular + i.vertexLight, 1);
            }
            ENDCG
        }


		Pass//前向渲染中Additional Pass
		{
			Tags{"LightMode" = "ForwardAdd"}

			Blend One One
			//开启并设置混合模式。光照是混合而非覆盖。(还可以换成其他混合模式)

			CGPROGRAM
			#pragma multi_compile_fwdadd
			#pragma vertex vert
			#pragma fragment frag

			#include "Lighting.cginc"
			#include "AutoLight.cginc"

			fixed4 _Diffuse;
			fixed4 _Specular;
			float _Gloss;

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

			struct v2f
			{
				float4 pos :SV_POSITION;
				float3 worldNormal : TEXCOORD0;
				float3 worldPos : TEXCOORD1;

				LIGHTING_COORDS(2,3)//与光照衰减相关。2,3分别指TEXCOORD2,3
			};

			v2f vert(a2v v)
			{
				v2f f;
				f.pos = UnityObjectToClipPos(v.vertex);
				f.worldNormal = UnityObjectToWorldNormal(v.normal);
				f.worldPos = mul(unity_ObjectToWorld,v.vertex).xyz;

				TRANSFER_VERTEX_TO_FRAGMENT(f);
				return f;
			}

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

				fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * max(0,dot(worldNormal,worldLightDir));

				fixed3 viewDir = normalize(UnityWorldSpaceViewDir(f.worldPos));
				fixed3 halfDir = normalize(worldLightDir + viewDir);
				fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(max(0,dot(viewDir,halfDir)),_Gloss);

				fixed atten = LIGHT_ATTENUATION(f);//计算衰减。已经为不同类型光源做出适应

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

			ENDCG
		}
    }
}

(2)

//最基础功能:Base中接收平行光环境光,add里接收其他逐像素光源并计算衰减(base里没有添加顶点光源与球鞋光源处理)

Shader "09-1" {
	Properties {
		_Diffuse ("Diffuse", Color) = (1, 1, 1, 1)
		_Specular ("Specular", Color) = (1, 1, 1, 1)
		_Gloss ("Gloss", Range(8.0, 256)) = 20
	}
	SubShader {
		Tags { "RenderType"="Opaque" }
		
		//Base Pass
		Pass {
			// Pass for ambient light & first pixel light (directional light)
			Tags { "LightMode"="ForwardBase" }
		
			CGPROGRAM
			
			
			//保证在Shader中使用光照衰减等变量可以被正确赋值
			#pragma multi_compile_fwdbase	
			
			#pragma vertex vert
			#pragma fragment frag
			
			#include "Lighting.cginc"
			
			fixed4 _Diffuse;
			fixed4 _Specular;
			float _Gloss;
			
			struct a2v {
				float4 vertex : POSITION;
				float3 normal : NORMAL;
			};
			
			struct v2f {
				float4 pos : SV_POSITION;
				float3 worldNormal : TEXCOORD0;
				float3 worldPos : TEXCOORD1;
			};
			
			v2f vert(a2v v) {
				v2f f;
				f.pos = UnityObjectToClipPos(v.vertex);
				
				f.worldNormal = UnityObjectToWorldNormal(v.normal);
				
				f.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
				
				return f;
			}
			
			fixed4 frag(v2f i) : SV_Target {
				fixed3 worldNormal = normalize(i.worldNormal);

				//_WorldSpaceLightPos0得到平行光方向
				fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz);
				
				//Base Pass计算环境光
				//只计算一次即可
				fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
				
				//然后在Base Pass中处理场景中的最重要的平行光
				//如果场景中包含了多个平行光,
				//Unity会选择最亮的平行光传递给Base Pass进行逐像素处理,
				//其他平行光会按照逐顶点或在Additional Pass中按逐像素的方式处理。
				//_LightColor0得到平行光强度
			 	fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * max(0, dot(worldNormal, worldLightDir));

			 	fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz - i.worldPos.xyz);
			 	fixed3 halfDir = normalize(worldLightDir + viewDir);
			 	fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(max(0, dot(worldNormal, halfDir)), _Gloss);
				
				//令平行光衰减值为1
				fixed atten = 1.0;
				
				return fixed4(ambient + (diffuse + specular) * atten, 1.0);
			}
			
			ENDCG
		}
		

		//Additional Pass
		Pass {
			// Pass for other pixel lights
			Tags { "LightMode"="ForwardAdd" }
			
			//使用Blend命令开启和设置混合模式
			//实现Additional Pass计算得到的光照结果在帧缓存中与之前的光照结果进行叠加
			Blend One One
		
			CGPROGRAM
			
			//保证在Shader中使用光照衰减等变量可以被正确赋值
			#pragma multi_compile_fwdadd
			
			#pragma vertex vert
			#pragma fragment frag
			
			#include "Lighting.cginc"
			#include "AutoLight.cginc"
			
			fixed4 _Diffuse;
			fixed4 _Specular;
			float _Gloss;
			
			struct a2v {
				float4 vertex : POSITION;
				float3 normal : NORMAL;
			};
			
			struct v2f {
				float4 pos : SV_POSITION;
				float3 worldNormal : TEXCOORD0;
				float3 worldPos : TEXCOORD1;
			};
			
			v2f vert(a2v v) {
				v2f o;
				o.pos = UnityObjectToClipPos(v.vertex);
				
				o.worldNormal = UnityObjectToWorldNormal(v.normal);
				
				o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
				
				return o;
			}
			
			fixed4 frag(v2f i) : SV_Target {
				fixed3 worldNormal = normalize(i.worldNormal);

				//判断当前处理的逐像素光源的类型
				#ifdef USING_DIRECTIONAL_LIGHT
					//如果是平行光,光源方向可以直接得到
					fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz);
				#else
					//如果是点光源或聚光灯,
					//光源方向需要用这个位置减去世界空间下的顶点位置。
					fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz - i.worldPos.xyz);
				#endif
				
				fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * max(0, dot(worldNormal, worldLightDir));
				
				fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz - i.worldPos.xyz);
				fixed3 halfDir = normalize(worldLightDir + viewDir);
				fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(max(0, dot(worldNormal, halfDir)), _Gloss);
				
				//处理不同光源的衰减
				#ifdef USING_DIRECTIONAL_LIGHT
					fixed atten = 1.0;
				#else
					#if defined (POINT)
					//点光
				        float3 lightCoord = mul(unity_WorldToLight, float4(i.worldPos, 1)).xyz;
				        fixed atten = tex2D(_LightTexture0, dot(lightCoord, lightCoord).rr).UNITY_ATTEN_CHANNEL;
						//使用宏UN1TY_ATTEN_CHANNEL来得到衰减纹理中衰减值所在的分量
				    #elif defined (SPOT)
					//聚光
				        float4 lightCoord = mul(unity_WorldToLight, float4(i.worldPos, 1));
				        fixed atten = (lightCoord.z > 0) * tex2D(_LightTexture0, lightCoord.xy / lightCoord.w + 0.5).w 
						* tex2D(_LightTextureB0, dot(lightCoord, lightCoord).rr).UNITY_ATTEN_CHANNEL;
				    #else
				        fixed atten = 1.0;
				    #endif
				#endif

				return fixed4((diffuse + specular) * atten, 1.0);
			}
			
			ENDCG
		}
	}
	FallBack "Specular"
}

(3)

//接收来自平行光的阴影

Shader "09-2" {
	Properties {
		_Diffuse ("Diffuse", Color) = (1, 1, 1, 1)
		_Specular ("Specular", Color) = (1, 1, 1, 1)
		_Gloss ("Gloss", Range(8.0, 256)) = 20
	}
	SubShader {
		Tags { "RenderType"="Opaque" }
		
		//Base Pass
		Pass {
			// Pass for ambient light & first pixel light (directional light)
			Tags { "LightMode"="ForwardBase" }
		
			CGPROGRAM

			#pragma multi_compile_fwdbase
			//保证在Shader中使用光照衰减等变量可以被正确赋值
			
			#pragma vertex vert
			#pragma fragment frag
			#include "Lighting.cginc"

			#include "AutoLight.cginc" 
			//该文件声明计算阴影时用的宏
			
			fixed4 _Diffuse;
			fixed4 _Specular;
			float _Gloss;
			
			struct a2v {
				float4 vertex : POSITION;
				float3 normal : NORMAL;
			};
			
			struct v2f {
				float4 pos : SV_POSITION;
				float3 worldNormal : TEXCOORD0;
				float3 worldPos : TEXCOORD1;

				SHADOW_COORDS(2)
				//添加内置宏,用于声明一个用于对阴影纹理采样的坐标。				
                //由于已经占用了2个插值寄存器,
                //因此传入的参数是2,阴影纹理坐标将占用第三个寄存器。
			};
			
			v2f vert(a2v v) {
				v2f f;
				f.pos = UnityObjectToClipPos(v.vertex);
				
				f.worldNormal = UnityObjectToWorldNormal(v.normal);
				
				f.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;

				TRANSFER_SHADOW(f);//计算v2f中声明的阴影纹理坐标
				
				return f;
			}
			
			fixed4 frag(v2f i) : SV_Target {
				fixed3 worldNormal = normalize(i.worldNormal);

				//_WorldSpaceLightPos0得到平行光方向
				fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz);
				
				//Base Pass计算环境光
				//只计算一次即可
				fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;

				fixed shadow = SHADOW_ATTENUATION(i);//使用阴影坐标对阴影贴图进行采样
			 	fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * max(0, dot(worldNormal, worldLightDir))* shadow;	

			 	fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz - i.worldPos.xyz);
			 	fixed3 halfDir = normalize(worldLightDir + viewDir);
			 	fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(max(0, dot(worldNormal, halfDir)), _Gloss)* shadow;//最后乘上阴影值shadow
				
				//令平行光衰减值为1
				fixed atten = 1.0;
				
				return fixed4(ambient + (diffuse + specular) * atten, 1.0);
			}
			
			ENDCG
		}
		

		//Additional Pass
		Pass {
			// Pass for other pixel lights
			Tags { "LightMode"="ForwardAdd" }
			
			//使用Blend命令开启和设置混合模式
			//实现Additional Pass计算得到的光照结果在帧缓存中与之前的光照结果进行叠加
			Blend One One
		
			CGPROGRAM
			
			//保证在Shader中使用光照衰减等变量可以被正确赋值
			#pragma multi_compile_fwdadd
			
			#pragma vertex vert
			#pragma fragment frag
			
			#include "Lighting.cginc"
			#include "AutoLight.cginc"
			
			fixed4 _Diffuse;
			fixed4 _Specular;
			float _Gloss;
			
			struct a2v {
				float4 vertex : POSITION;
				float3 normal : NORMAL;
			};
			
			struct v2f {
				float4 pos : SV_POSITION;
				float3 worldNormal : TEXCOORD0;
				float3 worldPos : TEXCOORD1;
			};
			
			v2f vert(a2v v) {
				v2f o;
				o.pos = UnityObjectToClipPos(v.vertex);
				
				o.worldNormal = UnityObjectToWorldNormal(v.normal);
				
				o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
				
				return o;
			}
			
			fixed4 frag(v2f i) : SV_Target {
				fixed3 worldNormal = normalize(i.worldNormal);

				//判断当前处理的逐像素光源的类型
				#ifdef USING_DIRECTIONAL_LIGHT
					//如果是平行光,光源方向可以直接得到
					fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz);
				#else
					//如果是点光源或聚光灯,
					//光源方向需要用这个位置减去世界空间下的顶点位置。
					fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz - i.worldPos.xyz);
				#endif
				
				fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * max(0, dot(worldNormal, worldLightDir));
				
				fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz - i.worldPos.xyz);
				fixed3 halfDir = normalize(worldLightDir + viewDir);
				fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(max(0, dot(worldNormal, halfDir)), _Gloss);
				
				//处理不同光源的衰减
				#ifdef USING_DIRECTIONAL_LIGHT
					fixed atten = 1.0;
				#else
					#if defined (POINT)
					//点光
				        float3 lightCoord = mul(unity_WorldToLight, float4(i.worldPos, 1)).xyz;
				        fixed atten = tex2D(_LightTexture0, dot(lightCoord, lightCoord).rr).UNITY_ATTEN_CHANNEL;
						//使用宏UN1TY_ATTEN_CHANNEL来得到衰减纹理中衰减值所在的分量
				    #elif defined (SPOT)
					//聚光
				        float4 lightCoord = mul(unity_WorldToLight, float4(i.worldPos, 1));
				        fixed atten = (lightCoord.z > 0) * tex2D(_LightTexture0, lightCoord.xy / lightCoord.w + 0.5).w 
						* tex2D(_LightTextureB0, dot(lightCoord, lightCoord).rr).UNITY_ATTEN_CHANNEL;
				    #else
				        fixed atten = 1.0;
				    #endif
				#endif

				return fixed4((diffuse + specular) * atten, 1.0);
			}
			
			ENDCG
		}
	}
	FallBack "Specular"
}

//统一管理衰减与阴影

Shader "09-3" {
	Properties {
		_Diffuse ("Diffuse", Color) = (1, 1, 1, 1)
		_Specular ("Specular", Color) = (1, 1, 1, 1)
		_Gloss ("Gloss", Range(8.0, 256)) = 20
	}
	SubShader {
		Tags { "RenderType"="Opaque" }
		
		//Base Pass
		Pass {
			// Pass for ambient light & first pixel light (directional light)
			Tags { "LightMode"="ForwardBase" }
		
			CGPROGRAM

			#pragma multi_compile_fwdbase
			//保证在Shader中使用光照衰减等变量可以被正确赋值
			
			#pragma vertex vert
			#pragma fragment frag
			#include "Lighting.cginc"

			#include "AutoLight.cginc" 
			//该文件声明计算阴影时用的宏
			
			fixed4 _Diffuse;
			fixed4 _Specular;
			float _Gloss;
			
			struct a2v {
				float4 vertex : POSITION;
				float3 normal : NORMAL;
			};
			
			struct v2f {
				float4 pos : SV_POSITION;
				float3 worldNormal : TEXCOORD0;
				float3 worldPos : TEXCOORD1;

				SHADOW_COORDS(2)
				//添加内置宏,用于声明一个用于对阴影纹理采样的坐标。
                //由于已经占用了2个插值寄存器,
                //因此传入的参数是2,阴影纹理坐标将占用第三个寄存器。
			};
			
			v2f vert(a2v v) {
				v2f f;
				f.pos = UnityObjectToClipPos(v.vertex);
				
				f.worldNormal = UnityObjectToWorldNormal(v.normal);
				
				f.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;

				TRANSFER_SHADOW(f);//计算v2f中声明的阴影纹理坐标
				
				return f;
			}
			
			fixed4 frag(v2f i) : SV_Target {
				fixed3 worldNormal = normalize(i.worldNormal);
				fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));
				
				fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
				
			 	fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * max(0, dot(worldNormal, worldLightDir));

			 	fixed3 viewDir = normalize(UnityWorldSpaceViewDir(i.worldPos));
			 	fixed3 halfDir = normalize(worldLightDir + viewDir);
			 	fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(max(0, dot(worldNormal, halfDir)), _Gloss);

				//用于计算光照衰减和阴影的宏,
				//第一个参数用于存储将光照衰减和阴影值相乘后的结果。
				//第二个参数是结构体v2f,这个参数会传递给SHADOW_ATTENUATION,用来计算阴影值。
				//第三个参数是世界空间的坐标,用于计算光源空间下的坐标,再对光照衰减纹理釆样来得到光照衰减。
				UNITY_LIGHT_ATTENUATION(atten, i, i.worldPos);
				
				return fixed4(ambient + (diffuse + specular) * atten, 1.0);
			}
			
			ENDCG
		}
		

		//Additional Pass
		Pass {
			// Pass for other pixel lights
			Tags { "LightMode"="ForwardAdd" }
			
			//使用Blend命令开启和设置混合模式
			//实现Additional Pass计算得到的光照结果在帧缓存中与之前的光照结果进行叠加
			Blend One One
		
			CGPROGRAM
			
			//保证在Shader中使用光照衰减等变量可以被正确赋值
			#pragma multi_compile_fwdadd
			
			#pragma vertex vert
			#pragma fragment frag
			
			#include "Lighting.cginc"
			#include "AutoLight.cginc" 
			//该文件声明计算阴影时用的宏
			
			fixed4 _Diffuse;
			fixed4 _Specular;
			float _Gloss;
			
			struct a2v {
				float4 vertex : POSITION;
				float3 normal : NORMAL;
			};
			
			struct v2f {
				float4 pos : SV_POSITION;
				float3 worldNormal : TEXCOORD0;
				float3 worldPos : TEXCOORD1;
				SHADOW_COORDS(2)
				//添加内置宏,用于声明一个用于对阴影纹理采样的坐标。
			};
			
			v2f vert(a2v v) {
				v2f o;
				o.pos = UnityObjectToClipPos(v.vertex);
				
				o.worldNormal = UnityObjectToWorldNormal(v.normal);
				
				o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
				
				return o;
			}
			
			fixed4 frag(v2f i) : SV_Target {
				//fixed3 worldNormal = normalize(i.worldNormal);

				判断当前处理的逐像素光源的类型
				//#ifdef USING_DIRECTIONAL_LIGHT
				//	//如果是平行光,光源方向可以直接得到
				//	fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz);
				//#else
				//	//如果是点光源或聚光灯,
				//	//光源方向需要用这个位置减去世界空间下的顶点位置。
				//	fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz - i.worldPos.xyz);
				//#endif
				
				fixed3 worldNormal = normalize(i.worldNormal);
				fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));

				fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * max(0, dot(worldNormal, worldLightDir));
				
				fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz - i.worldPos.xyz);
				fixed3 halfDir = normalize(worldLightDir + viewDir);
				fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(max(0, dot(worldNormal, halfDir)), _Gloss);
				
				处理不同光源的衰减
				//#ifdef USING_DIRECTIONAL_LIGHT
				//	fixed atten = 1.0;
				//#else
				//	#if defined (POINT)
				//	//点光
				//        float3 lightCoord = mul(unity_WorldToLight, float4(i.worldPos, 1)).xyz;
				//        fixed atten = tex2D(_LightTexture0, dot(lightCoord, lightCoord).rr).UNITY_ATTEN_CHANNEL;
				//		//使用宏UN1TY_ATTEN_CHANNEL来得到衰减纹理中衰减值所在的分量
				//    #elif defined (SPOT)
				//	//聚光
				//        float4 lightCoord = mul(unity_WorldToLight, float4(i.worldPos, 1));
				//        fixed atten = (lightCoord.z > 0) * tex2D(_LightTexture0, lightCoord.xy / lightCoord.w + 0.5).w 
				//		* tex2D(_LightTextureB0, dot(lightCoord, lightCoord).rr).UNITY_ATTEN_CHANNEL;
				//    #else
				//        fixed atten = 1.0;
				//    #endif
				//#endif

				UNITY_LIGHT_ATTENUATION(atten, i, i.worldPos);
				
				return fixed4((diffuse + specular)* atten, 1.0);

			}
			
			ENDCG
		}
	}
	FallBack "Specular"
}

2.延迟渲染

Shader "Unlit/002"
{
    Properties
    {
        _MainTex("Texture",2D) = "white" {}
        _Diffuse("Diffuse",Color) = (1,1,1,1)
        _Specular("Specular", Color) = (1,1,1,1)
        _Gloss("Gloss", Range(8.0, 50)) = 20
    }


//延迟渲染主要包含了两个Pass。
//在第一个Pass中,我们不进行任何光照计算,而是仅仅计算哪些片元是可见的,这主要是通过深度缓冲技术来实现
//当发现一个片元是可见的,我们就把它的相关信息存储到G缓冲区中。
//然后,在第二个Pass中,我们利用G缓冲区的各个片元信息进行真正的光照计算。

//不支持真正的抗锯齿(anti-aliasing)功能。
//不能处理半透明物体。
//对显卡有一定要求。如果要使用延迟渲染的话,显卡必须支持MRT (Multiple Render Targets)、Shader Mode 3.0及以上、深度渲染纹理以及双面的模板缓冲。

//伪代码
//Pass1
//{  
//    //第一个Pass不进行真正的光照计算  
//    //仅仅把光照计算需要的信息存储到G缓冲中  
//    for (each primitive in this model)
//    {  
//        for (each fragment covered by this primitive)
//        {  
//            if(failed in depth test)
//            {  
//                discard;  
//            }  
//            else
//            {  
//                //如果该片元可见  
//                //就把需要的信息存储到G缓冲中  
//                writeGBuffer(materialInfo,pos,normal,lightDir,viewDir);  
//            }  
//        }  
//    }  
//}

//Pass2
//{  
//    //利用G缓冲中的信息进行真正的光照计算  
//    for(each pixel in the screen)
//    {  
//        if(the pixel is valid)
//        {  
//            //如果该像素是有效的  
//            //读取它对应的G缓冲中的信息  
//            readGBuffer(pixel,materialInfo,pos,normal,lightDir,viewDir);  
//            //根据读到的信息进行光照计算  
//            float4 color = Shading(materialInfo,pos,normal,lightDir,viewDir);  
//            //更新帧缓冲  
//            writeFrameBuffer(pixel,color);  
//        }  
//    }  
//} 


    SubShader
    {
        Tags { "RenderType" = "Opaque" }
        LOD 100
        
        Pass

        {
            Tags{"LightMode" = "Deferred"}

            CGPROGRAM
            #pragma target 3.0
            #pragma vertex vert
            #pragma fragment frag
            #pragma exclude_renderers norm
            #pragma multi_compile __ UNITY_HDR_ON

            #include "UnityCG.cginc"

            sampler2D _MainTex;
            float4 _MainTex_ST;
            fixed4 _Diffuse;
            fixed4 _Specular;
            float _Gloss;

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

            struct v2f
            {
                float2 uv: TEXCOORD0;
                float4 vertex : SV_POSITION;
                float3 worldNormal : TEXCOORD1;
                float3 worldPos : TEXCOORD2;
            };

            struct DeferredOutput
            {
                float4 gBuffer0 : SV_TARGET0;
                float4 gBuffer1 : SV_TARGET1;
                float4 gBuffer2 : SV_TARGET2;
                float4 gBuffer3 : SV_TARGET3;
            };

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = TRANSFORM_TEX(v.uv,_MainTex);
                o.worldNormal = UnityObjectToWorldNormal(v.normal);
                o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
                return o;
            }

            DeferredOutput frag(v2f i)
            {
                DeferredOutput o;
                fixed3 color = tex2D(_MainTex, i.uv).rgb * _Diffuse.rgb;
                o.gBuffer0.rgb = color;
                o.gBuffer0.a = 1;
                o.gBuffer1.rgb = _Specular.rgb;
                o.gBuffer1.a = _Gloss/50.0;
                o.gBuffer2 = float4(i.worldNormal * 0.5 + 0.5,1);
                #if !defined(UNITY_HDR_ON)
                    color.rgb = exp2(-color.rgb);
                #endif
                o.gBuffer3 = fixed4(color,1);
                return o;
            }

            ENDCG
        }
    }
}
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值