James Wilkins
James Wilkins

Reputation: 7367

gl_FragData must be constant zero

I'm having an issue trying to compile a fragment shader. I keep getting this error:

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

This is the code:

#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.);
}

The whole setup works fine if I'm setting gl_FragColor (with the 4 textures attached to the frame buffer), but trying to do the code above (indexing the buffers to output to) seems to not compile. I have seen this working fine in WebGL1 using extensions. I'm using WebGL2, so perhaps something is different in this context? (I'm trying it in the latest version of Chrome).

Upvotes: 3

Views: 2456

Answers (1)

James Wilkins
James Wilkins

Reputation: 7367

So it appears there's some changes to consider going from WebGL1 to WebGL2. Given @gman's comment I thought it best to link to his article, since I know he's really the expert here. ;)

WebGL 1 to WebGL 2 conversion: https://webgl2fundamentals.org/webgl/lessons/webgl1-to-webgl2.html

I also found it helpful to remember the version differences:

WebGL 1.0 is based on OpenGL ES 2.0 and provides an API for 3D graphics. It uses the HTML5 canvas element and is accessed using Document Object Model (DOM) interfaces.

WebGL 2.0 is based on OpenGL ES 3.0 and made guaranteed availability of many optional extensions of WebGL 1.0 and exposes new APIs.

In a nutshell (referring also to the first link on the history):

  1. My shader code was designed for examples I've seen for WebGL 1 (OpenGL ES 2) using extensions. This worked fine because OpenGL 2.0 supported multiple color values via gl_FragData.

  2. Switching to WebGL 2 (OpenGL ES 3) this is depreciated in favour of a different way. Now there are out declarations required, like out vec4 out_0; main(void) { out_0 = vec4(1.0, 0.0, 0.0, 1.0); }. But I was still having some problems. It seems I needed to specify the buffer locations. Also, I was getting this error:

    ERROR: must explicitly specify all locations when using multiple fragment outputs

    Which means that I needed to add #version 300 es to the top of my program, so the correct code for WebGL 2 looks more like this:

    #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);
    }
    

    At one point I had the wrong version, which caused this error:

    invalid version directive ERROR: 0:24: 'out' : storage qualifier supported in GLSL ES 3.00 and above only

    But I found out that the version for WebGL 2 specifically is #version 300 es (notice the es part), which worked!

    Note: The version specifier must be on the FIRST line, and, unfortunately, cannot be in a preprocessor directive (i.e. #ifdef), so I had to dynamically change the string before sending it to be compiled. If not, you'll get this:

    #version directive must occur before anything else, except for comments and white space

  3. For vertex shaders, if compiled for WebGL 2 (ES 3) note that attribute is now in instead. The version of the vertex shader must ALSO match that of the fragment being compiled, or else you'll get this:

    ERROR: Shader Linking Error: Versions of linked shaders have to match.

I hope glueing all this confusion together helps save someone else lots of time. ;)

Upvotes: 3

Related Questions