读一读

Shader "Unlit/ForwardRendering"
{
	Properties
	{
	}
	SubShader
	{
		Tags { "RenderType"="Opaque" }
		LOD 100

		//第一个重要的平行光,计算环境光和自发光
		Pass
		{
			Tags{"LightMode" = "ForwardBase"}

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

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

			struct v2f
			{
				float4 vertex : SV_POSITION;
				float3 worldNormal : COLOR0;
			};

			
			v2f vert (appdata v)
			{
				v2f o;
				o.vertex = UnityObjectToClipPos(v.vertex);
				o.worldNormal = mul(unity_ObjectToWorld, v.normal);
				return o;
			}
			
			fixed4 frag (v2f i) : SV_Target
			{
				fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;//环境光,Base这里计算一次
				float3 worldLightDir = normalize(_WorldSpaceLightPos0);
				fixed3 diffuse = _LightColor0.rgb * max(0, dot(i.worldNormal, worldLightDir));
				return fixed4(ambient + diffuse,1);
			}
			ENDCG
		}

		//计算其他逐像素光照
		Pass
		{
				Tags{ "LightMode" = "ForwardAdd" }
				Blend One One //混合

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

				#include "UnityCG.cginc"
				#include "Lighting.cginc"
				#include "AutoLight.cginc" //unity_WorldToLight

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

			struct v2f
			{
				float4 vertex : SV_POSITION;
				float3 worldNormal : COLOR0;
				float4 worldPos :COLOR1;
			};


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

			fixed4 frag(v2f i) : SV_Target
			{

				//光照方向
				#ifdef USING_DIRECTIONAL_LIGHT        
				fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz);
				#else        
				fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz - i.worldPos.xyz);
				#endif

				//计算光照衰减
				#ifdef USING_DIRECTIONAL_LIGHT    
				fixed atten = 1.0;
				#else    
				float3 lightCoord = mul(unity_WorldToLight , float4(i.worldPos.xyz, 1)).xyz;
				fixed atten = tex2D(_LightTexture0, dot(lightCoord, lightCoord).rr).UNITY_ATTEN_CHANNEL;
				#endif


				fixed3 diffuse = _LightColor0.rgb * max(0, dot(i.worldNormal, worldLightDir));
				return fixed4(diffuse,1)* atten ;
			}
			ENDCG
		}
	}
}


blob.png


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


756.png


当场景有很多实时光照,前向渲染的性能就会极速下降。所以更古老的延迟渲染就有用了。延迟渲染除了颜色缓冲和深度缓冲外,还会利用额外的缓冲区叫做G缓冲。G缓冲存储了我们关心的表面(离相机近的表面)的其他信息,表面的法线、位置、用于光照计算的材质属性等。延迟渲染主要有两个Pass,第一个Pass不进行任何光照计算,仅仅计算哪些片元是可见的,然后将信息存储到G缓冲区中。然后第二个Pass,就会利用G缓冲中的片元信息,进行真正的光照计算。注意,使用延迟渲染不支持真正的抗锯齿、不能出来半透明物体。


前向渲染是一种传统的常用的渲染路径,在Unity中通过Quality Setting设置逐像素关照的个数,然后关照们根据光照的重要和距离排序决定是否是逐像素,直射光一定是逐像素的。前向渲染有两种Pass,一种是Base Pass,用来计算一个逐像素的平行光和所有逐顶点和SH光源,这个Pass只执行一次,所以环境光和自发光也是这里计算,这些是计算一次就行了。还有一种是Additional Pass,用来计算其他影响该物体的逐像素光源每个光源执行一次Pass,这个Pass会设置混合模式,然后计算到该光源影响的颜色和帧缓存混合起来。默认的AP是没有阴影效果的,但是可以使用#pragma multi_compile_fwdadd_fullshadows来替换掉#pragma multi_compile_fwdadd编译指令。


789.png


要实现双面物体其实就是关闭剔除,物体相对摄像机来说都有正面和反面的说法,我们可以关闭剔除,从而达到正反面都渲染的目的。

Cull Front | Back | Off


透明测试的只需要在Pass通道中加上 Cull Off 就可以实现透明的双面渲染,就是透过自己看到自己后面面的背面。

混合模式的透明需要加多一个Pass通道,两个通道的内容是一样的,但是一个 Cull Front (先渲染背面),一个 Cull Back(再渲染正面)。使用双通道会消耗性能,但是不用的话,混合中没有深度写入,就会有可能的背面渲染在正面前面,所以使用两个通道,先背面再正面。

注意具有深度写入的透明物体,在第一个Pass的时候,深度值就已经把背面的片元给排除掉了。


混合操作指的是源颜色*因子后和目标颜色*因子后的值的操作方式,一般默认是+起来的,但是我们可以使用混合操作命令修改操作。

BlendOp BlendOperation


BlendOperation有:

dc4390371e9eb44deb8373f5e0960171.png

1d8a5601d9c26aefb5a2b93d35e0e5af.png


