着色器扩展的令人不安的行为

时间:2017-05-23 15:25:05

标签: three.js glsl webgl shader fragment-shader

为了符合每个图形硬件配置,我试图让我的应用程序处理 MRT 渲染或单个 gl_FragColor 渲染。我通过使用 GLSL #extension#ifdef预处理程序指令,通过检查着色器中是否定义了 GL_EXT_draw_buffers ,对两种用法使用相同的着色器。当一些着色器使用此扩展而其他不使用时,我遇到了一些麻烦。实际上,即使指令被认为是假的,代码也被调用了。我决定创建一个简单的示例来检查 ThreeJS WebGL 中的这个问题。

方法:

为了可视化调试是否定义了扩展名,我使用以下 GLSL 片段着色器代码:

uniform vec3 diffuse;
uniform float opacity;
void main() {
    #ifdef GL_EXT_draw_buffers
        gl_FragColor = vec4( 0.0, 1.0, 0.0, 1.0 );
    #else
        gl_FragColor = vec4( 1.0, 0.0, 0.0, 1.0 );
    #endif
}

将着色器发送到 GPU 时,指令由 ThreeJS 添加。

调试:

以下是一些截图,详细介绍了不同的THREE.ShaderMaterial实例化顺序以及以下字幕:

  • 1.1(左上角)有extensions.drawBuffers : true,预计绿色
  • 1.2(右上角)有extensions.drawBuffers : false,预计红色
  • 2(底部)有extensions.drawBuffers : false,预计红色
  • 1.1和1.2共享相同的用户 GLSL 代码

(1)Test1(2)Test2 ...(3)Test3(4)Test4

  1. Instancing 1.1,然后是1.2,然后是2: 1.2和2是错误的
  2. Instancing 1.2,然后是1.1,然后是2: 1.1是错误的
  3. 实例2,然后是1.1,然后是1.2: 1.2是错误的
  4. 实例2,然后是1.2,然后是1.1: 1.1错误
  5. 此处的代码示例:Draw Buffer Define Strange Behavior

    检测问题:

    (1)当创建两个不同的THREE.ShaderMaterial共享相同的 GLSL 用户代码时,我启用extension.drawBuffers到第一个而不是第二个。但是,第二个进入#ifdef指令。我查看了 ThreeJS ,错误似乎来自管理新THREE.WebGLProgram的方式。

    实际上,当 ThreeJS 例程进入WEBGLPrograms.capabilities.acquireProgram时,它只会比较用户着色器代码而不是已编译的着色器代码。具有不同扩展标志的两个THREE.ShaderMaterial被认为是相同的。它只考虑已定义的第一个着色器。

    (2)此外,在使用新代码检查相同#ifdef创建新着色器时,它似乎依赖于先前的着色器扩展。我对此问题一无所知,我试图检查来自 ThreeJS 的已编译 GLSL 代码,似乎没有任何错误,这可能是本机 WebGL 问题

    我认为我需要深入研究这个问题,而且我不是母语人士。如果不完全清楚,我道歉。如果您需要,我会提供任何信息。

    提前感谢您为解决这个棘手的问题做出贡献:)

1 个答案:

答案 0 :(得分:0)

试图回答这个问题:

  • 问题(1):建议@WestLangley,您可以使用自定义定义来解决问题。您可以定义一个名为GL_EXT_draw_buffers的新变量,而不是检查DRAW_BUFFER。如果由ThreeJS管理每个可用的扩展,可能会更好。我将尝试拉取请求。

  • 问题(2):正如@gman所述,并且通过检查WebGL specifications,扩展是启用上下文而不启用着色器。因为一旦将着色器代码发送到GPU就会编译预处理器指令,所以最好在创建任何着色器程序之前调用glContext.getExtension以避免此类问题。

这两个问题彼此密切相关,但我试图将它们拆分以获得更简单的答案。