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:序列化图形数据

相关推荐
GISer_Jing2 天前
WebGL跨端兼容实战:移动端适配全攻略
前端·aigc·webgl
Aurora@Hui5 天前
WebGL & Three.js
webgl
CC码码7 天前
基于WebGPU实现canvas高级滤镜
前端·javascript·webgl·fabric
ct9787 天前
WebGL 图像处理核心API
图像处理·webgl
ct9789 天前
Cesium 矩阵系统详解
前端·线性代数·矩阵·gis·webgl
ct97812 天前
WebGL Shader性能优化
性能优化·webgl
棋鬼王12 天前
Cesium(一) 动态立体墙电子围栏,Wall墙体瀑布滚动高亮动效,基于Vue3
3d·信息可视化·智慧城市·webgl
Longyugxq14 天前
Untiy的Webgl端网页端视频播放,又不想直接mp4格式等格式的。
unity·音视频·webgl
花姐夫Jun15 天前
cesium基础学习-坐标系统相互转换及相应的场景
学习·webgl
ct97815 天前
WebGL开发
前端·gis·webgl