장면 만들기
장면 환경 만들기
Three.js가 장면 (scene) 을 렌더링하려면 scene, camera, renderer가 필요하다. JavaScript에서는 이전 글에서 언급한 대로 설치 방법에 따라 Three.js를 import해야 한다.
// main.js
import * as THREE from 'three'
또한 HTML에서 Three.js의 렌더링 결과를 표시하기 위해, Three.js가 장면을 렌더링할 <canvas> 요소를 생성하거나 지정해야 한다.
const canvas = document.createElement("canvas");
document.body.appendChild(canvas);
renderer는 canvas를 domElement로, 그리고 alpha, anti-alias 등을 options로 받는다. 앱이 화면을 가득 채우게 하려면 renderer의 크기를 window.innerWidth와 window.innerHeight로 설정하면 된다.
const renderer = new THREE.WebGLRenderer({canvas: canvas, alpha: true, antialias: true});
renderer.setSize( window.innerWidth, window.innerHeight );
다음으로, camera는 PerspectiveCamera 또는 OrthographicCamera로 정의할 수 있다. 예제에서는 원근 카메라 (perspective camera) 를 선택하였다. 원근 카메라는 시야각 (field of view), 종횡비 (aspect ratio), 최소깊이값 (near), 최대깊이값 (far) 을 인자로 받는다.
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.set(1, -5, 5);
camera.lookAt(new THREE.Vector3(0,0,0));
기본값의 장면 객체를 생성한 후 renderer.render(scene, camera)를 호출하면 렌더링 결과가 canvas에 나타난다.
const scene = new THREE.Scene();
renderer.render(scene, camera);
장면 객체 만들기
장면을 구성하려면 오브젝트 (object) 와 광원 (light) 이 필요하다. 오브젝트 객체를 생성하려면 geometry, material, mesh 속성이 필요하다. 아래에서는 큐브 geometry와 basic material을 정의한다. BoxGeometry(1,1,1)은 한 변의 길이가 1인 큐브를 만든다. MeshBasicMaterial은 오브젝트의 재질을 구성하며, 조명의 영향을 받지 않는다.
const geometry = new THREE.BoxGeometry(1, 1, 1);
const material = new THREE.MeshBasicMaterial({color: 0xff0000});
const cube = new THREE.Mesh(geometry, material);
scene.add(cube);

반면, MeshLambertMaterial을 사용하는 경우에는 장면에 광원을 추가해야 한다.
const geometry = new THREE.BoxGeometry(1, 1, 1);
const material = new THREE.MeshLambertMaterial({color: 0xff0000});
const cube = new THREE.Mesh(geometry, material);
scene.add(cube);
const light = new THREE.PointLight(0xffffff, 50);
light.position.set(2, -3, 5);
light.lookAt(new THREE.Vector3(0,0,0));
scene.add(light);

애니메이션
장면이 움직이게 하려면 renderer.render(scene, camera)를 반복적으로 실행해야 한다. canvas 애니메이션과 마찬가지로, setInterval()보다는 requestAnimationFrame()을 사용하는 것이 부드러운 렌더링과 자원 절약 측면에서 추천된다.
function animate () {
requestAnimationFrame(animate);
renderer.render(scene, camera);
}
animate();
애니메이션을 확인하기 위해 큐브를 회전시켜 보자. animate() 함수 안에 cube.rotateX(0.02)를 삽입한다.
function animate () {
requestAnimationFrame(animate);
cube.rotateX(0.02);
renderer.render(scene, camera);
}
animate();

장면의 시점 제어
마우스 조작으로 카메라의 자세를 제어하려면 Three.js의 애드온 (add-on) 을 사용할 수 있다. 애드온은 다양하고 유용한 컨트롤을 제공한다. 특히 orbit controls는 카메라가 대상 주위의 궤도를 따라 움직이도록 한다.
import { OrbitControls } from 'three/addons/controls/OrbitControls.js'
...
const controls = new OrbitControls(camera, canvas);
orbit controls의 댐핑 (damping) 효과를 활성화하려면 controls.enableDamping = true로 설정하고 animate() 함수를 다음과 같이 수정한다.
function animate () {
requestAnimationFrame(animate);
cube.rotateX(0.02);
controls.update();
renderer.render(scene, camera);
}
animate();
전체 코드
import * as THREE from 'three'
import { OrbitControls } from 'three/addons/controls/OrbitControls.js'
const canvas = document.createElement("canvas");
document.body.appendChild(canvas);
const renderer = new THREE.WebGLRenderer({canvas: canvas, alpha: true, antialias: true});
renderer.setSize( window.innerWidth, window.innerHeight );
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.set(1, -5, 5);
camera.lookAt(new THREE.Vector3(0,0,0));
const geometry = new THREE.BoxGeometry(1, 1, 1);
const material = new THREE.MeshLambertMaterial({color: 0xff0000});
const cube = new THREE.Mesh(geometry, material);
const light = new THREE.PointLight(0xffffff, 50);
light.position.set(2, -3, 5);
light.lookAt(new THREE.Vector3(0,0,0));
const scene = new THREE.Scene();
scene.add(cube);
scene.add(light);
const controls = new OrbitControls(camera, canvas);
controls.enableDamping = true;
function animate () {
requestAnimationFrame(animate);
cube.rotateX(0.02);
controls.update();
renderer.render(scene, camera);
}
animate();