2015-03-08 31 views
1

我爲OpenGL 3.3創建了一個Mesh類,當我使用非默認構造函數創建類時,它在我創建對象時創建頂點時正常工作。
但是,我現在想要通過將它們放入一個向量中來動態創建多個對象,所以我必須添加一個默認構造函數,以便使用與其他構造函數相同的函數來設置緩衝區數據。但它不起作用。據我所知,不是因爲它在向量中,而是它與構造函數有關,或者與稍後創建緩衝區數據有關。我真的不太確定。使用默認構造函數調用的網格類不工作OpenGL C++

這是我的課程。 (當我創建工作我調用構造函數與參數,當它不工作我構造不帶參數的網格,稱之爲「changeMes​​h」功能的目)

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

很可能是因爲你在'mesh'中聲明的任何成員變量都不能被默認構造。考慮使用默認構造函數的成員初始值設定項列表。 – 2015-03-08 17:20:11

回答

9

雖然您認爲問題與存儲矢量中的對象無關,但我有強烈的感覺,它可能的確如此。你在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:A 拷貝的網格對象被添加到向量,其中副本是用默認的拷貝構造函數創建的。這意味着將複製包含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中做到最好:With explicitly deleted member functions in C++11, is it still worthwhile to inherit from a noncopyable base class?

+0

事情是,即使我不把它放在一個向量中也不起作用。只做網格newMesh; newMesh.changeMes​​h(...); (...)newMesh.render()不起作用 – Tritzium 2015-03-08 18:48:24

+0

By不起作用我的意思是它沒有在屏幕上顯示任何東西。 (不渲染任何東西) – Tritzium 2015-03-08 19:11:24

+0

問題可能在發佈的代碼之外。你在哪裏調用'glUseProgram()'? – 2015-03-08 19:32:15