Unity ShaderLab開發實戰(三)Pass的通用指令開關
1. LOD:
通過給SubShader設定一個整型的Level of DetaiI,即LOD數值,可以在執行時根據硬體裝置能力來決定是否使用此Shader,以及使用哪一個層級的SubShader。
用法eg:
SubShader
{
LOD 600
Pass { }
}
可以針對某一特定的Shader設定最大LOD,也可以在執行時設定一個全域性的LOD。
eg1:
public Shader m_Shader;
void Awake()
{
m_Shader.maximumLOD = 800;//改變指定的
Shader.globalMaximumLOD = 600;// 改變全域性的
}
最終結果,如果上述值為全域性設為600,特定shader的設為800時,那麼Unity所有的Shader(除設定了LOD為800的shader)中LOD為600的SubShader,特定shader的設為800時,選用了LOD為800的SubShader。
測試程式碼:
Shader "Tut/Shader/Common/_SetShader" {
Properties {
_Color ("Main Color", Color) = (1,1,1,0.5)
_MainTex ("Base (RGB)", 2D) = "white" { }
}
SubShader {
LOD 800
Pass {
Material { Diffuse (0,0,1,1)}
Lighting On
SetTexture [_MainTex] {Combine texture * primary double}
}
}
SubShader {
LOD 600
Pass {
Material { Diffuse (0,1,0,1)}
Lighting On
SetTexture [_MainTex] {Combine texture * primary double}
}
}
SubShader {
LOD 500
Pass {
Material {Diffuse (1,1,0,1)}
Lighting On
}
}
SubShader {
LOD 400
Pass {
color(1,0,0,1)
}
}
}
using UnityEngine;
using System.Collections;
[ExecuteInEditMode]
public class _SetGlobalLOD : MonoBehaviour {
public Shader myShader;
public GUISkin skin;
public Rect rt;
public Rect r1;
public Rect r2;
string tipStr;
private float val=1;
void Update () {
Shader.globalMaximumLOD = (int)val * 100;
myShader.maximumLOD = 800;
}
void OnGUI()
{
GUI.skin = skin;
val =(int) GUI.HorizontalSlider(rt, val, 1, 8);
GUI.Label(r1, "Current Global LOD is: " + val * 100);
GUI.Label(r2, "Current myShader LOD is: " + 800);
}
}
測試結果如下圖,想要完整程式碼工程的留言吧。
2.渲染佇列
渲染佇列(renderQueue)決定了Unity渲染場景物體的先後順序。
ZTest可以取的值有Greater/GEqual/Less/LEqual/Equal/NotEqual/Always/Never/Off,預設值為LEqual,通過比較深度來更改顏色快取的值。eg:預設值LEqual的情況下,如果將要繪製的新畫素的z值小於等於深度快取中的值,則將用新畫素的顏色值更新深度快取中對應畫素的顏色值。
renderQueue會改變物體被渲染的先後順序,但不會改變物體的空間位置,對於ZTest為LEqual的,即使改變了renderQueue,作用也無法體現在渲染輸出上;但是對於ZTest為Always就會影響最好的渲染輸出。
unity內建的渲染佇列:有5個預設適合於Queue的值,它們是Background、Geometry、AlphaTest、Transparent和
overlay,分別對應數值1000、2000、2450、3000和4000。
3.透明
Alpha檢測用於在fragment函式完成最終的計算之後,在即將寫入幀之前通過和—個固定的數值相比較,來決定當前fragment函式的計算結果要不要寫入幀中。AlphaTest的比較條件有Greater、GEqual、Equal、NotEqual、Less、LEqual、Always和Never這8種情況,具體比較值可以執行時確定。
eg:
Properties {
_DstTex ("Dst Tex", 2D) = "white" {}
_SrcTex ("Src Tex", 2D) = "white" {}
_CutOff("_Cut Off",float)=0.5
}
SubShader {
Pass{
AlphaTest Off
SetTexture[_DstTex] {
combine texture alpha
}
}
Pass{
Blend SrcAlpha OneMinusSrcAlpha
AlphaTest GEqual [_CutOff]
SetTexture [_SrcTex] {
combine texture alpha
}
}
}
4.混合
Alpha Blend
用法eg:
Properties {
_DstTex ("DstTex", 2D) ="white"{}
_SrcTex ("SrcTex", 2D) ="white"{}
}
SubShader {
Pass{
SetTexture[_DstTex] {combine texture}
}
Pass {
BlendOp Sub//Min,Max,RevSub
Blend One One
SetTexture [_SrcTex] { combine texture}
}
Pass{//output Alpha to RGB
Blend DstAlpha zero
color(1,1,1,1)
}
}
5.通道遮罩
ColorMask,eg: ColorMask RG 渲染輸出只寫入RG通道,沒有B通道和A通道。
使用:可以單獨在一個Pass裡產生遮罩,然後在後續Pass裡使用,防止穿透
Properties {
_Color ("Main Color", Color) = (1,1,1,1)
}
SubShader {
Tags {"RenderType"="Opaque" "Queue"="Transparent"}
Pass {
ZWrite On
ColorMask 0
}
Pass {
ZWrite Off
Blend SrcAlpha OneMinusSrcAlpha
ColorMask RGB
Material {
Diffuse [_Color]
}
Lighting On
SetTexture[_]{
Combine primary double
}
}
}
6.ZTest
之前講過,渲染路徑:VertexLit、Forward、Deferred。
預設情況下,只有在渲染路徑是Deferred時,輸出的_CameraDepthTexture才會有深度值。如果Z深度緩衝在當前的渲染路徑下,在當前的硬體裝置中不能直接取得,那麼Unity會通過Shader Replacement的方法,單獨在一個Pass中產生,(所謂的替代渲染),這時會用到RenderType。儘量給RenderType賦值。
Deferred渲染路徑下,首先會渲染在Deferred模型下可渲染的材質,然後才是Forward或VertexLit渲染路徑。
7.可以干預正常的ZTest,用Offset,只是修正,不是改緩衝中的值。
8.面剔除。可以實現描邊,效果圖如下。
左邊的Cull Front,中間的Cull Back,右邊的有兩個Pass,第一個Pass用Cull Front,然後將球沿法線往外擠一些,第二個Pass用Cull Back,正常渲染,兩個結合就有描邊啦。精英怪就是這麼實現的哦。
程式碼:
SubShader {
Cull Front
pass{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct v2f{
float4 pos:SV_POSITION;
};
v2f vert(appdata_base v)
{
v2f o;
o.pos=v.vertex;
o.pos.xyz+=v.normal*0.03;
o.pos=mul(UNITY_MATRIX_MVP,o.pos);
return o;
}
float4 frag(v2f i):COLOR
{
return (1,0,0,1);
}
ENDCG
}
pass{
Cull Back
Lighting On
Material{ Diffuse(1,1,1,1) }
}
}
9.抓屏
Properties {
_MainTex ("Base (RGB)", 2D) = "white" { }
}
SubShader {
GrabPass {
"_MyGrab"
}
pass{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
sampler2D _MyGrab;
sampler2D _MainTex;
float4 _MainTex_ST;
struct v2f {
float4 pos:SV_POSITION;
float2 uv:TEXCOORD0;
};
v2f vert (appdata_full v) {
v2f o;
o.pos=mul(UNITY_MATRIX_MVP,v.vertex);
o.uv=TRANSFORM_TEX(v.texcoord,_MainTex);
return o;
}
float4 frag(v2f i):COLOR
{
float4 c=tex2D(_MainTex,i.uv);
c=c*tex2D(_MyGrab,i.uv);
return c;
}
ENDCG
}
}
10.Stencil測試,在Fragment函式之前。