본문 바로가기

개발/js

three.js 스터디 1주차) Hello Cube!

기본 개념

예시와 Three.js 구조도

저 예시 로봇을 Three.js로 구현하기 위해선

저 로봇의 형태를 구성하는 기하학 객체(구, 정육면체, 반구 등)의 정점 데이터들이 Geometry이다. 원시모델(Primitives), 직접 생성하기(세상에), obj 파일 등으로 불러오기 등으로 Geometry 객체를 생성할 수 있다.

로봇은 노랗고 무광인데, 이런 색깔과 밝기 등 기하학 객체의 표면의 속성이 Material 이다. 이때 단순히 색깔을 지정하는 대신 이미지를 불러와서 표면에 이미지를 매핑해 줄 수 있는 데, 이때 이미지를 Texture라고 한다.

그리고 저 로봇은 어떤  Material로 어떤 Geometry를 그리는 객체인 Mesh 여러 개로 구성되었다. 에스파는 둘이 될 수 없는 것처럼, 로봇을 하나 더 만들어야 한다면 Mesh 객체를 하나 더 생성해야 한다. 이때 Mesh 객체는 어떤 위치에 존재해야 하기 때문에 위치 정보도 속성으로 가지고 있으며, 여러 Mesh 가 여러 Geometry, Mesh를 참조할 수 있다.

저 로봇은 3D 공간에 존재하려면 Scene에 바로 속하든, Scene 아래의 어떤 3D공간에 속하든  Scene에 속해야 한다. Scene은 이 모든 객체들의 최상위 객체이다. 저 로봇의 부분들은 큰 부분부터 작은 부분까지 나눠질 텐데, 예를 들어 머리에 눈과 눈썹이 속하고, 몸통에 다리와 팔이 달려있을 것이다. Scene이라는 최상위 노드 아래 로봇 -> 로봇의 각 파트 -> 세부 파트 이런 식으로 계층 관계가 형성되고, 어떤 객체에 속하느냐에 따라 참조하는 위치와 방향도 달라진다. 이 계층구조를 Scene Graph라고 한다.

한편 저 로봇을 마치 정면 좌측 하단에서 비스듬하게 올려다보게 되는데, Camera 객체의 설정을 바꿔서 보는 방향, 각도 등을 조정할 수 있다. 

결국 우리가 저 로봇을 보고 있는 화면은 Scene Graph에 속한 객체들을 Camera의 속성에 따라 변환된 2차원 이미지인데, 이렇게 변형해 주는 객체를 Renderer라고 한다. 

 

카메라

카메라 설정에 따라 만들어지는 절두체

카메라에서 near far 평면의 높이는 시야각(fov), 너비는 시야각과 aspect에 의해 결정된다. (그래서 반응형 페이지에서 너비를 줄여도 화면이 안 달라지지만 높이를 줄이면 화면이 달라진다. )

개인적으로 fov 가 약간 헷갈려서 Camera 가 좀 어려웠는 데, 이 영상을 보고 좀 더 이해가 되었다. 어쨌든 60도쯤이 보통 사람의 Fov, 더 넓게 보려면 fov를 키우고, 하나에 집중해서 보려면 fov 를 낮춰야 한다. fov 가 커지면 시야가 넓어지지만 왜곡도 더 심해진다. three.js 에디터에서 값을 바꿔가며 확인해 봐도 좋은 것 같다.

영문으로도 읽고 챗지피티에게도 물어봤지만 아직 이해하지 못한 부분(아래)도 있는 데, 이건 스터디 때 어떻게 해결해 보는 걸로..

시야각은 canvas 크기의 영향을 받습니다. 앞서 만든 canvas는 두 배 더 크기 때문에 실제로는 시야각이 위에서 정의한 75도보다는 훨씬 넓을 것입니다.

 

Hello Cube! + 반응형

three.js 란부터 반응형 디자인까지 나오는 실습은 깃헙에 올렸다. 공식문서 튜토리얼에서 개발용 웹서버를 구성하는데 servez를 추천했는 데, 나는 전 프로젝트에 사용했던 webpack으로 구동했다. 

아래는 코드를 작성하며 알게 되거나 느꼈던 점이다. (튜토리얼에 나온 코드가 그렇게 어렵지 않기도 하고, 거의 그대로 작성해서 글에 작성할만한 내용이 별로 없다. )

WebGLRenderer 인스턴스 생성 시 antialias 옵션
이미지의 품질을 개선하기 위해 사용하는 옵션. 렌더링 된 이미지를 더 부드럽게 만들어 주는 안티 앨리어싱(Anti-aliasing) 처리가 적용. 렌더링된 객체의 모서리나 윤곽선에서 발생하는 계단 현상("jaggies")을 줄여주어 이미지의 품질을 향상. 기본값은 false. false 인 상태에서도 그렇게 큰 품질이슈는 느끼지 못했는 데, 복잡하거나 고품질의 작업을 할 때 고려할만할 것 같다.

canvas의 width, height
반응형 코드엔 윈도우의 device pixel ratio 값을 받아, 캔버스의 width, height 값에 반영해 주는 부분이 있다. 여기서 width, height 가 변경돼도 canvas 객체의 크기가 실제로 바뀌는 것은 아니다. canvas의 width, height 속성은 좌표공간의 너비와 높이로, css 픽셀단위이다.  그러니까 pixel ratio 가 높아지면, 그러니까 더 선명한 환경으로 바뀌면, 같은 크기의 canvas 객체에 그리는 그래픽 좌표 공간을 넓혀 압축적으로 표시해 깨지지 않게 한다. 

Mesh 회전은 라디안,,,
degrees * (Math.PI / 180). 값이 커져도 360도마다 다시 동일한 회전 상태. 유니티에선 GUI로 슥슥 만져서 별로 어렵지 않았는 데, 직접 회전시키려니까 너무 힘들었다,,,(난 공간감이 제로다,,,,)

바닐라 js
바닐라 js로 조작하는 건 정말 오랜만(5년..!)이었다. 번거롭지만 가벼워서 나름 나쁘지 않았달까.

 

참고

 

three.js manual

 

threejs.org