架构总览
@tripo3d/engine 是构建于 Three.js 之上、以 ECS + 系统 + 插件 为核心的 3D 运行时。它把 Three.js 的命令式 API 切分成若干可插拔子系统,通过一个 Engine 聚合对象暴露给宿主代码(Vue 组件、业务逻辑)。
一图概览
createEngine(options)工厂函数,返回聚合后的 Engine 实例viewThree.js 场景、相机、渲染器容器worldECS 世界(Entity / Component / Script)pipeline多阶段渲染管线(stage + pass)pointer基于 raycaster 的指针系统events类型化事件总线historyCommand 式 undo/redolifecycle生命周期总线(onUpdate / onBeforeRender ...)addSystem / use注册 System、安装 Plugin
五个抽象层次
1. View(视图层)
EngineView 对 Three.js 的 Scene、WebGLRenderer、Camera 做最小封装。createEngine 会:
- 根据
options.camera解析相机工厂(perspective/orthographic/ 自定义函数均可) - 根据
options.renderer构造 WebGLRenderer - 根据
options.scene或默认工厂创建 Scene
视图层本身是 被动的 —— 它只负责持有 Three.js 对象,不驱动渲染。真正的渲染由 pipeline 驱动。
2. ECS(实体层)
EngineWorld 把 Three.js 的 Object3D 包装成实体(Entity),并在此之上提供组件(Component)与脚本(Script)的附着能力。
- Component = 纯数据/工厂,描述「这个实体拥有什么」
- Script = 带生命周期钩子(onUpdate / onBeforeRender / onPointer ...)的逻辑块,描述「这个实体每帧做什么」
- Query = 按 Component 组合查询实体,命中最小候选集后过滤
详见 ECS。
3. System(系统层)
System 是 engine 范围的单例状态机,与特定实体无关。典型职责:
- 封装某种 Three.js 插件(
OrbitControls、TransformControls、ViewportGizmo) - 提供跨实体的统一能力(模型加载、材质切换、性能监控)
- 持有可被其他 System 读/改的共享状态
每个 System 通过 createSystem(name, setup) 定义,在 setup 里订阅生命周期钩子、暴露公共方法。详见 插件系统 与 createEngine。
4. Pipeline(渲染管线)
EnginePipeline 把每一帧的渲染切成若干 stage,每个 stage 内部再注册若干 pass。默认只有一个 'main' stage(等价于 renderer.render(scene, camera))。需要后处理、辉光、gizmo 图层时,在 'main' 之前/之后插入新 stage 即可。详见 渲染管线。
5. Services(横向服务)
- EventBus:类型化
on/off/emit,不带通配符。业务层自己定义事件名 - CommandHistory:通用
redo()/undo()命令对,支持事务批量 - LifecycleController:生命周期总线,统一分发
onInit / onEnable / onUpdate / onBeforeRender / onAfterRender / onResize / onDispose - Pointer:鼠标/触控事件 → raycaster 命中测试 → 事件派发到实体链
帧循环
每帧 engine.renderFrame(time) 的内部顺序:
lifecycle.onUpdate(frame)脚本/系统的 onUpdate、onLateUpdatepipeline.render(frame)逐个 stage 调用 pass.render,触发 onBeforeRender / onAfterRender
每个生命周期阶段内部都按 优先级数字(order) 排序后再执行——数字越小越先跑,并列则按注册顺序。
Plugin(插件)
插件是跨 System 的横切关注点。它在 engine 级别只安装一次,但可以:
- 改写每个新创建 System 的实例(
onSystemCreated) - 改写每个新创建 Component 的实例(
onComponentCreated) - 改写每个新创建 Script 的实例(
onScriptCreated) - 在 engine 销毁时清理(
dispose)
最典型的例子是 createPluginVue——把所有 Component/Script/System 实例包一层 shallowReactive,让 Vue 模板能直接响应 ECS 状态变化。
生命周期快览
1. createEngine(options)工厂实例化子系统,执行 options.plugins / options.systems2. engine.use(plugin)安装插件(触发 plugin.setup)3. engine.addSystem(def)注册 System,执行 setup,订阅生命周期4. engine.mount(target)挂载 canvas 到 DOM,启动 requestAnimationFrame5. 每帧: lifecycle.onUpdate → pipeline.render循环直到 unmount6. engine.unmount()断开 DOM 与 raf,但保留 state;可再次 mount7. engine.dispose()彻底释放:清空所有 system/plugin/world/pipeline/history/events
完整流程与代码示例见 createEngine。
如何选择抽象
| 需求 | 选哪个 |
|---|---|
| 描述一个实体「是什么」 | Component |
| 描述一个实体每帧的行为 | Script |
| 描述一个跨实体的能力(加载器、控件、gizmo) | System |
| 描述一个新渲染通道(辉光、描边、后处理) | Pipeline Pass |
| 向整个 engine 注入横切行为(响应式、埋点、错误捕获) | Plugin |
| 跨模块通信 | EventBus |
| 可撤销的用户操作 | CommandHistory |
下一步
- createEngine —— 最小可运行示例 + 所有 options
- ECS —— Entity / Component / Script / Query
- 插件系统 —— 自定义 Plugin & 内置 Vue 插件
- 渲染管线 —— Stage & Pass
- Vue 集成 ——
<EngineCanvas>&useEngine