使用 c++ 在 openGl 中启动不同模型的问题

Posted

技术标签:

【中文标题】使用 c++ 在 openGl 中启动不同模型的问题【英文标题】:Problems with initiating different models in openGl with c++ 【发布时间】:2016-02-13 08:33:38 【问题描述】:

我正在学习 openGL,我正在尝试做一些非常简单的事情。我有一个名为 Model 的图形对象,它包含一个用于顶点的 GLfloats 向量并具有一个绘图功能。除此之外,我还有一个 addVertex 函数,它接收 3 个浮点数和一个绘制函数,它绑定对象的 VAO,然后在绘制后解除绑定。我可以毫无问题地渲染其中一个对象并向其添加点,但是我不能同时绘制多个对象而不会导致程序崩溃并且 Visual Studio 告诉我“框架不在模块中”,这没有帮助.此外,只能渲染我创建的最后一个模型对象,任何在它之前出现的对象都会使程序崩溃。

这是模型对象的代码:

#include "Model.h"
#include <iostream>
#include <string>



Model::Model() 

    drawMode = 0;


    glGenVertexArrays(1, &VAO);
    glGenBuffers(1, &VBO); 
    glGenBuffers(1, &EBO);

    glBindVertexArray(VAO);
    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferData(GL_ARRAY_BUFFER, NULL, NULL, GL_STATIC_DRAW);

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, NULL, NULL, GL_STATIC_DRAW);

    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (GLvoid*)0);
    glEnableVertexAttribArray(0);
    glBindVertexArray(0);


Model::~Model() 
    glDeleteVertexArrays(1, &VAO);
    glDeleteBuffers(1, &VBO);
    glDeleteBuffers(1, &EBO);


void Model::addVertex(GLfloat x, GLfloat y, GLfloat z) 
    vertices.push_back(x);
    vertices.push_back(y);
    vertices.push_back(z);
    update();


void Model::addIndex(int i, int j, int k) 
    indices.push_back(i);
    indices.push_back(j);
    indices.push_back(k);



void Model::setShader(GLuint& shader) 
    shaderProgram = &shader;




void Model::clearModel() 
    vertices.clear();
    indices.clear();


int Model::sizeOfVertices() 
    return sizeof(GLfloat)*vertices.size();

int Model::sizeOfIndices() 
    return sizeof(GLuint)*(indices.size());


void Model::draw() 
    glUseProgram(*shaderProgram);
    GLuint transformLoc = glGetUniformLocation(*shaderProgram, "model");
    glUniformMatrix4fv(transformLoc, 1, GL_FALSE, glm::value_ptr(model));


    glBindVertexArray(VAO);
    switch (drawMode) 
    case 0: glDrawArrays(GL_POINTS, 0, vertices.size() / 3);
        break;
    case 1: glDrawArrays(GL_LINE_STRIP, 0, vertices.size() / 3);
        break;
    case 2: glDrawArrays(GL_TRIANGLES, 0, vertices.size() / 3);
        break;
    case 3: glDrawArrays(GL_TRIANGLE_STRIP, 0, vertices.size() / 3);
        break;
    default: break;
    

    glBindVertexArray(0); 



void Model::setDrawMode(int type) 
    drawMode = type;



void Model::move(glm::vec3 translation) 
    model = glm::translate(model, translation);

void Model::rotate(float degrees,glm::vec3 axis) 
    model = glm::rotate(model, degrees,axis);


void Model::update() 
    glBindVertexArray(0);
    glBindVertexArray(VAO);

    glBufferData(GL_ARRAY_BUFFER, NULL, NULL, GL_STATIC_DRAW);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, NULL, NULL, GL_STATIC_DRAW);

    glBufferData(GL_ARRAY_BUFFER, sizeOfVertices(), &vertices[0], GL_STATIC_DRAW);


    glEnableVertexAttribArray(0);
    glBindVertexArray(0);


Model 类中包含一个 EBO,但我还没有使用它,因为我想隔离问题。

模型.h:

#pragma once

#include <vector>;
#include <glew.h>;

#include "glm.hpp"
#include "gtc/matrix_transform.hpp"
#include "gtc/type_ptr.hpp"
#include "gtc/constants.hpp"

class Model 
public:
    int drawMode;
    GLuint VAO;
    GLuint VBO;
    GLuint EBO;
    GLuint *shaderProgram;
    std::vector<GLfloat> vertices;
    std::vector<GLuint> indices;

    glm::mat4 model;

    Model();
    ~Model();

    void addVertex(GLfloat, GLfloat, GLfloat);
    void addIndex(int, int, int);

    void setShader(GLuint&);

    void clearModel();

    int sizeOfVertices();
    int sizeOfIndices();

    void draw();
    void setDrawMode(int);

    void move(glm::vec3);
    void rotate(float, glm::vec3);

    void update();
;

主类:

#include <iostream>
#include <string>
#include <fstream>


#include <vector>

