Three.js/기초튼튼

three.js 장면, 카메라, 렌더러, 객체, 머티리얼 생성 - Scene, Camera, Renderer, Geometry, PerspectiveCamera, BoxGeometry, MeshBasicMaterial

carrotweb 2023. 6. 7. 00:14
728x90
반응형

이전에 설명들인 것처럼 three.js를 개발하기 위해서 NPM과 빌드 도구(Node.js, Vite)를 사용하거나 CDN으로 가져(Import) 오거나 직접 js 파일을 다운로드해서 사용하는 방법이 있습니다.

 

최근에 NPM과 빌드 도구(Node.js, Vite)를 많이 사용하고 있는 것 같아서 Node기반으로 개발하도록 하겠습니다.

 

 

우리는 어떻게 3차원으로 볼 수 있을 까요?

 

우리는 눈으로 공간에 있는 사물을 볼 수 있습니다. 그리고 우리는 몸을 움직여 공간에서 사물의 앞/뒤, 좌/우, 위/아래를 볼 수 있습니다. 그래서 사물을 입체적(3차원)으로 볼 수 있습니다.

 

그런데 우리가 움직이지 못한다면 사물이 평면으로 보일까요?

 

그렇지 않습니다. 그 이유는 공간이 평면이 아니기 때문입니다.

 

사물이 공간에서 항상 우리의 눈높이와 같은 곳에 있지 않고 상/하, 좌/우에도 있고 우리 중심으로 떨어져 있기도 하기 때문입니다. 그리고 빛이 있어 사물의 밝기가 달라지고 그림자가 생겨 더욱 입체감 있게 보입니다.

 

우리가 움직이지 못해도 공간 안에서 사물의 위치와 거리, 빛에 따라 우리의 눈에는 입체적(3차원)으로 보입니다.

 

three.js도 3차원을 만들기 위해서 우리의 눈과 같은 시점에서 구현하고 있습니다.

 

three.js도 사물이 있을 공간이 필요합니다.

그리고 우리의 눈처럼 사물을 촬영할 카메라(Camera)가 필요합니다.

그리고 카메라(Camera)에서 촬영한 장면(Scene)을 화면으로 볼 수 있게 처리하는 렌더러(Renderer)가 필요합니다.

 

즉, three.js는 우리의 눈과 같은 카메라(Camera)의 시점에서 촬영한 장면(Scene)을 화면으로 볼 수 있게 처리해 줍니다.

 

그러나 사물 입장에서는 장면(Scence)은 공간입니다. 그 공간에 있어야 사물이 촬영되기 때문입니다.

 

 

그럼 three.js로 3차원을 표현(Rendering, 렌더링) 하도록 하겠습니다.

 

1. main.js 파일을 오픈합니다.

 

2. 객체가 있을 공간을 생성하기 위해 Scence(씬, 장면)를 추가합니다.

// 장면 생성
const scene = new THREE.Scene();

 

3. 촬영할 Camera(카메라)로 원근법이 적용되는 카메라를 추가합니다.

PerspectiveCamera(fov : Number, aspect : Number, near : Number, far : Number)
  • fov(포브, field of view, 시야범위(각도)) : 화면이 보이는 각도입니다. 기본값 50도 (주로 45 ~ 75도 사이로 설정합니다.)
  • aspect(애스펙트, aspect ratio, 종횡비, 가로세로비(비율)) : 가로와 세로 비율(영상에서 사물을 둘러싼 공간의 크기)입니다. 웹 브라우저를 통해서 보기 때문에 화면의 너비를 화면의 높이로 나눈 값을 사용합니다.
  • near(니어, 카메라부터 가까운 거리) : 기본값 0.1 (입력하지 않으면 기본값으로 설정됩니다.)
  • far(파, 카메라부터 먼 거리) : 기본값 2000 (입력하지 않으면 기본값으로 설정됩니다.)

 

 

 

