我正在编写一个 PBR 着色器,并且正在尝试确定生成图像输出的 alpha 值的正确方法。目标是得到一个“预乘 alpha”的最终图像,以便稍后可以与另一个 Over 合成操作一起使用(例如,在另一个背景图像上合成它)。这一切都很好,除了透明表面上的镜面高光情况。
阅读本文: https ://google.github.io/filament/Filament.md.html#lighting/transparencyandtranslucencylighting
尤其是:
观察一个窗口,您会看到漫反射是透明的。另一方面,镜面反射率越亮,窗口看起来越不透明。这种效果可以在图 63 中看到:场景被适当地反射到玻璃表面,但太阳的镜面高光足够亮,看起来不透明。
它们还包括代码片段:
// baseColor has already been premultiplied
vec4 shadeSurface(vec4 baseColor) {
float alpha = baseColor.a;
vec3 diffuseColor = evaluateDiffuseLighting();
vec3 specularColor = evaluateSpecularLighting();
return vec4(diffuseColor + specularColor, alpha);
}
渲染玻璃时,金属级别将为 0,因此它根本不会从 baseColor 中提取,而只是使用镜面反射级别。这一切都是有道理的,这意味着即使在透明玻璃上仍然会出现镜面高光,根据上面的引用。我不想最后只乘以 alpha,因为我的 baseColor 纹理已经是预乘的 alpha 图像,例如包含贴花的东西。例如,假设我正在画一块玻璃,上面贴着字母“A”。
我的问题是:对于在玻璃的透明部分具有镜面高光的像素,alpha 值应该是多少才能在下游合成?根据上面的代码,alpha 将为 0,这将导致 Over 操作稍后表现不佳。我这样说是因为预乘 alpha 的一个属性是 max(R,G,B) <= A,但是这个镜面高光将具有 max(R,G,B) > A。这将导致过度操作高光和正在合成的背景之间的添加剂,吹出最终图像。我应该将 alpha 设置为 max(specular, alpha),以便为这些像素提供更有用的 alpha 值吗?有没有更“正确”的方法来处理这个问题?谢谢