Problem in passing position from vertex shader to fragment shader

0
//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.

opengl
glsl
access-violation
asked on Stack Overflow Jul 18, 2020 by Muneeb Ahmad • edited Jul 19, 2020 by Muneeb Ahmad

2 Answers

0

I finally was able to fix the issue:
I was calling glUseProgram(programObj) in my drawing loop, moving it out of it fixed the problem

I am not sure why that caused the issue to occur but my guess is the openGL did something when the vertex attribute was not being used and then that change caused the access violation in the next iteration.

Feel free to tell me if you know the reason

answered on Stack Overflow Jul 19, 2020 by Muneeb Ahmad
0

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,...).
answered on Stack Overflow Jul 19, 2020 by derhass • edited Jul 19, 2020 by derhass

User contributions licensed under CC BY-SA 3.0