UE4.22移动端降分辨率离屏半透明渲染的坑
上周着力于降分辨率离屏渲染,为啥是“降分辨率离屏半透明渲染”而不是“降分辨率离屏特效渲染”呢?因为根本没办法解决半透明排序的问题。离屏就意味着需要打断Render Pass,如果特效单独渲染在一个render texture上,其他的半透明物体渲染在Sence Color上渲染,因为半透明没有记录深度和透明度(除非单独开一个RT来存储这些信息,但成本提高了),所以没有办法在合成的时候解决深度冲突问题,因此,必须在同一个Pass中按深度顺序渲染所有的半透明物体。
因此,离屏特效变成了离屏半透明,但英伟达他们在GPU Gems chapter-23-high-speed-screen-particles中称为离屏特效,不知道他们怎么解决的这个问题233。
其实一路开发过来感觉还挺顺畅的,目前只需要考虑HDR情况,因此离屏渲染只需要向GRenderTargets额外申请一张16位的 HDR RGBA RT 和一个没有MSAA的 Depth RT。
其实主要的算法在Gems中都讲完了。我主要记录一下坑点:
渲染步骤与注意事项为:
-
在Base Pass Opaque and Mask渲染完后,打断Render Pass,新建一次Render Pass并且降分辨率复制场景深度。
-
复制场景深度时,因为HDR下Scene Color是RGBA写入,A通道存了MVP变换后的w分量的倒数,因此,复制场景深度时,直接复制场景颜色,而不需要管它的深度缓存,换言之,不需要管乱七八糟的MSAA Resolve和Store问题了。
复制时需要传入相机视锥参数并且在复制时重建场景深度。
比如原来的点坐标为 [ x,y,z,1 ],乘上MVP矩阵后得到 [ x1,y1,z1,w1 ],其中w1 = z,z1 = Az + B, 并且:
A = far / (far - near);
B = - A * near;
然后除上z1/w1就是齐次坐标下的深度值了。
另外小提示是在shader中使用关键字noperspective来避开uv的透视插值,也就是不要让它除w,这样在片元着色器中无需再乘上w来确保uv线性插值了。
最后下采样复制深度记得按照最大值原则复制。
-
接下来就是降分辨率渲染半透明。注意在Mesh Processor那里把Blend State设为RGBA,不然半透明通道不写入信息。另外UE4的SeparateAlphaBlendEnable是根据Render State在RHI那里自动判断设置的,无需考虑这个。
-
然后是合成Pass,记得换个降分辨率的渲染纹理的滤波模式,至少是双线性的滤波。
步骤4有一次全屏的混合,而且是HDR 16下的,性能消耗实际上挺高的,如果不要bloom,改到后处理的tonemap前合成,可以改成8位的RT,节省性能。