Three.js renderer를 editor core 뒤에 붙이기
마지막으로 Three.js를 독립 renderer backend로 붙입니다. 핵심은 editor core가 Three.js를 몰라도 되게 만드는 것입니다.
adapter를 둔다
interface EditorRenderer {
sync(document: EditorDocument): void;
render(camera: EditorCamera): void;
dispose(): void;
}
Three.js backend는 이 인터페이스 뒤에서 Scene, Mesh, Material, WebGLRenderer를 관리합니다.
node id를 Object3D에 매핑한다
node id -> Object3D
node style -> Material
node geometry -> BufferGeometry
문서가 바뀔 때마다 scene 전체를 버리는 대신, node id별 cache를 갱신합니다. 삭제된 node는 Object3D와 GPU resource를 정리합니다.
backend 구현 뼈대
class ThreeEditorRenderer implements EditorRenderer {
private scene = new THREE.Scene();
private objects = new Map<string, THREE.Object3D>();
constructor(
private renderer: THREE.WebGLRenderer,
private canvas: HTMLCanvasElement
) {}
sync(document: EditorDocument) {
const ids = new Set(document.nodes.map((node) => node.id));
for (const node of document.nodes) {
const object = this.objects.get(node.id) ?? this.createObject(node);
this.objects.set(node.id, object);
this.syncObject(object, node);
}
for (const [id, object] of this.objects) {
if (ids.has(id)) continue;
this.scene.remove(object);
disposeObject(object);
this.objects.delete(id);
}
}
render(cameraState: EditorCamera) {
const camera = toThreeOrthographicCamera(cameraState, this.canvas);
this.renderer.render(this.scene, camera);
}
}
이 구조에서는 editor core가 THREE.Mesh를 만들지 않습니다. core는 문서 상태만 만들고, Three.js backend가 그 상태를 자신의 resource로 변환합니다.
오늘의 핵심
Three.js를 사용해도 editor architecture는 그대로입니다. core는 문서와 command를 소유하고, renderer backend는 pixels와 GPU resource를 소유합니다.