对于混合,就会有一个等式来计算。结果颜色就是O,S就是源颜色(片元的颜色),D为目标颜色(颜色缓冲读取出来的)。这时候就需要一些因子来计算出结果O了,RGB和A是使用不同的因子的,所以将会有4个因子的存在。

O(rgb) = 因子1 * S(rgb) + 因子2 * D(rgb)

O(a) = 因子3 * S(a) + 因子4 * D(a)


我们能控制的,就是对这些因子的配置来控制混合的计算。

181c1f62f0de6257e048f58fd2eb7011.png

第一种设置表示 因子3 = 因子1,因子4 = 因子2。第二种就是一一对应了。


因子的值可设置为:

0.png


Shader "Unlit/pass2"
{
	Properties
	{
		_MainTex ("Texture", 2D) = "white" {}
		_Color("Color",Color) = (1,1,1,1)
		_AlphaScale("Alpha Scale",Range(0,5)) = 0.5
	}
	SubShader
	{
		Tags{ "Queue" = "Transparent" "IgnoreProjector" = "True" "RenderType" = "Transparent" }

		//第一个通道用来写入深度值,但是不写入颜色值
		Pass
		{
			ZWrite on
			ColorMask 0
		}

		Pass
		{
			Tags{ "LightMode" = "ForwardBase" }
			ZWrite Off  //关闭深度测试
			Blend SrcAlpha OneMinusSrcAlpha  //开启混合,设置混合因子

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

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

			sampler2D _MainTex;
			float4 _MainTex_ST;
			float3 _Color;
			float _AlphaScale;
			
			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);
				return o;
			}
			
			fixed4 frag (v2f i) : SV_Target
			{
				fixed4 col = tex2D(_MainTex, i.uv);
				fixed3 wn = normalize(i.worldNormal);
				fixed3 wl = normalize(UnityWorldSpaceLightDir(i.worldPos));
				fixed3 diffuse = (dot(wn, wl) * 0.5 + 0.5) * _LightColor0.rgb * _Color.rgb * col.rgb;
				return fixed4(diffuse,col.a * _AlphaScale);//只有开启了Blend,返回透明度才有用
			}
			ENDCG
		}
	}
}


这里和混合实例是差不多的,就是多了一个Pass通道来写入深度值,达到的效果就是在一些互相交叉的物体上有了深度值,剔除一些元素,使自身透明不能看到自身。

看图:左边双通道,右边单纯的混合

blob.png


Shader "Unlit/blend"
{
	Properties
	{
		_MainTex ("Texture", 2D) = "white" {}
		_Color("Color",Color) = (1,1,1,1)
		_AlphaScale("Alpha Scale",Range(0,5)) = 1
	}
	SubShader
	{
		Tags{ "Queue" = "Transparent" "IgnoreProjector" = "True" "RenderType" = "Transparent" }

		Pass
		{
			Tags{ "LightMode" = "ForwardBase" }    
			ZWrite Off  //关闭深度写入
			Blend SrcAlpha OneMinusSrcAlpha  //开启混合,设置混合因子

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

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

			sampler2D _MainTex;
			float4 _MainTex_ST;
			float3 _Color;
			float _AlphaScale;
			
			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);
				return o;
			}
			
			fixed4 frag (v2f i) : SV_Target
			{
				fixed4 col = tex2D(_MainTex, i.uv);
				fixed3 wn = normalize(i.worldNormal);
				fixed3 wl = normalize(UnityWorldSpaceLightDir(i.worldPos));
				fixed3 diffuse = (dot(wn, wl) * 0.5 + 0.5) * _LightColor0.rgb * _Color.rgb * col.rgb;
				return fixed4(diffuse,col.a * _AlphaScale);//只有开启了Blend,返回透明度才有用
			}
			ENDCG
		}
	}
}


TIM图片20180927171622.png


Shader "Unlit/transparent"
{
    Properties
    {
        _Color("Color",Color)=(1,1,1,1)
        _MainTex ("Texture", 2D) = "white" {}
        _Cutoff("CutOff",Range(0,1))=0.5
    }
    SubShader
    {
        Tags{ "Queue" = "AlphaTest" "IgnoreProjector"="True" "RenderType" = "TransparentCutout" }

        Pass
        {
            Tags{"LightMode"="ForwardBase"}
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            
            #include "UnityCG.cginc"
            #include "Lighting.cginc"

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

            sampler2D _MainTex;
            float4 _MainTex_ST;
            float3 _Color;
            float _Cutoff;
            
            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, o.vertex);
                return o;
            }
            
            fixed4 frag (v2f i) : SV_Target
            {
                fixed4 col = tex2D(_MainTex, i.uv);
                clip(col.a - _Cutoff);//透明度测试
                /*if ((col.a - _Cutoff) < 0.0) {
                     discard;//不通过直接舍弃
                }*/

                fixed3 wn = normalize(i.worldNormal);
                fixed3 wl = normalize(UnityWorldSpaceLightDir(i.worldPos));

                fixed3 diffuse = (dot(wn, wl) * 0.5 + 0.5) * _LightColor0 * _Color * col;

                return fixed4(diffuse,1);
            }
            ENDCG
        }
    }
}



123.gif