threejs hierarchy gui 구현하기
기껏 mesh를 분리하였는데 사용자 입장에서 object가 분리된건지 geometry가 따로 노는건지 알 턱이 없다.
나도 그래서 hierarchy 기능을 빠르게 추가하고자 한다.
구현 방법에 대해서 알아보자.
hierarchy 기능의 경우 많은 곳에서 구현되어있을 것 같다.
좀 찾아보니 방법이 보편적으로 있는게 아니라 구현 방법마다 다른 것 같다.
그중 object.traverse를 사용하는 방법도 제안된다.
https://threejs.org/docs/#api/en/core/Object3D.traverse
Object3D traverse
traverse. 이름만 들어도 object 계층을 탐색하는 느낌이다.
매개변수로 function을 넣는데, object3d를 첫 번째 변수로 가진 함수?
역시 공식문서의 설명은 부실하다. 좀 더 찾아보자.
질의 응답을 보다보면 callback 으로 들어간 function은 object의 all of children마다 호출된다고 한다.
즉 호출되는 함수에서 children object를 매개변수로 받아 계층 내 모든 object들을 순회하며 특정 기능을 실행시키는 것이다.
이를 hierarchy로 적용한다고 생각하면, gui에 하위 element로 추가하는 함수를 모든 children object마다 실행시키는 것이다.
그럼 각 object가 어떤 object 밑에 있는지는 각 parent children를 통해 끼워 넣는 건가.
이건 실제로 구현한 코드를 보는게 좋을 것 같다.
lil gui (dat gui) 이용하기
lil gui(dat gui)를 이용해서 hierarchy를 한 번 구현 테스트해보자.
import * as THREE from 'three';
import * as dat from 'lil-gui';
class HierarchyUI {
private gui: dat.GUI;
constructor() {
this.gui = new dat.GUI({ title: 'Hierarchy' });
}
public buildHierarchy(object: THREE.Object3D): void {
this.gui.destroy(); // 기존 GUI를 제거
this.gui = new dat.GUI({ title: 'Hierarchy' }); // 새로운 GUI 생성
this.addFolder(object, this.gui);
}
private addFolder(object: THREE.Object3D, parentGui: dat.GUI): void {
const folder = parentGui.addFolder(object.name || object.type);
object.children.forEach(child => {
this.addFolder(child, folder);
});
folder.open(); // 모든 폴더를 기본적으로 열어 둠
}
}
export default HierarchyUI;
hierarchy class를 만들어서 넣어보자.
scene에 있는 object들이 뜬다. 하지만 계층적으로 나오는지는 확인하기 어렵다.
임의의 children object를 넣어보자.
class HierarchyUI {
private gui: dat.GUI;
constructor() {
this.gui = new dat.GUI({ title: 'Hierarchy' });
this.setPosition()
}
public buildHierarchy(object: THREE.Object3D): void {
this.gui.destroy(); // 기존 GUI를 제거
this.gui = new dat.GUI({ title: 'Hierarchy' }); // 새로운 GUI 생성
this.setPosition()
this.addFolder(object, this.gui);
}
private setPosition(): void {
const guiDomElement = this.gui.domElement;
guiDomElement.style.position = 'absolute';
guiDomElement.style.top = '0';
guiDomElement.style.left = '0';
guiDomElement.style.zIndex = '100'; // GUI가 다른 요소 위에 표시되도록 z-index 설정
}
private addFolder(object: THREE.Object3D, parentGui: dat.GUI): void {
const folder = parentGui.addFolder(object.name || object.type);
object.children.forEach(child => {
this.addFolder(child, folder);
});
folder.open(); // 모든 폴더를 기본적으로 열어 둠
}
}
set position을 통해 hierarchy는 좌측 상단에 두자.
const testbox1 = new Mesh(new BoxGeometry(1), new MeshBasicMaterial({color: 'red'}))
const testbox2 = new Mesh(new BoxGeometry(1), new MeshBasicMaterial({color: 'red'}))
const testbox3 = new Mesh(new BoxGeometry(1), new MeshBasicMaterial({color: 'red'}))
testbox1.children.push(testbox2)
testbox2.children.push(testbox3)
scene.add(testbox1)
test mesh들이 children으로 들어간 게 잘 표현된다.
한 번 mesh separate가 바로 hierarchy 에 반영되는지 보자
mesh separate hierarchy
mesh separate를 실행하니 hierarchy에 cloth0, cloth1 로 나우어지는 것을 확인할 수 있다.
threejs editor
https://github.com/mrdoob/three.js/tree/master/editor
mugen87 이라는 개발자분이 개발한 threejs 기반 editor이다.
오픈소스로 되어있어서 참고하기 너무 좋고.
특히 이 mugen87이라는 분이 threejs를 사랑하셔서 forum에서 자주 활동하신다.
현재 lil-gui로 구현을 해놓았지만, clicked mesh의 경우 hierarchy에서표시해주면 좋겠어서
일단 threejs editor에서 hierarchy를 어떻게 구현하였는지 보면 좋을 것 같다.