用unity3d做游戏也有一段时间了,这周有一个渲染的需求,用到的技术不算很深,但确实也比较繁琐,值得记录一下。
需求大概是这样的,有四层图,我们称为A,B,C,D四层。他们的Blend顺序是A->B->C->D,其中C对D的Blend算法使用的是PS中的叠加算法,B->C,D是替换,A->B,C,D也是PS的叠加。这个问题的难点在于两部分:第一,有部分层的Blend算法是使用的PS的叠加,而叠加公式为(B < 128) ? (2 * A * B / 255):(255 - 2 * (255 - A) * (255 - B) / 255),由于存在条件判断,那么这个Blend必然不能使用普通的两个Pass之间Blend算式。第二,如果使用多个pass相互叠加,那屏幕的FillRate也会有较大开销。由于要使用叠加算法,那么需要使用叠加Blend的层必须在一个pass内,因此唯一的出路应该是使用多重纹理采样,在pixel shader中实现叠加公式。那么剩下的问题就是如何来划分多重纹理采样的pass了。
通过分析,由于B->C,D是替换关系,那么B可以作为一个独立的pass存在。那么底层就划分为B和D,A和C最为叠加层。我们先绘制D,由于D受到A和C的叠加影响,那么这个Pass就有3层纹理,分别是A,C,D。接着绘制B,而B只收到A的叠加影响。B和D之间的Pass使用基本的alpha blend混合。(由于是2D,3D可以考虑直接replace)。
剩下还有一些问题需要解决,比如说<1>A和C作为叠加层只会影响屏幕的部分像素,<2>叠加公式有条件判断,而shader只支持sm2.0。虽然sm2.0支持静态分支,但之前有一个问题就是因为使用了条件分支,造成了部分andriod手机显示异常,所以尽量还是不要使用条件分支。第一个问题只是在ps阶段使用clip空间的坐标判断即可,第二个则是自己手动计算两条分支的结果,最后通过判断条件,选取某一个分支作为最终的结果。