Search code examples
openglglslaccess-violation

Problem in passing position from vertex shader to fragment shader


//Vertex Shader
#version 450 core
out vec3 vs_color;
layout(location=0) in vec3 position;
layout(location=1) in vec3 colors;
uniform float x_offset;
void main(void)
{   
    gl_Position = vec4(position,1.0);
    gl_Position.x += x_offset;
    //vs_color = colors;
    vs_color = position;
}

//Fragment Shader
#version 450 core
out vec4 color;
in vec3 vs_color;
void main(void)
{
    color = vec4(vs_color,1);
}

This only works if I use vs_color = colors in vertex shader, for any other value like: position(contains xyz coordinates of vertex) or vec3(0.1,0.1,0.1), it throws this exception at glDrawArrays():

Exception thrown at 0x048D1AD0 (nvoglv32.dll) in OpenGL Starting Out.exe: 
0xC0000005: Access violation reading location 0x00000000.

Why does this happen, and how can I fix this? (I want to try to set position value as color value) EDIT:
Also if I don't enable the second vertex attribute using
glEnableVertexArrayAttrib(VAO,1) //VAO is my vertex array object I am able to do what I want (pass position to fragment shader)

But if I enable it, I need to pass it to fragment shader and then output the color(if I don't do anything with it in the fragment shader it gives the same error)
Here is how the attributes are set up:

    glBufferData(GL_ARRAY_BUFFER, sizeof(verticesAndcolors), verticesAndcolors, GL_STATIC_DRAW);
    glVertexAttribPointer(
        glGetAttribLocation(rendering_program,"position"),          
        3,                                                          
        GL_FLOAT,                                                   
        GL_FALSE,                                                   
        6*sizeof(float),        
        (void*)0                        
    );
    glVertexAttribPointer(
        glGetAttribLocation(rendering_program,"colors"),    
        3,                                                  
        GL_FLOAT,
        GL_FALSE,
        6*sizeof(float),    
        (void*)(3*sizeof(float))
    );
    glEnableVertexArrayAttrib(VAO, 0);
    glEnableVertexArrayAttrib(VAO, 1);

Edit-2:
If I do:

gl_Position = vec4(colors,1.0);
vs_color = position;

it does not give the access violation and works,
I checked how I set up my vertex attributes and I am not able to get further than this.


Solution

  • The root cause of the issue lies here:

    glVertexAttribPointer(glGetAttribLocation(rendering_program,"position"), ...)
    glVertexAttribPointer(glGetAttribLocation(rendering_program,"colors"), ...);    
    ...
    glEnableVertexArrayAttrib(VAO, 0);
    glEnableVertexArrayAttrib(VAO, 1);
    

    Only active attributes will have a location, and it does not matter if you qualify an attribute with layout(location=...). If the attribute is not used in the shader, the attribute will be optimized out, and therefor will not have a location. glGetAttribLocation() returns a signed integer and uses the return value -1 to signal that there was no active attribute with that name. glVertexAttribPointer() expects an unsigned attribute location, and (GLuint)-1 will end up in a very high number which is outside of the allowed range, so this function will just produce a GL error, but not set any pointer.

    However, you use glEnableVertexArrayAttrib() with hard-coded locations 0 and 1.

    The default vertex attribute pointer for each attribute is 0, and the default cvertex array buffer binding this attribute will be sourced from is 0 too, so the pointer will be interpreted as a pointer into client-side memory.

    This means that if both position and color are active (meaning: used in a way in the code so that the shader compiler/linker can't completely rule out that it may affect the output), your code will work as expected.

    But if you only use one, you will not set the pointer for the other, but still enable that array. Which means your driver will actually access the memory at address 0:

    Exception thrown at 0x048D1AD0 (nvoglv32.dll) in OpenGL Starting Out.exe: 0xC0000005: Access violation reading location 0x00000000.

    So there are few things things here:

    • Always check the result for glGetAttribLocation(), and handle the -1 case properly.
    • Never use different means to get the attribute index passed to glVertexAttribPointer and the corresponding glEnableVertexAttrib()
    • Check for GL errors. Wherever, possible use the GL debug output feature during application development to get a nice and efficient way to be notified of all GL errors (and other issues your driver can detect). For example, my implementation (Nvidia/Linux) will report API error high [0x501]: GL_INVALID_VALUE error generated. Index out of range. when I call glVertexAttribPointer(-1,...).