屏幕图像捕捉:

  • 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)

  • half4 tex2Dproj(sampler2D s, in half4 t) { return tex2D(s, t.xy / t.w); }

核心部分:

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;
}
05-11 22:06