Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/google-sheets/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ std::vector和VBO仅渲染最后一个形状_C++_Opengl_Vector_Shader - Fatal编程技术网

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);
    
  • 正确的解决方案:使用适当的RAII进行资源管理。使用MCVE代码将变成:

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