当前位置: 首页 > news >正文

Horse3D引擎研发记录(二):基于QtOpenGL使用仿Three.js的BufferAttribute结构重构三角形绘制

在Horse3D引擎的研发过程中,我们致力于构建一个高效、灵活且易于扩展的3D图形引擎。在本篇博客中,我们将详细记录如何基于QtOpenGL框架,使用仿Three.js的BufferAttribute结构,重构三角形绘制流程。通过这一过程,我们希望能够实现更高效的顶点数据管理,并为后续的3D模型渲染打下坚实的基础。


一、背景与目标

在3D图形渲染中,顶点数据的管理是一个核心问题。传统的顶点数据管理方式通常直接使用OpenGL提供的API(如glBufferData)来操作顶点缓冲对象(VBO)。然而,随着引擎复杂度的提升,我们需要一种更灵活、更高效的顶点数据管理方式。

Three.js作为WebGL领域的一个优秀框架,其BufferAttribute结构为我们提供了一个很好的参考。通过仿Three.js的BufferAttribute结构,我们希望能够实现以下目标:

  1. 封装顶点数据管理:将顶点数据的创建、绑定和更新封装到一个类中,简化OpenGL的使用。
  2. 提高代码复用性:通过统一的接口管理顶点数据,降低代码冗余。
  3. 支持更复杂的3D模型渲染:为后续的3D模型渲染提供更灵活的顶点数据管理能力。

二、Three.js中的BufferAttribute

在Three.js中,BufferAttribute类用于管理顶点属性数据,如顶点坐标、法线、纹理坐标等。它封装了WebGL缓冲区对象的创建和管理,使得开发者可以更方便地处理顶点数据。

BufferAttribute的主要功能包括:

  1. 数据存储:使用TypedArray(如Float32Array)存储顶点数据。
  2. 缓冲区管理:封装了WebGL缓冲区对象的创建、绑定和数据上传。
  3. 数据更新:支持动态更新顶点数据,适用于动画或实时变化的场景。
  4. 内存管理:提供方法释放缓冲区资源,避免内存泄漏。

通过BufferAttribute,Three.js实现了高效的顶点数据管理,使得开发者可以专注于场景构建,而不必过多关注底层OpenGL的实现细节。


三、Horse3D引擎中的BufferAttribute实现

在Horse3D引擎中,我们仿照Three.js的BufferAttribute结构,创建了一个类似的C++类。通过这种方式,我们实现了对顶点数据的高效管理和复用。

1. BufferAttribute类的设计与实现

BufferAttribute类主要用于管理顶点数据的缓冲区。其核心功能包括顶点缓冲对象(VBO)的创建、绑定以及顶点属性指针的设置。

class BufferAttribute {
private:std::vector<float> m_data;GLuint m_vbo;unsigned int m_position;unsigned int m_dimension;public:BufferAttribute(std::vector<float> data, unsigned int position, unsigned int dimension): m_data(data), m_position(position), m_dimension(dimension){}void createOpenGLState(IScreen* screen) {screen->glGenBuffers(1, &m_vbo);screen->glBindBuffer(GL_ARRAY_BUFFER, m_vbo);screen->glBufferData(GL_ARRAY_BUFFER, m_data.size() * sizeof(float), m_data.data(), GL_STATIC_DRAW);screen->glVertexAttribPointer(m_position, m_dimension, GL_FLOAT, false, m_dimension * sizeof(float), nullptr);screen->glEnableVertexAttribArray(m_position);}
};
  • 构造函数:初始化顶点数据、位置(顶点属性索引)和维度(顶点属性的分量个数)。
  • createOpenGLState方法:负责创建OpenGL状态,包括VBO的生成、绑定、数据上传以及顶点属性指针的设置。

2. IScreen类的设计与实现

IScreen类继承自QOpenGLWidgetQOpenGLFunctions_4_5_Core,并提供了统一的接口用于管理OpenGL上下文。

