将位置从顶点着色器传递到片段着色器的问题

时间:2020-07-18 05:45:34

标签: opengl glsl access-violation

//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);
}

这仅在我在顶点着色器中使用vs_color = colors时有效,对于任何其他值,例如:position(包含顶点的xyz坐标)或vec3(0.1,0.1,0.1),它将在glDrawArrays()处引发此异常: / p>

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

为什么会发生这种情况,我该如何解决? (我想尝试将位置值设置为颜色值) 编辑:
另外,如果我没有使用
启用第二个顶点属性 glEnableVertexArrayAttrib(VAO,1) //VAO is my vertex array object 我能够做我想做的(将位置传递到片段着色器)

但是如果启用它,我需要将其传递给片段着色器,然后输出颜色(如果我在片段着色器中不对其进行任何操作,则会产生相同的错误)
属性的设置方法如下:

    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);

编辑2:
如果我这样做:

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

它不会产生访问冲突并且可以正常工作,
我检查了如何设置我的顶点属性,但除此之外我做不到。

2 个答案:

答案 0 :(得分:1)

此问题的根本原因在于:

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

只有活动属性将具有位置,并且您是否可以使用layout(location=...)限定属性并不重要。如果在着色器中未使用该属性,则该属性将被优化,因此将没有位置。 glGetAttribLocation()返回一个 signed 整数,并使用返回值-1表示该名称不存在活动属性。 glVertexAttribPointer()期望一个 unsigned 属性位置,并且(GLuint)-1最终将以一个很大的数字出现,该数字超出了允许的范围,因此此函数只会产生GL错误,但未设置任何指针。

但是,您将glEnableVertexArrayAttrib()硬编码位置01一起使用。

每个属性的默认顶点属性指针为0,绑定该属性的默认cvertex数组缓冲区也将为0,因此该指针将被解释为指向客户端的指针侧存储器。

这意味着如果positioncolor都处于活动状态(意味着:在代码中以某种方式使用,以便着色器编译器/链接器无法完全排除它可能影响输出的可能性),您的代码将按预期运行。

但是,如果仅使用一个,则不会为另一个设置指针,但仍会启用该数组。这意味着您的驱动程序实际上将访问地址为0的内存:

在OpenGL Starting Out.exe中抛出0x048D1AD0(nvoglv32.dll)的异常: 0xC0000005:访问冲突读取位置0x00000000。

所以这里有几件事:

  • 始终检查glGetAttribLocation()的结果,并正确处理-1情况。
  • 从不使用其他方式来获取传递给glVertexAttribPointer和相应的glEnableVertexAttrib()的属性索引
  • 检查GL错误。无论何时何地,都可以在应用程序开发期间使用GL debug output功能,以一种不错的,高效的方式将所有GL错误(以及驱动程序可以检测到的其他问题)通知给您。例如,当我致电API error high [0x501]: GL_INVALID_VALUE error generated. Index out of range.时,我的实现(Nvidia / Linux)将报告glVertexAttribPointer(-1,...)

答案 1 :(得分:0)

我终于能够解决此问题:
我在绘图循环中调用glUseProgram(programObj),将其移出解决了问题

我不确定为什么会导致问题发生,但是我的猜测是openGL在未使用vertex属性时做了一些操作,然后该更改在下一次迭代中导致了访问冲突。

随时告诉我您是否知道原因