c++ - 如何正确链接 OpenGL 着色器的开放式 GL 法线

标签 c++ qt opengl qt5

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

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

struct Vertex
{
    QVector3D position;
    QVector3D normal;
};

我通过使用从该顶点到下一个或上一个顶点的两个 vector 的叉积来计算该顶点的法线。通过调试或将结果打印到控制台,结构的正常计算似乎没问题。

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。黑色方 block 的左上角是世界的原点。如您所见,法线在某个点似乎只是该点的位置,没有 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);

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

最佳答案

在我解决你的真正问题之前,这里有一些可能无关但同样错误的东西:

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

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

更新

所以我终于转身仔细查看了您的代码,您的问题是混合了 Qt 的抽象层和原始 OpenGL 命令的使用。本质上,您的问题归结为您在调用 QOpenGLShaderProgram::setAttribArray 之后调用 glVertexAttribPointer 时绑定(bind)了 VBO。

一个问题是,setAttribArray 会在内部为您调用 glVertexAttribPointer,因此您自己对它的调用是多余的,并且会覆盖 Qt 所做的任何事情。更严重的问题是,您确实有一个由 glBindBuffer 绑定(bind)的 VBO,因此对 glVertexAttribPointer 的调用实际上是将字节偏移量放入 VBO 数据而不是指针(实际上VBO 绑定(bind)传递 0,在指针术语中是空指针,将产生完全有效的数据偏移量)。请参阅我的这个答案,为什么这有点误导并且实际上违反了 C 规范:https://stackoverflow.com/a/8284829/524368

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

要使用的正确 Qt 方法是 QOpenGLShaderProgramm::setAttribBuffer。不幸的是,您的代码没有显示 m_boundaries 的确切定义以及您对 glBufferDataglBufferSubData 的调用;如果我有,我可以指导您如何更改您的代码。

关于c++ - 如何正确链接 OpenGL 着色器的开放式 GL 法线,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22683567/

相关文章:

c++ - Qt 获取由类成员发出的信号通知

qt - 是否可以将 QWidget 作为 QObject 的子级?

c++ - 如何使用OpenGL渲染到一个QMainWindow的两个QWidget?

C++ OpenGL 在 GL_QUAD、glVertex2f 中加载图像

c++ - OpenGL:一次只能有一个 FBO 工作

c++ - 我如何使用 switch 而不是 if else 来做到这一点?

macos - Qt 和 OpenGL OS X : GLSL shader version only 120 on Mountain Lion

c++ - Google 测试中的 EXPECT_NO_DEATH()

c++ - 如何区分外接显示器和笔记本屏幕本身?

c++ - 从(基对象的基引用)到(派生类引用)的静态转换