C++ 用于渲染不同对象的VAOs和VBOs
我编写了这个“Model”类来加载.obj文件,并在VBO中为它们分配数据。 其代码如下:(注意它如何不使用VAOs) 但事实证明OpenGL只能画两头奶牛或两个立方体。(取决于我最后在init()中加载的模型) 顺便说一句,我很确定在第一幅图像中,opengl确实尝试绘制两头奶牛,但是调用了glDrawArrays()函数,其中包含了立方体所需的顶点数量C++ 用于渲染不同对象的VAOs和VBOs,c++,c,opengl,vbo,vao,C++,C,Opengl,Vbo,Vao,我编写了这个“Model”类来加载.obj文件,并在VBO中为它们分配数据。 其代码如下:(注意它如何不使用VAOs) 但事实证明OpenGL只能画两头奶牛或两个立方体。(取决于我最后在init()中加载的模型) 顺便说一句,我很确定在第一幅图像中,opengl确实尝试绘制两头奶牛,但是调用了glDrawArrays()函数,其中包含了立方体所需的顶点数量 那么我错过了什么?每个缓冲区对象或类似对象是否需要不同的VAO?绑定缓冲区后,需要将顶点属性代码(设置和启用)移动到绘图函数。这些调用将作
那么我错过了什么?每个缓冲区对象或类似对象是否需要不同的VAO?绑定缓冲区后,需要将顶点属性代码(设置和启用)移动到绘图函数。这些调用将作用于当前绑定的缓冲区 如果对不同的模型使用不同的vao,属性数据将存储在vao中,并且每次绘制新对象时无需重新绑定属性(只需更改vao) 这里要归咎于“当前”状态,尤其是与
glvertexattributepointer
相关的状态。
对glvertexattributepointer(…)
的所有调用都建立了相对于当前绑定到GL\u数组\u缓冲区的缓冲区对象的内存指针。我们倾向于将绑定到该位置的缓冲区对象称为顶点缓冲区对象,但实际上单个缓冲区对象可用于多种目的,并且它们实际上没有类型
在现代OpenGL中可以这样想:
这个伪代码的目的是向您展示OpenGL中只有一个命令,您绑定到GL\u ARRAY\u BUFFER
的内容在整个代码中都很重要:glvertexattributepointer(…)
所有其他命令,如glDrawArrays(…)
实际使用存储在“current\u vao
”中的状态,如glvertexattributepointer(…)
的模拟实现所示
最后,您不使用VAOs实际上是一个问题。您正在覆盖软件当前与上次加载的模型一起使用的仅VAO的属性指针
检查伪代码中的代码>代码> GLVETEXRAYAbjult<代码>存储,然后考虑重构您自己的代码以充分利用这一点。否则,每次调用
void Model::Draw()
时,必须至少调用一次glvertexattributepointer
关于一个不太有趣的解释,请看这个。我写了一些伪代码来说明为什么//接下来的两行对两个对象都有效?
是一个无效的假设,但是如果你想了解它的要点,请看warsac的回答:p一旦你有了正确的想法,您应该认识到,void Model::Draw()
中的第一行和最后一行代码实际上什么都不做。
class Model {...}
void Model::LoadOBJ(const char *file)
{
//load vertices, normals, UVs, and put them all in _vec, which is a private data member of std::vector<glm::vec3>
...
//if an .obj file is loaded for the first time, generate a buffer object and bind it
if(glIsBuffer(_vbo) == GL_FALSE)
{
glGenBuffers(1, &_vbo);//_vbo is a private data member
glBindBuffer(GL_ARRAY_BUFFER, _vbo);
}
//load the data in the array buffer object
glBufferData(GL_ARRAY_BUFFER, sizeof(glm::vec3) * _vec.size(), &_vec[0][0], GL_STATIC_DRAW);
}
void Model::Draw()
{
glBindBuffer(GL_ARRAY_BUFFER, _vbo);
glDrawArrays(GL_TRIANGLES, 0, _numVertices);
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
void init()
{
//vao dummy (?)
GLuint VAO;
glGenVertexArrays(1, &VAO);
glBindVertexArray(VAO);
//load 3d models
Model cube = load("cube.obj");
Model cow = load("cow.obj");
//the next two lines should be valid for both objects?
glVertexAttribPointer(prog.GetAttribLocation("vertex"), 3, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(prog.GetAttribLocation("vertex"));
}
void render()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//draw cube:
//some matrix transformations
...
cube.Draw();
//draw cow:
//some matrix transformations
...
cow.Draw()
glutSwapBuffers();
}
GLuint GL_ARRAY_BUFFER_BINDING = 0; // Only 1 or 2 commands in GL care about this state
GLuint GL_VERTEX_ARRAY_BINDING = 0; // 0 is an invalid VAO (if this is 0, most vertex commands will generate `GL_INVALID_OPERATION`).
// Generic GPU-side Memory Store
struct GLBufferObject {
GLsizeiptr* gpu_base_addr;
} *gl_buffer_objects;
// Vertex Array State
struct GLVertexArrayObject {
GLsizeiptr* attribute_pointers [GL_MAX_VERTEX_ATTRIBUTES];
GLboolean attribute_enabled [GL_MAX_VERTEX_ATTRIBUTES];
GLuint GL_ELEMENT_ARRAY_BUFFER_BINDING;
} *gl_array_objects;
void glBindVertexArray (GLuint array)
{
GL_VERTEX_ARRAY_BINDING = array;
}
void glBindBuffer (GLenum target, GLuint buffer)
{
if (target == GL_ARRAY_BUFFER)
GL_ARRAY_BUFFER_BINDING = buffer;
}
void glVertexAttribPointer (GLuint index, ..., const GLvoid* offset)
{
GLBufferObject* current_vbo = &gl_buffer_objects [GL_ARRAY_BUFFER_BINDING];
GLVertexArrayObject* current_vao = &gl_array_objects [GL_VERTEX_ARRAY_BINDING];
current_vao->attribute_pointers [index] = current_vbo->gpu_base_addr + offset;
}