class IScreen : public QOpenGLWidget, public QOpenGLFunctions_4_5_Core {
public:IScreen(QWidget* parent = nullptr): QOpenGLWidget(parent){// 初始化OpenGL函数initializeOpenGLFunctions();}virtual ~IScreen() = default;virtual void initializeGL() = 0;virtual void paintGL() = 0;virtual void resizeGL(int w, int h) = 0;
};
  • 构造函数:初始化OpenGL函数,确保OpenGL上下文可用。
  • initializeGL方法:初始化OpenGL环境,创建和绑定顶点数组对象(VAO)及顶点缓冲对象(VBO)。
  • paintGL方法:执行渲染操作,绘制几何体。
  • resizeGL方法:处理窗口大小变化,调整视口。

3. FerghanaScreen类的设计与实现

FerghanaScreen类继承自IScreen,并实现了具体的渲染逻辑。

class FerghanaScreen : public IScreen {
private:GLuint VAO; // 顶点数组对象BufferAttribute* bufferAttribute;public:FerghanaScreen(QWidget* parent = nullptr): IScreen(parent){// 三角形的三个顶点static const std::vector<GLfloat> vertices = {-0.5f, -0.5f, 0.0f,0.5f, -0.5f, 0.0f,0.0f,  0.5f, 0.0f};bufferAttribute = new BufferAttribute(vertices, 0, 3);}~FerghanaScreen() {delete bufferAttribute;}protected:void initializeGL() override {// 初始化OpenGL环境glClearColor(0.2f, 0.3f, 0.3f, 1.0f);// 创建并绑定顶点数组对象glGenVertexArrays(1, &VAO);glBindVertexArray(VAO);// 调用BufferAttribute的createOpenGLState方法bufferAttribute->createOpenGLState(this);// 解绑顶点数组对象glBindVertexArray(0);}void paintGL() override {// 清除颜色缓冲区glClear(GL_COLOR_BUFFER_BIT);// 绑定顶点数组对象并绘制glBindVertexArray(VAO);glDrawArrays(GL_TRIANGLES, 0, 3);glBindVertexArray(0);}void resizeGL(int w, int h) override {// 调整视口glViewport(0, 0, w, h);}
};
  • 构造函数:初始化顶点数据,并创建BufferAttribute对象。
  • initializeGL方法:初始化OpenGL环境,创建并绑定顶点数组对象(VAO),并调用BufferAttributecreateOpenGLState方法。
  • paintGL方法:执行渲染操作,绘制三角形。
  • resizeGL方法:处理窗口大小变化,调整视口。

四、代码优化与改进

在实现过程中,我们发现以下几点可以进一步优化:

  1. 顶点数组对象(VAO)的管理:

    • BufferAttribute类中,可以进一步封装VAO的管理,使其与VBO的管理更加统一。
    • 通过VAO的管理,可以进一步提高渲染效率。
  2. 顶点数据的动态更新:

    • 当前实现中,顶点数据是静态的。未来可以支持动态顶点数据的更新,例如通过glBufferSubData方法实现局部更新。
  3. 内存管理:

    • BufferAttribute类中,可以使用智能指针(如std::unique_ptr)来管理内存,避免内存泄漏。
  4. 批处理渲染:

    • 为了提高渲染效率,可以考虑将多个几何体的顶点数据合并到一个VBO中,实现批处理渲染。

五、总结与展望

通过本次重构,我们成功地将顶点数据的管理封装到BufferAttribute类中,实现了更高效的顶点数据管理。同时,通过FerghanaScreen类的实现,我们完成了三角形的绘制流程。

在未来的工作中,我们将继续优化BufferAttribute类的功能,支持更多类型的顶点数据(如法线、纹理坐标等),并为后续的3D模型渲染打下坚实的基础。同时,我们也将探索更多OpenGL的高级功能,进一步提升引擎的性能和功能。

http://www.lryc.cn/news/613890.html

相关文章:

  • 技术融合赋能文旅元宇宙:虚实共生重构产业新生态
  • 天翼云与飞轮科技达成战略合作,共筑云数融合新生态
  • Web 图像捕获革命:ImageCapture API 全面解析与实战指南
  • 【昇腾】基于RK3588 arm架构Ubuntu22.04系统上适配Atlas 200I A2加速模块安装EP模式下的驱动固件包_20250808
  • 新手向:Python实现图片转ASCII艺术
  • 《Leetcode》-面试题-hot100-链表
  • 从深度伪造到深度信任:AI安全的三场攻防战
  • 【杂谈】-逆缩放悖论:为何更多思考会让AI变“笨“?
  • 从C学C++(8)——友元
  • VScode 文件标签栏多行显示
  • Wegame 界面英雄联盟进不去游戏,打不开,LOL登陆错误码7620296等解决办法
  • 实战:在已有K8S集群如何新增和删除Node节点
  • 汽车零部件深孔加工质控升级:新启航激光频率梳 3D 测量解决传统光学扫描遮挡
  • 登录注册前端详细实现 (Angular 15+)
  • 5.0.9 C# wpf通过WindowsFormsHost嵌入winform控件
  • (第二篇)spring cloud之Eureka注册中心
  • 【射频 PCB 设计】从芯片到天线的 50 Ω 之路:微带线、CPWG、匹配
  • 应用层自定义协议
  • 相机Camera日志实例分析之十:相机Camx【萌拍调节AE/AF拍照】单帧流程日志详解
  • LeetCode 面试经典 150_数组/字符串_加油站(14_134_C++_中等)(贪心算法)
  • 力扣 hot100 Day69
  • GISBox私有云+SaaS:安全协同的地理智能平台
  • C++-->stl: list的使用
  • 《Java枚举类深度解析:定义与实战应用》
  • 一洽客服系统:APP路由等级与路由条件设置
  • SITIME汽车时钟发生器Chorus保障智能汽车安全
  • 【MATLAB技巧】打开脚本(m文件)后,中文乱码的解决方案
  • TensorFlow深度学习实战(29)——自监督学习(Self-Supervised Learning)
  • element plus table 表格操作列根据按钮数量自适应宽度
  • 宝龙地产债务化解解决方案二:基于资产代币化与轻资产转型的战略重构