[Three.js] 맛보기

Study·2021년 8월 9일
2

Three.js

목록 보기
1/8
post-thumbnail
post-custom-banner

본문은 Three.js 를 맛보기위해 Three.js Document 의 내용을 간단하게 익혀본다.

장면 만들기

가장 먼저 HTML 파일을 만들고 tree.js 파일을 가져와서 실행한다.

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>My first three.js app</title>
		<style>
			body { margin: 0; }
			canvas { display: block; }
		</style>
	</head>
	<body>
		<script src="js/three.js"></script>
		<script>
			// 트리 JS 코딩
		</script>
	</body>
</html>

Scene 만들기

three.js 로 뭔가를 표현하기 위해선 scene , camera , renderer 가 필요하다.

다음과 같이 장면을 구현할 수 있다.

const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera( 75,
	window.innerWidth / window.innerHeight, 0.1, 1000 );

const renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );

여러 종류의 카메라가 있지만, 지금은 PerspectiveCamera 를 사용해보자.

매개변수는 다음과 같다.

  1. field of view(시야각) FOV 는 해당 시점의 화면이 보일 정도를 나타낸다.
  2. aspect ratio(종횡비) 는 해당 요소를 틀어져 보일 수 있는 정도이다.
  3. near 은 해당 값보다 가까이 있는 오브젝트는 렌더링되지 않는다.
  4. farnear 과 반대로 멀 수록 렌더링되지 않는다.

nearfar 은 앱 성능 향상을 위해 사용할 수 있다.

renderer 는 WebGL 지원을 안할 때의 대비용으로 사용한다.
인스턴스로 생성하면 렌더링할 사이즈를 설정해야 한다.
사이즈는 그대로 유지하되 더 낮은 해상도로 렌더링하고 싶으면 세 번째 매개변수에 false 를 전달한다.

마지막으로 렌더링한 것을 <canvas> 엘리먼트로 HTML 문서에 넣어준다.

이제 큐브를 추가한다.

const geometry = new THREE.BoxGeometry();
const material = new THREE.MeshBasicMaterial( { color: 0x00ff00 } );
const cube = new THREE.Mesh( geometry, material );
scene.add( cube );

camera.position.z = 5;

큐브를 만들 객체로 BoxGeometry 를 사용한다.

geometry 에 색칠을 해줄 요소로 MeshBasicMaterial 에 매개변수로 녹색인 0x00ff00 을 전달한다.

CSS 나 Photoshop 처럼 hex colors 도 가능하다.

세 번째로 Mesh 로 화면 안에 삽입하여 자유롭게 해줄 수 있는 객체를 사용한다.

scene.add() 로 추가를 하고, 기본 설정으로 (0, 0, 0) 속성을 가진다.

scene 렌더링

아직 렌더링을 하지 않아 보이지 않을 것이다.

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

1초에 60번 렌더링될 것이다.
setInterval 보다 requestAnimationFrame 사용이 더 이점이 많으니 이를 사용한다.

큐브 애니메이팅

초록 박스를 확인할 수 있다. 이제 큐브를 회전시켜보자.

다음 코드를 추가한다.

function animate() {
	requestAnimationFrame( animate );
  
	cube.rotation.x += 0.01;
	cube.rotation.y += 0.01;
  
	renderer.render( scene, camera );
}

WebGL 호환성 검사

몇몇 브라우저에선 WebGL 이 지원하지 않을 수 있다.
지원 여부를 체크하여 가능한지 메시지를 띄우는 코드를 작성해본다.

스크립트를 추가하고 렌더링하기 전 아래 코드를 실행해보자.

if ( WEBGL.isWebGLAvailable() ) {
	animate();
} else {
	const warning = WEBGL.getWebGLErrorMessage();
	document.getElementById( 'container' ).appendChild( warning );
}

선 그리기

Mesh 를 사용하지 않고 선이나 원을 그려보자.

먼저 renderer , scene , camera 를 설정한다.

const renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );

const camera = new THREE.PerspectiveCamera( 45, 
	window.innerWidth / window.innerHeight, 1, 500 );
camera.position.set( 0, 0, 100 );
camera.lookAt( 0, 0, 0 );

const scene = new THREE.Scene();

다음으로 재질을 설정한다.
LineBasicMaterial 이나 LineDashedMaterial 를 사용하면 된다.

const material = new THREE.LineBasicMaterial( { color: 0x0000ff } );

