0

我正在编写一个 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 值吗?有没有更“正确”的方法来处理这个问题?谢谢

4

1 回答 1

1

预乘方法背后的想法是我们假设 alpha/opacity 仅影响漫反射(即进入材料/表面内部的光),而假设镜面反射不受影响(至少对于电介质的情况) ,光只是从未着色的表面反射)。

本质上,你应该有:

return vec4(diffuseColor * alpha + specularColor, alpha);

其中 alpha 与漫反射颜色“预乘”,而镜面反射颜色保持全强度(应该如此)。

您的混合模式也需要效仿:在我的头顶一个/一个/目标颜色,因为颜色需要以加法方式渲染。

于 2021-04-11T17:00:50.740 回答