Search code examples
openglattributesglslvariable-assignmentvarying

Strange and annoying GLSL error


My vertex shader looks as follows:

#version 120
uniform float m_thresh;

varying vec2 texCoord;

void main(void)
{   
    gl_Position = ftransform();
    texCoord = gl_TexCoord[0].xy;
}

and my fragment shader:

#version 120
uniform float m_thresh;
uniform sampler2D grabTexture;

varying vec2 texCoord;

void main(void)
{
    vec4    grab = vec4(texture2D(grabTexture, texCoord.xy));
    vec3    colour = vec3(grab.xyz * m_thresh);
    gl_FragColor = vec4( colour, 0.5 );
}

basically i am getting the error message "Error in shader -842150451 - 0<9> : error C7565: assignment to varying 'texCoord'"

But I have another shader which does the exact same thing and I get no error when I compile that and it works!!!

Any ideas what could be happening?


Solution

  • For starters, there is no sensible reason to construct a vec4 from texture2D (...). Texture functions in GLSL always return a vec4. Likewise, grab.xyz * m_thresh is always a vec3, because a scalar multiplied by a vector does not change the dimensions of the vector.

    Now, here is where things get interesting... the gl_TexCoord [n] GLSL built-in you are using is actually a pre-declared varying. You should not be reading from this in a vertex shader, because it defines a vertex shader output / fragment shader input.

    The appropriate vertex shader built-in variable in GLSL 1.2 for getting the texture coordinates for texture unit N is actually gl_MultiTexCoord<N>


    Thus, your vertex and fragment shaders should look like this:

    Vertex Shader:

    #version 120
    
    //varying vec2 texCoord; // You actually do not need this
    
    void main(void)
    {   
      gl_Position = ftransform();
    
      //texCoord  = gl_MultiTexCoord0.st; // Same as comment above
      gl_TexCoord [0] = gl_MultiTexCoord0;
    }
    

    Fragment Shader:

    #version 120
    
    uniform float m_thresh;
    uniform sampler2D grabTexture;
    
    //varying vec2 texCoord;
    
    void main(void)
    {
      //vec4  grab   = texture2D (grabTexture, texCoord.st);
    
      vec4  grab   = texture2D (grabTexture, gl_TexCoord [0].st);
      vec3  colour = grab.xyz * m_thresh;
      gl_FragColor = vec4( colour, 0.5 );
    }
    

    Remember how I said gl_TexCoord [n] is a built-in varying? You can read/write to this instead of creating your own custom varying vec2 texCoord; in GLSL 1.2. I commented out the lines that used a custom varying to show you what I meant.


    The OpenGL® Shading Language (1.2) - 7.6 Varying Variables - pp. 53

    The following built-in varying variables are available to write to in a vertex shader. A particular one should be written to if any functionality in a corresponding fragment shader or fixed pipeline uses it or state derived from it.

    [...]

    varying vec4 gl_TexCoord[]; // at most will be gl_MaxTextureCoords

    The OpenGL® Shading Language (1.2) - 7.3 Vertex Shader Built-In Attributes - pp. 49

    The following attribute names are built into the OpenGL vertex language and can be used from within a vertex shader to access the current values of attributes declared by OpenGL.

    [...]

    attribute vec4 gl_MultiTexCoord0;

    The bottom line is that gl_MultiTexCoord<N> defines vertex attributes (vertex shader input), gl_TexCoord [n] defines a varying (vertex shader output, fragment shader input). It is also worth mentioning that these are not available in newer (core) versions of GLSL.