双通道法线贴图

在移动端用于带宽受限的缘故,延迟管线下不能设定太多GBuffer,否则会导致手机发热。对于normal tex,是可以通过xy来算出z的

inline float3 GetNormalTSFromXY(float4 normal, float normalIntensity = 1.f)
{
    float3 o = 0.f;

    float2 normalXY = normal.rg * 2.f - 1.f;
    o.z = max(1e-16, sqrt(1.f - saturate(dot(normalXY, normalXY))));
    o.xy = normalXY * normalIntensity;

    return o;
}

这样可以省出一个通道来装填其他数据,如AO

存在的问题

  • 但双通道也存在一定的问题,因为第三个通道填充了AO数据,对于normal tex有特定的图片压缩方式,而normal.xy数据和ao本来就没什么关联,所以很可能会导致normal.xy的数据不对

  • 纹理过滤丢失高频信息

    normal tex因为存储的是一个向量,所以对normal tex进行纹理过滤,本质上是一个球面插值的过程。最终在插值两个normal向量时,当方向差距越大,会使得normal.z的数据越错误

纹理压缩与通道储存

  • 为了支持双通道normal tex,从最早的PC端DXT5开始,到现在移动端ASTC,都推出了相应的压缩算法——需要将rg数据放在ag中计算

    因此在计算normal时,需要将r通道的值赋给a通道,并使用ag通道来计算normal

GBuffer应该压缩Normal吗?

大部分厂商都没有压缩GBuffer,即使是移动端也是如此,如UE等

因为压缩Normal可能会导致normal的偏差,最终导致渲染的误差,如高光、贴画等,而且是比较明显的,为了稳定还是更建议不压缩

当然CryEngine用到了奇淫技巧MicroGBuffer来压缩Normal,也是可以的

Reference

法线贴图的压缩格式比较

为什么用2个通道pack法线不是一个好注意

Using ASTC Texture Compression for Game Assets

GBuffer的压缩及CryEngine的MicroGBuffer的实现


他们曾如此骄傲的活过,贯彻始终