나에게 지금 필요한 것은 threejs editor example에서는 hierarchy를 어떻게 구현했냐는 것이다.
그 부분만 이 거대한 threejs editor source에서 파헤쳐보자.
우선 다시 editor class(?)를 보면 초기화하고 있는 객체들 중 hierarchy와 관련될 법한 것을 보자.
Selector.js
우선 selector. 이름만 들어도 이게 마우스로 오브젝트를 클릭하는 것과 관련된 스크립트라는 것을 알 수있다.
그래서 실제로 개인적으로 개발한 방법과 동이랗게 intersection된 object 들 중에 첫 번째 오브젝트를 select object로 지정해놓는다.
오브젝트를 클릭하면 translation interface가 뜨고, scene hierarchy에서는 selected object에 표시가 된다.
get intersects를 보면 picker 라는 이름의 helper(interface를 말한다)를 클릭하는 경우의 처리도 object를 분리한다.
intersect는 mouse의 위치 point를 잡아서 실행하고.
보아하니 selected object를 config의 selected 라는 key에다가 해당 object의 uuid를 저장하는 방식이다.
storage는 indexed db에 state를 저장하는 것으로 생각하고, Strings.js는 각 설정언어의 데이터가 담겨있다.
helpers
여기 helpers라는 객체는 보아하니 object에 표시되는 interface를 말하는 모양이다.
아무래도 translation에 관련된 부분은 helpers 객체를 어떻게 사용하는지를 보면 답이 나오겠지.
Editor prototype
editor prototype에는 editor에서 사용될 함수들이 정의되어있다.
먼저 set scene을 보면
이렇게 scene에 object를 추가하는 파트가 있다.
scene에 object를 추가하는데 hierarchy에 관련된 것도 있지 않을까
object를 추가하는 addObject는 바로 밑에 함수가 정의되어있는데,
보면 scope 라는 것에 각 object를 traverse로 순회하면서 geometry와 material을 세팅하는데,
이무래도 이걸 scope라고 하는 것일까.
그리고 밑에는 parent 유무에 따라서 scene에 바로 추가하거나, splice를 통해 parent에 children을 추가한다.
Sidebar.Scene.js
editor를 쭉 읽어봤는데 마땅히 scene hierarchy에 해당한다는 느낌이 안든다.
여기 scene의 hierarchy에 해당하는 곳은 sidebar라는 스크립트들로 표현되어있다.
그래서 결국 sidebar 스크립트에서 찾아보기로 했다.
결과 Sidebar.Scene.js라는 스크립크를 발견했고, 이름으로 보아 scene의 hierarchy 창을 의미하는게 맞는 것 같다.
일단 이쪽은 UI 부분이기 때문에 ui에 대한 import가 많다.
실제로 three.js 상에서 UI를 이용해본적이 없는데. 좀 보면 웹과 별 다를바 없이 js를 이용해서 dom 구조를 짜는 것이다.
생각보다 UI코드는 생소하고 코드만 보면 원래 뭔지 알기 힘들기 때문에 쭉 읽어보자.
그래도 어느정도의 주석이 달려있는데, outliner? opener? 뭘 의미하는 걸까
option이라는 건 위의 네비 버튼을 드롭다운으로 열었을 때 나오는 걸 말하는 것 같다.
그럼 outliner panel은 상단 패널을 말하는 걸 수 있다.
아닌 것 같다;;
onDblClick이라는 함수가 있다.
Dbl.. 즉 Double의 줄임말임을 알 수 있고 더블클릭 이벤트라는 것이다.
더블클릭? threejs editor에는 더블클릭이 지원되는 기능이 어딨지?
더블 클릭 이벤트가 별도로 엔진에서 필요한 경우는 hierarchy에서 object를 더블 클릭하여 camera focus를 object를 바라보게하는 기능뿐이다. 마침 DblClick 이벤트도 focus by id 로 object를 바라보는 기능을 담고 있다.
그래서... outliner라는 것을 찾아보니 문서 탐색기? 같은 느낌의 단어이다.
그렇게 생각해보면 확실히 상단의 네이게이션 패널보다는 확실히 scene hierarchy를 말하는게 맞는 것 같다.
지금 보고있는 Sidebar.Scene.js 스크립트도 hierarchy에 대한 코드블럭 스크립트인데 상단 네이게이션을 의미할 이유가 없다.
이 함수는 select라는 걸로 보아 hierarchy(=outline)에서 오브젝트를 클릭시 배경이 바뀌는 기능을 담고 있다.
감탄스러운 것은 UIElement 들이 하나씩 정의되어 있다는 점이다. 이걸 직접 짠 걸까?
아니면 library나 오픈 소스를 가져온 걸까.
위에 보이는 코드들은 backgound에 대한 설정이다.
background에는 color, texture 등 설정이 있는데 이 부분이다.
일단 우리가 보려는 것은 hierarchy 즉 outline에 대한 것이므로 넘어가자.
마찬 가지로 environment, fog도 넘거가고
refreshUI
이 refreshUI 함수의 경우에는 100 line이 넘어갈 정도로 내용이 상당히 많은데
outline의 opener에서 호출하고 있다.
함수명으로 추정해보면 역시 특정 원하는 시점에 component를 rerendering하는 동작이 아닐까 예상된다.
opener와 같이 toggle 이벤트로 인해 dom구조가 변경되는 경우 사용되는 것 같다.
refresh UI에 add object 함수가 있다. option이라는 배열에 object를 추가하는 역할인데
outliner 안에 있는 object 한 줄 한 줄들이 option이다.
즉 add objects함수는 이 hierarchy 구조에 object를 추가해주는 역할이다. 중요한 역할이지.
buildOption
아까부터 build option이라는 함수가 종종 보이는데 이게 뭘까.
outliner에 가장 먼저 등장하는 함수인데 object와 drag 여부를 받는다.
몰랐는데 outline상에서 오브젝트를 위 아래로 드래그하는 기능도 있었다.
이 기능이 scene와 camera에는 false로 되어있어 작동하지 않는다.
build option이라는건 outline에 object를 추가할 때 DOM에 적용되는 설정이다.
buildHTML은 뭘까
buildHTML에서는 span 태그를 이용한다.
span 태그는 여기에 해당한다.
buildHTML을 보면 mesh를 확인해서 geometry와 material의 여부를 따로 표시한다.
사진에서 object들은 text 오른쪽에 점이 두 개 더 있는 걸 표현한 것이다.
다시 build option으로 돌아와서
그럼이 node states가 scene 계층구조를 표현하는 노드들이라는 것을 알 수 있다.
이건 weak map이라는 자료 구조를 이용하는데 처음본다. JS에만 있는 구조인 듯 하다.
weak map은 key가 객체인 형태이고, 객체이기 때문에 reference형태의 key를 취하고
reference가 없으면 자동으로 가비지 컬렉터에서 제거하는 효과를 지닌다고 한다.
그러한 사실 외에는 기본적으로 Map와 유사하다.
이제 조금씩 보이기 시작한다.
위 opener 부분에서는 object 하나를 buildOption을 통해 outliner에 넣었을 때, dom 구조로 만들어 넣어주는 역할을 한다.
이때 if문의 역할은 이 object가 scene이나 camera인지, 아니면 scene의 children으로 들어가는 객체인지를 구분한다.
scene이나 camera라면 opener를 만들지 않기 때문에, nodeState에 넣지 않고 바로 option만 return한다.
그리고 scene.children에 포함된 object들은 add objects 함수를 통해서 nodeStates에 먼저 넣어준 뒤,
buildOption을 호출하여 object에 대응하는 div태그를 생성한다.
특히 이 부분,
이 부분이 자식 object가 있는 경우 재귀의 개념으로 모든 children 객체들을 outliner에 add한다.
자식은 한 depth마다 padding을 왼쪽에 적용하며
사진과 같이 오른쪽으로 한 단계씩 밀리게 된다.
padding을 추가하거나 div에 대해서 어떤 효과를 여기서는 option이라는 형태로 넣는데,
이 option들은 setOptions에서 적용된다.