为什么 fwidth 表现不同?

Why fwidth behaves differently?

我正在开发一个 WebGL 项目,以在 macOS/amd GPU 上的 3D 表面上创建等值线。我的想法是根据片段着色器中的高程为像素着色。通过一些优化,我可以获得相对一致的线宽,对此我很高兴。但是,当我在 windows 上对其进行测试时,它的行为有所不同。

然后我发现这是因为 fwidth()。我使用 fwidth() 来防止片段着色器在恰好位于等值层时为整个水平面着色。请看截图:

我通过添加以下 glsl 行解决了这个问题:

    if (fwidth(vPositionZ) < 0.001) { /**then do not colour isoline on these pixels**/ };

它在 macOS 上工作得很好,因为我得到了这个: 。 但是,在 windows/nvidia GPU 上,所有等值线都消失了,因为 fwidth(vPositionZ) 始终计算为 0.0。这对我来说没有意义。

我做错了什么?有没有更好的方法来解决第一个屏幕截图中出现的问题?谢谢大家!

编辑: 在这里我附加了我的片段着色器。它被简化了,但我认为这都是相关的。我知道循环很慢,但现在我不担心它。

uniform float zmin; // min elevation
uniform vec3 lineColor;
varying float vPositionZ; // elevation value for each vertex
float interval;
vec3 originColor = finalColor.rgb; // original surface color

for ( int i = 0; i < COUNT; i ++ ) {
    float elevation  = zmin + float( i + 1 ) * interval;
    lineColor = mix( originColor, lineColor, step( 0.001, fwidth(vPositionZ)));

    if ( vPositionZ <= elevation + lineWidth && vPositionZ >= elevation - lineWidth ) {
        finalColor.rgb = lineColor;
    }
    // same thing but without condition:
    // finalColor.rgb = mix( mix( originColor, lineColor, step(elevation - lineWidth, vPositionZ) ),
    //                     originColor,
    //                     step(elevation + lineWidth, vPositionZ) );
}
gl_FragColor = finalColor;

环境:WebGL2.0,es版本300,chrome浏览器。

在循环工作之前放置 fwidth(vPosistionZ)。否则,如果在循环内,fwidth() 会将任何值计算为 0。 我怀疑这是 Nvidia GPU 的错误。