opengl着色器程序中的重复顶点

Posted

技术标签:

【中文标题】opengl着色器程序中的重复顶点【英文标题】:Duplicated vertices in opengl shader programs 【发布时间】:2014-02-11 23:07:30 【问题描述】:

我正在使用两个渲染程序将两个不同的对象渲染到屏幕上。每个程序都有自己的顶点和与之关联的片段着色器。

在以下代码中,我创建了第一个渲染程序并使用 GL_ARRAY_BUFFER 将顶点加载到着色器中:

boardRenderingProgram = compileBoardShaders();

vector<GLfloat> boardVertices = board.getBorderVertices();
GLfloat* borderVertices = &boardVertices[0];

GLuint numberOfVerts = boardVertices.size();

GLuint anotherVBO;
GLuint anotherBuffer;

glGenVertexArrays(1, &anotherVBO);
glBindVertexArray(anotherVBO); 
glGenBuffers(1, &anotherBuffer);
glBindBuffer(GL_ARRAY_BUFFER, anotherBuffer);

glBufferData(GL_ARRAY_BUFFER, numberOfVerts*3*sizeof(GLfloat), NULL, GL_STATIC_DRAW);
glBufferSubData(GL_ARRAY_BUFFER, 0, numberOfVerts*3*sizeof(GLfloat), borderVertices);

vert = glGetAttribLocation(boardRenderingProgram, "vBoardPosition");
glVertexAttribPointer(vert, 3, GL_FLOAT, GL_FALSE, 0, 0);   

glEnableVertexAttribArray(vert);

第一个程序的顶点着色器:

#version 330 core                           
layout(location = 0) in vec4 vBoardPosition;    

void main()                                
    gl_Position = vBoardPosition;               
                                           

然后我对第二个渲染程序做同样的事情,我也在第二个程序中设置了一个旋转和平移矩阵:

renderingProgram = compileShaders();

moveMatrix = glm::make_mat4(moveArray);

currentBlockVertices = generator.getRandomBlock(blockNumber).getVertices();

numberOfVertices = 8;

GLfloat* vertices = &currentBlockVertices[0];

glGenVertexArrays(1, &vertexArrayObject);
glBindVertexArray(vertexArrayObject); 
glGenBuffers(1, &buffer);
glBindBuffer(GL_ARRAY_BUFFER, buffer);

glBufferData(GL_ARRAY_BUFFER, numberOfVertices*7*sizeof(GLfloat), NULL, GL_STATIC_DRAW);

glBufferSubData(GL_ARRAY_BUFFER, 0, numberOfVertices*3*sizeof(GLfloat), vertices);


vpos = glGetAttribLocation(renderingProgram, "vPosition"); 
glVertexAttribPointer(vpos, 3, GL_FLOAT, GL_FALSE, 0, 0);   

mpos = glGetUniformLocation(renderingProgram, "mMove");
rpos = glGetUniformLocation(renderingProgram, "mRotate");

glProgramUniformMatrix4fv(renderingProgram, mpos, 1, GL_FALSE, glm::value_ptr(moveMatrix));
glProgramUniformMatrix4fv(renderingProgram, rpos, 1, GL_FALSE, glm::value_ptr(rotateMatrix));

glEnableVertexAttribArray(vpos);

第二个程序的顶点着色器:

#version 330 core                           
layout(location = 0) in vec4 vPosition; 
layout(location = 1) uniform mat4 mMove;    
layout(location = 2) uniform mat4 mRotate;  

void main()                                
    gl_Position = mMove * mRotate * vPosition;      
                                           

创建这些程序后,我在渲染函数中使用以下代码将它们绘制到屏幕上:

glUseProgram(boardRenderingProgram);
glDrawArrays(GL_POINTS, 0, 8);

glUseProgram(renderingProgram);
glDrawArrays(GL_LINE_LOOP, 0, 8);
SwapBuffers(hDC_);

然而,尽管指定了不同的顶点加载到每个渲染程序中,但两个渲染程序都将相同的顶点绘制到屏幕上。似乎第二个创建的渲染程序决定了使用哪些顶点。

我尝试在设置顶点和矩阵属性之前和之后添加额外的 glUseProgram() 调用,但这似乎没有帮助。

当我将不同的顶点加载到每个程序中时,为什么两个程序会绘制相同的顶点?

【问题讨论】:

compileBoardShaders()compileShaders() 在哪里? @genpfault 我已经在代码的其他地方声明了 compileShaders() 和 compileBoardShaders() 。我在着色器编译和程序链接的两种方法中都进行了调试,但都没有失败。我假设因为我看到两个程序都在屏幕上绘制了顶点,所以这些方法没有错。如果有帮助,我可以发布两者的代码。 【参考方案1】:
#version 330 core 
...
layout(location = 1) uniform mat4 mMove;    
layout(location = 2) uniform mat4 mRotate;
^^^^^^^^^^^^^^^^^^^^  

Explicit uniform locations 自 OpenGL 4.3 起才成为核心。在之前的版本中,您需要在 using them 之前检查 GL_ARB_explicit_uniform_location

我怀疑您的第二个着色器编译失败。确保在调用glUseProgram() 之前通过GL_COMPILE_STATUS/GL_LINK_STATUS 检查着色器编译和程序链接是否成功。

【讨论】:

我在 compileShaders() 和 compileBoardShaders() 中添加了 GL_COMPILE_STATUS 和 GL_LINK_STATUS 检查,看起来好像两个顶点着色器都在成功编译和链接。【参考方案2】:

好的,经过进一步调查,我发现在加载第二个着色器时清除顶点的行是 glBindVertexArray()。

听从这里的建议: https://gamedev.stackexchange.com/questions/49749/why-doesnt-glbindvertexarray-work-in-this-case 我更改了渲染代码,在每次绘制调用之前添加了 glBindVertexArray():

glBindVertexArray(boardVertexArrayObject);
glUseProgram(boardRenderingProgram);
glDrawArrays(GL_LINES, 0, 6);

glBindVertexArray(pieceVertexArrayObject);
glUseProgram(renderingProgram);
glDrawArrays(GL_LINE_LOOP, 0, 8);
SwapBuffers(hDC_); 

显然 glBindVertexArray() 应该在修改 VBO 之前和绘制之前调用。代码现在可以正常工作了!

【讨论】:

glBindVertexArray() 指定您正在使用的一个顶点缓冲区。不管那可能是什么操作。它是一个状态机,所以除非你告诉它,否则什么都不会改变。

以上是关于opengl着色器程序中的重复顶点的主要内容,如果未能解决你的问题,请参考以下文章

着色器存储缓冲区中的 OpenGL 顶点

OpenGL相机移动程序顶点着色器问题

✠OpenGL-13-几何着色器

OpenGL着色器没有将变量从顶点传递到片段着色器

SpriteKit 中的顶点着色器

为啥在使用 OpenGL 编译顶点着色器时会出现着色器编译器错误 #143、#160 和 #216?