Webgl gl_FragData必须为常数零

Webgl gl_FragData必须为常数零,webgl,webgl2,Webgl,Webgl2,我在编译片段着色器时遇到问题。我不断地发现这个错误: Uncaught Error: Fragment Shader Compiler Error: ERROR: 0:21: '[' : array index for gl_FragData must be constant zero ERROR: 0:21: '[' : array index for gl_FragData must be constant zero ERROR: 0:21: '[' : array index for gl

我在编译片段着色器时遇到问题。我不断地发现这个错误:

Uncaught Error: Fragment Shader Compiler Error: ERROR: 0:21: '[' :
array index for gl_FragData must be constant zero ERROR: 0:21: '[' :
array index for gl_FragData must be constant zero ERROR: 0:21: '[' :
array index for gl_FragData must be constant zero
代码如下:

#ifdef GL_EXT_draw_buffers
#extension GL_EXT_draw_buffers : require
#endif
#ifdef GL_ES
precision highp float;
#endif
void main() {
    gl_FragData[0] = vec4(1.,2.,3.,4.);
    gl_FragData[1] = vec4(1.,2.,3.,4.);
    gl_FragData[2] = vec4(1.,2.,3.,4.);
    gl_FragData[3] = vec4(1.,2.,3.,4.);
}

如果我设置
gl\u FragColor
(将4个纹理附加到帧缓冲区),整个设置工作正常,但尝试执行上述代码(将缓冲区索引以输出到)似乎无法编译。我在使用扩展的WebGL1中看到了这一点。我使用的是WebGL2,所以在这种情况下可能有些不同?(我在最新版本的Chrome)中尝试。

所以看来从WebGL1到WebGL2会有一些变化。鉴于@gman的评论,我认为最好链接到他的文章,因为我知道他确实是这里的专家

WebGL 1到WebGL 2的转换:

我还发现记住这个版本很有帮助:

WebGL 1.0基于OpenGL ES 2.0,并提供了3D应用程序接口 绘图。它使用HTML5画布元素,并使用 文档对象模型(DOM)接口

WebGL 2.0基于OpenGL ES 3.0,保证了可用性 WebGL 1.0的许多可选扩展,并公开了新的API

简而言之(也指历史上的第一个链接):

  • 我的着色器代码是为我看到的使用扩展的WebGL 1(OpenGL ES 2)示例而设计的。这很好,因为OpenGL 2.0通过
    gl\u FragData
    支持多个颜色值

  • 切换到WebGL 2(OpenGL ES 3)这是一种不同的折旧方式。现在需要
    out
    声明,比如
    out vec4 out\u 0;main(void){out_0=vec4(1.0,0.0,0.0,1.0);}
    。但我还是有一些问题。似乎我需要指定缓冲区的位置。此外,我还遇到了以下错误:

    Uncaught Error: Fragment Shader Compiler Error: ERROR: 0:21: '[' :
    array index for gl_FragData must be constant zero ERROR: 0:21: '[' :
    array index for gl_FragData must be constant zero ERROR: 0:21: '[' :
    array index for gl_FragData must be constant zero
    
    错误:使用多个片段输出时,必须显式指定所有位置

    这意味着我需要将
    #version 300 es
    添加到程序的顶部,因此WebGL 2的正确代码更像这样:

    #version 300 es
    layout(location = 0) out vec4 out_0;
    layout(location = 1) out vec4 out_1;
    main(void) {
        out_0 = vec4(1.0, 0.0, 0.0, 1.0);
        out_1 = vec4(1.0, 0.0, 0.0, 1.0);
    }
    
    有一次我的版本错误,导致了这个错误:

    Uncaught Error: Fragment Shader Compiler Error: ERROR: 0:21: '[' :
    array index for gl_FragData must be constant zero ERROR: 0:21: '[' :
    array index for gl_FragData must be constant zero ERROR: 0:21: '[' :
    array index for gl_FragData must be constant zero
    
    无效的版本指令错误:0:24:“out”:存储限定符 仅GLSL ES 3.00及以上版本支持

    但是我发现WebGL 2的版本是
    #version 300 es
    (注意
    es
    部分),这很有效

    注意:版本说明符必须在第一行,不幸的是,它不能在预处理器指令中(即
    #ifdef
    ),因此我必须在发送字符串进行编译之前动态更改字符串。如果没有,您将得到以下结果:

    #除注释和空白外,版本指令必须出现在任何其他指令之前

  • 对于顶点着色器,如果为WebGL 2(ES 3)编译,请注意
    属性现在是
    中的
    。顶点着色器的版本也必须与正在编译的片段的版本匹配,否则您将得到以下结果:

    错误:着色器链接错误:链接着色器的版本必须匹配


  • 我希望把所有这些困惑集中在一起能帮别人节省很多时间

    如果你使用WebGL2,我认为你必须彻底改变你的语法以适应GLSL3.3标准。。。请看这里:在
    GLSL 3.30(OpenGL 3.3)
    一章,也就是说:“在OpenGL[3.3,4.4]和OpenGL ES 3.0上,指定给命名片段着色器输出,通过使用布局限定符将命名输出与编号绘制缓冲区相关联。”WebGL2不支持GLSL 3.3。它支持。如果参考GLSL 3.3规范,却发现很多东西都不起作用,因为它是错误的规范,这将是非常令人困惑的。这里没有破坏更改的历史记录。链接到的文档与WebGL或WebGL2完全无关。这都是关于OpenGL的,它不是一回事,甚至与WebGL也没有关系。WebGL和WebGL2与OpenGL ES相关。塞德尼翁没有给你指明正确的方向。他把你指错方向了。你很幸运,它帮你解决了你的问题。答案中的第一个链接是关于OpenGL而不是OpenGL ES的。OpenGL与WebGL无关。引用它只会引起混乱。您的回答表明,在您尝试各种OpenGL相关版本的地方,您也链接到了一篇OpenGL ES转换文章,但您使用的是WebGL2而不是OpenGL ES,因此您真的应该感谢您提供的详细信息。在远离它太长时间之后,我开始重新回到这一切,而这一切都是模糊的。写这些答案(我已经找不到好的答案)也能帮助我学习。如果我早点看到你的文章,我想这会节省我很多时间