[Three.js journey 강의노트] 01 ~ 03

9rganizedChaos·2021년 7월 5일
29
post-thumbnail

🙌🏻 해당 글은 Three.js Journey의 강의 노트입니다.

01 Introduction

  • 가장 먼저 공부할 Basic: scene 만들기, object 추가하기, materials 고르기, texture 추가하기 그리고 animation 추가하기
  • 다음으로 공부할 보편적인 기술: geometry 만들기, 빛과 그림자, 3D object와의 인터랙션, particle 추가
  • 심화 기술: physics, realistic render 연출, custom shader, post-processing 추가하기, 나만의 blender model 만들고 사용하기

물론 Stunning한 WebGL을 위한 high-end PC가 있다면 좋겠지만, 우리는 가급적 많은 장치에서 WebGL을 경험할 수 있도록 하는 다양한 tip을 함께 학습할 것이다.

  • 3D 소프트웨어는 Blender를 다룰 것이다.

02 What is WebGL and why use Three.js

Three.js는 개발자들이 3D를 웹 상에 구현할 수 있도록 도와주는 JS라이브러리이다.

물론 SVG와 CSS를 통해서도 3D experience를 구현할 수는 있다. 하지만 이는 매우 제한적이고 어렵다.

WebGL은 매우 빠른 속도로 캔버스에 삼각형을 렌더하는 JS API이다.

대부분의 모던 브라우저에서 잘 동작하고, 수천 개의 병렬 계산이 가능한 GPU를 이용하기 때문에 빠르다.

WebGL의 렌더링 로직을 간단하게 설명하면!

1) 수많은 삼각형으로 구성된 모델에서 먼저 삼각형들을 구성하고 있는 점들을 배치한다.
2) 점들을 배치하고 나면 GPU가 삼각형들의 픽셀을 눈에 보이도록 그려낸디.
(이때, 점들을 어디에 위치시키고, 어떻게 필셀들을 그릴 것인가에 대한 지침이 바로 Shader에 들어있는 것이다.)

A shader is a small program written in GLSL that runs on the GPU.

3) 그리고 우리는 이 모델의 변형과 카메라의 속성에 따라 점들을 어디에 위치시킬지, 픽셀들을 어떻게 칠해줄 지 등의 정보들(이것을 matrice라고 한다)을 Shader에 제공해야 한다.

이것이 바로 WebGL이 어려운 이유다.

삼각형 하나를 그리는데 최소 100줄의 코드가 필요하다. 거기에 원근감, 조명, 애니메이션을 적용한다고 생각하면, 수천, 수만 줄의 코드를 작성해야 할지도 모른다. (그러나 물론 native WebGL은 좀 더 날 것의 상태이고 GPU에 더 가깝기 떄문에, 더 뛰어난 최적화와 컨트롤이 가능하다는 장점이 있다)

Three.js를 사용한다면 WebGL을 간편히 사용할 수 있다.

단 몇 줄의 코드만으로 3D 애니메이션을 구현할 수 있다. 더 이상 복잡한 shader와 matrice를 제공할 필요가 없다. 물론 ThreeJS 자체가 WebGL위에서 돌아가는 것이므로, 우리는 여전히 shader와 matrices를 통해 WebGL에 접근할 수 있고, 그 방법에 대해서도 추후에 학습할 것이다!

ThreeJS 깃헙에서 만나기

  • Mr.doo이라 불리는 ThreeJS를 개발한 Ricardo Cabello의 깃헙에 방문하면, ThreeJS에 대한 다양한 정보를 접할 수 있다. 소스코드는 물론, contributors에는 도움을 받을 수 있는 큰 커뮤니티가 형성되어 있고, release 탭에서는 업데이트 내용도 확인할 수 있다.
  • ThreeJS에 대한 공식적인 정보는 공식문서에서!

03 Basic scene

첫 수업에서는 가장 단순한 방법(번들러나 디펜던시, 그 어떤 모듈도 없이, html과 js만으로)으로 ThreeJS를 활용해볼 것이다.

어떻게 Three.js 라이브러리를 로드할까? 😅

여러가지 방법이 있지만, 일단 지금은 library를 다운로드하고 <script> 태그를 활용해 로드해올 것이다!

우선 threejs 페이지에서 Download를 클릭한다!

(아래 이미지 참고!)

다운받은 파일을 압축해제한 후에, three.min.js 파일을 가져와 태그에 삽입!

다운 받은 파일을 압축해제하면 아래와 같은 폴더구조가 보인다!
three.js 파일의 경우 몹시 무거운 파일로, 굳이 three.js를 가져오기보다는 minify된 three.min.js를 가져오자! 파일을 가져오고나면 body태그가 종료되기 직전 script.js를 가져오는 script태그 위에서 script 태그를 활용해 해당 three.min.js 스크립트를 가져온다!
(당연하게도 script.js를 먼저 가져오면, js 파일에 작성된 three.js 관련 속성들을 읽어올 수 없을 것.)

// 순서에 유의하자!
<script src="./three.min.js"></script>
<script src="./script.js"></script>

Three.js를 가져오고 나면 😉

이제 THREE 라는 키워드를 통해 라이브러리를 사용할 수 있다!

console.log(THREE)
const scene = new THREE.Scene()

이제 자바스크립트 파일에서 아래와 같이 코드를 작성하고, 브라우저에서 html파일을 동작시키면
아래 이미지와 같은 객체가 콘솔창에 찍히는 것을 확인할 수 있다.

ThreeJS 프로젝트에서 필요한 다양한 클래스와 속성들이 존재한다! 물론 아쉽게도 모든 클래스가 THREE라는 variable에 담겨있는 것은 아니다. (이 부분에 대해서는 추후에 어떻게 접근할 수 있는지 알아볼 것이다.)

