프론트엔드

Three.js를 이용한 3D 그래픽 입문기

CyberI 2018. 2. 8. 18:37

Three.js 란?

 

 

 

The aim of the project is to create an easy to use, lightweight, 3D library.

웹기반의 3D그래픽 표현작업을 간소화 해주는 라이브러리인 Three.js입니다.

주요 브라우저 업체들이 지원하는 웹기반 3D표현기술인 WebGL을 lightweight한 가벼움과 간단한 코드 작성만으로 멋있는 3D 그래픽을 만들 수 있습니다.

API 구조의 인터페이스로 구성되어 있어 자바스크립트를 다루시는 분들이라면 익히기 쉽고, 
외국에서도 이미 많이 사용하고 있습니다. 

물론, IE나 모바일기기 브라우저에서 WebGL이 호환되지 않지만, Three.js에는 WebGL의 결과물을 캔버스나 SVG로 변환하실 수 있어 동일한 모양의 결과물을 확인할 수 있습니다.

Three.js 사이트에 들어가시면 다른 유저들이 올린 작품을 보실 수 있는데 화려하고 멋있는 작품들을 보실 수 있습니다. 저도 언젠가는 그런 멋진 작품을 만들 날을 기약하며, API문서에 있는 간단한 예제를 따라해보면서 3D 그래픽에 대해 익혀보려고 합니다.

시간 나실때 three.js 사이트에 들어가셔서 다른 유저의 작품들을 꼭 구경해보시길 추천드려요!

설치는 git에서 minified한 버전을 다운받으시거나 다운받아 import하셔도 됩니다.
git : https://github.com/mrdoob/three.js/

Three.js에서는 크게 scene, camera, renderer 로  나누어지는데
카메라(camera)로 보여지는 화면(scene)을 랜더링(renderer) 해주는 방식으로 각각 영역을 나누어 세부적으로 설정해 줄 수 있습니다.

카메라로 사진을 찍는다고 가정해볼게요, 우선 찍을 장소(scene)와 부피와 질감을 갖고 있는 피사체(mesh)가 있어야 겠죠?  찍은 화면을 종이에 인화해주면(renderer)을 사진이 나옵니다.


다른 방식으로 말하자면, 물체를 가리키느 '메쉬(mesh)' 와 빛을 뜻하는 '라이트(light)'로 공간을 구성하고 시점을 카메라로 조정하며 화면에 보이게 도와줍니다.

그럼 예제를 통해서 한줄씩 알아가보도록 할게요!

var scene = new THREE.Scene(); var camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 ); var renderer = new THREE.WebGLRenderer(); renderer.setSize( window.innerWidth, window.innerHeight ); document.body.appendChild( renderer.domElement );

순서대로 보자면, THREE.Scene(); 으로 장소를 생성해 주고,

THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 ); 로 카메라를 세팅해줍니다.

PerspectiveCamera의 들어가는 속성들을 보기전에 추가적으로 이야기하자면 Three.js에는 많지는 않지만 여러 카메라가 존재한답니다.....

위에 예제에서 사용된 PerspectiveCamera 외에도 OrthographicCamera라는 카메라가 있습니다.  물론,모델링 하시는 분이라면 저보다 자세히 알고계실테니 그냥 넘어가도 무관합니다만 모르시는 분들을 위해 둘의 차이를 잠깐 알아보고 가려합니다.

영어단어 그대로 해석해서 이해하자면 Perspective(원근법) 와 Orthographic(정투영법)인데, 너무나 잘 알듯이 원근법은 실제 눈으로 보이는 것과 비슷하죠. 물체와의 거리와 각도에 영향을 받아 같은 너비에 제품도 가까이 있는 것이 크게 멀리 있는 것이 작게 보입니다.

그와 다르게, 정투영법은 같은 크기는 거리와 관계없이 같은 크기로 표시해주는 방법입니다.
물체의 정확한 크기를 표현해주는 것이죠. 정투상 상태에서 모델링을 할때는 격자를 참고해서 정확하게 표현해주는것이 중요합니다. 입체적인 모습보다는 상대적 크기를 파악하고 사용할때 유용하죠.

