C++ std::vector和VBO仅渲染最后一个形状
我遇到了一个奇怪的问题。基本上我有一个网格类,根据一个标志,我可以画一个点,一条线,或一个三角形。例如,如果我想画两条线,我可以做以下操作C++ std::vector和VBO仅渲染最后一个形状,c++,opengl,vector,shader,C++,Opengl,Vector,Shader,我遇到了一个奇怪的问题。基本上我有一个网格类,根据一个标志,我可以画一个点,一条线,或一个三角形。例如,如果我想画两条线,我可以做以下操作 Vertex vertices1[] = { Vertex(glm::vec3(-.5, -.5, 0)), Vertex(glm::vec3( 0, .5, 0)) }; Vertex vertices2[] = { Vertex(glm::vec3( .5, -.5, 0))
Vertex vertices1[] = {
Vertex(glm::vec3(-.5, -.5, 0)),
Vertex(glm::vec3( 0, .5, 0))
};
Vertex vertices2[] = {
Vertex(glm::vec3( .5, -.5, 0)),
Vertex(glm::vec3( -.5, .5, 0))
};
Mesh mesh1(vertices1, sizeof(vertices1)/sizeof(vertices1[0]), 'L');
Mesh mesh2(vertices2, sizeof(vertices2)/sizeof(vertices2[0]), 'L');
// Rendering Loop:
while( Window.isOpen() ){
...
//================( Rendering )=========================
ourShader.Use();
mesh1.draw();
mesh2.draw();
//======================================================
...
}
结果是
现在我想使用std::vector
并在网格中循环。我的尝试如下
std::vector<Mesh> meshes;
meshes.push_back(mesh1);
meshes.push_back(mesh2);
while( Window.isOpen() ){
...
//================( Rendering )=========================
ourShader.Use();
for ( int i(0); i < meshes.size(); ++i )
meshes[i].draw();
//======================================================
...
}
着色器
#version 330 core
out vec4 color;
void main()
{
color = vec4(1.0f,0.5f,0.2f,1.0f);
}
#version 330 core
layout (location = 0) in vec3 position;
void main()
{
gl_PointSize = 10.0;
gl_Position = vec4(position, 1.0);
}
编辑
主要问题是,将Mesh
对象添加到向量时会调用析构函数,因此底层数据会被清除。
进一步阅读:|
我个人会为我的Mesh
类创建单独的init\u buffers
和free\u buffers
方法,并适当地使用它们。(获取OpenGL上下文后初始化缓冲区,关闭窗口时释放缓冲区。)
通过这种方式,您可以在实际使用OpenGL上下文之前开始构建网格(并将其添加到场景中)
我已经实现了缺少的代码部分,并使用GLFW和CLion尝试了您的代码 它起作用了。请参见此处的code/CLion项目: 我添加的唯一代码基本上就是这些代码,所以现在轮到您找出差异/错误
// Constants
const size_t NUM_BUFFERS = 1;
const size_t POSITION_VB = 0;
// Vertex class
class Vertex {
private:
glm::vec3 mCoords;
public:
Vertex(glm::vec3 coords) : mCoords(coords) {};
};
// Mesh class
class Mesh {
private:
GLuint m_vertexArrayObject;
char m_flag;
unsigned int m_drawCount;
GLuint m_vertexArrayBuffers[NUM_BUFFERS];
public:
/* your ctor and draw method */
}
正如我所怀疑的,问题在于(缺少)复制构造函数。默认值仅复制所有成员。因此,您的VAO和缓冲区会被多次删除,甚至在您尝试绘制任何内容之前(向量在重新分配期间移动,如果无法移动,则复制)。经验法则:如果您有一个非默认析构函数,那么您还必须实现一个复制构造函数和一个赋值运算符,或者如果您的类不打算是可复制的,则显式删除它们 对于您的具体情况,解决方案如下:
std::vector<Mesh*> meshes;
meshes.emplace_back(&mesh1);
meshes.emplace_back(&mesh2);
std::矢量网格;
网格。向后放置网格(&mesh1);
网格。向后放置网格(&mesh2);
class Mesh
{
public:
Mesh(Vertex* vertices, unsigned int numVertices, const char& flag);
void draw();
private:
//...
GLvertexarray m_vertexArrayObject;
GLbuffer m_vertexArrayBuffers[NUM_BUFFERS];
unsigned int m_drawCount;
char m_flag;
};
Mesh::Mesh(Vertex* vertices, unsigned int numVertices, const char& flag) : m_flag(flag), m_drawCount(numVertices)
{
GLuint id;
glGenVertexArrays(1, &id);
glBindVertexArray(id);
m_vertexArrayObject.reset(id);
for(int i = 0; i < NUM_BUFFERS; ++i)
{
glGenBuffers(1, &id);
glBindBuffer(GL_ARRAY_BUFFER, id);
m_vertexArrayBuffers[i].reset(id);
glBufferData(GL_ARRAY_BUFFER, numVertices*sizeof(vertices[0]), vertices, GL_STATIC_DRAW);
}
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
glBindVertexArray(0);
}
void Mesh::draw()
{
switch(m_flag)
{
case 'P':
glBindVertexArray(m_vertexArrayObject.get());
glDrawArrays(GL_POINTS, 0, m_drawCount);
glBindVertexArray(0);
break;
case 'L':
glBindVertexArray(m_vertexArrayObject.get());
glDrawArrays(GL_LINES, 0, m_drawCount);
glBindVertexArray(0);
break;
case 'T':
glBindVertexArray(m_vertexArrayObject.get());
glDrawArrays(GL_TRIANGLES, 0, m_drawCount);
glBindVertexArray(0);
break;
}
}
int main()
{
//...
Mesh mesh1(vertices1, sizeof(vertices1)/sizeof(vertices1[0]), 'L');
Mesh mesh2(vertices2, sizeof(vertices2)/sizeof(vertices2[0]), 'L');
std::vector<Mesh> meshes;
meshes.emplace_back(std::move(mesh1));
meshes.emplace_back(std::move(mesh2));
// ...
return 0;
}
类网格
{
公众:
网格(顶点*顶点、无符号整数、常量字符和标志);
无效抽取();
私人:
//...
GLvertexarray m_vertexArrayObject;
GLbuffer m_vertexArrayBuffers[NUM_BUFFERS];
无符号整数m_支取计数;
charm_旗;
};
网格::网格(顶点*顶点,无符号整数维,常量字符和标志):m_标志(标志),m_支数(整数维)
{
颖片id;
glgenvertexarray(1,&id);
glBindVertexArray(id);
m_vertexArrayObject.reset(id);
对于(int i=0;i
请注意,不再需要定义析构函数,您的类将自动变为可移动但不可复制。此外,如果您有OpenGL4.5或ARB\u direct\u state\u access
,那么事情会变得更简单你的代码看起来不错。如果没有
Mesh
code,很难判断问题出在哪里。它是否包含VAO描述符?也许问题出在它的赋值运算符或复制构造函数中?如果不创建mesh1
和mesh2
对象,而是使用带有适当参数的std::vector::emplace
,会发生什么情况?@Sergey,是的,它确实包含VAO。请查看更新。我尝试过同样的问题。如果你以相反的顺序迭代你的向量…是否只绘制了第一个?有没有可能“画图”正在擦除场景?这可能是复制构造函数的问题。“如果不看a,很难远程解决您的问题。@ybungalobill,我会很快准备一个。谢谢您的回答。”。我可能会在我的Mac中编译相同的代码,看看这是否有什么不同。
class Mesh
{
public:
Mesh(Vertex* vertices, unsigned int numVertices, const char& flag);
void draw();
private:
//...
GLvertexarray m_vertexArrayObject;
GLbuffer m_vertexArrayBuffers[NUM_BUFFERS];
unsigned int m_drawCount;
char m_flag;
};
Mesh::Mesh(Vertex* vertices, unsigned int numVertices, const char& flag) : m_flag(flag), m_drawCount(numVertices)
{
GLuint id;
glGenVertexArrays(1, &id);
glBindVertexArray(id);
m_vertexArrayObject.reset(id);
for(int i = 0; i < NUM_BUFFERS; ++i)
{
glGenBuffers(1, &id);
glBindBuffer(GL_ARRAY_BUFFER, id);
m_vertexArrayBuffers[i].reset(id);
glBufferData(GL_ARRAY_BUFFER, numVertices*sizeof(vertices[0]), vertices, GL_STATIC_DRAW);
}
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
glBindVertexArray(0);
}
void Mesh::draw()
{
switch(m_flag)
{
case 'P':
glBindVertexArray(m_vertexArrayObject.get());
glDrawArrays(GL_POINTS, 0, m_drawCount);
glBindVertexArray(0);
break;
case 'L':
glBindVertexArray(m_vertexArrayObject.get());
glDrawArrays(GL_LINES, 0, m_drawCount);
glBindVertexArray(0);
break;
case 'T':
glBindVertexArray(m_vertexArrayObject.get());
glDrawArrays(GL_TRIANGLES, 0, m_drawCount);
glBindVertexArray(0);
break;
}
}
int main()
{
//...
Mesh mesh1(vertices1, sizeof(vertices1)/sizeof(vertices1[0]), 'L');
Mesh mesh2(vertices2, sizeof(vertices2)/sizeof(vertices2[0]), 'L');
std::vector<Mesh> meshes;
meshes.emplace_back(std::move(mesh1));
meshes.emplace_back(std::move(mesh2));
// ...
return 0;
}