WebGL2D渲染引擎

🧱 WebGL2 2D 渲染引擎技术文档

基于模块化设计 + gl-matrix + WebGL2 的高性能 2D 图形渲染系统

支持:点、线段、矩形、圆形、多边形、圆弧 绘制,支持缩放、平移、自由绘图交互


📋 模块职责总览

模块名 核心职责 依赖模块 生命周期
CanvasCore(核心入口) 1. 获取 WebGL 上下文 2. 管理画布清空(clear) 3. 驱动渲染循环(requestAnimationFrame) 4. 协调 View 与 Renderer 执行 View, Renderer2D 初始化 1 次 + 每帧执行
View(视口与矩阵) 1. 设置视口尺寸 2. 管理视图矩阵(viewMatrix) 3. 管理正交投影矩阵(projectionMatrix) 4. 支持平移、缩放变换 无(依赖 canvas 尺寸) 初始化 1 次 + resize 时更新 + 每帧复用
ShaderProgram(着色器管理) 1. 编译顶点/片段着色器 2. 链接 WebGLProgram 3. 缓存 attribute/uniform 位置 4. 提供 ProgramInfo 接口 无(仅依赖 gl) 初始化 1 次(每个着色器程序)
GLBuffer(VBO/EBO 封装) 1. 创建 VBO(顶点数据)或 EBO(索引数据) 2. 上传数据到 GPU 3. 绑定/解绑缓冲区 无(依赖 gl) 每个 RenderGeometry 对应 1~2 个,初始化 1 次
VertexArray(VAO 封装) 1. 创建和绑定 VAO 2. 配置顶点属性布局(attribute → VBO) 3. 自动启用/禁用 attribute GLBuffer 每个 RenderGeometry 对应 1 个,初始化 1 次
RenderGeometry(图形数据生成) 1. 根据类型生成顶点数据(position) 2. 生成索引数据(indices) 3. 支持点、线、矩形、圆、多边形、圆弧等 无(纯数据生成类) 每次绘制新图形时创建 1 个
Event(交互事件) 1. 监听鼠标事件(点击、拖拽、滚轮) 2. 实现缩放(zoom)、平移(pan) 3. 在 isdrawing 模式下驱动 RenderGeometry 生成 View, RenderGeometry 初始化 1 次 + 交互时动态触发
Renderer2D(2D 渲染执行) 1. 激活着色器程序 2. 遍历 RenderGeometry 列表 3. 创建/复用 VAO + VBO 4. 设置 uniforms(矩阵、颜色) 5. 调用 drawElements 绘制 ShaderProgram, VertexArray, GLBuffer, RenderGeometry 每帧执行

⏳ 三大执行阶段详解

1. 初始化阶段(仅一次)

js 复制代码
// main.js 中执行顺序
const view = new View();                    // → 初始化视口与投影矩阵
const shaderProgram = new ShaderProgram(gl); // → 编译着色器,生成 ProgramInfo
const renderer2D = new Renderer2D(gl, shaderProgram); // → 准备渲染器
const canvasCore = new CanvasCore('canvas'); // → 获取 gl 上下文
canvasCore.init(view, renderer2D);           // → 启动渲染循环
const event = new Event(canvas, view, renderer2D, geometryList); // → 绑定交互

关键行为:

  • WebGL 上下文建立
  • 着色器编译与链接
  • 默认视图矩阵初始化(正交投影)
  • 事件监听器注册(鼠标、滚轮)

2. 渲染循环阶段(每帧执行)

js 复制代码
// CanvasCore.renderLoop → renderFrame → Renderer2D.render
canvasCore.renderFrame = () => {
  resizeCanvasToDisplaySize(canvas);        // 自动适配高清屏
  view.setViewport(canvas.width, canvas.height); // 更新视口
  canvasCore.clear();                       // 清空画布
  renderer2D.render(view);                  // 执行绘制
};

每帧流程:

步骤 模块 说明
1 CanvasCore 检测 canvas 尺寸变化,自动调整 viewport
2 View 若尺寸变化,重新计算 projectionMatrix
3 Renderer2D 遍历所有 RenderGeometry,绘制每个图形
4 VertexArray + GLBuffer 复用已创建的 VAO/VBO,避免重复上传数据
5 ShaderProgram 设置 uniform:u_viewMatrix, u_projectionMatrix, u_color

🔁 使用 requestAnimationFrame 循环驱动,确保流畅动画


3. 交互阶段(事件驱动)

js 复制代码
// Event 模块监听
canvas.addEventListener('mousedown', ...)   // 开始绘图
canvas.addEventListener('mousemove', ...)   // 动态生成图形预览
canvas.addEventListener('mouseup', ...)     // 结束并提交图形
canvas.addEventListener('wheel', ...)       // 缩放
canvas.addEventListener('contextmenu', ...) // 右键平移(模拟)

交互行为:

事件 行为
mousedown + drawingType set 开启 isdrawing = true,记录起点
mousemove 实时计算图形参数,临时生成 RenderGeometry 并加入列表
mouseup 结束绘制,提交图形,isdrawing = false
wheel 以鼠标为中心缩放,更新 View.zoom()
mousemove + 右键按下 触发 View.pan() 实现平移

