c++ - 使用纹理、法线和索引列表从 VBO 绘制 OpenGL 对象的问题

标签 c++ opengl vbo indices

我希望这看起来不是太多的代码转储,但我真的不知道为什么这不起作用。我试过从 glGetError() 获取错误,它似乎总是返回 0。 我试图只包含我认为会影响问题的代码,因为其他代码在我使用它的大多数其他情况下都运行良好。

无论如何,先写代码:

这是我的主要渲染循环:

float rotate = 0.0f;
void Render(SDL_Window *window)
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glLoadIdentity();

    gluLookAt(-2,-2,-10,   0,0,0,   0,1,0);

    glRotatef(rotate, 0, 1, 0);
    // Start drawing
    glUseProgramObjectARB( *shader->GetShaderProgram() );
    texture->EnableTexture( *shader->GetShaderProgram(),"tex" );
    cube->Render();
    SDL_GL_SwapWindow(window);
    rotate = rotate+1;
    glUseProgramObjectARB(0);
}

这是我的对象渲染(立方体->渲染()):

void Object3DVBO::Render()
{

    //Bind the buffers and tell OpenGL to use the Vertex Buffer Objects (VBO's), which we already prepared earlier
    glBindBufferARB(GL_ARRAY_BUFFER_ARB, vboID); 
    glBindBufferARB(GL_ARRAY_BUFFER_ARB, texcoordsID);
    glBindBufferARB(GL_ARRAY_BUFFER_ARB, normalID);
    glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, indiceID);

    //Enable states, and render (as if using vertex arrays directly)
    glEnableClientState(GL_VERTEX_ARRAY);
    glEnableClientState(GL_TEXTURE_COORD_ARRAY);
    glEnableClientState(GL_NORMAL_ARRAY);

    glTexCoordPointer(2, GL_FLOAT, 0, 0);
    glNormalPointer(GL_FLOAT, 0, 0);
    glVertexPointer(3, GL_FLOAT, 0,  0);

    if(textureid > 0) {
        glEnable(GL_TEXTURE_2D);      // Turn on Texturing
        //glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
        glBindTexture(GL_TEXTURE_2D, textureid);
    }

    //Draw the thing!
    glDrawElements(GL_TRIANGLES, indexCount, GL_UNSIGNED_BYTE, 0);
    //restore the GL state back
    glDisableClientState(GL_NORMAL_ARRAY);
    glDisableClientState(GL_TEXTURE_COORD_ARRAY);
    glDisableClientState(GL_VERTEX_ARRAY);
    if(textureid > 0) {
        glDisable(GL_TEXTURE_2D);      // Turn off Texturing
        glBindTexture(GL_TEXTURE_2D, textureid);
    }

    glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); //Restore non VBO mode
    glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
};

这是初始化 VBO 的代码:

void Object3DVBO::SetVBO()
{
    // Vertices:
    glGenBuffersARB(1, &vboID);
    glBindBufferARB( GL_ARRAY_BUFFER_ARB, vboID);
    glBufferDataARB( GL_ARRAY_BUFFER_ARB, sizeof(GLfloat)*vertices.size(), &vertices, GL_STATIC_DRAW_ARB );

    // Vertices:
    glGenBuffersARB(1, &indiceID);
    glBindBufferARB( GL_ELEMENT_ARRAY_BUFFER_ARB, indiceID);
    glBufferDataARB( GL_ELEMENT_ARRAY_BUFFER_ARB, sizeof(GLubyte)*indices.size(), &indices, GL_STATIC_DRAW_ARB );

    // Normals:
    glGenBuffersARB(1, &normalID);
    glBindBufferARB( GL_ARRAY_BUFFER_ARB, normalID);
    glBufferDataARB( GL_ARRAY_BUFFER_ARB, sizeof(GLfloat)*normals.size(), &normals, GL_STATIC_DRAW_ARB );

    // Texture coordinates:
    glGenBuffersARB(1, &texcoordsID);
    glBindBufferARB( GL_ARRAY_BUFFER_ARB, texcoordsID);
    glBufferDataARB( GL_ARRAY_BUFFER_ARB, sizeof(GLfloat)*texCoords.size(), &texCoords, GL_STATIC_DRAW_ARB );

    vertices.clear();
    normals.clear();
    texCoords.clear();
    indices.clear();
}

最后是我在文本文件中制作的最简单的模型:

mesh:
-0.5 -0.5 0.0
0.5 -0.5 0.0
0.5 0.5 0.0
-0.5 0.5 0.0
normals:
0 0 -1
0 0 -1
0 0 -1
0 0 -1
texcoords:
0.0 0
1.0 0
1.0 1.0
0.0 1.0
indices:
0 0 0 1 1 1 2 2 2 0 0 0 2 2 2 3 3 3
end:

除此之外的是读取文本文件并将其存储到函数的 vector 中。 这是对象的头文件:

class Object3DVBO
{
public:
    Object3DVBO(const char* objectfilename, GLuint textureid);
    ~Object3DVBO();
    void Render();
private:
    GLuint  vboID, 
            texcoordsID, 
            normalID, 
            textureid,
            indiceID;
    int     vertCount,
            indexCount;
    std::vector<GLfloat> vertices;
    std::vector<GLfloat> normals;
    std::vector<GLfloat> texCoords;
    std::vector<GLubyte> indices;

    void ConvertToReadable( std::vector<GLfloat> v, std::vector<GLfloat> n, std::vector<GLfloat> tc, std::vector<GLint> i);
    void ReadObjectData( const char* objectfilename);
    void SetVBO();
};

其他部分基本上对着色器对和纹理执行相同的操作,这些似乎工作正常(着色器目前只有 120 版,因此它使用 ftransform() 等)

我遇到的问题是,当我使用这段代码和使用索引的 glDrawElements 时,我得到一个黑屏(任何地方都没有错误),如果我然后切换到 glDrawArrays 它工作(或者至少我看到一些东西。我读了很多教程、示例和其他 SO 帖子试图找出我做错了什么,但到目前为止,没有任何解决方案/教程产生任何影响。

我这样做是出于教育目的,所以我确实需要使用 glDrawElements 和索引。 任何帮助将不胜感激!

附言。如果有人想知道 SDL 版本,那就是 SDL2。

最佳答案

问题的关键在于:

//Bind the buffers and tell OpenGL to use the Vertex Buffer Objects (VBO's), which we already prepared earlier
glBindBufferARB(GL_ARRAY_BUFFER_ARB, vboID);          // 1
glBindBufferARB(GL_ARRAY_BUFFER_ARB, texcoordsID);    // 2
glBindBufferARB(GL_ARRAY_BUFFER_ARB, normalID);       // 3
glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, indiceID);

//Enable states, and render (as if using vertex arrays directly)
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);

glTexCoordPointer(2, GL_FLOAT, 0, 0);                 // 2
glNormalPointer(GL_FLOAT, 0, 0);                      // 3
glVertexPointer(3, GL_FLOAT, 0,  0);                  // 1

标记为 1、2 和 3 的行需要成对出现。也就是说,由于您一次只能绑定(bind)一个 VBO,并且它为调用 glTexCoordPointer (...) 提供上下文,因此您需要在适当的时候设置指针VBO 已绑定(bind)。

你可以这样修复它:

//Bind the buffers and tell OpenGL to use the Vertex Buffer Objects (VBO's), which we already prepared earlier
glBindBufferARB(GL_ARRAY_BUFFER_ARB, vboID);          // 1
glVertexPointer(3, GL_FLOAT, 0,  0);                  // 1

glBindBufferARB(GL_ARRAY_BUFFER_ARB, texcoordsID);    // 2
glTexCoordPointer(2, GL_FLOAT, 0, 0);                 // 2

glBindBufferARB(GL_ARRAY_BUFFER_ARB, normalID);       // 3
glNormalPointer(GL_FLOAT, 0, 0);                      // 3


glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, indiceID);

//Enable states, and render (as if using vertex arrays directly)
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);

您还有一个问题,与其说是错误,不如说是性能问题。 GL_UNSIGNED_BYTE 不是硬件支持的顶点索引类型。驱动程序必须将您的索引数组转换为 16 位类型以便硬件使用它,因此当您要将它们存储在 VBO 中时使用 8 位索引没有实际好处。如果您尝试这样做,大多数启用了调试输出的 OpenGL 分析器和驱动程序都会生成性能警告。

关于c++ - 使用纹理、法线和索引列表从 VBO 绘制 OpenGL 对象的问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19801859/

相关文章:

c++ - OpenGL : multiple VAOs for one VBO

c++ - Visual Studio 2013 模板别名

c - 使用 glfw 和 vsync 时桌面感觉迟钝

java - OpenGL ATI 与 NVIDIA GLSL 问题

opengl - 绘制不同尺寸的FBO

android - 在 Android 上使用 OpenGL ES 显示透明纹理时出现问题

c++ - 提高克隆模式的安全性

c++ - Qt 4.8.7 内存问题

c++ - OS X 上 Carbon OpenGL 应用程序的字体

c++ - VBO 和 glTranslatef 是否需要将 GLSL 着色器中的 gl_vertex 与某些东西相乘?