이제 정말 무언가를 스크린에 만들어보자!

ThreeJS에서 가장 기본적인 요소라 하면, 총 네 가지가 있다.
그것들이 바로, object를 포함할 scene, 그리고 objects, camera, 그리고 renderer이다!
하나씩 살펴보도록 한다.

1) Scene 🎆

const scene = new THREE.Scene()

위와 같이 작성해 scene을 만든다! scene은 three.js에서 콘테이너이다. objects, models, particles, lights 등을 담는다.

2) Objects ⌛️

Object는 아주 다양한 것들이 될 수 있다.
기본적인 geometries부터 시작해서, import된 models, particles, lights 등!
지금은 기본적인 파란색 도넛 모양을 만들어보자!

일단은 Mesh라고 하는 Object가 필요하다.

A Mesh is the combination of a geometry (the shape) and a material (how it looks).

Mesh는 geometry와 material의 결합인데, Geometry와 Material은 아주 다양한 것들이 존재한다.

Object를 만드는 순서는 다음과 같다.

  • geometry, material 각각을 생성
  • mesh를 통해 둘을 결합하기
  • 결합한 mesh를 scene에 추가하기
    (scene에 추가하지 않으면 눈으로 확인할 수 없다.)

위 과정을 코드로 작성하면 아래와 같다.

const geometry = new THREE.TorusGeometry(10, 3, 16, 100);
const material = new THREE.MeshBasicMaterial({ color: 0xffff00 });
const mesh = new THREE.Mesh(geometry, material);
scene.add(mesh)

3) Camera 📹

카메라는 눈에 보이지 않는다. 이론적으로 이야기하면 카메라는 사실 시점에 가깝다. 영화촬영장 처럼 여러 개의 카메라를 가질 수도, 그것들 사이의 전환을 시도할 수도 있다. 심지어 카메라도 다양한 타입의 카메라가 존재한다. 그러나 이번 레슨에서는 perspective camera만 다룰 것이다.

perspective camera에는 두개의 필수 인자를 넘겨줘야 하는데,

1) 첫 번째 인자는 the field of view.
이것은 시야각을 조절한다. 큰 앵글을 사용하면, 모든 방향을 한 번에 볼 수 있지만, 왜곡이 생긴다.
작은 앵글을 사용하면, 사물이 확대된 것처럼 보인다.
사람의 시야와 유사한 건 75도 정도이다.


🔼 the field of view인자가 각각 20, 35, 70, 150도일 때 렌더링되는 모습

2) perspective camera에 넘기는 두 번째 인자는 The aspect ratio.
보통 aspect ratio는 캔버스의 너비를 높이로 나눈 값이다!

그리고 나서 아래 코드와 같이 camera를 scene에 추가할 수 있다.

const sizes = {
    width: 800,
    height: 600
}

// Camera
const camera = new THREE.PerspectiveCamera(75, sizes.width / sizes.height)
scene.add(camera)

4) Renderer 🎛

위와 같이 코드를 작성해도 아직까지 아무것도 눈으로 확인할 수 없다!
Render를 해주지 않았기 때문이다.
우리가 renderer에게 render를 요청하면, renderer는 camera의 시점에서 보이는 모습을 캔버스 위에 그려낸다. 그렇다면 일단 renderer가 그림을 그릴 canvas를 html파일에 추가해주어야 한다.

<canvas class="webgl"></canvas>

그리고 나서 자바스크립트 파일에서 renderer를 만들어준다.
renderer를 생성해줄 때는 canvas 엘리먼트를 인자로 넘겨준다!
그리고 setSize 메서드를 통해 canvas의 크기를 조정한다.

const canvas = document.querySelector('canvas.webgl')

const renderer = new THREE.WebGLRenderer({
    canvas: canvas
})
renderer.setSize(sizes.width, sizes.height)

이렇게 작성하고 나면 여전히 우리는 브라우저에서 아무것도 볼 수 없지만,
우리가 원하는대로 리사이징된 캔버스를 확인할 수 있다.

이제 renderer를 이용해 진짜 렌더를 해볼 시간이다!

renderer 내장 render 메소드에 scene과 camera를 인자로 넘겨준다.

renderer.render(scene, camera)

아직 아무것도 보이지 않는 것은 카메라와 object의 위치를 지정하지 않았기 때문이다.
기본 위치는 모두 scene의 중앙이다. 현재 우리의 카메라도 object도 scene의 중심에 있기 때문에 아무것도 보이지 않는다. (기본적으로 object의 내부에서는 물체를 확인할 수 없다!)
때문에 object의 위치를 변경해주어야 하는데, 위치 변경 시에는 position, rotation, scale과 같은 속성들을 이용한다. 지금은 position만 이용할 것이다.
이때 중요한 것은 render 전에 위치를 변경해주어야 한다는 점이다.

const canvas = document.querySelector("canvas.webgl");
const scene = new THREE.Scene();

const geometry = new THREE.TorusGeometry(10, 3, 16, 100);
const material = new THREE.MeshBasicMaterial({ color: 0x0000ff });
const mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);

const sizes = {
  width: 800,
  height: 600,
};

const camera = new THREE.PerspectiveCamera(75, sizes.width / sizes.height);
camera.position.z = 50;
scene.add(camera);

const renderer = new THREE.WebGLRenderer({
  canvas: canvas,
});
renderer.setSize(sizes.width, sizes.height);

renderer.render(scene, camera);

위와 같이 코드를 작성해주면, 아래와 같은 이미지를 확인할 수 있다!

profile
부정확한 정보나 잘못된 정보는 댓글로 알려주시면 빠르게 수정토록 하겠습니다, 감사합니다!

1개의 댓글

comment-user-thumbnail
2022년 4월 14일

좋은 글 감사합니다. ^^

답글 달기