如何正确链接OpenGL着色器的打开GL法线

时间:2014-03-27 09:41:03

标签: c++ qt opengl qt5

我正在尝试在OpenGL 2.1和Qt5中渲染一个简单的地图。但我在非常基本的问题上失败了。我在这里展示的是表面法线。

我有4个由三角形几何体组成的物体。一个简单的geoetry,是一个动态分配的Vertex数组,其中一个顶点是两个QVector3D,一个在Qt中预定义的3D位置类。

struct Vertex
{
    QVector3D position;
    QVector3D normal;
};

我通过使用从该顶点到下一个或前一个顶点的两个向量的叉积来计算顶点处的法线。通过调试或将结果打印到控制台,结构的正常计算似乎很好。

QVector3D(-2, -2, -2) has normal QVector3D(0, 0, 1) 
QVector3D(2, -2, -2) has normal QVector3D(0, 0, 1) 
QVector3D(-2, 2, -2) has normal QVector3D(0, 0, 1) 
...

但是当我将数据提供给着色器时,结果是荒谬的!这是在每个位置用正常值着色的多边形图片:

unexpected rendering result

与法线贴图一样,红色= x,绿色= y,蓝色= z。黑色方块的左上角是世界的起源。正如你所看到的那样,某些点处的法线似乎只是那个点的位置,没有z值。你知道绘画代码是:

,你能否告诉我可能出错的地方?
glUseProgram(program.programId());
glEnableClientState(GL_NORMAL_ARRAY);
program.setUniformValue("modelViewProjectionMatrix", viewCamera);
program.setUniformValue("entityBaseColor", QColor(0,120,233));
program.setUniformValue("sunColor", QColor("white"));
program.setUniformValue("sunBrightness", 1.0f);
static QVector3D tmpSunDir = QVector3D(0.2,-0.2,1.0).normalized();
program.setUniformValue("sunDir",tmpSunDir);

for( size_t i = 0; i < m_numberOfBoundaries; ++i)
{
    glBindBuffer(GL_ARRAY_BUFFER, m_bufferObjects[i]);

    int vertexLocation = program.attributeLocation("vertexPosition");
    program.setAttributeArray( vertexLocation, GL_FLOAT, &(m_boundaries[i].data->position), sizeof(Vertex) );
    program.enableAttributeArray(vertexLocation);
    glVertexAttribPointer( vertexLocation, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), 0 );

    int vertexNormal = program.attributeLocation("vertexNormal");
    program.setAttributeArray( vertexNormal, GL_FLOAT, &(m_boundaries[i].data->normal), sizeof(Vertex) );
    program.enableAttributeArray(vertexNormal);
    glVertexAttribPointer( vertexNormal, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), 0 );

    glDrawArrays( GL_POLYGON, 0, m_boundaries[i].sizeOfData );
}

glDisableClientState(GL_NORMAL_ARRAY);

其中边界是多边形的几何连接组件。 programQOpenGLShaderProgramQt abstraction for shader programs。每个边界都绑定到缓冲区对象。缓冲区对象编号存储在数组m_bufferObjects中。多边形“边界”在struct数组中存储为m_boundaries。它们有两个字段:data,指向循环顶点数组起点的指针,以及sizeOfData,即多边形的点数。

1 个答案:

答案 0 :(得分:2)

直到我解决你的真正问题,这里有一些东西,可能是无关的,但也是错误的:

glEnableClientState(GL_NORMAL_ARRAY);
/*...*/
glDisableClientState(GL_NORMAL_ARRAY);

您正在使用自定义顶点属性,因此使用那些旧的固定功能管道客户端状态位置绝对没有意义。请改用glEnableVertexAttribArray(location_index)

更新

所以我终于来看看你的代码,你的问题是Qt的抽象层和原始OpenGL命令的混合使用。基本上你的问题可归结为你在调用QOpenGLShaderProgram::setAttribArray后调用glVertexAttribPointer时绑定了VBO。

一个问题是,setAttribArray在内部为你调用glVertexAttribPointer,所以你自己的调用是多余的,并且会覆盖Qt的所有内容。更严重的问题是,你确实有一个受glBindBuffer约束的VBO,所以对glVertexAttribPointer的调用实际上会将一个字节偏移量放入VBO数据而不是一个指针(事实上,VBO绑定通过一个0,在指针术语中是空指针将产生完全有效的数据偏移量)。我看到这个答案,为什么这有点误导,实际上违反了C规范:https://stackoverflow.com/a/8284829/524368

最近的OpenGL版本实际上有一个新的API,用于指定符合C语言规范的attrib数组偏移量。

使用的正确Qt方法是QOpenGLShaderProgramm::setAttribBuffer。很遗憾,您的代码未显示m_boundaries的确切定义以及您对glBufferDataglBufferSubData的调用;如果我有,我可以给你关于如何改变你的代码的说明。