【问题标题】:Drawing VBOs in OpenGL not working在 OpenGL 中绘制 VBO 不起作用
【发布时间】:2017-10-12 03:53:46
【问题描述】:

我正在编写一个简单的类来解析 OBJ 并在此之后呈现 obj。我已经编写了一种从 RAM 中绘制顶点数组的方法,我想对其进行一些优化(我读到使用 VBO 可以获得 x4 倍的帧速率!)。

可悲的是,我失败了,我按照一堆教程无济于事。 这是解析器和在 GPU 上存储顶点和索引缓冲区的调用,我已经彻底调试了解析器本身,没关系。 vertexBuffer 和 vertexIndices 都加载得很好(我已经打印了它们,并根据 obj 文件手动检查了它们)。

Mesh::Mesh(string path) {
float* normals;
float* faces;
float* textures;
string fullpath = path + ".obj";
this->mats = loadMtl(path); //Loads a Material list, not used now drawing white
string line;
ifstream objFile(fullpath.c_str());
if (objFile.is_open()) {
    objFile.seekg(0, ios::end);
    long fileSize = long(objFile.tellg());
    objFile.seekg(0, ios::beg);

    // Init buffers and indices
    unsigned int inserted = 0;

    string currentMtl = "";

    float* vertexBuffer = new float[fileSize];
    float* textureBuffer = new float[fileSize];
    float* normalBuffer = new float[fileSize];

    unsigned int* vertexIndices = new unsigned int[fileSize];
    unsigned int* normalIndices = new unsigned int[fileSize];
    unsigned int* textureIndices = new unsigned int[fileSize];

    int connectedVert = 0;
    int textureCoords = 0;
    int normalsCount = 0;

    int vertexIndex = 0;

    string prefix = "usemtl";

    while (!objFile.eof()) {
        getline(objFile, line);
        if (line.c_str()[0] == 'v' && line.c_str()[1] == ' ') {
            line[0] = ' ';
            sscanf_s(line.c_str(), "%f %f %f ",
                &vertexBuffer[connectedVert],
                &vertexBuffer[connectedVert + 1],
                &vertexBuffer[connectedVert + 2]);
            connectedVert += 3;
        }
        else if (line.c_str()[0] == 'v' && line.c_str()[1] == 't') {
            line[0] = ' ';
            line[1] = ' ';
            sscanf_s(line.c_str(), "%f %f ",
                &textureBuffer[textureCoords],
                &textureBuffer[textureCoords + 1]);
            textureCoords += 2;
        }
        else if (line.c_str()[0] == 'v' && line.c_str()[1] == 'n') {
            line[0] = ' ';
            line[1] = ' ';
            sscanf_s(line.c_str(), "%f %f %f ",
                &normalBuffer[normalsCount],
                &normalBuffer[normalsCount + 1],
                &normalBuffer[normalsCount + 2]);
            normalsCount += 3;
        }
        else if (line.c_str()[0] == 'f') {
            line[0] = ' ';

            if (textureCoords > 0) {
                sscanf_s(line.c_str(), "%i/%i/%i %i/%i/%i %i/%i/%i",
                    &vertexIndices[vertexIndex], &textureIndices[vertexIndex], &normalIndices[vertexIndex],
                    &vertexIndices[vertexIndex + 1], &textureIndices[vertexIndex +1], &normalIndices[vertexIndex +1],
                    &vertexIndices[vertexIndex + 2], &textureIndices[vertexIndex +2], &normalIndices[vertexIndex +2]);
            }
            else {
                sscanf_s(line.c_str(), "%i//%i %i//%i %i//%i",
                    &vertexIndices[vertexIndex], &normalIndices[vertexIndex],
                    &vertexIndices[vertexIndex+1], &normalIndices[vertexIndex +1],
                    &vertexIndices[vertexIndex+2], &normalIndices[vertexIndex +2]);
            }

            for (int j = 0; j < 3; j++) {
                vertexIndices[vertexIndex+j] -= 1;
                normalIndices[vertexIndex +j] -= 1;
                textureIndices[vertexIndex +j] -= 1;
            }
            vertexIndex += 3;
        }
        else if (!strncmp(line.c_str(), prefix.c_str(), strlen(prefix.c_str()))) {
            inserted++;
            // No more vertices, normals or texture coords to load, gen arrays on GPU
            if (currentMtl == "") {
                //Copy vertices to GPU
                glGenBuffers(1, &this->verticesID);
                glBindBuffer(GL_ARRAY_BUFFER, this->verticesID);
                glBufferData(GL_ARRAY_BUFFER, sizeof(float) * connectedVert, vertexBuffer, GL_STATIC_DRAW);
                /*
                //Won't be bothered with normals or textures right now...
                //Copy normals to GPU
                glGenBuffers(1, &this->normalsID);
                glBindBuffer(GL_ARRAY_BUFFER, this->normalsID);
                glBufferData(GL_ARRAY_BUFFER, sizeof(float) * normalsCount, &normalBuffer[0], GL_STATIC_DRAW);

                //Copy UV to GPU
                if (textureCoords > 0) {
                    glGenBuffers(1, &this->textID);
                    glBindBuffer(GL_ARRAY_BUFFER, this->textID);
                    glBufferData(GL_ARRAY_BUFFER, sizeof(float) * textureCoords, &textureBuffer[0], GL_STATIC_DRAW);
                }*/
            }
            else {
                // Filled up an index array, copy it.
                this->indices.push_back(0);
                this->faces.push_back(vertexIndex);
                glGenBuffers(1, &this->indices[this->indices.size() - 1]);
                glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this->indices[this->indices.size() - 1]);
                glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned int) * vertexIndex, vertexIndices, GL_STATIC_DRAW);
            }
            currentMtl = line.substr(7, line.length());
            vertexIndex = 0;
        }
    }
    // Copy the last indices buffer.
    if (currentMtl != "" && indices.size() < inserted) {
        this->indices.push_back(0);
        this->faces.push_back(vertexIndex);
        glGenBuffers(1, &this->indices[this->indices.size() - 1]);
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this->indices[this->indices.size() - 1]);
        glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned int) * vertexIndex, vertexIndices, GL_STATIC_DRAW);
    }

    objFile.close();
    delete[] vertexBuffer;
    delete[] textureBuffer;
    delete[] normalBuffer;

    delete[] vertexIndices;
    delete[] normalIndices;
    delete[] textureIndices;
}
else {
    throw runtime_error("Unable to load obj file: " + path + ".obj");
}
}

