屏幕圖像捕捉:
- Shader的GrabPass
GrabPass可以很方便地捕獲當前渲染時刻的FrameBuffer中的圖像。
其原理就是從當前FrameBuffer中copy一份紋理,通過SetTexture的方式設置紋理。
至於GrabPass的性能問題,一般認為是對FrameBuffer 進行的一些pixel copy operations造成的,
具體Unity是怎么實現的,不得而知。
GrabPass { } 不帶參數的 默認名字為 "_GrabTexture" 會在當時為每一的使用的obj抓取一次
GrabPass { "TextureName" } 每個名字在 每幀,第一次使用時抓取一次 - commandBuffer
GrapPass在每幀至少捕獲一次,優化思路是可以統一關閉,減少抓取次數
基本思路是,獨立一個只繪制扭曲層的相機,在OnPreRender中檢查抓取cd,引用次數,扭曲開關等,
用Graphics.ExecuteCommandBuffer(commandBuffer);的方式手動抓取
核心部分代碼
private void Awake()
{
... ...
var cam = GetComponent<Camera>();
rt = RenderTexture.GetTemporary(cam.pixelWidth, cam.pixelHeight, 16, RenderTextureFormat.ARGB32, RenderTextureReadWrite.Default, 1);
commandBuffer = new CommandBuffer();
commandBuffer.name = "GrabScreenCommand";
commandBuffer.Blit(BuiltinRenderTextureType.CurrentActive, rt);
}
void OnPreRender()
{
if (UseCount <= 0 || Time.time < nextGrapTime)
return;
nextGrapTime = Time.time + grapCD;
Graphics.ExecuteCommandBuffer(commandBuffer);
}
扭曲效果
主要使用兩個內置函數 https://www.jianshu.com/p/df878a386bec
- float4 ComputeScreenPos(float4 pos)
將攝像機的齊次坐標下的坐標轉為齊次坐標系下的屏幕坐標值,其范圍為[0, w]
值用作tex2Dproj指令的參數值,tex2Dproj會在對紋理采樣前除以w分量。
當然你也可以自己除以w分量后進行采樣,但是效率不如內置指令tex2Dproj - half4 tex2Dproj(sampler2D s, in half4 t) { return tex2D(s, t.xy / t.w); }
扭曲使用貼圖計算UV偏移
核心部分:
v2f vert (input v) {
v2f o;
o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
o.texcoord = v.texcoord;
o.uvgrab = ComputeGrabScreenPos(o.vertex);
return o;
}
fixed4 frag (v2f i) : COLOR {
fixed2 norm = UnpackNormal(tex2D(_Distortion, i.texcoord)).rg;
i.uvgrab.xy -= _Strength * norm.rg * _RaceDropTex_TexelSize.xy;
fixed4 col = tex2Dproj(_RaceDropTex, i.uvgrab);
return col;
}