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
}
}
}
Pass { Tags { "LightMode" = "ForwardBase" } }
当场景有很多实时光照,前向渲染的性能就会极速下降。所以更古老的延迟渲染就有用了。延迟渲染除了颜色缓冲和深度缓冲外,还会利用额外的缓冲区叫做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编译指令。

要实现双面物体其实就是关闭剔除,物体相对摄像机来说都有正面和反面的说法,我们可以关闭剔除,从而达到正反面都渲染的目的。
Cull Front | Back | Off
透明测试的只需要在Pass通道中加上 Cull Off 就可以实现透明的双面渲染,就是透过自己看到自己后面面的背面。
混合模式的透明需要加多一个Pass通道,两个通道的内容是一样的,但是一个 Cull Front (先渲染背面),一个 Cull Back(再渲染正面)。使用双通道会消耗性能,但是不用的话,混合中没有深度写入,就会有可能的背面渲染在正面前面,所以使用两个通道,先背面再正面。
注意具有深度写入的透明物体,在第一个Pass的时候,深度值就已经把背面的片元给排除掉了。
混合操作指的是源颜色*因子后和目标颜色*因子后的值的操作方式,一般默认是+起来的,但是我们可以使用混合操作命令修改操作。
BlendOp BlendOperation
BlendOperation有:


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

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

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通道来写入深度值,达到的效果就是在一些互相交叉的物体上有了深度值,剔除一些元素,使自身透明不能看到自身。
看图:左边双通道,右边单纯的混合

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