Shader經驗分享

  • 2019 年 12 月 3 日
  • 筆記

流水線 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個裁剪面,分別是左右上下近遠、 —————————- 1.表面著色器 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。 ——————————— 2.頂點著色器 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;//頂點顏色 }; 3.片段著色器 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 遮罩紋理 —————————————- 1.透明度測試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//不渲染任何像素。 2.模板測試: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不進行顏色輸出。 3.深度測試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:遺留的頂點照明渲染 1.前向渲染:包括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進行渲染。就得到了運動模糊效果。

常見的幾種混合類型:

//正常(Normal) 即透明度混合

Blend SrcAlpha OneMinusSrcAlpha

//柔和相加 (Soft Additive)

Blend OneMinusDstColor One

//正片疊底(Multiply) 即相乘

Blend DstColor Sero

//兩倍相乘(2x Multiply)

Blend DstColor SrcColor

//變暗(Darken)

BlendOp Min

Blend One One

//變亮(Lighten)

BlendOp Max

Blend One One

//濾色(Screen)

Blend OneMinusDstColor One 等同於 Blend One OneMinusSrcColor

//線性減淡(Linear Dodge)

Blend One One

—————————————————————————- 深度和法線紋理 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); 全局(動態)霧效:通過時間控制雜訊紋理的偏移距離,然後根據雜訊顏色值來參與計算霧效濃度,然後計算霧效,就有了流動和淡濃的效果。