OpenGL:动态修改VBO/EBO

23 篇文章 4 订阅
18 篇文章 0 订阅

最近做的一个Demo,需要在运行过程中,支持切换模型,就是需要更改数据

自己OpenGL又没有系统的学过,水的一批,搞了好久就是不行

class GlWidget : public QOpenGLWidget, protected QOpenGLFunctions_3_3_Core
{
    Q_OBJECT
public:
    GlWidget(QWidget *parent);
    ~GlWidget()  Q_DECL_OVERRIDE;

    void LoadModel();

protected:
    //在第一次调用resizeGL()或paintGL()之前调用一次。
    void initializeGL() Q_DECL_OVERRIDE;
    //每当调整Widget的大小时(第一次显示窗口Widget时会调用它,因为所有新创建Widget都会自动获得调整大小的事件)。
    void resizeGL(int width, int height) Q_DECL_OVERRIDE;
    void paintGL() Q_DECL_OVERRIDE;//渲染OpenGL场景,需要更新Widget时就会调用。
    void mousePressEvent(QMouseEvent *event) Q_DECL_OVERRIDE;
    void mouseMoveEvent(QMouseEvent *event) Q_DECL_OVERRIDE;
    void mouseReleaseEvent(QMouseEvent *event) Q_DECL_OVERRIDE;
    void wheelEvent(QWheelEvent *event) Q_DECL_OVERRIDE;

上面重载的initializeGL函数主要是初始化,将一些不需要变动的模型数据绑定VAO

重载函数paintGL主要是不断刷新,这里也可以修改数据,但是加载模型放这里就不合适了,因为这里是不断刷新的地方,而模型加载的频率会很少,而且还要有按键触发

所以加载模型的函数是LoadModel,就是需要在这里修改数据,修改后数据随即同步到paintGL,paintGL实时刷新

我开始的LoadModel代码大概是这样:

//-------------从文件中读取模型数据存入动态数组-----------
    float* screen = new float[N];
    unsigned int* screen_idx = new unsigned int[M];

    //----------------------  screen  VAO ----------------------
    screenProgram.bind();//绑定着色器
    glGenVertexArrays(1, &screenVao);//生成VAO
    glBindVertexArray(screenVao);//绑定VAO

    glGenBuffers(1, &screenVbo);//生成VBO
    glBindBuffer(GL_ARRAY_BUFFER, screenVbo);///绑定VBO
    glBufferData(GL_ARRAY_BUFFER, N * sizeof(float), screen, GL_STATIC_DRAW);//往VBO填数据

    glGenBuffers(1, &screenEbo);//生成EBO
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, screenEbo);//绑定EBO
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, M * sizeof(unsigned int), screen_idx, GL_STATIC_DRAW);//往EBO填数据

    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), reinterpret_cast<void*>(0));
    glEnableVertexAttribArray(0);

    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(3 * sizeof(float)));
    glEnableVertexAttribArray(1);

    glBindVertexArray(screenVao);
    glDrawElements(GL_TRIANGLES, vbo_num, GL_UNSIGNED_INT, 0);
    screenProgram.release();

    delete[]screen;
    delete[]screen_idx;

这样就是不行,怎么试都不行,搞得一度怀疑是不是动态数组那里出问题了,后来又换成了向量

    //...
    QVector<float> screen;
    QVector<unsigned int> screen_idx;
    //...
    glBufferData(GL_ARRAY_BUFFER, N * sizeof(float), &screen[0], GL_STATIC_DRAW);
    //...
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, M * sizeof(unsigned int), &screen_idx[0], GL_STATIC_DRAW);

不行。

后来一位大佬的一段话启发了我opengl VAO VBO 理解误区修正_杂七杂八-CSDN博客

误区一:

给 VBO 赋予数据时,即 调用glBindBuffer(GL_ARRAY_BUFFER,vbo)
glBufferData(GL_ARRAY_BUFFER,sizeof(data),GL_STATIC_DRAW)
这两个函数时,需要事先 通过glBindVertexArray() 绑定到一个 VAO 上。

勘误:

实际上,glBufferData(),把 数组数据 写入 一个 vbo 时,完全没有必要绑定 glBindVertexArray() 一个 VAO.
道理也很简单:我要给一个 vbo 写入数据,其实并不关心 vao是哪个,跟我要写数据这件事完全没有关系!
只有在 把 vbo 的数据,真正传递到 shader 时候,也就是 调用 glVertexAttribPointer() 等针对 shader 的操作时(比如 glUseProgram,glEnableVertexAttribArray )时,才必须明确指定绑定到哪个 VAO 上.
在 glBufferData() 时,只是简答的给一个 vbo 传数据,跟 shader 无关,完全没有必要 bind 任何 VAO.

然后将主要代码修改为下:

    glBindBuffer(GL_ARRAY_BUFFER, screenVbo);
    glBufferData(GL_ARRAY_BUFFER, N * sizeof(float), screen, GL_STATIC_DRAW);

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, screenEbo);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, M * sizeof(unsigned int), screen_idx, GL_STATIC_DRAW);

    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), reinterpret_cast<void*>(0));
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(3 * sizeof(float)));
    glEnableVertexAttribArray(1);

 就是去掉了重新绑定VAO,因为这个VAO其实在初始化里已经绑定过了

也不需要重新再生成VAOVBOEBO之类的,因为也都有了,只需要绑定VBO/EBO,然后填数据就可以。

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值