💡 所有交互最终通过修改 View 矩阵 或 向 geometryList 添加新 RenderGeometry 来影响下一帧渲染


🧩 关键模块代码说明与设计亮点

View:使用 gl-matrix 管理变换

js 复制代码
import { mat4 } from 'gl-matrix';

this.projectionMatrix = mat4.create();
this.viewMatrix = mat4.create();

// 正交投影:适合 2D 场景
mat4.ortho(this.projectionMatrix, -w, w, -h, h, -1, 1);

// 支持以某点为中心缩放(如鼠标位置)
mat4.translate(this.viewMatrix, this.viewMatrix, [centerX, centerY, 0]);
mat4.scale(this.viewMatrix, this.viewMatrix, [this.scale, this.scale, 1]);
mat4.translate(this.viewMatrix, this.viewMatrix, [-centerX, -centerY, 0]);

📌 优势: 精确控制缩放中心,避免"缩放偏离鼠标"问题


RenderGeometry:支持多种图形生成

类型 数据生成方式
point [x, y]
line [x0,y0, x1,y1] + indices [0,1]
rect 四个角点 + 闭合索引 [0,1,2,3,0]
circle 极坐标生成 n 个点,连接成 LINE_STRIP
arc startAngle ~ endAngle 范围内采样
polygon 用户传入 points 数组,自动生成索引

📌 设计亮点: 解耦"数据生成"与"渲染",便于扩展(如添加贝塞尔曲线)


Renderer2D:VAO/VBO 缓存优化

js 复制代码
this.buffers = new WeakMap();  // geometry → GLBuffer
this.vaos = new WeakMap();     // geometry → VertexArray

📌 性能优化:

  • 首次绘制时创建 VAO/VBO
  • 后续复用,避免每帧重新上传顶点数据
  • 使用 WeakMap 自动随 RenderGeometry 被回收

Event:支持多种绘图模式切换

js 复制代码
window.startRect = () => event.setDrawingMode('rect');
window.startLine = () => event.setDrawingMode('line');

📌 用户可通过按钮切换绘图模式,临时生成预览图形,提升交互体验


CanvasCore:自动适配高清屏(Retina)

js 复制代码
function resizeCanvasToDisplaySize(canvas) {
  const dpr = window.devicePixelRatio || 1;
  const displayWidth = canvas.clientWidth * dpr;
  const displayHeight = canvas.clientHeight * dpr;
  if (canvas.width !== displayWidth || canvas.height !== displayHeight) {
    canvas.width = displayWidth;
    canvas.height = displayHeight;
    gl.viewport(0, 0, canvas.width, canvas.height);
  }
  return true;
}

📌 关键: 不依赖 CSS 尺寸,确保清晰渲染


📐 架构关系图(文字版)

scss 复制代码
[Event] ←→ [View] (缩放/平移)
             ↓
         [Renderer2D] ←→ [ShaderProgram] (着色器)
             ↓
         [RenderGeometry] → [GLBuffer] → [VertexArray]
             ↓
        [CanvasCore] → requestAnimationFrame → 渲染循环
             ↓
          WebGL Context

所有模块通过 gl 上下文连接,数据流清晰,职责分明


✅ 总结:系统优势

特性 实现方式
🚀 高性能 VAO/VBO 缓存、避免重复上传
🖱️ 高交互性 支持绘图、缩放、平移、预览
🧱 模块化 各模块独立,易于维护与扩展
📐 精确变换 gl-matrix 支持专业矩阵运算
🖥️ 响应式 自动适配 canvas 尺寸与 DPI
🔌 可扩展 易添加新图形类型、新着色器、新交互

🛠️ 后续可扩展方向

  1. 图形编辑:点击选中图形并拖拽调整
  2. 图层系统:支持 zIndex、可见性控制
  3. 纹理支持:为矩形添加图片贴图
  4. 批量渲染 :使用 gl.drawArraysInstanced 绘制大量相同图形
  5. 撤销/重做 :维护 geometryList 历史栈
  6. 导出 SVG / JSON:序列化图形数据

相关推荐
goodName1 天前
如何实现精准操控?Cesium模型移动旋转控件实现
webgl·cesium
丫丫7237344 天前
Three.js 模型树结构与节点查询学习笔记
javascript·webgl
allenjiao6 天前
WebGPU vs WebGL:WebGPU什么时候能完全替代WebGL?Web 图形渲染的迭代与未来
前端·图形渲染·webgl·threejs·cesium·webgpu·babylonjs
mapvthree7 天前
mapvthree Engine 设计分析——二三维一体化的架构设计
webgl·数字孪生·mapvthree·jsapi2d·jsapigl·引擎对比
GISer_Jing8 天前
3D Cesium渲染架剖析
javascript·3d·webgl
Swift社区8 天前
用 Chrome DevTools 深度分析 Vue WebGL 内存泄漏(进阶篇)
vue.js·webgl·chrome devtools
GISer_Jing10 天前
3DThreeJS渲染核心架构深度解析
javascript·3d·架构·webgl
ThreePointsHeat10 天前
Unity 关于打包WebGL + jslib录制RenderTexture画面
unity·c#·webgl
GISer_Jing11 天前
Three.js核心技术解析:3D开发指南
javascript·3d·webgl