在之前的学习中,一个摄像机的渲染结果会输出到颜色缓冲中,并显示到我们的屏幕上。现在的GPU允许我们把整个三维场景渲染到一个中间缓冲中,即渲染目标纹理(Render Target Texture,RTT),而不是传统的帧缓冲或后备缓冲。与之相关的是多重渲染目标(Multiple Render Target,MRT),这种技术指的是GPU允许我们把场景同时渲染到多个渲染目标纹理中,而不再需要为每个渲染目标纹理单独渲染完整的场景,延迟渲染就是使用多重渲染目标的一个应用。
unity为渲染目标纹理定义了一个专门的纹理类型——渲染纹理(Render Texture)。在unity中使用渲染纹理通常有两种方式:
1.一种方式在Project目录下创建一个渲染纹理,然后把某个摄像机的渲染目标设置成该渲染纹理,这样一来该摄像机的渲染结果会实时更新到渲染纹理中,而不会显示在屏幕上。使用这种方法,我们还可以选择渲染纹理的分辨率、滤波模式等纹理属性。
2.另一种方式是在屏幕后处理时使用GrabPass命令或OnRenderImage函数来获取当前屏幕图像,unity会把这回屏幕图像放到一张 和屏幕分辨率等同的渲染纹理中,然后我们可以在自定义的Pass中把他们当成普通的纹理来处理,从而实现各种屏幕特效。
一、镜子效果
首先在project视图下创建一个渲染纹理,然后为了得到从镜子出发观察到的场景图像,还需要创建一个摄像机,并调整它的位置、裁剪平面、视角等,使得它的显示图像是我们希望的镜子图像。由于这个摄像机不需要直接显示在屏幕上,而是用于渲染到纹理。因此我们把刚刚创建的Render Texture拖拽到该摄像机的Target Texture上。
镜子效果的实现是使用一个渲染纹理作为输入属性,并把该渲染纹理在水平方向上翻转后直接显示到物体上即可。
实现:
1.声明一个纹理属性,它对应了由镜子摄像机渲染得到的渲染纹理(之前创建的render texture纹理面板赋值给它):
Properties {
_MainTex ("Main Tex", 2D) = "white" {}
}
2.在顶点着色器中计算纹理坐标:
v2f vert(a2v v) {
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
o.uv = v.texcoord;
// Mirror needs to filp x
o.uv.x = 1 - o.uv.x;
return o;
}
在上面的代码中,我们翻转了x分量的纹理坐标,这是因为镜子里显示的图像都是左右相反的。
3.在片元着色器中对渲染纹理进行采样和输出:
fixed4 frag(v2f i) : SV_Target {
return tex2D(_MainTex, i.uv);
}
在上面的实现中,我们把渲染纹理的分辨率大小设置为2