glVertexAttribPointer 问题(OpenGL 3.x 前向兼容上下文)

Posted

技术标签:

【中文标题】glVertexAttribPointer 问题(OpenGL 3.x 前向兼容上下文)【英文标题】:glVertexAttribPointer trouble (OpenGL 3.x forward-compatible context) 【发布时间】:2012-03-02 19:44:32 【问题描述】:

按照现代标准,渲染多边形网格的首选方式似乎涉及使用Vertex Buffer Objects 和索引缓冲区(最终通过调用glDrawElements()),这正是我试图包装我的围绕这些概念。另外,我坚持使用glVertexAttribPointer() 而不是deprecated glVertexPointer()glNormalPointer() 等。

我正在使用自定义的二进制 3d 文件格式(Wavefront .OBJ 衍生文件),其内容可以或多或少直接memcpy()'d 到顶点数组。以下是我声明 vertex 结构的方式:

   typedef struct vertex_ 

            float vx,vy,vz;
            float nx,ny,nz;
            float padding[2];  // align to 32 bytes 
   
    vertex; 

loadBObj() 函数返回一个索引缓冲区(实现为unsigned short ints 的简单数组),并用相关的顶点/法线数据填充顶点数组(模型使用所有已导出为具有 per-vertex-normals 以获得更平滑的着色结果)。

indices = loadBObj("pharaoh.bobj", false, &VBOid);

加载代码本身经过验证可以正常工作。

现在,loadBObj() 中正在做的事情是正在创建一个新的 VBO,如下所示:

    glGenBuffers(1, VBOid);
    glBindBuffer(GL_ARRAY_BUFFER, *VBOid);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertex)*vcount, &vertarray[0].vx, GL_STATIC_DRAW);

loadBObj() 被调用后,一个索引缓冲区对象(可能不应该这样称呼)被创建如下:

    glGenBuffers(1, &IBOid);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IBOid);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned short int)*qfcount*4, indices, GL_STATIC_DRAW);

好的。在实际渲染网格时,我使用了以下代码:

    #define BUFFER_OFFSET(i) ((char *)NULL + (i))
    ...
    glBindBuffer(GL_ARRAY_BUFFER, VBOid);
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(vertex), BUFFER_OFFSET(0));
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(vertex), BUFFER_OFFSET(3*sizeof(float)));

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IBOid);
    glDrawElements(GL_QUADS, qfcount*4, GL_UNSIGNED_SHORT, BUFFER_OFFSET(0));

这会产生绝对正确的几何图形,但阴影不太正确:

这是模型的图像,以立即模式呈现:

img http://i44.tinypic.com/i36zcg.png

这是由上述程序生成的:

我的 VBO 处理过程中发生了什么有趣的事情吗?

【问题讨论】:

在 gDEBugger 或类似的东西下运行它,并验证 VBO 中的所有数据是否正确。如果是,是时候检查着色器了。此外,GL_QUADS 已被弃用并从核心配置文件中消失。 @CatPlusPlus:好的,我现在已经彻底检查了 VBO 的内容(gDEBugger = fantabulous 实用程序顺便说一句,干杯),看起来没问题。现在,“检查着色器”到底是什么意思? 【参考方案1】:

您的法线似乎没有正确通过

这可能是由于您应该拥有的事实造成的

glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);

由于您同时指定了 0 和 1 指针。 (目前你只有第一行)

【讨论】:

- 添加行 glEnableVertexAttribArray(1); 似乎没有任何效果。还是)感谢你的建议;无论如何,我都会把它留在那里。【参考方案2】:

你在使用着色器吗?您只应该将 glVertexAttribPointer 与着色器一起使用,并且您必须明确告诉它哪个属性数组与哪个输入变量一起使用。 (glGetAttribLocation/glBindAttribLocation)。

如果您使用的是固定管道,则必须坚持使用 glVertexPointer/glNormalPointer。

【讨论】:

经过测试:glVertexPointer / glNormalPointer 等效项产生类似的结果。事实上,即使我用零/随机数据初始化了法向量分量,结果也不会改变。我一直在提到OpenGL wiki VBO examples page,它确实提到了设置着色器:“另外,我们没有使用着色器,但您必须设置着色器并将顶点属性设置为着色器才能正常工作。”对于类似于即时模式图片的着色,我会使用什么样的着色器程序? @elmov 它比我在这里介绍的要复杂得多,但我相信你可以在网上找到很多示例,搜索如何编写着色器以及如何实现光照和着色。跨度> +1 当他不使用着色器时,这正是他的问题。它适用于位置属性的原因是(至少在 GL 3 之前或在兼容模式下)通用顶点属性 0 是内置 glVertex 属性的别名。【参考方案3】:

我认为这里可能发生的情况是三角形*颠倒了。您可以通过将每个第一个顶点与每个第三个顶点交换来进行测试。

由于您使用的是四边形,这显然不是错误。但是您可以尝试每秒与第三个顶点交换一次。

【讨论】:

以上是关于glVertexAttribPointer 问题(OpenGL 3.x 前向兼容上下文)的主要内容,如果未能解决你的问题,请参考以下文章

Opengl顶点着色器为每个顶点设置布尔值(glVertexAttribPointer)

缓冲区和 glVertexAttribPointer 之间的关系

带有 glvertexattribpointer 问题的 glsl 布局

glVertexAttribPointer 出现 JOGL 错误

OpenGL glVertexAttribPointer 正常

glVertexAttribPointer 返回 GL_INVALID_OPERATION