v_j*_*han 1 c++ opengl class mesh c++11
我为OpenGL 3.3创建了一个Mesh类,当我使用非默认构造函数创建类时,它在我创建对象时创建顶点时工作正常.
但是,我现在想要通过将它们放在向量中来动态创建多个对象,所以我必须添加一个默认构造函数,我使用相同的函数来设置缓冲区数据,就像使用其他构造函数一样...但是它不起作用.据我所知,这是因为它存在于向量中,但它与构造函数有关,或者事后缓冲区数据会被创建.我真的不太确定.
这是我的课程.(当我创建一个有效的网格时,我用参数调用构造函数,当它不起作用时,我构造一个没有参数的网格并调用"changeMesh"函数)
mesh.h
#ifndef MESH_H
#define MESH_H
#include <iostream>
#include <vector>
#include <GL/glew.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
class mesh
{
public:
mesh();
mesh(std::vector<GLfloat> vertices, std::vector<GLuint> triangles, GLuint shaderProgram);
~mesh();
void changeMesh(std::vector<GLfloat> vertices, std::vector<GLuint> triangles, GLuint shaderProgram);
void render();
void Translate(glm::vec3 addVector);
void Rotate(glm::vec3 rotVector, GLfloat angle);
protected:
private:
GLuint vertexArrayObject, vertexBuffer, elementBuffer, shaderProgram;
std::vector<GLfloat> vertices;
std::vector<GLuint> indices;
glm::mat4 transform;
void setUpMesh();
void bindVertices();
};
#endif // MESH_H
Run Code Online (Sandbox Code Playgroud)
mesh.cpp
#include "../include/mesh.h"
mesh::mesh(std::vector<GLfloat> vertices, std::vector<GLuint> indices, GLuint shaderProgram)
{
this->shaderProgram = shaderProgram;
this->vertices = vertices;
this->indices = indices;
setUpMesh();
}
mesh::mesh(){
glGenVertexArrays(1, &vertexArrayObject);
glBindVertexArray(vertexArrayObject);
glGenBuffers(1, &vertexBuffer);
glGenBuffers(1, &elementBuffer);
}
mesh::~mesh()
{
glDeleteBuffers(1, &elementBuffer);
glDeleteBuffers(1, &vertexBuffer);
glDeleteVertexArrays(1, &vertexArrayObject);
}
void mesh::changeMesh(std::vector<GLfloat> vertices, std::vector<GLuint> triangles, GLuint shaderProgram){
this->shaderProgram = shaderProgram;
this->vertices = vertices;
this->indices = indices;
bindVertices();
}
void mesh::setUpMesh(){
glGenVertexArrays(1, &vertexArrayObject);
glBindVertexArray(vertexArrayObject);
glGenBuffers(1, &vertexBuffer);
glGenBuffers(1, &elementBuffer);
bindVertices();
glBindVertexArray(0);
}
void mesh::bindVertices(){
glBindVertexArray(vertexArrayObject);
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
glBufferData(GL_ARRAY_BUFFER, this->vertices.size() * sizeof(GLfloat), this->vertices.data(), GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementBuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, this->indices.size() * sizeof(GLuint), this->indices.data(), GL_STATIC_DRAW);
GLint amountDataPerVert = 5;
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, amountDataPerVert*sizeof(GLfloat), 0);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, amountDataPerVert*sizeof(GLfloat), (void*)(3*sizeof(GLfloat)));
glBindVertexArray(0);
}
void mesh::render(){
glBindVertexArray(vertexArrayObject);
glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "transform"), 1, GL_FALSE, glm::value_ptr(transform));
glDrawElements(GL_TRIANGLES, indices.size(), GL_UNSIGNED_INT, 0);
glBindVertexArray(0);
}
void mesh::Translate(glm::vec3 addVector){
transform = glm::translate(transform, addVector);
}
void mesh::Rotate(glm::vec3 rotVector, GLfloat angle){
transform = glm::rotate(transform, glm::radians(angle), rotVector);
}
Run Code Online (Sandbox Code Playgroud)
Ret*_*adi 10
虽然您认为问题与将对象存储在向量中无关,但我有一种强烈的感觉,它可能会这样做.你在C++包装器中封装OpenGL对象的方式是痛苦的一个方法,你可能会发现很多人在你之前做过.
典型的问题是由复制和销毁对象时发生的事情的组合引起的.在析构函数中删除C++包装器拥有的OpenGL对象:
mesh::~mesh()
{
glDeleteBuffers(1, &elementBuffer);
glDeleteBuffers(1, &vertexBuffer);
glDeleteVertexArrays(1, &vertexArrayObject);
}
Run Code Online (Sandbox Code Playgroud)
为了说明这个问题,我们来看一个典型的序列.假设您有一个网格对象的向量,以及一个向此向量添加新网格的方法(注释点供以后参考):
std::vector<mesh> m_meshes;
void createMesh(...) {
mesh newMesh; // point 1
newMesh.changeMesh(...);
m_meshes.push_back(newMesh); // point 2
} // point 3
Run Code Online (Sandbox Code Playgroud)
看起来无害吗?它根本不是.这里发生了不好的事:
所有这些之后你所拥有的是存储在向量中的网格对象,其中OpenGL对象名称存储在其成员变量中,而实际的OpenGL对象已被删除.这意味着存储在此网格对象中的对象名称现在无效.
根本问题是您的类没有适当的复制构造函数和赋值运算符.遗憾的是,在成员变量中存储OpenGL对象名,并在构造函数/析构函数中生成/删除对象名时,实现它们并不容易.
有很多方法可以解决这个问题.它们都不是很漂亮:
不要在构造函数/析构函数中生成/删除OpenGL对象.相反,请使用您明确调用的某种形式的init()
/ cleanup()
方法.缺点是你必须小心正确地调用这些方法.例如,如果您有一个对象向量,并且想要删除该向量,则必须cleanup()
手动调用该向量的所有成员.
始终使用指针引用对象.不使用网格对象的矢量,而是使用网格对象指针的矢量.这样,不会复制对象.您还必须小心正确地管理对象的生命周期,而不是泄漏它们.如果您使用某种形式的智能指针而不是裸指针,这是最简单的.
使用某种形式的混合,您仍然使用实际的C++对象,但它们将基础OpenGL对象的名称存储在引用计数的嵌套对象中.这样,他们就可以实现正确的复制/分配语义.
我认为最简单,最干净的方法是使用智能指针的选项2.较新版本的C++在标准库中具有智能指针,因此您无需实现任何内容.例如,在C++ 11中,您可以使用该类型std::shared_ptr<mesh>
来引用网格对象.上面的代码片段如下所示:
std::vector<std::shared_ptr<mesh> > m_meshes;
void createMesh(...) {
std::shared_ptr<mesh> newMesh = std::make_shared<mesh>();
newMesh->changeMesh(...);
m_meshes.push_back(newMesh);
}
Run Code Online (Sandbox Code Playgroud)
为了确保您不会意外地复制对象,为类声明未实现的(私有)复制构造函数和赋值运算符也是一个好主意.本主题解释了如何在C++ 11中做到最好:在C++ 11中使用显式删除的成员函数,是否仍然值得从不可复制的基类继承?.