Search code examples
glslshadervertex-shader

The difference between a color attribute and using gl_Color


Most GLSL shaders are using a attribute for the color in the vertex shader, which will be forwarded as varying to the fragment shader. Like this:

attribute vec4 position;
attribute vec4 color;
uniform mat4 mvp;
varying vec4 destinationColor;

void main(){
  destinationColor = color;
  gl_Position = mvp * position;
};

Setting the color can be done with glVertexAtribPointer() to pass one color per vertex or with glVertexAttrib4fv() to pass a global color for all vertexes. I try to understand the difference to the predefined variable gl_Color in the vertex shader (if there is any difference at all). i.e.

attribute vec4 position;
uniform mat4 mvp;
varying vec4 destinationColor;

void main(){
  destinationColor = gl_Color;
  gl_Position = mvp * position;
};

and using glColorPointer() to pass one color per vertex or glColor4fv() to use a global color for all vertexes. To me the second shader looks better (= more efficient?), because it uses less attributes. But all tutorials & online resources are using the first approach - so I wonder if I missed anything or if there is no difference at all. What is better practice when writing GLSL shaders?


Solution

  • To me the second shader looks better (= more efficient?), because it uses less attributes.

    It does not use fewer attributes. It just uses fewer explicit attribute declarations. All of the work needed to get that color value to OpenGL is still there. It's still being done. The hardware is still fetching data from a buffer object or getting it from the glColor context value or whatever.

    You just don't see it in your shader's text. But just because you don't see it doesn't mean that it happens for free.

    User-defined attributes are preferred for the following reasons:

    • User-defined attributes make it clear how many resources your shaders are using. If you want to know how many attributes you need to provide to a shader, just look at the global declarations. But with predefined attributes, you can't do this; you have to scan through the entire vertex shader for any gl_* names that name a predefined attribute.
    • User-defined attributes can do more things. If you want to pass integer values as integers to the vertex shader, you must use a user-defined attribute. If you need to pass a double-precision float to the vertex shader, again, a predefined attribute cannot help you.
    • Predefined attributes were removed from core OpenGL contexts. OSX, for example, does not allow the compatibility profile. You can still use OpenGL 2.1, but if you want to use any OpenGL version 3.2 or greater on OSX, you cannot use removed functionality. And the built-in vertex attributes were removed in OpenGL 3.1.
    • Predefined attributes were never a part of OpenGL ES 2.0+. So if you want to write shaders that can work in OpenGL ES, you again cannot use them.

    So basically, there's no reason to use them these days.