Three.js 는
웹 페이지에 3D 객체를 쉽게 렌더링할 수 있도록 도와주는 자바스크립트 3D 라이브러리
WebGL 기술을 기반으로 렌더링과 카메라, 조명 등의 3D프로그래밍 기술을 간단하게 사용할 수 있도록 해준다.
설치하기
npm 을 통해 설치 (CDN도 있긴 하지만 권장은 npm)
https://threejs.org/docs/index.html#manual/en/introduction/Installation
npm install three
npm install -D vite
vite 는 실행도구이다.
vite
빠르고 간결한 개발 경험에 초점을 맞춘 번들러
Webpack 과 동일한 기능을 하지만 공식문서에서 Vite 를 권장하길래 사용해보았다.
기본적으로 ES Modules 를 사용하며 뷰를 위해 만들어졌으나 다른 프레임웤에도 지원하기 시작함.
패키지와 소스 코드를 분리하여 빌드하는 특징이 있음. (패키지는 설치 후 내용이 바뀌지 않지만 소스 코드는 빈번히 바뀐다)
npx vite 로 매번 확인해주면 된다.
HTML
script 태그에 type 을 module 로 주자.
<script type="module" src="./app.js"></script>
그다음, Three.js 라이브러리를 사용하기 위한 three 모듈을 불러와준다.
import * as THREE from 'three';
Three.js 은 크게 Scene, Camera, Renderer 로 나뉜다.
Scene
렌더링할 객체와 광원을 저장하는 공간
scene 이 없으면 어떤 객체든 표시할 수 없으므로 필수적
three 모듈의 Scene() 메서드를 사용하여 Scene 객체를 생성해준다.
let scene = new THREE.Scene();
scene.background = new THREE.Color('#ccc');
scene 의 배경색은 위처럼 THREE.Color() 로 지정해줄 수 있다.
Camera
Scene 객체를 어떻게 촬영하여 보여줄 것인가 결정
- 원근법을 무시하는 OrthographicCamera
- 원근법을 적용하는 PerspectiveCamera
let camera = new THREE.PerspectiveCamera(
45, // field of view (시야각)
window.innerWidth / window.innerHeight, // aspect (비율)
0.1, // near
1000, // far
);
카메라의 설정 파라미터 중
- 시야각은 해당 시점이 화면에 보일 정도를 의미
- 비율은 웹 브라우저로 보기 때문에 화면의 너비를 높이로 나눈 값을 전달해준다.
- near 는 해당 수치보다 가까운 경우 보이지 않게 설정
- far 은 해당 수치보다 먼 경우 보이지 않게 설정
프로그램 성능 향상을 위해 near 와 far 를 조정해준다.
Renderer
Scene 과 Camera 객체를 넘겨받아 카메라의 절두체 안 3D 씬의 일부를 평면(2D)으로 렌더링
const renderer = new THREE.WebGLRenderer({
canvas: document.getElementById('canvas'), // canvas 가 있는 경우
antialias: true, // 안티앨리어싱 처리
});
렌더러 인스턴스는 WebGLRenderer() 메서드로 불러올 수 있으며,
렌더러 인스턴스를 생성하면서 앱을 렌더링할 크기를 설정해줘야 한다.
앱으로 채우려는 영역의 너비와 높이를 사용(브라우저의 너비와 높이)
renderer.setSize( window.innerWidth, window.innerHeight );
// canvas 가 없는 경우 넣어주면 canvas 가 추가됨
document.body.appendChild( renderer.domElement );
setSize() 메서드로 브라우저 크기에 맞추고 body 의 자식돔으로 넣어준다.
여기서 setSize() 메서드의 3번째 인자에 false 를 넣으면 앱 크기를 유지하면서 더 낮은 해당도로 렌더링이 가능하다.
그다음 큐브 모양을 직접 만들어보자
BoxGeometry
큐브의 모든 정점과 채우기를 포함한 객체로,
const geometry = new THREE.BoxGeometry( width, height, depth );
큐브의 너비 높이 깊이의 크기를 지정해줄 수 있다.
const material = new THREE.MeshBasicMaterial( { color: 0xcccccc } );
MeshBasicMaterial 로 재질을 적용한 속성을 줄 수 있다.
다음은 Mesh 정보로 3D 화면을 구성하는 물체이다.
geometry 와 material 정보를 넣어서 적용해줄 수 있다.
geometry : 기하하 객체의 정점 데이터
material : 기하학 객체를 그리는데 사용하는 표면 속성 (색/밝기 등)
const cube = new THREE.Mesh( geometry, material );
만들어준 큐브는 scene 에 add 해줘야 볼 수 있다.
scene.add( cube );
여기서 카메라 이동이 따로 없을 경우 같은 위치에 있어서 볼 수 없다.
camera.position.set(0, 0, 5);
카메라의 position은 set해준다. x, y, z 순서이며 카메라 위치를 지정해줄 수있음!
아직 끝이 아님.. 이제 장면 렌더링 과정이 필요하다.
render / animate loop
function animate() {
requestAnimationFrame( animate );
renderer.render( scene, camera );
}
animate();
requestAnimationFrame() : 화면이 새로 고쳐질 때마다 렌더러가 장면을 그리는 루프가 생성, 다른 브라우저 탭으로 이동할 때 일시 중지되므로 연산 비용과 배터리를 낭비하지 않을 수 있다!
renderer.render() 로 씬과 카메라를 넣어주면 쨘. 아래처럼 보인다.
큐브 애니메이션
cube.rotation.x += 0.01;
cube.rotation.y += 0.01;
모든 프레임으로 실행되며 큐브에 회전 애니메이션을 제공해준다.
가장 기초적인 큐브는 불러와봤으니, 이젠..
3D 모델 불러와보기
여기 사이트에서 3D Model 을 gltf 로 구해와준다.
https://sketchfab.com/models?features=downloadable&sort_by=-likeCount&type=models
Mesh 생성자를 활용하여 Scene 에 객체를 추가해줄 수 있다. Mesh 생성자는 위에서 봤듯이 geometry 와 material 정보를 전달 받는다.
또는 Loader 객체를 통해 3D 모델을 생성할 수도 있다.
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
기본적으로 GLTFLoader 객체를 임포팅 할 수 있으며, 해당 객체의 load() 메서드로 미리 준비된 3D 모델을 불러올 수 있다.
gltf 란?
3차원 장면과 모델을 표현하는 파일 포멧 중 하나.
메인이 되는 JSON 형식의 파일, 형태 동작 등 버퍼 데이터가 저장되는 바이너리 파일(bin) 그리고 모델마다 상이하지만 다수의 텍스처 이미지로 구성된다.
let loader = new GLTFLoader();
loader.load('./sources/models/scene.gltf', (gltf) => {
scene.add(gltf.scene);
})
위처럼 GLTFLoader() 를 통해 만들어준 로더가 load 되면 실행해줄 콜백 함수 안에 scene 에 add 해준다.
광원(조명)
물체를 보기 위해선 조명을 추가해줘야 한다. (유니티에서.. 많이 본 것들)
color 는 광원의 색
intensity 는 빛의 강도
- AmbientLight : 모든 면을 골고루 비춰주는 빛
let light = new THREE.AmbientLight(color, intensity);
// OR
let light = new THREE.AmbientLight();
light.color = 0xffff00;
light.intensity = 5;
- HemisphereLight : 땅과 하늘, 두 곳의 광원을 가지는 빛
let light = new THREE.HemisphereLight(skyColor, groundColor, intensity);
- DirectionalLight : 태양과 같이 무한대의 먼 거리에서 모든 물체에 같은 각도로 비추는 빛
let light = new THREE.DirectionalLight(color, intensity);
- PointLight : 전구같이 한 지점에서 모든 방향으로 방출되는 빛
let light = new THREE.PointLight(color, intensity, distance, decay);
distance 는 빛이 방출되는 거리
decay 를 통해 빛이 거리에 따라 얼마나 어두워지는지 결정
- SpotLight : 한 지점에서 단방향 원뿔형으로 방출되는 빛
let light = new THREE.SpotLight(color, intensity, distance, angle, penumbra, decay);
angle 은 빛이 퍼지는 각도로 PI / 2 가 최댓값이다.
penumbra 는 빛의 가장자리의 선명도 설정, 커질수록 가장자리가 흐릿해진다.
- RectAreaLight : 사각 평면에서 균일하게 방출되는 빛
let light = new THREE.RectAreaLight(color, intensity, width, height);
width와 height 는 광원의 가로/세로 크기를 의미(기본값은 10)
let light = new THREE.DirectionalLight(0xffffff,10);
scene.add(light);
나는 태양광으로 사용해줬다.
애니메이션
자바스크립트에서 애니메이션을 구현하는 방식에는
- setInterval
- requestAnimationFrame
으로 두가지가 있다고 한다. 하지만 알다시피 setInterval 은 애니메이션을 위한 메서드가 아니고 쓸데없는 콜스택이 많이 발생하여 딜레이가 생길 가능성이 크므로 requestAnimationFrame 을 사용해준다!
반복할 인자를 매개변수로 받아주어 해당 인자를 1초에 최대 60번까지 실행하여 호출 스택이 과도하게 커지는 것을 방지하고
딜레이 없이 부드러운 애니메이션을 확인할 수 있다.
그리고 위에 기재했듯이 requestAnimationFrame 메서드를 페이지가 비활성 상태라면 렌더링을 중지하므로 CPU 리소스와 배터리를 낭비하지 않아 성능 향상에 도움이된다고 한다.
requestAnimationFrame 메서드는 재귀적으로 호출시켜주는 방식으로 사용해준다.
GLTFLoader 쪽에 애니메이션 추가해줬다. (gltf.scene 에 애니메이션을 추가해줘서 사용한다)
function animate(){
requestAnimationFrame(animate);
gltf.scene.rotation.y += 0.010;
renderer.render(scene,camera);
}
animate();
일단은 여기까지! 귀여운 시바를 빙글빙글 돌렸다.
다음에는 클릭해서 여러 각도로 볼 수 있게끔(카메라 조정) 공부해볼 요량이다.
'Ect. > Library' 카테고리의 다른 글
Toast UI (feact. React) 사용기 3 - Grid (0) | 2023.07.13 |
---|---|
Toast UI (feat.React) 사용기 2 - Chart 기능 (0) | 2023.07.12 |
Toast UI (feat.React) 사용기 1 - 텍스트 에디터 (0) | 2023.07.08 |
OrbitControls -Threejs (0) | 2023.06.21 |
openGL 과, WebGL 기초 (0) | 2023.06.09 |