#include "Callbacks.h"
#include "Shader.h"
#include "GlState.h"
#include "Model.h"

#include <glew.h>
#include <glfw3.h>
#include "glm.hpp"
#include "gtc/matrix_transform.hpp"
#include "gtc/type_ptr.hpp"
#include "gtc/constants.hpp"



Model *model;
Model *model2;
Model *model3;

void mainLoop(GLFWwindow* window) 
    glfwPollEvents();
//RENDER UNDER HERE
    glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glPointSize(5);


        Callbacks::update(model3);
        model3->draw();
        model2->draw();
        model->draw();



    glfwSwapBuffers(window);




int main() 
    GLFWwindow* window = GlState::Initialize(800,600);
    GLuint shaderProgram = Shader::makeProgram("vertex.vs", "fragment1.fs");
    GLuint shaderProgram2 = Shader::makeProgram("vertex.vs", "fragment2.fs");
    model = new Model();
    model2 = new Model();
    model3 = new Model();


    model->setShader(shaderProgram);
    model2->setShader(shaderProgram);
    model3->setShader(shaderProgram2);


    while (!glfwWindowShouldClose(window))
    

        mainLoop(window);

    

    delete(model);
    delete(model2);
    delete(model3);
    glfwTerminate();
    return 0;

我还将包括回调的重要部分,由 update(Model* m) 调用

void Callbacks::checkMouse(Model* m) 
    if (leftMousePressed) 
        if (tics == 0) 
            m->addVertex(2*(mouseXCurrent-0.5), 2*(0.5-mouseYCurrent), 0.0f);

        
    tics++;
    

我还没有设置相机,所以它是默认的正交视图。

由于我只能在不崩溃的情况下向最后一个模型对象添加点(在本例中为模型 3),我认为这一定与这些模型的启动方式有关,但我不知道是什么!快把我逼疯了。

这是一个崩溃的例子:

在main中的代码段之后:

    model->setShader(shaderProgram);
    model2->setShader(shaderProgram);
    model3->setShader(shaderProgram2);

如果你输入 模型->addVertex(0.1f,0.2f,0.0f); 或者 model2->addVertex(0.1f,0.2f,0.0f);

但是程序会崩溃

model3->addVertex(0.1f,0.2f,0.0f);

没有问题

【问题讨论】:

到目前为止我找不到一些错误。但我注意到的一件事是,您使用 vertices.size() 函数来计算要为 glDrawArrays 调用绘制的顶点数。但是,如果您在不更新缓冲区数据的情况下更改顶点的某些数据,这可能会变得很危险,因为您可能会尝试绘制不存在的顶点。 【参考方案1】:

代码将崩溃,因为您正在访问缓冲区之外的数据。在构造函数中,创建大小为NULL 的缓冲区:

glBufferData(GL_ARRAY_BUFFER, NULL, NULL, GL_STATIC_DRAW)

请注意,指针类型 NULL 对于该调用的 size 参数是完全无效的,但这不是这里的问题。

当您调用addVertex 方法时,会将数据附加到std::vector,但不会附加到VBO。你永远不会调用 update 方法,它实际上将数据传输到缓冲区中,所以你的属性指针仍然指向 0 大小的缓冲区,当从中绘制超过 0 个顶点时,你只是在未定义的行为领域。

【讨论】:

我对 update() 的错误,它是在添加顶点之后调用的,但它最初是在 Callback::checkMouse() 中,当我在这里从 checkMouse 中删除它时,我没有在 addVertex 中添加它() 这里。它在我的代码中,所以这不是错误。不过谢谢【参考方案2】:

所以我发现了问题所在。在更新方法中,我将绑定 VAO,问题是我认为这也绑定了 VBO 进行编辑,这显然从未发生过。所以当我打电话时

glBufferData(GL_ARRAY_BUFFER, sizeOfVertices(), &amp;vertices[0], GL_STATIC_DRAW);

我以为我正在修改 VAO 中的 VBO,但实际上我正在修改最后一个 VBO 绑定。上次绑定 VBO 是在构造函数中,所以这就是为什么我只能修改最后创建的 Model 对象,而其他的会崩溃,因为我会绑定他们的 VAO 并尝试修改另一个 Model 的 VBO。

至少我认为这是问题所在,因为我正在调用,所以现在没有错误

    glBindBuffer(GL_ARRAY_BUFFER, VBO);

在我修改之前。

【讨论】:

以上是关于使用 c++ 在 openGl 中启动不同模型的问题的主要内容,如果未能解决你的问题,请参考以下文章

C++ Opengl - 使用聚光灯照明

c++ OpenGL坐标变换

在 OpenGL c++ 项目中使用资源中的 .tga (targa) 文件

使用 DevIL 在 C++ OpenGL 中加载纹理

基于Qt的OpenGL可编程管线学习- 使用Subroutine绘制不同光照的模型

如何在 C++ builder 中渲染 openGL 框架?