Qt Opengl VBO 数据损坏
Qt Opengl VBO data corrupted
到目前为止,我已经尝试将近两周让 VBO 在 Qt 环境中工作,但到目前为止没有任何效果。我的目标是创建一个三角形网格以用作某些地形的基础,就像在 Lighthouse3D 教程中那样。我程序的相关部分如下:
GameWindow.h
class GameWindow : public QOpenGLWidget, protected QOpenGLFunctions_3_3_Core
{
Q_OBJECT
public:
GameWindow(QWidget *parent = 0);
~GameWindow();
protected:
virtual void initializeGL() override;
virtual void resizeGL(int width, int height) override;
virtual void paintGL() override;
QGLShaderProgram *shaderProgram;
private:
int frame;
std::vector<GLfloat> grid;
QOpenGLBuffer vbo;
GLuint vboId;
QVector3D position;
};
GameWindow.cpp
GameWindow::GameWindow(QWidget *parent) :
QOpenGLWidget(parent),
position(QVector3D(0, 5, -5)),
vbo(QOpenGLBuffer(QOpenGLBuffer::VertexBuffer))
{}
GameWindow::~GameWindow()
{}
void GameWindow::initializeGL()
{
QOpenGLWidget::initializeGL();
initializeOpenGLFunctions();
shaderProgram = new QGLShaderProgram(QGLContext::currentContext());
QGLShader vertex(QGLShader::Vertex);
vertex.compileSourceFile(QDir(":/shaders").absoluteFilePath("basic.vert"));
shaderProgram->addShader(&vertex);
QGLShader fragment(QGLShader::Fragment);
fragment.compileSourceFile(QDir(":/shaders").absoluteFilePath("basic.frag"));
shaderProgram->addShader(&fragment);
shaderProgram->link();
QImage image;
image.load("C:\test.png");
int width = image.width(); //=10
int height = image.height(); //=10
for (int i = 0; i < height-1; i++) {
for (int j = 0; j < width-1; j++) {
grid.push_back(GLfloat(j));
grid.push_back(GLfloat(0.0f));
grid.push_back(GLfloat(i));
grid.push_back(GLfloat(j));
grid.push_back(GLfloat(0.0f));
grid.push_back(GLfloat(i+1));
grid.push_back(GLfloat(j+1));
grid.push_back(GLfloat(0.0f));
grid.push_back(GLfloat(i+1));
grid.push_back(GLfloat(j+1));
grid.push_back(GLfloat(0.0f));
grid.push_back(GLfloat(i+1));
grid.push_back(GLfloat(j+1));
grid.push_back(GLfloat(0.0f));
grid.push_back(GLfloat(i));
grid.push_back(GLfloat(j));
grid.push_back(GLfloat(0.0f));
grid.push_back(GLfloat(i));
}
}
vbo.create();
vbo.bind();
vbo.allocate(grid.size()*sizeof(GLfloat));
vbo.write(0, grid.data(), grid.size()*sizeof(GLfloat));
vbo.release();
/*
glGenBuffers(1, &vboId);
glBindBuffer(GL_ARRAY_BUFFER, vboId);
glBufferData(GL_ARRAY_BUFFER, grid.size() * sizeof(GLfloat), grid.data(), GL_STATIC_DRAW);
//*/
std::cout << std::boolalpha << (glGetError() == GL_NO_ERROR) << std::endl;
}
void GameWindow::resizeGL(int width, int height)
{
QOpenGLWidget::resizeGL(width, height);
}
void GameWindow::paintGL()
{
shaderProgram->bind();
QMatrix4x4 projection;
projection.perspective(45, qreal(width())/qreal(height() > 0 ? height() : 1), 0.1f, 100.0f);
QMatrix4x4 view;
view.lookAt(position, QVector3D(0, 0, 0), QVector3D(0, 1, 0));
QMatrix4x4 model;
model.translate(-0.5f, 0, 0);
QMatrix4x4 mvp;
mvp = projection * view * model;
shaderProgram->setUniformValue("matrix", mvp);
glClear(GL_COLOR_BUFFER_BIT);
vbo.bind();
shaderProgram->enableAttributeArray("vertex");
shaderProgram->setAttributeBuffer("vertex", GL_FLOAT, 0, 3);
glDrawArrays(GL_TRIANGLES, 0, vbo.size());
shaderProgram->disableAttributeArray("vertex");
/*
glBindBuffer(GL_ARRAY_BUFFER, vboId);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3, 0);
glDrawArrays(GL_TRIANGLES, 0, grid.size());
glDisableVertexAttribArray(0);
*/
shaderProgram->release();
update();
}
着色器
//Vertex Shader
attribute vec3 vertex;
uniform mat4 matrix;
varying vec3 pos;
void main(void)
{
gl_Position = matrix * vec4(vertex, 1);
pos = vertex;
}
//Fragment Shader
void main(void)
{
gl_FragColor.rgb = pos;
}
最后我像这样打开 window:
QSurfaceFormat format;
format.setVersion(3, 3);
format.setProfile(QSurfaceFormat::CoreProfile);
format.setSamples(4);
QSurfaceFormat::setDefaultFormat(format);
GameWindow *w = new GameWindow();
w->show();
在 运行 运行这个程序后,我得到了类似的东西,虽然它经常变化:
正如您从代码中看到的那样,我尝试使用 QOpenGLBuffer
和原始 gl*
命令创建和绘制我的 VBO,结果相似。 Google 没有任何帮助,所以现在我向您寻求帮助。我的 VBO 出了什么问题,为什么数据损坏了?
注:
当我 运行 我在标准输出中得到这个错误:
[opengl\qopenglframebufferobject.cpp line 565] OpenGL Error: 1286
QOpenGLFramebufferObject: Unsupported framebuffer format.
QOpenGLFramebufferObject: Unsupported framebuffer format.
[opengl\qopenglframebufferobject.cpp line 720] OpenGL Error: 1280
不过不知道跟这个有没有关系
注2:
尝试使用 vbo.read()
会使我的程序崩溃。
在 Qt 中,OpenGL 操作只有在 makeCurrent
… doneCurrent
块或 …GL
方法中才有效。在这两个前提条件都不满足的情况下,没有可以在其上创建 VBO 的 OpenGL 活动。
解决方案:将您的 OpenGL 初始化代码从构造函数移至 initializeGL
。
当您发出此命令时:
shaderProgram->setAttributeBuffer("vertex", GL_FLOAT, 0, 3);
你确实是说每 3 个浮点数都被解释为 1 个属性。因此,要绘制,您需要调用:
glDrawArrays(GL_TRIANGLES, 0, grid.size()/3);
注意。在我看来 vbo.size() 给你的是 vbo 对象中的字节数,而不是缓冲区中的元素数
到目前为止,我已经尝试将近两周让 VBO 在 Qt 环境中工作,但到目前为止没有任何效果。我的目标是创建一个三角形网格以用作某些地形的基础,就像在 Lighthouse3D 教程中那样。我程序的相关部分如下:
GameWindow.h
class GameWindow : public QOpenGLWidget, protected QOpenGLFunctions_3_3_Core
{
Q_OBJECT
public:
GameWindow(QWidget *parent = 0);
~GameWindow();
protected:
virtual void initializeGL() override;
virtual void resizeGL(int width, int height) override;
virtual void paintGL() override;
QGLShaderProgram *shaderProgram;
private:
int frame;
std::vector<GLfloat> grid;
QOpenGLBuffer vbo;
GLuint vboId;
QVector3D position;
};
GameWindow.cpp
GameWindow::GameWindow(QWidget *parent) :
QOpenGLWidget(parent),
position(QVector3D(0, 5, -5)),
vbo(QOpenGLBuffer(QOpenGLBuffer::VertexBuffer))
{}
GameWindow::~GameWindow()
{}
void GameWindow::initializeGL()
{
QOpenGLWidget::initializeGL();
initializeOpenGLFunctions();
shaderProgram = new QGLShaderProgram(QGLContext::currentContext());
QGLShader vertex(QGLShader::Vertex);
vertex.compileSourceFile(QDir(":/shaders").absoluteFilePath("basic.vert"));
shaderProgram->addShader(&vertex);
QGLShader fragment(QGLShader::Fragment);
fragment.compileSourceFile(QDir(":/shaders").absoluteFilePath("basic.frag"));
shaderProgram->addShader(&fragment);
shaderProgram->link();
QImage image;
image.load("C:\test.png");
int width = image.width(); //=10
int height = image.height(); //=10
for (int i = 0; i < height-1; i++) {
for (int j = 0; j < width-1; j++) {
grid.push_back(GLfloat(j));
grid.push_back(GLfloat(0.0f));
grid.push_back(GLfloat(i));
grid.push_back(GLfloat(j));
grid.push_back(GLfloat(0.0f));
grid.push_back(GLfloat(i+1));
grid.push_back(GLfloat(j+1));
grid.push_back(GLfloat(0.0f));
grid.push_back(GLfloat(i+1));
grid.push_back(GLfloat(j+1));
grid.push_back(GLfloat(0.0f));
grid.push_back(GLfloat(i+1));
grid.push_back(GLfloat(j+1));
grid.push_back(GLfloat(0.0f));
grid.push_back(GLfloat(i));
grid.push_back(GLfloat(j));
grid.push_back(GLfloat(0.0f));
grid.push_back(GLfloat(i));
}
}
vbo.create();
vbo.bind();
vbo.allocate(grid.size()*sizeof(GLfloat));
vbo.write(0, grid.data(), grid.size()*sizeof(GLfloat));
vbo.release();
/*
glGenBuffers(1, &vboId);
glBindBuffer(GL_ARRAY_BUFFER, vboId);
glBufferData(GL_ARRAY_BUFFER, grid.size() * sizeof(GLfloat), grid.data(), GL_STATIC_DRAW);
//*/
std::cout << std::boolalpha << (glGetError() == GL_NO_ERROR) << std::endl;
}
void GameWindow::resizeGL(int width, int height)
{
QOpenGLWidget::resizeGL(width, height);
}
void GameWindow::paintGL()
{
shaderProgram->bind();
QMatrix4x4 projection;
projection.perspective(45, qreal(width())/qreal(height() > 0 ? height() : 1), 0.1f, 100.0f);
QMatrix4x4 view;
view.lookAt(position, QVector3D(0, 0, 0), QVector3D(0, 1, 0));
QMatrix4x4 model;
model.translate(-0.5f, 0, 0);
QMatrix4x4 mvp;
mvp = projection * view * model;
shaderProgram->setUniformValue("matrix", mvp);
glClear(GL_COLOR_BUFFER_BIT);
vbo.bind();
shaderProgram->enableAttributeArray("vertex");
shaderProgram->setAttributeBuffer("vertex", GL_FLOAT, 0, 3);
glDrawArrays(GL_TRIANGLES, 0, vbo.size());
shaderProgram->disableAttributeArray("vertex");
/*
glBindBuffer(GL_ARRAY_BUFFER, vboId);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3, 0);
glDrawArrays(GL_TRIANGLES, 0, grid.size());
glDisableVertexAttribArray(0);
*/
shaderProgram->release();
update();
}
着色器
//Vertex Shader
attribute vec3 vertex;
uniform mat4 matrix;
varying vec3 pos;
void main(void)
{
gl_Position = matrix * vec4(vertex, 1);
pos = vertex;
}
//Fragment Shader
void main(void)
{
gl_FragColor.rgb = pos;
}
最后我像这样打开 window:
QSurfaceFormat format;
format.setVersion(3, 3);
format.setProfile(QSurfaceFormat::CoreProfile);
format.setSamples(4);
QSurfaceFormat::setDefaultFormat(format);
GameWindow *w = new GameWindow();
w->show();
在 运行 运行这个程序后,我得到了类似的东西,虽然它经常变化:
正如您从代码中看到的那样,我尝试使用 QOpenGLBuffer
和原始 gl*
命令创建和绘制我的 VBO,结果相似。 Google 没有任何帮助,所以现在我向您寻求帮助。我的 VBO 出了什么问题,为什么数据损坏了?
注:
当我 运行 我在标准输出中得到这个错误:
[opengl\qopenglframebufferobject.cpp line 565] OpenGL Error: 1286
QOpenGLFramebufferObject: Unsupported framebuffer format.
QOpenGLFramebufferObject: Unsupported framebuffer format.
[opengl\qopenglframebufferobject.cpp line 720] OpenGL Error: 1280
不过不知道跟这个有没有关系
注2:
尝试使用 vbo.read()
会使我的程序崩溃。
在 Qt 中,OpenGL 操作只有在 makeCurrent
… doneCurrent
块或 …GL
方法中才有效。在这两个前提条件都不满足的情况下,没有可以在其上创建 VBO 的 OpenGL 活动。
解决方案:将您的 OpenGL 初始化代码从构造函数移至 initializeGL
。
当您发出此命令时:
shaderProgram->setAttributeBuffer("vertex", GL_FLOAT, 0, 3);
你确实是说每 3 个浮点数都被解释为 1 个属性。因此,要绘制,您需要调用:
glDrawArrays(GL_TRIANGLES, 0, grid.size()/3);
注意。在我看来 vbo.size() 给你的是 vbo 对象中的字节数,而不是缓冲区中的元素数