WebGLRenderer(렌더러)가 Camera의 far 보다 멀리 있는 객체나 near 보다 가까이 있는 객체는 표현(Rendering, 렌더링) 하지 않는다는 뜻입니다.

// 원근법이 적용되는 카메라 생성
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);

 

4. 카메라의 시점으로 공간을 렌더링 하기 위해 WebGLRenderer(렌더러)를 추가합니다.

WebGLRenderer(parameters : Object)

자주 사용하는 속성만 간단하게 설명하겠습니다.

  • canvas 속성은 렌더러가 렌더링 한 결과가 출력될 canvas 객체입니다. 속성이 설정되지 않으면 canvas 객체를 생성합니다.
  • antialias 속성은 픽셀로 되어 있는 선들을 부드럽게 만드는 옵션이다.

WebGLRenderer(렌더러) 파라미터에 antialias 속성을 추가합니다.

// WebGL 렌더러 생성
const renderer = new THREE.WebGLRenderer({antialias: true});

웹 브라우저의 크기로 WebGLRenderer(렌더러)가 렌더링 할 화면의 크기를 설정합니다.

// 랜더링할 화면의 크기(width, height) 설정
renderer.setSize(window.innerWidth, window.innerHeight);

WebGLRenderer(렌더러)가 렌더링 한 결과를 <body> 태그 안에 추가합니다.

// 랜더러가 렌더링한 결과를 HTML에 추가 - canvas 생성
document.body.appendChild(renderer.domElement);

 

만약, index.html에 <canvas> 태그가 있다면 다음 처럼 하시면 됩니다.

<!DOCTYPE html>
<html lang="en">
	<head>
		<meta charset="utf-8">
		<title>My first three.js app</title>
		<style>
			body { margin: 0; }
			#myCanvas {width: 800px; height: 450px;}
		</style>
	</head>
	<body>
		<canvas id="myCanvas"></canvas>
		<script type="module" src="/main.js"></script>
	</body>
</html>

main.js에서 canvas 객체를 가져와 WebGLRenderer(렌더러) 파라미터에 추가합니다.

// canvas 객체
const myCanvas = document.getElementById('myCanvas');
// WebGL 렌더러 생성
const renderer = new THREE.WebGLRenderer({canvas: myCanvas, antialias: true});

그리고 canvas 객체에 설정된 크기로 WebGLRenderer(렌더러)가 렌더링 할 화면의 크기를 설정합니다.

// 랜더링할 화면의 크기(width, height) 설정
renderer.setSize(myCanvas.clientWidth, myCanvas.clientHeight);

 

5. WebGLRenderer(렌더러)가 Scence(씬, 장면)과 Camera(카메라)을 사용하여 렌더링 하게 추가합니다.

// 랜더링
renderer.render(scene, camera);

 

 

그럼, Vite(비트)를 통해 확인해 보겠습니다.

 

