当前位置: 首页 > 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.dtcms.com/a/321562.html

相关文章:

  • 复数的复平面加减乘除运算与在极坐标中的运算对应关系
  • 算法训练之栈
  • provide 和 inject 最佳实践
  • 多任务实时进度监控系统:基于ABP vNext与SignalR的架构实践
  • [激光原理与应用-175]:测量仪器 - 频谱型 - 拉曼光谱仪的工作原理、内部组成、核心芯片、核心算法
  • 项目一系列-第3章 若依框架入门
  • Java中的方法引用操作符(::)详解与实战应用
  • “A flash of inspiration“, protect us from prompt injection?
  • 实习的收获
  • 【Jmeter】设置线程组运行顺序的方法
  • 安装部署K8S集群环境(实测有效版本)
  • 复杂姿态漏检率↓79%!陌讯多模态算法在安全带穿戴识别的落地实践
  • Node.js Turbo 包入门教程
  • web端-登录页面验证码的实现(springboot+vue前后端分离)超详细
  • (Arxiv-2025) CINEMA:通过基于MLLM的引导实现多主体一致性视频生成
  • 基于Jeecgboot3.8.1的flowable流程审批人与发起人相同设置-前端部分
  • Vue2与Vue3 Hooks对比:写法差异与演进思考
  • 【3d61638 渍韵】001 png pdf odt 5与明天各种号(虚拟文章スミレ数据)
  • PDF处理控件Aspose.PDF教程:使用 C#、Java 和 Python 代码调整 PDF 页面大小
  • 以rabbitmq为例演示podman导出导入镜像文件
  • kafka 为什么需要分区?分区的引入带来了哪些好处
  • Kafka + 时间轮 + 数据库实现延迟队列方案
  • 前端开发:JavaScript(7)—— Web API
  • 机器学习视角下的黄金市场动态:3400美元关口的多因子驱动机制
  • Seata分布式事务环境搭建
  • Access开发右下角浮窗提醒
  • RS485转Profibus网关在QDNA钠离子分析仪与S7-300PLC系统集成中的应用
  • 深入解析K-means聚类:从原理到调优实战
  • 基于STM32F030C8T6单片机实现与CH224Q诱骗芯片的I2C通信和电压输出配置
  • 9:USB摄像头的最后一战(上):MP4音视频合封!