아래 사진의 projection image에 집중해보면 이해하기 쉬울거다. 둘의 실제적인 사이즈대로 보여주는 (a)가 정투영법 가까이 있는 파란 물체가 더 크게 보이는 (b)가 원근법입니다.

 

 

출처: https://www.researchgate.net/figure/Projection-modes-a-orthographic-projection-and-b-perspective-projection_fig2_265693452

이제 예제에서 원근법카메라를 사용한 것을 알았으니 안에 들어가는 속성에 대해 보면 다음과 같습니다.

THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );

위에 들어가는 4개의 매개변수는 (시야, 가로 세로비율, 가까운 정도, 먼 정도) 라고 보시면 됩니다.
가까운 정도와 먼정도라뇨...? 그게 어느 정도 까지의 가까이있는 또는 멀리 있는 물체를 볼 것인지를 설정해주는 속성입니다. 가까운정도와 먼정도의 범위에 해당되지 않으면 출력되지 않아 보여지지 않습니다. 주로 게임에 많이 사용되어지죠.

 

자, 화면도 카메라도 다 설정했다면 이제 render해줘야죠. THREE.WebGLRenderer(); 로 renderer를 생성해 주는데 WevbGL은 위에서 언급한것처럼 호환되지 않는 브라우저들이 있죠...( IE10이하의 버전 ) 그런 경우를 대비해서 호환되는지를 window.WebGLRenderingContext 로 체크를 해서 안되는 경우 THREE.CanvasRenderer() 를 이용하시면 canvas 기반 렌더러가 대신 사용되어 정상적으로 작동 된다고 합니다. (짝짝짝) 단지, 속도가 느리고 품질이 낮아질 뿐이죠....ㅠ,ㅠ

기본적인 구성을 다 이루었으면 renderer의 사이즈를 세팅해주고 화면에 appendChild 해주시면 이제 그림을 그릴 준비가 다 되신겁니다. 

기본 세팅이 완성 되신겁니다. 그럼, 이제 뽑을 피사체를 그려봐야겠쥬?
3D그래픽은 메시를 만들어 기본적인 구조에 재질을 입히는 방식으로 만들어지는데요.
다시 말해, mesh(피사체)는 geometry + meterial 로 구성됩니다. 

var geometry = new THREE.BoxGeometry( 1, 1, 1 ); var material = new THREE.MeshBasicMaterial( { color: 0x00ff00 } ); var cube = new THREE.Mesh( geometry, material ); scene.add( cube ); camera.position.z = 5;

도형의 가로세로높이의 비율은 geometry를 생성할 때 정의해 주고, 재질의 색상은 material을 정의해줄 때 추가해 준 후 cube라는 변수에 three.js에서 제공하는 BoxGeometry로 생성된 geometry와 기본적인 재질인 MeshBasicMeterial 을 매개변수에 넣어주고 메시를 만들어 정의해주고 scene에 추가해주는 과정입니다.

scene.add()를 통해 추가하게 되면 (0,0,0) 위치에 추가되기 때문에 아직 화면에서 제대로 된 큐브를 보실 수 없습니다. 그렇기때문에 간단히 카메라를 움직여서 위에서 만든 피사체를 확인해보겠습니다.

function animate() { requestAnimationFrame( animate ); renderer.render( scene, camera ); } animate();

위의 소스를 requestAnimationFrame 같은 경우 사용자가 다른 탭으로 잠시 넘어간다면 애니메이션 작동을 멈추어 컴퓨터의 소중한 프로세스 전력을 낭비하지 않는답니다.

여기까지 소스를 돌린다면 화면에는 나타나지만 멈추어있는 사각형을 발견하실 수 있습니다.
큐브의 동적인 움직임을 위해 위에 만든 animate() 기능에 아래처럼 회전기능을 추가합니다.

cube.rotation.x += 0.1; cube.rotation.y += 0.1;

그렇다면 아래와 같이 보이실겁니다. 형광 초록색 네모가 돌아가가는 것이 보이시죠?
 
 

여기서 더 나아가 속성값들을 바꿔보고 API문서에 있는 다양한 기능들을 추가해보시길 바랍니다!

참고 : http://threejs.org/docs