In addition, we have a predefined gl_FragColor.
Let's start with this. No, you do not have a predefined gl_FragColor . This has been removed from the core of OpenGL 3.1 and higher. If you are not using compatibility (in this case, your shaders 3.30 should say #version 330 compatibility at the top), you should never use this.
Now back to the user-defined outputs of the fragment shaders. But, firstly, a quick analogy.
Remember how vertex shaders have inputs? And these inputs are vertex attribute indices, the numbers you pass to glVertexAttribPointer and glEnableVertexAttribArray , etc.? You configure which input extracts from which attribute. In GLSL 3.30, you use this syntax:
layout(location = 2) in color;
This sets the vertex shader color input, which comes from the location of attribute 2. Until 3.30 (or without ARB_explicit_attrib_location) you will have to either set this explicitly with glBindAttrbLocation before linking or querying the program for the attribute index using glGetAttribLocation . Unless you explicitly specify an attribute location, GLSL will assign the location arbitrarily (i.e.: as per implementation).
Setting up in a shader is almost always the best option.
In any case, the outputs of the shader fragment work almost exactly the same. Fragment shaders can write in several output colors , which themselves get mapped to several buffers in the framebuffer . Therefore, you need to specify which output goes to which color of the fragment output.
This process begins with a fragment output location value. It is very similar to the vertex shader input location:
layout(location = 1) out secColor;
There are also API functions glBindFragDataLocation and glGetFragDataLocation , which are similar to glBindAttribLocation and glGetAttribLocation .
If you do not make any explicit assignments, implementations usually assign one of your output variables to 0. However, the OpenGL standard does not require this behavior, so you should not depend on it either.
Now, to be honest, your program should not have been linked when you used two outputs that did not receive different output. It probably happened that your compiler optimized the one you did not write, so he forgot about it when it came time to check the linker errors.