使用 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(), &vertices[0], GL_STATIC_DRAW);
我以为我正在修改 VAO 中的 VBO,但实际上我正在修改最后一个 VBO 绑定。上次绑定 VBO 是在构造函数中,所以这就是为什么我只能修改最后创建的 Model 对象,而其他的会崩溃,因为我会绑定他们的 VAO 并尝试修改另一个 Model 的 VBO。
至少我认为这是问题所在,因为我正在调用,所以现在没有错误
glBindBuffer(GL_ARRAY_BUFFER, VBO);
在我修改之前。
【讨论】:
以上是关于使用 c++ 在 openGl 中启动不同模型的问题的主要内容,如果未能解决你的问题,请参考以下文章
在 OpenGL c++ 项目中使用资源中的 .tga (targa) 文件