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 操作只有在 makeCurrentdoneCurrent 块或 …GL 方法中才有效。在这两个前提条件都不满足的情况下,没有可以在其上创建 VBO 的 OpenGL 活动。

解决方案:将您的 OpenGL 初始化代码从构造函数移至 initializeGL

当您发出此命令时:

shaderProgram->setAttributeBuffer("vertex", GL_FLOAT, 0, 3);

你确实是说每 3 个浮点数都被解释为 1 个属性。因此,要绘制,您需要调用:

glDrawArrays(GL_TRIANGLES, 0, grid.size()/3);

注意。在我看来 vbo.size() 给你的是 vbo 对象中的字节数,而不是缓冲区中的元素数