6. Visual Studio Code의 메뉴 Terminal(터미널) > New Terminal(새 터미널)를 클릭하거나 Ctrl + Shift + `(backtick) 키를 누릅니다. 그리고 Vite(비트)를 실행하기 위해 Terminal(터미널)에서 npx 명령어를 입력하고 Enter 키를 누릅니다.

npx vite

그러면 localhost(로컬호스트, IP가 127.0.0.1)로 포트번호 5173으로 웹 서버가 실행됩니다.

 

7. Terminal(터미널)에서 Local에 있는 URL(http://localhost:5173/)에 마우스를 이동한 후 Ctrl 키를 누른 후 마우스를 클릭합니다. 그러면 기본 웹 브라우저가 실행됩니다.

 

아직 Scence(씬, 장면)에 객체가 없기 때문에 아무것도 나타나지 않았습니다.

 

그럼 Scence(씬, 장면)에 육면체를 추가해 보도록 하겠습니다.

 

8. Scence(씬, 장면)에 추가할 BoxGeometry(박스 지오메트리, 육면체)를 생성합니다.

BoxGeometry(width : Float, height : Float, depth : Float, widthSegments : Integer, heightSegments : Integer, depthSegments : Integer)
  • width(가로, 너비, 폭) : 가로길이입니다. 기본값 1 (입력하지 않으면 기본값으로 설정됩니다.)
  • height(세로, 높이) : 세로길이입니다. 기본값 1 (입력하지 않으면 기본값으로 설정됩니다.)
  • depth(깊이) : 깊이입니다. 기본값 1 (입력하지 않으면 기본값으로 설정됩니다.)
  • widthSegments(수평 세그먼트, 가로 분절 수) : 가로를 분할 면의 수입니다. 기본값 1 (입력하지 않으면 기본값으로 설정됩니다.)
  • heightSegments(수직 세그먼트, 세로 분절 수) : 세로를 분할 면의 수입니다. 기본값 1 (입력하지 않으면 기본값으로 설정됩니다.)
  • depthSegments(깊이 세그먼트, 깊이 분절 수) : 깊이를 분할 면의 수입니다 기본값 1 (입력하지 않으면 기본값으로 설정됩니다.)

 

// 육면체 지오메트리 생성
const box1Geometry = new THREE.BoxGeometry(1, 1, 1);

 

BoxGeometry(박스 지오메트리, 육면체)에 색상과 질감을 표현하는 Material(머티리얼)을 생성합니다.

MeshBasicMaterial(메쉬 베이식 머티리얼)은 조명을 고려하지 않고 단순하게 면을 렌더링 합니다.

MeshBasicMaterial(parameters : Object)

간단하게 color 속성만 설명하겠습니다.

  • color 속성은 객체의 면에 적용할 색상입니다. 기본값 0xffffff (흰색) (입력하지 않으면 기본값으로 설정됩니다.)

 

파라미터에 color 속성을 추가합니다.

const box1Material = new THREE.MeshBasicMaterial( { color: 0x00ff00 } );

 

BoxGeometry(박스 지오메트리, 육면체) Material(머티리얼)을 사용하여 객체를 생성합니다.

// 육면체와 색상과 질감의 데이터를 결합하여 육면체 객체 생성
const box1 = new THREE.Mesh(box1Geometry, box1Material);

 

Scence(씬, 장면)에 생성한 객체 추가합니다.

// 장면에 육면체 객체 추가
scene.add(box1);

 

main.js를 저장하면 Vite(비트)가 자동으로 웹 브라우저를 갱신해 줍니다.

 

Scence(씬, 장면)에 객체를 추가했지만 아무것도 나타나지 않았습니다.

그 이유는 Camera(카메라)의 위치가 객체 앞에 있어 렌더링이 되지 않기 때문입니다.

 

왜 Camera(카메라)가 객체의 앞에 있을 까요?

 

객체를 Scence(씬, 장면)에 추가할 때 객체의 위치(position)를 설정하지 않으면 Scence(씬, 장면)의 중앙에 추가됩니다.

 

그리고 Camera(카메라)도 위치(position)를 설정하지 않으면 Scence(씬, 장면)의 중앙을 보게 됩니다. 즉, Camera(카메라)의 Z 좌표가 0 좌표로 됩니다.

 

 

객체와 Camera(카메라) 사이의 거리를 계산해 보면 거리가 0이 나옵니다.

console.log(box1.position.distanceTo(camera.position));

 

그래서 Camera(카메라)의 Z 위치를 이동시켜 렌더링이 되게 합니다.

// 카메라 Z 위치를 이동
camera.position.z = 5;

 

웹 브라우저를 보면 녹색의 사각형이 나타난 것을 확인할 수 있습니다.

 

입체적으로 보이지 않는 이유는 Camera(카메라)의 위치가 정면을 바라보고 있기 때문입니다.

 

이어서 입체적으로 보기 위해 카메라(Camera)의 위치를 변동시키고 객체을 회전시켜서 Animating(애니메이팅)를 해보겠습니다.

728x90
반응형