다음으로 꼭짓점에 대한 벡터를 설정한다.

const points = [];
points.push( new THREE.Vector3( - 10, 0, 0 ) );
points.push( new THREE.Vector3( 0, 10, 0 ) );
points.push( new THREE.Vector3( 10, 0, 0 ) );

const geometry = new THREE.BufferGeometry().setFromPoints( points );

선은 연속된 꼭짓점 쌍으로 그려져 첫 번째와 마지막 꼭짓점엔 그려지지 않는다. (선이 닫혀있지 않음)

이제 두 선을 그리기 위한 점과 재질을 합쳐 선으로 만든다.

const line = new THREE.Line( geometry, material );

이제 scene 에 추가하고 render 하자

scene.add( line );
renderer.render( scene, camera );

텍스트 만들기

텍스트 만들기엔 여러 방법이 있다.

  1. DOM + CSS

HTML 로 텍스트를 추가한다.

z-index 를 활용하여 절대 위치를 설정한다.

  1. 캔버스에 텍스트 그리기

  2. 3D 모델을 사용

  3. 절차적 텍스트 geometry

THREE.js 만의 절차적 및 동적 3D 텍스트 geometry 를 사용하고 싶다면 THREE.TextGeomtry 의 인스턴스인 mesh 를 사용한다.

new THREE.TextGeometry( text, parameters );

이 작업을 수행하려면 TextGeometry 의 font 파라미터가 THREE.Font 인스턴스로 설정돼있어야 한다.

  1. 비트맵 글꼴

BMFonts (비트맵 폰트) 는 단일 BufferGeometry에 글자들을 일괄적으로 활용할 수 있다.

렌더링은 word-wrapping, letter spacing, kerning 등을 지원한다.

3D 모델 불러오기

3D 모델을 다양한 three.js 의 로더로 불러올 수 있다.

가능하다면 glTF(GL Transmission Format)를 사용하는 것을 추천한다.
.GLB , .GLTF 버전의 포맷 모두 잘 지원될 것이다.
glTF 는 런타임 자원 효율에 초점을 맞추고 있어 로딩이 빠르고 정확하다.

속성으로는 meshes , materials , textures , skins , skeletons , morph targets , animations , lights 그리고 cameras 가 있다.

glTF 파일은 Sketchfab 사이트 등에서 이용할 수 있다.

로딩

three.js 엔 몇몇 로더를 제외하고(예: ObjectLoader) 기본적으로 포함되어있지 않아 개별적으로 추가해야 한다.

import { GLTFLoader } from 'loader/GLTFLoader.js';

로더를 import 한 후, scene 모델을 로드한다.
glTF의 경우 스크립트는 다음과 같다.

const loader = new GLTFLoader();

loader.load('path/model.glb', function ( gltf ) {
  scene.add( gltf.scene )
}, undefined, function (  error ) {
  console.error( error );
} );

위 자동차 모델은 무료 모델을 가져와 GLTFLoader 를 사용하여 모델을 사용해보았다.

문제해결

모델링이 아예 나오지 않거나 색이 안칠해져있을 경우가 있는데 이런 경우엔 다음 순서로 해결해보자.

  1. 콘솔 에러를 체크
  2. 다른 애플리케이션에서 모델 확인
  3. 모델을 1000배 혹은 축소. 모델이 매우 커서 카메라에 안담기는 경우가 있다.
  4. 밝은 모델을 사용하거나 위치를 바꾸어 본다.
  5. 네트워크 탭에서 failed texture requests 를 확인한다.

지원 요청

위 문제 해결 절차도 먹히지 않는다면 three.js 포럼에 문제 제기를 해보자.

기타

meta

<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">

meta 태그로 모바일 브라우저들의 뷰포트 크기와 확대정도를 조절한다.

화면 사이즈와 관계없는 크기 유지

모든 오브젝트들이 카메라의 거리와 상관 없이, 화면 사이즈가 변경된다고 해도, 같은 크기로 보여지고 싶다고 가정하자면 다음 공식을 통해 유지할 수 있다.

visible_height = 2 * Math.tan( ( Math.PI / 180 ) * camera.fov / 2 ) * distance_from_camera;

오브젝트 일부가 안보일 경우

컬링의 문제로 뒷편의 면을 제거해 버리면 된다. 이 문제가 의심된다면 재질의 면을 THREE.DoubleSide로 변경해보자.

material.side = THREE.DoubleSide
profile
Study
post-custom-banner

0개의 댓글