最后,这里是draw call。我猜问题就在这里,但我不能完全解决这个问题。我使用 glIntercept 来查看是否有问题,但我没有发现任何错误。

void Mesh::draw() {
    //Binding Vertex array
    glBindBuffer(GL_ARRAY_BUFFER, this->verticesID);
    glEnableClientState(GL_VERTEX_ARRAY);
    glVertexPointer(3, GL_FLOAT, 0, (void*)0);
    for (unsigned int i = 0; i < this->indices.size(); i++) {
        glColor3f(1.0f, 1.0f, 1.0f); // Draw it in plain ol' white
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this->indices[i]);
        glDrawElements(GL_TRIANGLES,this->faces[i], GL_UNSIGNED_INT,(void*)0);
    }
    glDisableClientState(GL_VERTEX_ARRAY);
}

如果需要,这里是 Mesh 类声明:

class Mesh {
    public:
        GLuint verticesID, textID, normalsID;
        vector<GLuint> indices;
        vector<GLuint> faces;
        vector<Material> mats;
    public:
       Mesh(string path);
       void draw();
        ~Mesh();
};

将 OpenGL 主要版本设置为 2,次要版本设置为 1。正如我之前提到的,我认为 OpenGL 设置正确,因为我能够在直接模式下绘制三角形并使用 RAM 中的顶点指针。欢迎任何帮助:)

【问题讨论】:

  • minimal reproducible example 中编辑。随意使用this 作为基础。
  • @Rabbid76 上下文是设置的第一件事(使用 SDL)。否则我将无法使用绘图数组。
  • @genpfault 我试图避免 glVertexPointer 调用,因为它的效率较低。您要我将加载到另一个函数的顶点、索引分开吗?
  • @Rabbid76 我现在要去上课了,但我会编辑代码,使其独立。这是现在的来源,如果你有时间阅读它:drive.google.com/open?id=0BxpdwU_OmJtnYlRHS3l5aVZpTUE
  • 好吧,stackoverflow 不允许我编辑评论。这是现在的源代码,如果您有时间阅读它:drive.google.com/open?id=0BxpdwU_OmJtnYlRHS3l5aVZpTUE 这只是一个相机类,一个包装场景中每个 vbo 的世界类,一个网格类和一个现在不使用的材质类。 EXPERIMENTAL_MESH 是 VBO 的代码。我回来后会修复帖子!

标签: c++ opengl wavefront


【解决方案1】:

读取文件并生成对象缓冲区 (glGenBuffers) 的 calss Mesh 的构造函数。在析构函数 Mesh::~Mesh 中,对象缓冲区被销毁 (glDeleteBuffers)。

但是你 push_back Meshstd::vector。这意味着会生成一个临时的Mesh 对象,它会读取文件并在其构造函数中生成对象缓冲区。此时所有数据都有效并生成对象缓冲区(GPU)。当调用std::vector::push_back 时,会在std::vector 中生成一个新的Mesh 对象。该对象由默认的复制构造函数构造,并获取第一个Mesh 对象的所有成员的副本。完成此操作后,临时对象Mesh 立即被销毁,对象缓冲区被临时对象的析构函数Mesh::~Mesh 删除(glDeleteBuffers)。至此所有数据都消失了。

std::vector::push_back。在析构函数Mesh::~Mesh中打断点,就可以简单的跟踪过期了。

您不应该在类的构造函数和析构函数中生成和删除 GPU 对象,除非您使类不可可复制且不可可复制构造:

class Mesh
{
    Mesh(const Mesh &) = delete;
    Mesh & operator = (const Mesh &) = delete;

    ....
};

您可以出于调试原因快速修复此行为,方法是替换

test.meshes.push_back(Mesh("tri"));

test.meshes.emplace_back("tri");

(见std::vector::emplace_back


但最后你应该这样做:

vector<std::unique_ptr<Mesh>> meshes;

meshes.emplace_back(new Mesh("tri")); 

【讨论】:

  • 我知道我的 Heap-fobia 有一天会搞砸我。你救了我无数我们的。非常感谢,现在运行良好。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-10-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多