Skip to content

5 分钟接入 ​

本页从零创建一个会旋转、可点击的 Entity。Engine 只在调用 createEngine() 时访问浏览器与 WebGL;模块导入本身保持 SSR-safe。

1. 安装 ​

bash
pnpm add @tripo3d/engine three

three 由宿主提供,版本需满足 >=0.183.0。

2. 创建 Engine ​

ts
import { createEngine } from '@tripo3d/engine';

const engine = createEngine();

Engine 已创建并暴露:

  • engine.canvas:Engine 唯一拥有的 Canvas;
  • engine.renderer:原生 WebGLRenderer;
  • engine.world / engine.view / engine.camera:默认 World、全屏 View 与透视 Camera;
  • engine.pipeline / engine.pointer:管线和鼠标事件控制面。

此时帧循环尚未启动。

默认 Canvas antialias 与 Pipeline 离屏 samples 都关闭。需要抗锯齿时,可按画质与性能要求显式启用 FXAA 或离屏 MSAA;两项设备配置彼此独立。

3. 接纳 Object3D 子树 ​

ts
import {
  AmbientLight,
  BoxGeometry,
  DirectionalLight,
  Group,
  Mesh,
  MeshStandardMaterial,
} from 'three';

const root = new Group();
const cube = new Mesh(
  new BoxGeometry(),
  new MeshStandardMaterial({ color: 0x4f8cff }),
);
root.add(cube, new AmbientLight(0xffffff, 1.5));

const keyLight = new DirectionalLight(0xffffff, 3);
keyLight.position.set(2, 3, 4);
root.add(keyLight);

// 一次性为 root 的完整 Object3D 子树建立 Entity binding。
const rootEntity = engine.createEntity(root);
engine.world.root.add(rootEntity);

const cubeEntity = engine.getEntity(cube)!;

createEntity(root) 要求 root.parent === null,并全量绑定整棵子树。接纳后,层级变化只通过 Entity.add/remove/attach/clear/removeFromParent 完成;不要再直接调用原生 Object3D.add/remove/attach。

4. 添加 Component、System 与 Script ​

ts
import {
  createComponent,
  createEvent,
  createScript,
  createSystem,
} from '@tripo3d/engine';

const Rotation = createComponent('rotation-speed', ({ entity, onDestroy }) => {
  const state = { speed: 1 };
  const name = entity.object.name;
  onDestroy(() => console.log(`${name} rotation state removed`));
  return state;
});
const selected = createEvent<string>('selected');

const SpinSystem = createSystem('spin', ({ engine, onUpdate }) => {
  const query = engine.world.createQuery(Rotation);

  onUpdate(({ delta }) => {
    query.forEach((entity) => {
      entity.object.rotation.y += entity.getComponent(Rotation)!.speed * delta;
    });
  });
}, { order: 0 });

const Selectable = createScript('selectable', ({ emitEvent, entity, onDestroy }) => {
  const off = entity.onPointer('click', () => {
    emitEvent(selected, entity.object.name);
  });
  onDestroy(off);
});

cube.name = 'Cube';
const rotation = cubeEntity.addComponent(Rotation);
rotation.speed = 1.2;
cubeEntity.addScript(Selectable);
engine.addSystem(SpinSystem);
engine.onEvent(selected, name => console.log('selected:', name));

Component、System 与 Script 都是同步 setup Definition。Component 为每个 Entity 建立局部状态并通过 onDestroy 持有 cleanup;System 服务整个 Engine;Script 服务一个 Entity。addComponent() 直接返回 setup 创建的原始对象,因此可以立即配置它。

5. 放入 DOM 并启动 ​

ts
const host = document.querySelector<HTMLElement>('#app')!;
host.append(engine.canvas);
engine.start();

// 暂停但保留场景和 GPU 资源:
engine.stop();

// 再次测量 Canvas 并继续:
engine.start();

// 最终释放:
engine.dispose();

Engine 使用 Canvas 的 CSS content-box 作为逻辑尺寸来源。请给 host 与 Canvas 可测量的宽高;Engine 会处理 renderer、内部 Composer、默认 Camera aspect 与 DPR。

dispose() 是不可逆终态。它会销毁所有 Entity,并释放接纳子树的标准 geometry、material、direct texture 与 skeleton 资源;业务创建且借给 Pipeline 的 Camera 和原生 Pass 仍由业务释放。

下一步 ​

基于 MIT 协议发布(内部使用)