繁体   English   中英

用默认构造函数调用的网格类无法运行OpenGL C ++

[英]Mesh class called with default constructor not working OpenGL C++

我为OpenGL 3.3创建了一个Mesh类,当我使用非默认构造函数创建类时,当创建对象时创建顶点时,它可以正常工作。
但是,我现在想要有多个对象,可以通过将它们放在向量中来动态创建,因此我必须添加一个默认构造函数,我使用与其他构造函数相同的函数来设置缓冲区数据...但是它不起作用。 据我所知,并不是因为它在向量中,而是与构造函数有关,或者与稍后创建缓冲区数据有关。 我真的不太确定。

这是我的课。 (当我创建一个有效的网格时,我用参数调用构造函数,当它无效时,我构建一个不带参数的网格并调用“ changeMes​​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对象的方式是一个痛苦的秘诀,您可能会发现许多像之前一样的事情。

典型的问题是由于复制和销毁对象时发生的情况相结合而引起的。 由C ++包装器拥有的OpenGL对象在析构函数中被删除:

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

    glDeleteVertexArrays(1, &vertexArrayObject);
}

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

std::vector<mesh> m_meshes;

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

看起来无害? 一点也不。 坏事发生在这里:

  • 点1:创建了新对象。 构造函数创建OpenGL对象,并将其名称存储在成员变量中。
  • 第2点: 网格对象的副本添加到向量中,并使用默认的副本构造函数创建副本。 这意味着将复制包含OpenGL对象名称的成员变量。
  • 第3点:网格物体超出范围。 调用析构函数,这将删除OpenGL对象。

毕竟,这是在矢量中存储的网格对象,在其成员变量中存储了OpenGL对象名称,而实际的OpenGL对象已被删除。 这意味着此网格对象中存储的对象名称现在无效。

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

有多种方法可以解决此问题。 它们都不是非常漂亮的:

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

  2. 始终使用指针引用对象。 代替使用矢量对象,而使用矢量对象指针。 这样,不会复制对象。 您还必须注意正确管理对象的生存期,并且不要泄漏它们。 如果您使用某种形式的智能指针而不是裸指针,这是最简单的。

  3. 使用某种形式的混合体,您仍然使用实际的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);
}

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM