流水線:
1.應用階段:(CPU)輸出渲染圖元,粗粒度剔除等 比如完全不在相機范圍內的需要剔除,文件系統的粒子系統實現就用到粗粒度剔除。
2.幾何階段:(GPU)把頂點坐標轉換到屏幕空間,包含了模型空間 到世界空間 到觀察空間(相機視角view) 到齊次裁剪空間(投影project2維空間,四維矩陣,通過-w<x<w判斷是否在裁剪空間)
到歸一化設備坐標NDC(四維矩陣通過齊次除法,齊次坐標的w除以xyz實現歸一化) 到屏幕空間(通過屏幕寬高和歸一化坐標計算)。
a.頂點着色器:坐標變換和逐頂點光照,將頂點空間轉換到齊次裁剪空間。
b.曲面細分着色器:可選
c.幾何着色器:可選
d.裁剪:通過齊次裁剪坐標的-w<x<w判斷不在視野范圍內的部分或者全部裁剪,歸一化。
e.屏幕映射:把NDC坐標轉換為屏幕坐標
3.光柵化階段:(GPU)把幾何階段傳來的數據來產生屏幕上的像素,計算每個圖元覆蓋了哪些像素,計算他們的顏色、
a.三角形設置:計算網格的三角形表達式
b.三角形遍歷:檢查每個像素是否被網格覆蓋,被覆蓋就生成一個片元。
c.片元着色器:對片元進行渲染操作
d.逐片元操作:模板測試,深度測試 混合等
e.屏幕圖像
-------------------------------------------------------
矩陣:
M*A=A*M的轉置(M是矩陣,A是向量,該公式不適合矩陣與矩陣)
坐標轉換:
o.pos = mul(UNITY_MATRIX_MVP, v.vertex);頂點位置模型空間到齊次空間
o.worldNormal = mul((float3x3)_Object2World,v.normal);//游戲中正常的法向量轉換,轉換后法向量可能不與原切線垂直,但是不影響游戲顯示,而且大部分顯示也是差不多的。一般用這個就行了。
o.worldNormal = mul(v.normal, (float3x3)_World2Object);頂點法向量從模型空間轉換到世界空間的精確算法,公式是用_Object2World該矩陣的逆轉置矩陣去轉換法線。然后通過換算得到該行。
-------------------------------------------------------
API:
UNITY_MATRIX_MVP 將頂點方向矢量從模型空間變換到裁剪空間
UNITY_MATRIX_MV 將頂點方向矢量從模型空間變換到觀察空間
UNITY_MATRIX_V 將頂點方向矢量從世界空間變換到觀察空間
UNITY_MATRIX_P 將頂點方向矢量從觀察空間變換到裁剪空間
UNITY_MATRIX_VP 將頂點方向矢量從世界空間變換到裁剪空間
UNITY_MATRIX_T_MV UNITY_MATRIX_MV的轉置矩陣
UNITY_MATRIX_IT_MV UNITY_MATRIX_MV的逆轉置矩陣,用於將法線從模型空間轉換到觀察空間
_Object2World將頂點方向矢量從模型空間變換到世界空間,矩陣。
_World2Object將頂點方向矢量從世界空間變換到模型空間,矩陣。
模型空間到世界空間的矩陣簡稱M矩陣,世界空間到View空間的矩陣簡稱V矩陣,View到Project空間的矩陣簡稱P矩陣。
_WorldSpaceCameraPos該攝像機在世界空間中的坐標
_ProjectionParams
_ScreenParams
_ZBufferParams
unity_OrthoParams
unity_Cameraprojection
unity_CameraInvProjection
unity_CameraWorldClipPlanes[6]攝像機在世界坐標下的6個裁剪面,分別是左右上下近遠、
-------------------------------------------------------
表面着色器:
void surf (Input IN, inout SurfaceOutput o) {}表面着色器,unity特殊封裝的着色器
Input IN:可以引用外部定義輸入參數
inout SurfaceOutput o:輸出參數
struct SurfaceOutput//普通光照
{
half3 Albedo;//紋理,反射率,是漫反射的顏色值
half3 Normal;//法線坐標
half3 Emission;//自發光顏色
half Specular;//高光,鏡面反射系數
half Gloss;//光澤度
half Alpha;//alpha通道
}
-------------------------------------------------------
基於物理的光照模型:
金屬工作流SurfaceOutputStandard 高光工作流SurfaceOutputStandardSpecular
half3,half4代表rgba或者xyz,可以分開用 Albedo.xy=1.或Albedo.ga=1
#pragma surface surfname lightModel op - 指出函數surfname 表面着色器。
lightModel的光照模型和可選op操作,還可以添加頂點修改函數vertex和顏色修改函數finalcolor。
#pragma surface surf CustomLambert vertex:myvert finalcolor:mycolor addshadow exclude_path:deferred exclude_path:prepass nometa
#pragma vertex name - 指出函數name 是頂點着色器。
#pragma fragment name - 指出函數name 是片段着色器。
#pragma fragmentoption option - 添加option 到編輯的OpenGL片段程序。參看ARB fragment program說明書了解被允許的選項列表。這個指示在頂點程序或者編輯到非OpenGL targets的程序沒有影響。
#pragma multi_compile_builtin - 為了pixel-lit shaders;;這個將告知Unity去編輯大量的這個着色器程序數列以支持所有的照明種類,和所有的陰影選項。
#pragma multi_compile_builtin_noshadows - 對於pixel-lit 着色器,不接受陰影。這將告知Unity去編輯幾個該着色器程序的數列來支持所有的照明種類。這比multi_compile_builtin pragma可以更快的編輯,而且結果着色器也更小。
#pragma target name - 那個着色器target 去編輯。細節參看shader targets。
#pragma only_renderers space separated names - 只為給定的渲染器編輯着色器。默認情況下,着色器為所有的渲染器被編輯。細節參看 renderers。
#pragma exclude_renderers space separated names - 不為給定的渲染器編輯着色器。默認情況下,着色器為所有的渲染器被編輯。細節參看 renderers。
-------------------------------------------------------
頂點着色器:
struct appdata_full {//vertex輸入
float4 vertex : POSITION;//must
float4 tangent : TANGENT;
float3 normal : NORMAL;
float4 texcoord : TEXCOORD0;//該頂點的紋理坐標,第一組紋理坐標uv 也就是第一張貼圖的坐標、為了實現多重紋理貼圖,比如子彈打在牆上的彈痕等
float4 texcoord1 : TEXCOORD1;//n的數量和shadermodel版本有關
float4 texcoord2 : TEXCOORD2;
float4 texcoord3 : TEXCOORD3;
fixed4 color : COLOR;//頂點顏色
};
-------------------------------------------------------
片段着色器:
struct v2f{//vertec的輸出和frag的輸入
float4 vertex :SV_POSITION;//must
float3 color0:COLOR0;
float3 color1:COLOR1;
float4:texcoord:TEXCOORD0;//TEXCOORD0-TEXCOORD7自定義紋理坐標
}
SV_Tatget //frag的輸出,輸出float4的顏色
-------------------------------------------------------
光照:
1.逐頂點光照:在頂點着色器階段計算光照,效率高但是效果不好,在邊緣像素映射的時候插值可能會產生鋸齒。
2.逐像素光照:在片元着色器階段計算光照,計算量大,但是邊緣表現效果好。
3.半蘭伯特模型:處理無光照的地方,也讓其有光,不然可能是全黑。經驗模型。
#include "Lighting.cginc"
Tags { "LightMode"="ForwardBase" }
WorldSpaceViewDir(float4 v) 輸入模型空間中的頂點坐標,返回世界空間中從該點到攝像機的觀察方向
UnityWorldSpaceViewDir(float4 v) 輸入世界空間中的頂點坐標,返回世界空間中從該點到攝像機的觀察方向
ObjSpaceViewDir(float4 v)輸入模型空間中的頂點坐標,返回模型空間中從該點到攝像機的觀察方向
WorldSpaceLightDir()僅用於前向渲染,輸入模型空間中的頂點坐標,返回世界空間中從該點到光源光照方向,沒有歸一化。
UnityWorldSpaceLightDir()僅用於前向渲染,輸入世界空間中的頂點坐標,返回世界空間中從該點到光源光照方向,沒有歸一化。
ObjSpaceLightDir()僅用於前向渲染,輸入模型空間中的頂點坐標,返回模型空間中從該點到光源光照方向,沒有歸一化。
UnityObjectToWorldNormal(float3 v)把法線從模型空間轉換到世界空間
UnityObjectToWorldDir(float3 v)把方向矢量從模型空間轉換到世界空間
UnityWorldToObjectDir(float3 v)把方向矢量從世界空間轉換到模型空間
_WorldSpaceLightPos0.xyz獲取平行光光源方向,或者點光源的光源位置
_LightColor0.rgb獲取當前pass的光源顏色和強度
UNITY_LIGHTMODEL_AMBIENT.xyz; 環境光
normalize(_WorldSpaceCameraPos.xyz - worldPos.xyz); 視覺方向 UnityWorldSpaceViewDir
-------------------------------------------------------
a.漫反射公式:
diff=C*max(0,cos<L,N>);//C是顏色和強度_LightColor0.rgb
代碼: diff=max(0,dot(i.normal,i.lightDir))//i的單位向量and單位法向量
c=tex2D(tex,i.uv)*_LightColor0*diff//_LightColor0表示的是場景中平行光的顏色和強度
-------------------------------------------------------
b.高光反射公式:
Spec=pow(max(0,cos(R,V),gloss))//R 單位反射向量reflect(ray,normal)函數獲取,V視線單位方向向量 ,gloss光色度
代碼: Spec=pow(max(0),dot(reflect(-i.lightDir,i.normal),32))
c=c**_LightColor0*(diff+Spec)
-----------------------------------------------
紋理 uv坐標是頂點存儲了圖片上的坐標
_MainTex ("Main Tex", 2D) = "white" {}
sampler2D _MainTex;
float4 _MainTex_ST;//Unity中 紋理_ST來默認聲明該紋理的屬性_MainTex_ST.xy表示Scale, Till縮放,_MainTex_ST.zw表示Transform 偏移
o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);//vs輸入紋理坐標和紋理值輸出UV,ps對uv進行紋理采樣和計算。UV通常在0-1范圍,等於o.uv = v.texcoord.xy * _MainTex_ST.xy + _MainTex_ST.zw;
fixed3 albedo = tex2D(_MainTex, i.uv).rgb * _Color.rgb;//反射率
-------------------------------------------------------
法線貼圖:
xyz映射存成rgb值。一般存在切線空間,z軸法線方向,x軸切線方向,y軸副(法)切線方向
TANGENT_SPACE_ROTATION;//Unity來獲取rotation矩陣,從模型空間到切線空間變換的矩陣。僅存在旋轉和平移時,一個矩陣的轉置矩陣等於他的逆矩陣。
自己實現:
float3 binormal = cross( normalize(v.normal), normalize(v.tangent.xyz) ) * v.tangent.w; //切線空間的w分量用來存儲負法線向內還是向外
float3x3 rotation = float3x3(v.tangent.xyz, binormal, v.normal);//float3x3是按行存儲
float3 tangentNormal = UnpackNormal(packedNormal);Unity將法線貼圖紋理坐標0,1映射到正常法線坐標-1,1,返回切線空間下的法線方向。法線貼圖要設置成Normal格式。該設置unity有優化 rgb值不再是法線xyz的映射了,如果不設置的話要自己算 該公式不能用。
自己實現:
tangentNormal.xy = (packedNormal.xy * 2 - 1) * _BumpScale;//坐標反映射,自己計算的方法
tangentNormal.z = sqrt(1.0 - saturate(dot(tangentNormal.xy, tangentNormal.xy)));//通過xy計算z
-------------------------------------------------------
透明度測試AlphaTest:
只要有一個片元的透明度不滿足條件就被裁剪,用來優化顯示。
AlphaTest Greater AlphaValue//僅渲染 alpha 值大於 AlphaValue 的像素。AlphaValue :0-1
AlphaTest GEqual AlphaValue//僅渲染 alpha 值大於或等於 AlphaValue 的像素。
AlphaTest LessAlphaValue//僅渲染 alpha 值小於 AlphaValue 的像素。
AlphaTest LEqual AlphaValue//僅渲染 alpha 值小於或等於 AlphaValue 的像素。
AlphaTest Equal AlphaValue//僅渲染 alpha 值等於 AlphaValue 的像素。
AlphaTest NotEqual AlphaValue//僅渲染 alpha 值不等於 AlphaValue 的像素。
AlphaTest Always //渲染所有像素。這在功能上相當於 Alpha 測試關 (AlphaTest Off)。
AlphaTest Never//不渲染任何像素。
-------------------------------------------------------
模板測試:
Stencil如果開啟了模板測試,GPU會首先會讀取模板緩沖區的值,然后把該值和讀取的參考值ref進行比較,比較方式由Comp指定,比如大於Greater就表示通過模板測試,
然后由Pass Fail ZFail去指定通過和不通過模板和深度測試后對緩沖區的值進行的Operation處理。
Stencil
{Ref 2 //設置模板參考值為2
Comp equal//比較方式,有8種比較方式。
Pass Operation //這個是當stencil測試和深度測試都通過的時候,進行的stencilOperation操作方法
Fail Operation //這個是在stencil測試通過的時候執行的stencilOperation方法
ZFail Operation//這個是在stencil測試通過,但是深度測試沒有通過的時候執行的stencilOperation方法。
ReadMask readMask//readMask默認是255,一般不用該功能,設置隱碼后 讀取ref和buff值都需要與該碼進行與操作。(0-255)
WriteMask writeMask//寫操作進行與操作
}
Comp 的參數包括Greater/GEqual/Less/LEqual/Equal/NotEqual/Always/Never
Operation的參數包括:
Keep保持
Zero歸零
Replace拿比較的參考值替代原來buffer的值
IncrSat值增加1,但是不溢出,如果是255,就不再加
DecrSat值減少1,不溢出,到0就不再減
Invert翻轉所有的位,所以1會變成254
IncrWrap值增加1,會溢出,所以255會變成0
DecrWrap值減少1,會溢出,所以0會變成255
clip(x) //x的任何分量小於0 被裁剪掉
discard//舍棄當前片元
ZWrite Off//關閉深入寫入
ColorMask RGB|A|0 //設置顏色通道的寫掩碼,為0表示該pass不進行顏色輸出。
-------------------------------------------------------
深度測試ZTEST:
一個片元離攝像機的遠近,渲染后會進行深度寫入,通常會判斷緩存深度和當前片元深度 可知前后關系。
ZTest Always //指的是直接將當前像素顏色(不是深度)寫進顏色緩沖區中 相當於ZTest Off
ZTest Never//而Never指的是不要將當前像素顏色寫進顏色緩沖區中,相當於消失。
ZTest Greater/GEqual/Less/LEqual/Equal/NotEqual/Always/Never/Off,默認值為LEqual 即當物體深度小於或等於緩存深度值時(越遠深度越大),該物體渲染,就是默認的先后順序渲染。
透明度混合AlphaBlending:
該片元需要關閉深度寫入,不關閉深度測試。會導致片元之間深度穿插。可以采用2個pass,第一個pass只用來做深度寫入ZWrite On,第二個pass只用來輸出顏色ZWrite Off,這樣深度和顏色效果才會正確
Blend Off//關閉混合,只有blend打開后ps輸出a通道才有意義
Blend SrcFactor DstFactor//用同樣的因子對rgba進行混合(默認都開啟混合)第一個參數對源顏色(當前片元顏色,ps輸出的顏色)*SrcFactor混合,
第二個參數對目標顏色(當前讀到的緩沖區顏色)*DstFactor混合,混合后默認相加后會重新寫入緩沖區(相加后超過1的自動截斷到1)。混合包括RABG值。結果都是源顏色和目標顏色與各自因子相乘后再加起來作為輸出顏色。
shader里邊的向量相乘不同於點乘叉乘,相當於各項分別相乘。
Blend SrcFactor DstFactor,SrcFactorA DstFactorA//把rgb和a的混合因子分開。
混合因子
One //因子是1
Zero //因子是0
SrcColor//因子為源顏色值,當前片元顏色,對應rgba分量分別與SrcColor分量相乘
SrcCAlpha//因子為源顏色透明值值,對應rgba分別與SrcCAlpha相乘。
DstColor//因子為目標顏色值,當前讀到的緩沖區顏色
DstAlpha//因子為目標顏色透明值值
OneMinusSrcColor//因子為1-源顏色
OneMinusSrcAlpha//因子為1-源alpha
OneMinusDstColor//因子為1-目標顏色
OneMinusDstAlpha//因子為1-目標alpha
例子:
Blend SrcAlpha OneMinusSrcAlpha// Alpha混合,正常的透明度混合
Blend OneMinusDstColor One //柔和相加Soft Additive
Blend One One // Additive相加 線性減淡
Blend One OneMinusDstColor // Soft Additive比較柔和的相加
Blend DstColor Zero // Multiplicative乘法
Blend DstColor SrcColor // 2x Multiplicative2倍乘法
BlendOp OP//對源和目標顏色進行其他操作,而不是默認的相加,op操作包括:
Add //相加
Sub//源顏色減目標顏色
RevSub//目標顏色減源顏色
Min //使用2者較小的值
Min //使用2者較大的值
chen
BlendOp Min
Blend One One //組合變暗
-------------------------------------------------------
雙面渲染:
一般采用多個pass分別渲染正面和背面
Cull Back|Front|Off
Cull Back默認的背對相機圖元不渲染
Cull Front朝向相機圖元不渲染,只顯示背面
Cull Off關閉剔除功能 全部渲染 性能低,但是可以實現比如看見物體內部結構。
不透明物體有深度測試,先渲前后沒有關系,但是先渲染近的效率會更高,因為遠的會被深度測試自動剔除不用渲染。
透明物體一般要先渲遠的,再渲近的才能保證視覺順序正確。
------------------------------------------
SubShader的Tag{}標簽類型:
Queue:渲染順序,保證渲染順序小的先渲 大的后渲
RenderType:Unity可以運行時替換符合特定RenderType的所有Shader,着色器分類
ForceNoShadowCasting:值為”true”時,表示不接受陰影。
IgnoreProjector:值為”true”時,表示不接受Projector組件的投影。常用語半透明物體
DisableBatching:是否對subshader進行批處理,當shader中需要對頂點進行偏移的時候,該項設置為true
CanUseSpriteAtlas:當該subshader用於sprite時 該標簽設為false
PreviewType:指明材質面包怎么預覽材質 比如 "PreviewType"="Plane"
LightMode : 渲染路徑 ,pass的標簽類型
-------------------------------------------------------
渲染隊列:
"Queue"="Transparent"
Background:1000 //該聲明的物體最先被渲染
Geometry:2000//默認的不透明物體使用的渲染隊列
AlphaTest:2450//透明度測試,默認不透明物體渲染完后就渲染該物體
Transparent:3000//透明物體,在Geometry和AlphaTest后渲染,保證不透明物體渲染完了再渲染透明的。
Overlay:4000//該隊列用來實現疊加效果,該物體會在最后被渲染。
------
RenderType:
Opaque:絕大部分不透明的物體都使用這個;
Transparent:絕大部分透明的物體、包括粒子特效都使用這個;
Background:天空盒都使用這個;
Overlay:GUI、鏡頭光暈都使用這個
-------------------------------------------------------
渲染路徑:
Tag{ "LightMode" = "ForwardBase"}//為每個pass指定渲染路徑
LightMode包括:
Always:所有渲染路徑該pass都會渲染,但不計算光照
ForwardBase:前向渲染,該pass會計算環境光,最重要的平行光,逐頂點光和 Lightmaps
ForwardAdd:前向渲染,該pass會計算額外的逐像素光源,每個pass對應一個光源。光源多該pass會被多次調用 效率變低。
Deferred:延時渲染,該Pass會渲染G-buffer
ShadowCaster:把物體的深度信息渲染到陰影映射紋理或深度紋理中
PrepassBase:遺留的延遲渲染,該pass會渲染法線和高光反射的指數部分、
PrepassFinal:遺留的延遲渲染,該pass通過合並紋理 光照 自發光來渲染得到最后的顏色
Vertex:遺留的頂點照明渲染
-------------------------------------------------------
前向渲染:
包括ForwardBase類型渲染常用光照和ForwardAdd額外光照
#pragma multicompile_fwdbase //ForwardBase中用來保證光照衰減等參數正確賦值。
#pragma multicompile_fwdadd //ForwardAdd中用來保證可以訪問到正確的光照變量.
#pragma multicompile_fwdadd_fullshadows //ForwardAdd中用來計算陰影效果
USING_DIRECTIONAL_LIGHT//平行光的宏定義
_LightColor0//該pass的桌像素光照顏色
_WorldSpaceLightPos0//獲取平行光光源方向,或者點光源的光源位置
_LightMatrix0//世界空間到光源空間(光源位置為坐標原點的坐標系)的變換矩陣
_LightTexture0//光照衰減紋理
...........
tips:光源的RendeMode參數設置為Important unity會自動采用像素光源,如果不重要就是頂點光源。還有qualitysetting里邊的PixelLIghtCount,超過這個數也會用頂點光照
-------------------------------------------------------
光照衰減:
float3 lightCoord = mul(_LightMatrix0, float4(i.worldPos, 1)).xyz;
fixed atten = tex2D(_LightTexture0, dot(lightCoord, lightCoord).rr).UNITY_ATTEN_CHANNEL;//UNITY_ATTEN_CHANNEL獲得衰減值所在的分量
float shadow=SHADOW_ATTENUATION(i);//負值使用SHADOW_COORDS對相關紋理進行采樣,返回值為陰影。關閉陰影的狀態是等於1
return fixed4(ambient + (diffuse + specular) * atten * shadow, 1.0);//atten為衰減,shadow為陰影
------計算別人投到自己身上的陰影和衰減
SHADOW_COORDS(n)//聲明一個_ShadowCoord的陰影紋理坐標 ps輸入坐標,n的值是聲明TEXCOORD0-7坐標使用的個數
TRANSFER_SHADOW(o);//用於在頂點着色器中計算上一步聲明中的陰影紋理坐標 並傳向ps階段。
float shadow=SHADOW_ATTENUATION(i);//負值使用SHADOW_COORDS對相關紋理進行采樣,返回值為陰影。關閉陰影的狀態是等於1
UNITY_LIGHT_ATTENUATION(atten,v2f i, i.worldPos);//計算別人投影到身上的陰影#include "AutoLight.cginc" Unity會將光照衰減和陰影相乘后存在第一個參數中,並自動聲明atten變量。第二個參數結構體包含SHADOW_COORDS,第三個參數世界空間坐標
return fixed4((diffuse + specular) * atten, 1.0);//UNITY_LIGHT_ATTENUATION出的atten為衰減和陰影
-----計算陰影投影到別人身上,自己的陰影
V2F_SHADOW_CASTER//unity里邊定義陰影投射需要定義的變量
TRANSFER_SHADOW_CASTER_NORMALOFFSET(0)//unity對頂點進行自動處理
SHADOW_CASTER_FRAGMENT(i)//unity自動完成陰影投射部分,把結果輸出到深度圖和陰影映射紋理中
--ds2的陰影采用的是屏幕后處理的方式去計算陰影,延遲渲染
2.頂點照明渲染:過時的渲染方式。效果差。
3.延遲渲染:通常2個pass,第一個pass計算哪些片元可見,第二個pass計算真實光照。
-------------------------------------------------------
1.反射o.worldRefl = reflect(-o.worldViewDir, o.worldNormal);//入射光線,表面法線
2.折射o.worldRefr = refract(-normalize(o.worldViewDir), normalize(o.worldNormal), _RefractRatio);//入射光線,表面法線,介質比
3.鏡子效果:使用相機的RenderTexture來設置渲染紋理。o.uv.x = 1 - o.uv.x;坐標需要翻轉一下。
4.玻璃效果:反射和折射使用cubemap進行采樣 是天空盒的cubemap,然后反射需要采樣的是周圍環境的光照和紋理。
GrabPass { "_RefractionTex" }//會把屏幕輸出到_RefractionTex的texture中, _RefractionTex_TexelSize 可以得到該紋理紋素大小,例如255*255的紋素是(1/255,1/255)
GrabPass{} //然后用_GrabTexture直接訪問屏幕圖像,但是這樣效率比較低,推薦要上面需要聲明的方法。
o.scrPos = ComputeGrabScreenPos(o.pos);//得到對應被抓取的屏幕圖像的采樣坐標
反射和折射需要顯示環境的效果,所以需要對環境的cubemap進行采樣。先用反射和折射的公式計算出光線,然后對環境貼圖進行采樣texCUBE(_Cubemap, i.worldRefl).rgb就可以得到具體效果了。
反射skybox 3d采樣,折射屏幕抓取圖像2d采樣。
-------------------------------------------------------
時間變量:
_Time:float4 //t是自該場景加載開始所經過的時間,4個分量是(t/20,t,2t,3t)
_SinTime:float4//t是時間的正玄弦值,四個分量的值分別是(t/8,t/4,t/2,t)
_CosTime:float4//t是時間的余玄弦值,四個分量的值分別是(t/8,t/4,t/2,t)
unity_DeltaTime:float4// dt是時間增量,4個分量分別是(dt,1/dt,smoothDt,1/smoothDt)
序列幀動畫:時間去控制uv坐標映射轉換。uv坐標的xy是頂點坐標,映射到小格子里邊,和UItexture的xy和寬高不一樣。
背景偏移動畫:時間控制uv坐標偏移。
水流動畫:通過時間和正弦函數去控制頂點偏移,通過時間控制uv移動。設置DisableBatching=true
廣告牌BillBoarding:根據視覺方向來旋轉被紋理着色的多邊形。頂點動畫
-------------------------------------------------------------------------
屏幕后處理:
void OnRenderImage(RenderTexture src, RenderTexture dest){}//全部渲染完后將調用,屏幕紋理存在src上,用來計算后通過dest返回,添加[ImageEffectOpaque]屬性,可使不透明物體(AlphaTest)被渲染完后立即調用.
Graphics.Blit(src, dest);//直接copy紋理。src是屏幕當前或上一步渲染的紋理,dest是目標紋理
Graphics.Blit(src, dest, material,pass=-1);//將把src傳到shader的material的_MainTex紋理。經過material(shader)的處理后輸出到dest渲染到屏幕.pass默認是-1會調用所有pass,否則只調用給定順序的pass。指定pass渲染很重要。
基於顏色變化的邊緣檢測:Sobel卷積算法,對邊緣點進行采樣計算 和特定矩陣卷積相乘。
高斯模糊:多次采樣紋理混合 消耗較大
Bloom效果:把較亮區域提取出來進行高斯模糊 模擬擴散效果,然后再與原紋理混合。
運動模糊:將上一幀的屏幕圖像存到renderTexture中,然后執行Graphics.Blit(src, renderTexture, material),shader將開啟混合Blend SrcAlpha OneMinusSrcAlpha把src紋理和目標緩沖紋理renderTexture進行混合,然后再Blit輸出到dst進行渲染。就得到了運動模糊效果。
----------------------------------------------------------------------------
深度和法線紋理:
float linearDepth = LinearEyeDepth(SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, i.uv_depth));
_CameraDepthNormalsTexture //unity中調用camera.depthTextureMode=DepthTextureMode.Depth/DepthNormal;這句話后可以通過該變量訪問深度紋理或者深度和法線紋理,project空間
float depth=SAMPLE_DEPTH_TEXTURE(tex,uv)//對深度紋理進行采樣,返回project空間下非線性深度值。和tex2D類似 只是封裝了平台。自動將NDC坐標下的深度映射(0,1)需要轉換到(-1,1)veiw空間去計算
LinearEyeDepth(depth)負責把深度紋理的采樣結果轉換到視角view空間下的線性深度值
Linear01Depth(depth)則會返回一個范圍在0,1的線性深度值
half4 sample1 = tex2D(_CameraDepthNormalsTexture, i.uv);
half2 centerNormal = DecodeViewNormalStereo(sample1);//center.xy存的法線的映射值
float centerDepth = DecodeFloatRG(center.zw);//zw深度
DecodeDepthNormal(sample1,out centerNormal,out centerDepth)//獲取采樣的法線和深度
Camera.worldToCameraMatrix //世界轉相機矩陣 world2view
Camera.cameraToWorldMatrix //相機轉世界矩陣
Camera.projectionMatrix //get投影矩陣viewToproject 視角空間到2維投影空間矩陣,set自定義的投影矩陣。如果你改變這個矩陣,相機的渲染不再基於它的fieldOfView更新,直到調用ResetProjectionMatrix
默認把view2project矩陣叫成project矩陣,默認把World2view矩陣叫做view矩陣。比如ViewProject就是world 2 project矩陣
全局霧效
深度霧效:通過每個頂點的深度值計算出該點到攝像機的距離d,然后把距離d進行參與公式計算得到霧效圖(遠的霧濃 rgb值大,近的霧淡 rgb值小),再把原圖和霧效圖進行混合。一般用線性,指數,指數平方公式,ds采用指數平方。
地面霧效:通過深度值和攝像機的方向向量計算該點到攝像機的偏移量,再加上攝像機的位置得到該頂點在世界空間中的坐標,然后把該坐標的y值參與霧效計算。如果用坐標z參與計算和深度霧類似。
#pragma multi_compile_fog
基於法線的邊緣檢測:防止陰影等信息干擾檢測,判斷臨近的4個點的法線和深度值是否是近似,如果差距過大則是邊緣roberts算法。(屏幕后處理)
---
渲染輪廓線:第一個pass對頂點進行法線方向擴散渲染,第二個pass用真實渲染實際光照,覆蓋第一次,對擴散的頂點未被覆蓋的像素就產生了輪廓效果。(模型輪廓)
---------------------------------------------------------------------------------
噪聲:
消融效果:怪物消失漸散的效果,把某個像素值小於閾值的裁剪掉,閾值附近的值用burncolor進行混合。陰影的pass里邊算陰影時也把該項給clip掉,這樣陰影就動態變化了//clip(burn.r - _BurnAmount);
水面擾動效果:用時間去控制偏移距離,然后對該頂點的uv偏移兩點的法線平均值來代替該點的法線值。水面=反射+折射+繞動
float2 speed = _Time.y * float2(_WaveXSpeed, _WaveYSpeed);
/ Get the normal in tangent space
fixed3 bump1 = UnpackNormal(tex2D(_WaveMap, i.uv.zw + speed)).rgb;
fixed3 bump2 = UnpackNormal(tex2D(_WaveMap, i.uv.zw - speed)).rgb;
fixed3 bump = normalize(bump1 + bump2);
全局(動態)霧效:通過時間控制噪聲紋理的偏移距離,然后根據噪聲顏色值來參與計算霧效濃度,然后計算霧效,就有了流動和淡濃的效果。
伽馬空間 線性空間(伽馬矯正) HDR
一、Cg頂點程序必須在結構中傳遞頂點數據。幾種常用的頂點結構定義在文件UnityCG.cginc中。在大部分情況下僅僅使用它們就夠了。結構如下:
1、appdata_base: 包含頂點位置,法線和一個紋理坐標。
2、appdata_tan:包含頂點位置,切線,法線和一個紋理坐標。
3、appdata_full:包含位置、法線、切線、頂點色和兩個紋理坐標。
4、appdata_img:包含位置和一個紋理坐標。
二、如果你想訪問個別的頂點數據,你必須自己聲明頂點結構。結構中的成員必須是屬於以下列表中的:
1、float4 vertex:POSITION 頂點位置
2、float3 normal:NORMAL 頂點法線
3、float4 texcoord:TEXCOORD0 第一UV坐標
4、float4 texcoord1:TEXCOORD1 第二UV坐標
5、float4 tangent:TANGENT 切線向量(用在法線貼圖中)
6、float4 color:COLOR 每個頂點(per-vertex)顏色
三、內置矩陣
1、UNITY_MATRIX_MVP:當前模型*視*投影矩陣。(注:模型矩陣為 本地->世界)
2、UNITY_MATRIX_MV:當前模型*視圖矩陣
3、UNITY_MATRIX_V:當前視圖矩陣
4、UNITY_MATRIX_P:當前投影矩陣
5、UNITY_MATRIX_VP:當前視圖*投影矩陣
6、UNITY_MATRIX_T_MV:轉置模型*視圖矩陣
7、UNITY_MATRIX_IT_MV:逆轉置模型*視矩陣
8、UNITY_MATRIX_TEXTURE0 to UNITY_MATRIX_TEXTURE3:紋理變換矩陣
四、內置向量
1、UNITY_LIGHTMODEL_AMBIENT:當前環境色
不同光源的結果都是相加的,而光源作用在材質上就是相乘。
黑白rgb 分量
float luminosity = 0.299 * r + 0.587 * g + 0.114 * b;
light=光
ambient=環境反射(光/色/強度/系數)=陰影色
diffuse=漫反射(光/色/強度/系數)=固有色
specular=鏡面反射(光/色/強度/系數)=高光色
emissive=自發光(光/色/強度/系數)=輻射色
shininess=rough=光澤度=鏡面反射加權系數n
ka=環境反射系數
kd=漫反射系數
ks=鏡面反射系數
N=法線方向單位向量
L=入射光方向單位向量
R=反射光方向單位向量
V=視點方向單位向量
H=半方向單位向量
Input中的可選變量
float3 viewDir - 視圖方向 (view direction)。為了計算視差效果(Parallax
effects),邊緣光照等
float4 with COLOR semantic -每個頂點插值后的顏色
float4 screenPos - 屏幕空間中的位置。 為了反射效果,需要包含屏幕空間中的位置信息。
float3 worldPos - 世界空間中的位置。
float3 worldRefl - 世界空間中的反射向量。 如果surface
shader沒有賦值o.Normal,將會包含世界反射向量。參見例子:Reflect-Diffuse shader。
float3 worldRefl; INTERNAL_DATA - 世界空間中的反射向量。如果surface
shader沒有賦值o.Normal,將會包含這個參數。為了獲得逐像素法線貼圖的反射向量,請使用WorldReflectionVector
(IN, o.Normal)。參見例子: Reflect-Bumped shader。
float3 worldNormal; INTERNAL_DATA -世界空間中的法線向量。如果surface
shader沒有賦值o.Normal,將會包含世界法向量。為了獲得逐像素法線貼圖的法向量,請使用WorldNormalVector
(IN, o.Normal)。
The SurfaceOutput struct has the following properties:
fixed3 Albedo;: This is the diffuse color of the material
fixed3 Normal;: This is the tangent space, normal, if written
fixed3 Emission;: This is the color of the light emitted by the material (this property is declared as half3 in the Standard Shaders)
fixed Alpha;: This is the transparency of the material
half Specular;: This is the specular power from 0 to 1
fixed Gloss;: This is the specular intensity
The SurfaceOutputStandard struct has the following properties:
fixed3 Albedo;: This is the base color of the material (whether it's diffuse or specular)
fixed3 Normal;
half3 Emission;: This property is declared as half3, while it was defined as fixed3 in SurfaceOutput
fixed Alpha;
half Occlusion;: This is the occlusion (default 1)
half Smoothness;: This is the smoothness (0 = rough, 1 = smooth)
half Metallic;: 0 = non-metal, 1= metal
The SurfaceOutputStandardSpecular struct has the following properties:
fixed3 Albedo;
fixed3 Normal;
half3 Emission;
fixed Alpha;
half Occlusion;
half Smoothness;
fixed3 Specular; This is the specular color. This is very different from the Specular property in SurfaceOutput as it allows you to specify a color rather
than a single value.
Render Queue: Background, Geometry, AlphaTest,Transparent,Overlay
一、基本數據類型:Cg支持7種基本的數據類型
1、float,32位浮點數據,一個符號位。浮點數據類型被所有的圖形接口支持;
2、half,16位浮點數據;
3、int,32位整形數據
4,fixed,12位定點數,
5、bool,布爾數據,被所有的圖形接口支持;
6、sampler*,紋理對象的句柄,分為sampler、sampler1D、sampler2D、sampler3D、samplerCUBE和samplerRECT。
二、內置的數據類型
基於基礎數據類型,如float3,表示float類型的三維向量;同理,bool2表示布爾類型的二維向量。
注:向量最長不能超過四元,如float5 vector;//編譯錯誤
向量的賦值:
float2 a=float(1.0,1.0); //編譯通過
float2 a=float(1.0f,1.0f); //編譯錯誤
float3 b=float(a,0.0); //編譯通過
矩陣數據類型:
float1X1 m1; //即float m1,一維矩陣
float3X4 m34 //3*4階矩陣
注:X是字符,不是乘號,最大的維數為4*4階,矩陣的初始化 float 2*2 m22={1.0,2.0,3.0,2.3};
float3 x和floatx[3]是不同的,前者為向量是內置的數據類型,而數組則是一種數據結構,不是內置的數據類型。
三、類型轉換
Cg中的類型轉換有強制轉換和隱式轉換;如果是隱式轉換則數據類型從低精度向高精度轉換。如:
float a=1.0; half b=2.0; loat c=a+b; //等價於float c=a+(float)b;
Cg語言中可以對常量數據加上類型后綴表示該數據類型的數據,如:
float a=1.0h; //1.0h為half類型常量數據
這樣的后綴類型有三種:
f:表示float;
h:表示half;
x:表示fixed;
四、Swizzle操作符
Cg語言中的其他操作符和高級CPU語言C++類似,包括關系操作符、邏輯操作符和位移操作符以及條件操作符。而Swizzle操作符是Cg語言中特有的,它可以將一個向量的成員取出組成一個新的向量。對於坐標或者角度等其他多維向量,Swizzle操作符(.)后接x、y、z、w分別表示原始向量的第一個、第二個、第三個和第四個元素;同樣,對於顏色可以后接r、g、b和a來表示同樣的索引。
例如:
float4(a,b,c,d).xwz 等價於 float(a,d,c)
float4(a,b,c,d).xxy 等價於 float(a,a,b)
注:Swizzle操作符只對結構體和向量使用,不能對數組使用。
五、輸入數據關鍵字:Cg中輸入數據流一般分為兩類
1、varying 參數:在Cg程序中通過語義進行綁定變量, Cg語言提供了一組語義詞,用以表示參數是由頂點的那些數據初始化的,一旦這個變量使用了語義詞進行綁定,那么這個變量值被初始化的同時也意味着它有了特殊的含義,如表示位置、法線等含義。語義提供了一種使用隨頂點變化或隨片段變化而變化的值來初始化Cg程序參數的方法,這些數據都是從應用程序輸入到GPU的數據,如頂點位置、法向量、紋理坐標數據等。
2、Uniform 參數:Uniform是用來限制一個變量的初始值的來源,當聲明一個變量為Uniform類型的時候,表示這個變量的初始值來自於外部的其他環境。除了獲取初始值的這點之外,Uniform關鍵字聲明的變量和其他變量是完全一樣的。通常用Uniform來定義一些與三維渲染有關的離散信息數據,並通常不會隨着圖元信息的變化而變化,如材質對光的反射信息。Uniform表示一個參數,通常使用 uniform表示函數的形參,不能定義一個uniform表示的局部變量。
Unity的內置Uniform輸入參數如下:
uniform float4 _Time, _SinTime, _CosTime; // 時間量
uniform float4 _ProjectionParams; // x = 1 or -1 (如果投影翻轉就是-1)
// y = 近平面; z = 遠平面; w = 1/遠平面
uniform float4 _ScreenParams; // x = width; y = height; z = 1 +1/width; w = 1 + 1/height
uniform float3_WorldSpaceCameraPos;
uniform float4x4 _Object2World; //模型矩陣
uniform float4x4 _World2Object; // 模型矩陣的逆
uniform float4 _LightPositionRange; // xyz = pos, w = 1/range
uniform float4 _WorldSpaceLightPos0; // 光源的位置和方向
uniform float4x4 UNITY_MATRIX_MVP; // 模型視圖投影矩陣
uniform float4x4 UNITY_MATRIX_MV; // 模型視圖矩陣
uniform float4x4 UNITY_MATRIX_V; // 視圖矩陣
uniform float4x4 UNITY_MATRIX_P; // 投影矩陣
uniform float4x4 UNITY_MATRIX_VP; // 視圖投影矩陣
uniform float4x4 UNITY_MATRIX_T_MV; // 模型視圖矩陣的轉置矩陣
uniform float4x4 UNITY_MATRIX_IT_MV; // 模型視圖矩陣的逆矩陣的轉置矩陣
uniform float4x4 UNITY_MATRIX_TEXTURE0; // 貼圖紋理矩陣
uniform float4x4 UNITY_MATRIX_TEXTURE1; //貼圖紋理矩陣
uniform float4x4 UNITY_MATRIX_TEXTURE2; //貼圖紋理矩陣
uniform float4x4 UNITY_MATRIX_TEXTURE3; //貼圖紋理矩陣
uniform float4 UNITY_LIGHTMODEL_AMBIENT; // 環境色
六、輸入輸出
對於程圖形渲染管線,可編程控制的部分只有兩個,頂點着色器和片段着色器。對於編程控制這兩個部分,首要的任務就是要怎么給它們傳參數。Cg語言的參數傳遞同樣也有“值傳遞”和“引用傳遞”之分。因為GPU不支持指針,所以Cg語言采用了如下的方式來修辭參數傳遞:
1、in:修辭一個形參只是用於輸入,進入函數體時被初始化,且該形參值的改變不會影響實參值,傳遞方式為值傳遞。
2、out:修辭一個形參只是用於輸出,進入函數體時沒有被初始化,一般為函數的返回值。
3、inout:修辭一個形參即用於輸入也用於輸出,這是典型的引用傳遞。
一些常用 Shader 變量的Attribute設置
1.1 枚舉, 使用系統自帶的枚舉
[Enum(UnityEngine.Rendering.BlendMode)] _Blend ("Blend mode", Float) = 1
1.2 枚舉, Shader中設置的枚舉並指定枚舉值
[Enum(One,1,SrcAlpha,5)] _Blend2 ("Blend mode subset", Float) = 1
1.3 枚舉, 控制宏關鍵字, 自動添加變量
[KeywordEnum(None, Add, Multiply)] _Overlay ("Overlay mode", Float) = 0
會自動生成變量_OVERLAY_NONE _OVERLAY_ADD _OVERLAY_MULTIPLY
#pragma multi_compile _OVERLAY_NONE _OVERLAY_ADD _OVERLAY_MULTIPLY
這個關鍵字需要在CGPROGRAM ... ENDCG 中定義
2.1. 普通開關
[Toggle] _Invert("Invert color?", Float) = 0
2.2 關鍵字開關
[Toggle(ENABLE_FANCY)] _Fancy ("Fancy?", Float) = 0
需要手動添加 #pragma multi_compile _ ENABLE_FANCY
或 #pragma shader_feature ENABLE_FANCY
3.1 數值變量拖動條
_Blend("Blend", Range(0,1)) = 0.5 // 普通拖動條
[PowerSlider(3.0)] _Shininess ("Shininess", Range (0.01, 1)) = 0.08 // 二次方拖動條
4.1 一般擴展
// Default small amount of space. [Space] _Prop1 ("Prop1", Float) = 0
// Large amount of space. [Space(50)] _Prop2 ("Prop2", Float) = 0
[Header(A group of things)] _Prop1 ("Prop1", Float) = 0 // 提示信息
頂點和片段着色器
input結構體構成
POSITION, SV_POSITION
|
The position of a vertex in world coordinates (object space)
|
NORMAL
|
The normal of a vertex, relative to the world (not to the camera)
|
COLOR, COLOR0, DIFFUSE, SV_TARGET
|
The color information stored in the vertex
|
COLOR1, SPECULAR
|
The secondary color information stored in the vertex (usually the pecular)
|
TEXCOORD0, TEXCOORD1,
…, TEXCOORDi
|
The i-th UV data stored in the vertex
|
POSITION, SV_POSITION, HPOS
|
The position of a vertex in camera coordinates (clip space, from zero to one for each dimension)
|
COLOR, COLOR0, COL0,
COL, SV_TARGET
|
The front primary color
|
COLOR1, COL1
|
The front secondary color
|
TEXCOORD0, TEXCOORD1,
…, TEXCOORDi, TEXi
|
The i-th UV data stored in the vertex
|
WPOS
|
The position, in pixels, in the window (origin in the lower left corner)
|
編寫shader時的一些建議:
1、只計算需要計算的東西;
2、通常,需要渲染的像素比頂點數多,而頂點數又比物體數多很多。所以如果可以,盡量將運算從PS移到VS,或直接通過script來設置某些固定值;
3、在使用Surface Shader時,可以通過一些指令讓shader優化很多。
通常情況下,Surface shader的很多默認選項都是開啟的,以適應大多數情況,但是很多時候,你可以關閉其中的一些選項,從而讓你的shader運行的更快:
(1) approxview 對於使用了view direction的shader,該選項會讓view dir的normalize操作per-vertex進行,而不是per-pixel。這個優化通常效果明顯。
(2) halfasview 可以讓Specular shader變得快一些,使用一個介於光照方向和觀察方向之間的half vector來代替真正的觀察方向viewDir來計算光照函數。
(3) noforwardadd Forward Render時,完全只支持一盞方向光的per-pixel渲染,其余的光照全部按照per-vertex或SH渲染。這樣可以確保shader在一個pass里渲染完成。
(4) noambient 禁掉ambient lighting和SH lighting,可以讓shader快一點兒。
4、浮點數精度相關:
float:最高精度,通常32位
half:中等精度,通常16位,-60000到60000,
fixed:最低精度,通常11位,-2.0到2.0,1/256的精度。
盡量使用低精度。對於color和unit length vectors,使用fixed,其他情況,根據取值范圍盡量使用half,實在不夠則使用float。
在移動平台,關鍵是在fragment shader中盡可能多的使用低精度數據。另外,對於多數移動GPU,在低精度和高精度之間轉換是非常耗的,在fixed上做swizzle操作也是很費事的。
5、Alpha Test
Alpha test和clip()函數,在不同平台有不同的性能開銷。
通常使用它來cull那些完全透明的像素。
但是,在ios和一些android上使用的PowerVR GPUs上面,alpha test非常的昂貴。
6、Color Mask
在移動設備上,Color Mask也是非常昂貴的,所以盡量別使用它,除非真的是需要。
shader多版本編譯:
shader variants(shader 變種)使用方式:
(1)#pragma multi_compile FANCY_STUFF_OFF FANCY_STUFF_ON
(2)#pragma shader_feature FANCY_STUFF_OFF FANCY_STUFF_ON
#pragma shader_feature FANCY_STUFF是#pragma shader_feature _ FANCY_STUFF的快捷方式,同樣會生成兩個變種
shader_feature和multi_compile的區別:
shader_feature:未使用的變種不會build進游戲;
multi_compile:會編譯生成所有變種。
用法:shader_feature更適用於材質的關鍵字,而multi_compile更適用於代碼設置的全局關鍵字。
關鍵字個數限制:
unity最多支持256個關鍵字,並且unity內部已經使用了60個左右。另外,可以在unity的工程設置中定義一些全局有效的關鍵字,這樣也會消耗一些數量,所以在編寫shader時要注意數量不要超過上限。
內置的multi_compile快捷組合:
#pragma multi_compile_fwdbase 編譯ForwardBase需要的所有關鍵字變種,包括不同的lightmap類型,主要的方向光是否開啟陰影等。
#pragma multi_compile_fwdadd 編譯ForwardAdd Pass包含的關鍵字變種。
#pragma multi_compile_fwdadd_fullshadows 和上一個類似,另外還包含了光照實施陰影的能力。
#pragma ulti_compile_fog 霧效。
上面內置的快捷方式包含了很多的變種,但可以通過skip_variants來屏蔽某些關鍵字:
#pragma skip_variants POINT POINT_COOKIE
硬件級別shader變種:
提供針對不同硬件(比如gles和gles 3.0)的shader變種。(針對硬件能力級別的優化)
#pragma hardware_tier_variants renderer
d3d11 - Direct3D 11/12
glcore - OpenGL 3.x/4.x
gles - OpenGL ES 2.0
gles3 - OpenGL ES 3.x
metal - iOS
/Mac Metal
vulkan - Vulkan
d3d11_9x - Direct3D 11 9.x feature level, as commonly used on WSA platforms
xboxone - Xbox One
ps4
- PlayStation 4
psp2 - PlayStation Vita
n3ds - Nintendo 3DS
wiiu - Nintendo Wii U
添加了上述#pragma的shader會自動生成三個關鍵字變種:
UNITY_HARDWARE_TIER1
UNITY_HARDWARE_TIER2
UNITY_HARDWARE_TIER3
編輯器模式下,可以在Graphics Emulation中來手動設置使用哪個變體。
上述三中變體,同時只會加載其中一種,
指定方式:
(1)自動檢測:在加載時,Unity檢測GPU並進行設置;如果檢測不到,默認選擇最高級。
(2)手動設置來制定使用哪一個tier,代碼如下:(一定是在shader加載之前制定,在某個shader加載之后再指定是不會影響該shader的)
Graphics.activeTier = UnityEngine.Rendering.GraphicsTier.Tier1;
平台shader設置:
可以通過代碼手動設置[平台, tier, 設置]
UnityEditor.Rendering.EditorGraphicsSettings.SetTierSettings(BuildTargetGroup target, GraphicsTier tier, TierSettings settings);
Shader預處理宏、內置狀態變量、多版本編譯等
預定義shader預處理宏:
Target platform:
SHADER_API_OPENGL - desktop OpenGL
SHADER_API_D3D9 - Direct3D 9
SHADER_API_XBOX360 - Xbox 360
SHADER_API_PS3 - PlayStation 3
SHADER_API_D3D11 - desktop Direct3D 11
SHADER_API_GLES - OpenGL ES 2.0 (desktop or mobile), use presence of SHADER_API_MOBILE to determine.
SHADER_API_FLASH - Flash Stage3D
SHADER_API_D3D11_9X - Direct3D 11 target for Windows RT
Surface shader pass indicators:
UNITY_PASS_FORWARDBASE - 前向渲染的base pass(主方向光、lightmaps、SH)
UNITY_PASS_FORWARDADD - 前向渲染的add pass(沒盞燈一個pass)
UNITY_PASS_PREPASSBASE - 延遲渲染base pass(renders normals & specular exponent).
UNITY_PASS_PREPASSFINAL - 延遲渲染final pass (applies lighting & textures).
UNITY_PASS_SHADOWCASTER - 陰影投射渲染pass.
UNITY_PASS_SHADOWCOLLECTOR - 陰影手機pass for directional light shadows.
內置全局狀態變量:
內置的矩陣:
UNITY_MATRIX_MVP float4x4 Current model * view * projection matrix.
UNITY_MATRIX_MV float4x4 Current model * view matrix.
UNITY_MATRIX_V float4x4 Current view matrix.
UNITY_MATRIX_P float4x4 Current projection matrix.
UNITY_MATRIX_VP float4x4 Current view * projection matrix.
UNITY_MATRIX_T_MV float4x4 Transpose of model * view matrix.
UNITY_MATRIX_IT_MV float4x4 Inverse transpose of model * view matrix.
UNITY_MATRIX_TEXTURE0 to UNITY_MATRIX_TEXTURE3 float4x4 Texture transformation matrices.
_Object2World float4x4 Current model matrix.
_World2Object float4x4 Inverse of current world matrix.
_WorldSpaceCameraPos float3 World space position of the camera.
unity_Scale float4 xyz components unused; w contains scale for uniformly scaled objects.
內置的向量:
UNITY_LIGHTMODEL_AMBIENT: Current ambient color.
光照相關的:
_ModelLightColor float4 Material’s Main * Light color
_SpecularLightColor float4 Material’s Specular * Light color
_ObjectSpaceLightPos float4 Light’s position in object space. w component is 0 for directional lights, 1 for other lights
_Light2World float4x4 Light to World space matrix
_World2Light float4x4 World to Light space matrix
_Object2Light float4x4 Object to Light space matrix
變量:
_Time float4 Time (t/20, t, t*2, t*3), use to animate things inside the shaders.
_SinTime float4 Sine of time: (t/8, t/4, t/2, t).
_CosTime float4 Cosine of time: (t/8, t/4, t/2, t).
unity_DeltaTime float4 Delta time: (dt, 1/dt, smoothDt, 1/smoothDt).
_ProjectionParams float4 x is 1.0 (or –1.0 if currently rendering with a flipped projection matrix), y is the camera’s near plane, z is the camera’s far plane and w is 1/FarPlane.
_ScreenParams float4 x is the current render target width in pixels, y is the current render target height in pixels, z is 1.0 + 1.0/width and w is 1.0 + 1.0/height.
內置光照參數:
對於不同的Rendering Path和Pass Tag,可以使用的光照參數是不一樣的。(當然所有參數你都可以在shader中使用,但並不能保證其一定會存儲有效的值)。
Forward rendering(ForwardBase和PorwardAdd標記的pass)支持的變量:
LightColor0 (declared in Lighting.cginc) | fixed4 |Light color. | |WorldSpaceLightPos0 float4 Directional lights: (world space direction, 0). Other lights: (world space position, 1).
_LightMatrix0 (declared in AutoLight.cginc) float4x4 World-to-light matrix. Used to sample cookie & attenuation textures.
unity_4LightPosX0, unity_4LightPosY0, unity_4LightPosZ0 float4 (ForwardBase pass only) world space positions of first four non-important point lights.
unity_4LightAtten0 float4 (ForwardBase pass only) attenuation factors of first four non-important point lights.
unity_LightColor half4[4] (ForwardBase pass only) colors of of first four non-important point lights.
說明:
(1)_LightColor0在ForwardBass里面表示:主光,一定是Pixel(Important)、Directional光源,沒有的話則改值不可用;
(2)_LightColor0在ForwardAdd里面表示:當前執行的ForwardAdd的pixel光;
_WorldSpaceLightPos0的意義和_LightColor類似,也是在Base里表示主光,Add里表示像素光。
(3)unity_LightColor是距離物體最近的4個point光,也就是說同一個場景中每個物體的這4個光不一樣,注意這4個point光的選擇非常有意思;
(a)當shader中沒有ForwardAdd Pass的時候,unity_LightColor記錄了4盞vertex point光源,無視pixel光;
(b)當shader中包含ForwardAdd Pass的時候,unity_LightColor記錄了4盞point光源,pixel比vertex優先。
(4)如果場景中有多個pixel光,則對每一個物體,所有的非主光的pixel光都會執行一遍ForwardAdd Pass,按照強度大小、平行光優先的順序來執行;
(5)不要在ForwardAdd Pass里面使用unity4LightPosX/Y/Z等數據,因為它們就是給ForwardBase Pass使用的,而且如果其中有pixel光,它們本身就會對ForwardAdd執行一遍;
(6)可以使用Shade4PointLights函數在ForwardBase中計算Vertex光源的照明。
Deferred shading:
LightColor | float4 | Light color. | |LightMatrix0 float4x4 World-to-light matrix. Used to sample cookie & attenuation textures.
Vertex-lit rendering(Vertex標記的pass):
頂點光照可以使用最多8盞光源,這些光源按照亮度排序,按順序存儲在一下這些數據結構中,如果光源數量少於8,那么多出來的都將黑色:
unity_LightColor half4[8] Light colors.
unity_LightPosition float4[8] View-space light positions. (-direction,0) for directional lights; (position,1) for point/spot lights.
unity_LightAtten half4[8] Light attenuation factors. x is cos(spotAngle/2) or –1 for non-spot lights; y is 1/cos(spotAngle/4) or 1 for non-spot lights; z is quadratic attenuation; w is squared light range.
unity_SpotDirection float4[8] View-space spot light positions; (0,0,1,0) for non-spot lights.
說明:
(1)_LightColor0表示unity_LightColor[0]
(2)unity_LightPosition是MV空間中的位置
(3)逐頂點光照函數float4 ShadeVertexLights(float4 vertex, float3 normal)
注意:
(1)_LightColor0變量不代表某個具體含義,它在不同的Render Path和Pass里面是有不同的意義的
(2)ShaderLab里面的內置變量是不會及時清理的,這是Unity處於性能方面的考慮,因為在CPU和GPU之間頻繁傳遞數據是很耗資源的
Fog和Ambient環境光信息:
UNITY_LIGHTMODEL_AMBIENT fixed4 Ambient lighting color (Equator ambient in three-color lighting case).
unity_AmbientSky fixed4 Sky ambient lighting color in three-color lighting case.
unity_AmbientGround fixed4 Ground ambient lighting color in three-color lighting case.
unity_FogColor fixed4 Fog color.
unity_FogParams float4 Parameters for fog calculation: (density / sqrt(ln(2)), density / ln(2), –1/(end-start), end/(end-start)). x is useful for Exp2 fog mode, y for Exp mode, z and w for Linear mode.
使用multi_compile編譯Shader的多個版本:
有時候我們希望保留一個shader的大多數實現,而只是做一些細節的修改,此時我們就可以通過該方式來生成shader的多個版本,然后在代碼中控制使用哪個版本。
命令:
#pragma multi_compile FANCY_STUFF_OFF FANCY_STUFF_ON
控制:
Material.EnableKeyword(keyword: string)/DisableKeyword(keyword: string)
Shader.EnableKeyword(keyword: string)/DisableKeyword(keyword: string)
在shader中根據定義好的關鍵字處理具體顯示方案:
float4 frag(vertOut i):COLOR
{
float4 c = float4(0, 0, 0, 0);
#ifdef MY_multi_1
c = float4(0, 1, 0, 0);
#endif
#ifdef MY_multi_2
c = float4(0, 0, 1, 0);
#endif
return c;
}
注意不要在shader中大量使用此命令,因為關鍵字的個數是有上限的,而多條multi_complie會交叉匹配產生很多種結果。
GLSL shader編程
在Shader中,除了Cg/HLSL以外,GLSL(OpenGL Shading Languate)也可以直接使用。
一般不建議使用GLSL,除非你確定你的目標平台只有Max OS X或兼容OpenGL ES 2.0的移動設備。
Unity默認都會將Cg/HLSL交叉編譯出優化過得GLSL,以此來支持多平台。在desktop平台下可以通過打開#pragma glsl選項來支持。
平台特性相關的渲染差異:
Unity封裝了大多數的平台問題,但有些時候還是需要自己處理一下的。
紋理坐標:
Direct3D里面是左上角為原點;
OpenGL和OpenGL ES是左下角為原點。
多數時候都ok,除了在Render To Texture時。但是在RTT時,Unity對於D3D平台會自動將渲染的貼圖上下翻轉一下,以此隱藏了各平台的差異。
D3D平台下,有一種情況不需要Unity自動翻轉渲染貼圖,那就是使用Image Effects和Anti-Aliasing時,因為直接渲染到Screen了,
需要手動處理的情況:但同時使用screen texture和RenderTexture時,有可能會得到不一致的坐標朝向,此時就需要在shader里面通過代碼處理了:
// On D3D when AA is used, the main texture and scene depth texture
// will come out in different vertical orientations.
// So flip sampling of the texture when that is the case (main texture
// texel size will have negative Y).
#if UNITY_UV_STARTS_AT_TOP
if (_MainTex_TexelSize.y < 0)
uv.y = 1-uv.y;
#endif
AlphaTest:
在OpenGL ES 2.0和Direct3D 11中,沒有alpha testing的固定函數。所以在編寫programmable shader時,建議在pixel shader中使用CG/HLSL clip()函數來替代。
D3D 11 shader編譯器比較挑剔:
D3D 9和OpenGL使用NVIDIA的Cg來編譯shader,但D3D 11使用微軟的HLSL來編譯,此時就會產生一些差異化。
OpenGL ES 2.0只支持部分GLSL原生的東西,所以Unity實現了一些內置的參數,讓其以OpenGL的方式工作,但是也有一些參數是沒有的。
_WorldSpaceLightPos0:
在UnityCG.cginc里,提供了獲取世界空間下的光照方向的函數
// Computes world space light direction
inline float3 WorldSpaceLightDir( in float4 v )
{
float3 worldPos = mul(_Object2World, v).xyz;
#ifndef USING_LIGHT_MULTI_COMPILE
return _WorldSpaceLightPos0.xyz - worldPos * _WorldSpaceLightPos0.w;
#else
#ifndef USING_DIRECTIONAL_LIGHT
return _WorldSpaceLightPos0.xyz - worldPos;
#else
return _WorldSpaceLightPos0.xyz;
#endif
#endif
}
其中,由於平行光的方向不隨頂點位置發生變化,因此直接使用_WorldSpaceLightPos0.xyz即可,此時里面存儲的其實就是平行光的方向,而非位置。同時,
_WorldSpaceLightPos0.w可以表明該光源的類型,如果為0表示是平行光,為1表示是點光源或者聚光燈光源。
TANGENT_SPACE_ROTATION:
創建一個正切空間的旋轉矩陣,TANGENT_SPACE_ROTATION由下面兩行組成
等同於如下兩行代碼:
float3 binormal = cross( v.normal, v.tangent.xyz ) * v.tangent.w;
float3x3 rotation = float3x3( v.tangent.xyz, binormal, v.normal );
一、
#pragma surface surfaceFunction lightModel [optionalparams]
surfaceFunction(指明使用的表面函數):
void surf(Input IN, inout SurfaceOutput o)
void surf(Input IN, inout SurfaceOutputStandard o) 基於PBR
void surf(Inout IN, inout SurfaceOutputStandardSpecular o) 基於PBR
lightModel(指明使用的光照模型):
內置不基於物理的:
Lambert,BlinnPhong
內置基於物理的:
Standard,StandardSpecular
自定義光照模型
[optionalparams](可選參數):
透明度混合與透明度測試
alpha or alpha:auto 為簡單光照選擇褪色透明度(等同於alpha:fade) ,以及基於物理照明的預乘透明度(等同於alpha:premul)
alpha:blend 開啟透明度混合
alpha:fade 開啟傳統漸變透明
alpha:premul 開啟預乘a透明度
alphatest:VariableName 根據VariableName的變量來控制透明度混合和透明度測試,VariableName是一個float型的變量,剔除不滿足條件的片元,此時往往需要用到addshadow來生成正確陰影投射的Pass
keepalpha 默認不透明表面着色器將1寫入A通道,不管alpha輸出值以及光照函數的返回值
decal:add 對其他表面上的物體使用additive blending
decal:blend 對其他表面上的物體使用alpha blending
自定義修改函數
vertex:VertexFunction 頂點修改函數,用於修改計算頂點位置、信息等
finalcolor:ColorFunction 最終顏色修改函數
finalgbuffer:ColorFunction 自定義延遲路徑,用於更改gbuffer
finalprepass:ColorFunction 自定義預處理路徑
陰影
addshadow 生成一個陰影投射的Pass,為一些使用了頂點動畫、透明度測試的物體產生正確的陰影
fullforwardshadows 支持前向渲染路徑中所有光源類型的陰影,shader默認只支持最重要平行光的陰影,添加該參數可以支持點光源或聚光燈的陰影效果
tessellate:TessFunction 使用DX11 GPU曲面細分
控制代碼生成(表面着色器默認處理所有坑能的光照、陰影、光照烘培,可手動調整跳過一些不必要的加載提升性能)
exclude_path:deferred, exclude_path:forward, exclude_path:prepass 不為某個渲染路徑生成代碼
noshadow 禁用陰影
noambient 不應用任何環境光以及光照探針
novertexlights 在前向渲染路徑中不應用任何逐頂點光照及光照探針
nolightmap 不應用任何光照烘培
nodynlightmap 不應用實時GI
nodirlightmap 不應用directional lightmaps
nofog 不應用任何霧效
nometa 生成meta這個Pass(that’s used by lightmapping & dynamic global illumination to extract surface information)
noforwardadd 不應用前向渲染中所有的additive pass,使得shader只支持一個重要平行光,其他光用逐頂點/SH光源計算光照影響,使shader更精簡
nolppv 不應用光照探針代理Light Probe Proxy Volume(LPPV)
noshadowmask 不應用Shadowmask
其他
softvegetation 只有當Soft Vegetation(軟植被)開啟時該shader才被渲染
interpolateview 在頂點而不是片元着色器中計算 view direction並插值,需多使用一張紋理插值器,提升渲染速度
halfasview Pass half-direction vector into the lighting function instead of view-direction. Half-direction will be computed and normalized per vertex. This is faster, but not entirely correct.
dualforward 在前向渲染中使用dual lightmaps
dithercrossfade 使表面着色器支持 dithering effects
二、Input
包含表面屬性數據來源,作為表面函數的輸入結構體,頂點修改函數的輸出結構體
其中的采樣坐標必須以uv為前綴,如uv_MainTex(uv2也可,表明使用次級紋理坐標集合)
各個變量往往由Unity自動准備好,直接在表面函數中使用即可,但如自定義了頂點修改函數用Input作為輸出時需在里面自定義相應變量
float3 viewDir 包含視角方向
float4 with COLOR semantic 包含插值后的逐頂點顏色
float4 screenPos 包含屏幕空間坐標,用於反射、屏幕特效等,不支持 GrabPass ,需自己用ComputeGrabScreenPos計算UV
float3 worldPos 包含世界空間位置
float3 worldRefl 包含世界空間下反射方向,前提是沒有修改表面法線o.Normal
float3 worldNormal 包含世界空間下法線方向,前提是沒有修改表面法線o.Normal
float3 worldRefl; INTERNAL_DATA 如果修改了表面法線o.Normal,需要使用該變量告訴Unity要基於修改后的法線計算世界空間下的反射方向。用WorldReflectionVector (IN, o.Normal)得到世界空間下的反射方向。
float3 worldNormal; INTERNAL_DATA 如果修改了表面法線o.Normal,需要使用該變量告訴Unity要基於修改后的法線計算世界空間下的法線方向。用WorldReflectionVector (IN, o.Normal)得到世界空間下的法線方向。
三、SurfaceOutput
作為表面函數的輸出,作為光照函數的輸入進行各種光照計算
結構體中的變量是提前聲明好的,不可增加或減少,若沒有賦值則使用默認值
struct SurfaceOutput(非物理的光照模型)
{
fixed3 Albedo; // diffuse color
fixed3 Normal; // tangent space normal, if written
fixed3 Emission;
half Specular; // specular power in 0..1 range
fixed Gloss; // specular intensity
fixed Alpha; // alpha for transparencies
};
struct SurfaceOutputStandard(默認金屬工作流程)
{
fixed3 Albedo; // base (diffuse or specular) color
fixed3 Normal; // tangent space normal, if written
half3 Emission;
half Metallic; // 0=non-metal, 1=metal
half Smoothness; // 0=rough, 1=smooth
half Occlusion; // occlusion (default 1)
fixed Alpha; // alpha for transparencies
};
struct SurfaceOutputStandardSpecular(高光工作流程)
{
fixed3 Albedo; // diffuse color
fixed3 Specular; // specular color
fixed3 Normal; // tangent space normal, if written
half3 Emission;
half Smoothness; // 0=rough, 1=smooth
half Occlusion; // occlusion (default 1)
fixed Alpha; // alpha for transparencies
};
其中,Specular為高光反射中指數部分的系數,Gloss為高光反射中強度系數
四、自定義光照模式
half4 LightingName (SurfaceOutput s, half3 lightDir, half atten);
用於表示前向渲染路徑中的光照模式,不取決於view direction
half4 LightingName (SurfaceOutput s, half3 lightDir, half3 viewDir, half atten);
用於表示前向渲染路徑中的光照模式,包含view direction
half4 LightingName_PrePass (SurfaceOutput s, half4 light);
用於延遲光照路徑
half4 LightingName_DirLightmap(SurfaceOutput s, fixed4 color, fixed4 scale, bool surfFuncWritesNormal);
half4 LightingName_DirLightmap(SurfaceOutput s, fixed4 color, fixed4 scale, half3 viewDir, bool surfFuncWritesNormal,out half3 specColor);
前者不包含,后者包含view direction,這兩個函數會自動處理前向渲染路徑和延遲渲染路徑
half4 Lighting<Name> (SurfaceOutput s, UnityGI gi); Use this in forward rendering paths for light models that are not dependent on the view direction.
half4 Lighting<Name> (SurfaceOutput s, half3 viewDir, UnityGI gi); Use this in forward rendering paths for light models that are dependent on the view direction.
half4 Lighting<Name>_Deferred (SurfaceOutput s, UnityGI gi, out half4 outDiffuseOcclusion, out half4 outSpecSmoothness, out half4 outNormal); Use this in deferred lighting paths.
half4 Lighting<Name>_PrePass (SurfaceOutput s, half4 light); Use this in light prepass (legacy deferred) lighting paths.
half4 Lighting<Name>_GI (SurfaceOutput s, UnityGIInput data, inout UnityGI gi);