网格类调用与默认构造函数不工作OpenGL C ++ [英] Mesh class called with default constructor not working OpenGL C++

查看:151
本文介绍了网格类调用与默认构造函数不工作OpenGL C ++的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我为OpenGL 3.3创建了一个Mesh类,当我创建一个非默认的构造函数,当我创建的顶点创建对象时,它工作正常。

然而,我现在想有多个对象,我可以通过将它们放在一个向量中动态创建,所以我不得不添加在一个默认的构造函数我使用相同的函数设置缓冲区数据与其他构造函数...但它不工作。它是我可以告诉不是因为它在向量中的事实,但它是与构造函数或事情,事实缓冲区数据后创建的事情。我真的不太确定。

I created a Mesh class for OpenGL 3.3, it works fine when I create the class with a non-default constructor, when I create the vertices when I create the object.
However, I now want to have multiple objects that I can create dynamically by putting them in a vector, so I had to add in a default constructor I use the same functions for setting up the buffer data as with the other constructor... but it doesn't work. It's as far as I can tell not because of the fact it's in the vector but it's something to do with the constructor or something with the fact the buffer data is created later. I'm really not quite sure.

这里是我的课。 (当我创建一个网格工作我调用的参数的构造函数,当它不工作我构造一个没有参数的网格并调用changeMes​​h函数)

Here are my classes. ( When I create a mesh that works I call the constructor with parameters and when it doesn't work I construct a mesh with no parameters and call the "changeMesh" function)

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

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);
}


推荐答案

与向量中存储对象无关,我有一种强烈的感觉,它可能是。你在C ++封装器中封装OpenGL对象的方式是一种痛苦的方法,你可能发现了很多在你之前。

While you believe that the problem has nothing to do with storing the objects in a vector, I have a strong feeling that it probably does. The way you are encapsulating OpenGL objects in C++ wrappers is a recipe for pain, and you're probably finding out like many did before you.

典型的问题是由当对象被复制和销毁时发生的组合。 C ++包装器拥有的OpenGL对象在析构函数中被删除:

The typical problems are caused by the combination of what happens when objects are copied and destructed. The OpenGL objects owned by the C++ wrapper are deleted in the destructor:

mesh::~mesh()
{
    glDeleteBuffers(1, &elementBuffer);
    glDeleteBuffers(1, &vertexBuffer);

    glDeleteVertexArrays(1, &vertexArrayObject);
}

为了说明这个问题,让我们来看一个典型的序列。假设你有一个网格物体的向量,以及一个向这个向量添加一个新网格的方法(点注释供以后参考):

To illustrate the problem with this, let's look at a typical sequence. Let's say you have a vector of mesh objects, and a method to add a new mesh to this vector (points annotated for later reference):

std::vector<mesh> m_meshes;

void createMesh(...) {
    mesh newMesh;  // point 1
    newMesh.changeMesh(...);
    m_meshes.push_back(newMesh);  // point 2
}  // point 3

看起来无害?这根本不是。这里发生的错误:

Looks harmless? It's not at all. Bad things happened here:


  • 点1:创建新对象。

  • 点2:将网格对象的复制添加到向量中,其中复制使用默认复制构造函数创建。这意味着将复制包含OpenGL对象名称的成员变量。

  • 点3:网格对象超出范围。

  • Point 1: New object is created. The constructor creates the OpenGL objects, and stores their names in member variables.
  • Point 2: A copy of the mesh object is added to the vector, where the copy is created with the default copy constructor. This means that the member variables, which contain the OpenGL object names, are copied.
  • Point 3: The mesh object goes out of scope. The destructor is invoked, which deletes the OpenGL objects.

所有这些都是存储在向量中的网格对象, OpenGL对象名称存储在其成员变量中,而实际的OpenGL对象已被删除。这意味着存储在此网格物体中的对象名称现在无效。

What you have after all of this is a mesh object stored in the vector, with OpenGL object names stored in its member variables, while the actual OpenGL objects have been deleted. This means that the object names stored in this mesh object are now invalid.

根问题是您的类没有正确的复制构造函数和赋值运算符。不幸的是,在成员变量中存储OpenGL对象名称,以及在构造函数/析构函数中生成/删除对象名称时,很难实现它们。

The root problem is that your class does not have proper copy constructors and assignment operators. And unfortunately, it is not easily possible to implement them when storing OpenGL object names in member variables, and generating/deleting the object names in constructor/destructor.

处理这种情况的方式的数量。没有一个是完美的:

There are a number of ways to handle this. None of them are perfectly pretty:


  1. 不要在构造函数/析构函数中生成/删除OpenGL对象。而是使用您明确调用的某种形式的 init() / cleanup()方法。缺点是你必须小心调用这些方法正确。例如,如果你有一个对象的向量,并且想要删除向量,你必须手动调用向量的所有成员 cleanup()

  1. Do not generate/delete the OpenGL objects in constructor/destructor. Instead, use some form of init()/cleanup() methods that you invoke explicitly. The downside is that you have to be careful to invoke these methods correctly. For example, if you have a vector of objects, and want to delete the vector, you have to invoke cleanup() on all members of the vector manually.

始终使用指针引用对象。代替具有网格对象的向量,使用网格对象指针的向量。这样,对象不会被复制。您还必须小心管理对象的生命周期,而不是泄漏它们。

Always reference the objects with pointers. Instead of having a vector of mesh objects, use a vector of mesh object pointers. This way, the objects are not copied. You also have to be careful to manage the lifetime of the objects correctly, and not leak them. This is easiest if you use some form of smart pointer instead of naked pointers.

使用某种形式的混合,你仍然使用实际的C ++对象,但他们将基础OpenGL对象的名称存储在引用计数的嵌套对象中。

Use some form of hybrid, where you still use actual C++ objects, but they store the names of the underlying OpenGL objects in a nested object that is reference counted. This way, they can implement proper copy/assign semantics.

我认为最简单和最干净的方法是选项2使用智能指针。较新版本的C ++在标准库中有智能指针,所以没有什么你需要实现。例如在C ++ 11中,您可以使用 std :: shared_ptr< mesh> 类型来引用您的网格物体。上面的代码片段将如下所示:

I think the easiest and cleanest approach is option 2 with using smart pointers. Newer versions of C++ have smart pointers in the standard library, so there isn't anything you need to implement. For example in C++11, you can use the type std::shared_ptr<mesh> to reference your mesh objects. The code fragment above would then look like this:

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);
}

为了确保你不会无意中复制对象,一个好主意,声明未实现(私有)复制构造函数和类的赋值运算符。本主题说明如何在C ++ 11中做到最好:在C ++ 11中显式删除成员函数时,仍然值得继承自不可复制的基类?

To be sure that you don't accidentally copy the objects anyway, it's also a good idea to declare unimplemented (private) copy constructors and assignment operators for the class. This topic explains how to do that best in C++11: With explicitly deleted member functions in C++11, is it still worthwhile to inherit from a noncopyable base class?.

这篇关于网格类调用与默认构造函数不工作OpenGL C ++的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