InstancedMesh로 많은 rectangle 그리기
Figma-like editor에는 비슷한 rectangle이 많이 생깁니다. 같은 geometry와 material을 반복해서 쓴다면 InstancedMesh로 draw call을 줄일 수 있습니다.
하나의 mesh를 여러 transform으로 그린다
const mesh = new THREE.InstancedMesh(geometry, material, nodes.length);
nodes.forEach((node, index) => {
matrix.compose(node.position, node.quaternion, node.scale);
mesh.setMatrixAt(index, matrix);
});
mesh.instanceMatrix.needsUpdate = true;
rectangle geometry는 하나만 만들고, instance마다 matrix만 다르게 넣습니다.
rectangle 중심 기준 matrix를 만든다
PlaneGeometry(1, 1)처럼 중심이 원점인 unit rectangle을 쓰면, 각 instance matrix는 center position과 size scale로 만들 수 있습니다.
const tempMatrix = new THREE.Matrix4();
const position = new THREE.Vector3();
const quaternion = new THREE.Quaternion();
const scale = new THREE.Vector3();
function setRectInstance(mesh, index, rect) {
position.set(rect.x + rect.width / 2, -(rect.y + rect.height / 2), 0);
quaternion.setFromEuler(new THREE.Euler(0, 0, -rect.rotation));
scale.set(rect.width, rect.height, 1);
tempMatrix.compose(position, quaternion, scale);
mesh.setMatrixAt(index, tempMatrix);
}
raw WebGL instancing에서 instance buffer에 x y w h color를 넣었다면, Three.js에서는 instanceMatrix가 그 역할을 합니다.
node id 매핑을 유지한다
const instanceToNodeId = nodes.map((node) => node.id);
선택, hover, hit test 결과를 editor state로 돌려보내려면 instance index와 node id를 연결해야 합니다.
function nodeIdFromInstanceHit(hit, instanceToNodeId) {
if (hit.instanceId == null) return null;
return instanceToNodeId[hit.instanceId] ?? null;
}
instanceId는 renderer 내부 index입니다. document id로 바꾸는 테이블이 없으면 selection state를 안정적으로 만들 수 없습니다.
오늘의 핵심
InstancedMesh는 Three.js에서 batching을 시작하는 가장 현실적인 방법입니다. 하지만 editor interaction을 위해 instance id 관리가 같이 필요합니다.