Three.js는 기본적으로 애니메이션과 상호작용을 쉽게 구현할 수 있는 기능을 제공하며, 이를 통해 3D 장면에 생동감을 더하고 사용자와의 상호작용을 가능하게 한다. 이번 글에서는 Three.js에서 애니메이션을 추가하고, 마우스 클릭이나 드래그 같은 이벤트를 통해 상호작용을 구현하는 방법을 알아보겠다.
이전 글
1. [개발자일기/3D 웹 세상] - 웹에서의 3D 그래픽
2. [개발자일기/3D 웹 세상] - GPU와 렌더링의 관계: GPU가 하는 일
3. [개발자일기/3D 웹 세상] - Three.js의 기본 개념과 원리
4. [개발자일기/3D 웹 세상] - React와 Three.js의 결합: react-three-fiber
5. [개발자일기/3D 웹 세상] - react-three-fiber로 간단한 3D 객체 렌더링하기
6. [개발자일기/3D 웹 세상] - Three.js에서 조명과 재질을 사용해보자!
1. Three.js 애니메이션의 기본 개념
Three.js에서는 매 프레임마다 장면을 업데이트하는 방식으로 애니메이션을 구현한다. 기본적으로 requestAnimationFrame 메서드를 사용해 루프(Loop)를 만들고, 매 프레임마다 객체의 속성을 업데이트하여 애니메이션을 연출한다.
기본 애니메이션 구현 예제
간단한 예로 큐브가 지속적으로 회전하는 애니메이션을 구현해 보자.
import * as THREE from 'three';
function init() {
// 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);
// 큐브 생성
const geometry = new THREE.BoxGeometry();
const material = new THREE.MeshStandardMaterial({ color: 0x0077ff });
const cube = new THREE.Mesh(geometry, material);
scene.add(cube);
// 조명 추가
const light = new THREE.DirectionalLight(0xffffff, 1);
light.position.set(5, 10, 7.5);
scene.add(light);
camera.position.z = 5;
// 애니메이션 함수
function animate() {
requestAnimationFrame(animate);
// 큐브 회전
cube.rotation.x += 0.01;
cube.rotation.y += 0.01;
renderer.render(scene, camera);
}
animate();
}
init();
- requestAnimationFrame: 애니메이션 루프를 만드는 함수로, 브라우저의 화면 새로고침 속도에 맞춰 함수를 호출하여 부드러운 애니메이션을 제공한다.
- cube.rotation: 큐브의 rotation 속성을 지속적으로 업데이트하여 매 프레임마다 큐브가 조금씩 회전하도록 한다.
이 코드를 실행하면 3D 큐브가 화면에서 지속적으로 회전하는 모습을 볼 수 있다.
2. Three.js에서 상호작용 구현하기
Three.js는 사용자와의 상호작용을 위해 다양한 이벤트를 지원한다. 기본적으로 마우스 클릭, 드래그, 호버와 같은 이벤트를 활용할 수 있으며, 이를 통해 객체와 상호작용하거나 카메라를 이동시키는 등 다양한 인터랙션을 구현할 수 있다.
마우스 클릭 이벤트와 상호작용 예제
아래는 마우스 클릭으로 3D 객체의 색상을 변경하는 예제다. 이 예제에서는 Raycaster를 사용해 마우스 클릭이 특정 객체와 교차하는지 확인하고, 클릭된 객체의 색상을 변경한다.
import * as THREE from 'three';
function init() {
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);
// 큐브 생성
const geometry = new THREE.BoxGeometry();
const material = new THREE.MeshStandardMaterial({ color: 0x0077ff });
const cube = new THREE.Mesh(geometry, material);
scene.add(cube);
const light = new THREE.DirectionalLight(0xffffff, 1);
light.position.set(5, 10, 7.5);
scene.add(light);
camera.position.z = 5;
// Raycaster와 마우스 설정
const raycaster = new THREE.Raycaster();
const mouse = new THREE.Vector2();
// 마우스 클릭 이벤트
function onMouseClick(event) {
// 마우스 위치를 정규화(-1에서 1 사이 값)
mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
// Raycaster로 교차 검사
raycaster.setFromCamera(mouse, camera);
const intersects = raycaster.intersectObjects(scene.children);
if (intersects.length > 0) {
intersects[0].object.material.color.set(Math.random() * 0xffffff); // 색상 변경
}
}
window.addEventListener('click', onMouseClick, false);
function animate() {
requestAnimationFrame(animate);
cube.rotation.x += 0.01;
cube.rotation.y += 0.01;
renderer.render(scene, camera);
}
animate();
}
init();
- Raycaster: Raycaster는 카메라에서 쏘는 보이지 않는 광선을 이용해 객체와의 교차점을 찾는 데 사용된다. 이를 통해 마우스 위치에 있는 객체를 감지할 수 있다.
- 마우스 위치 정규화: Three.js에서 마우스 위치는 -1에서 1 사이의 값으로 변환된다. event.clientX와 event.clientY를 정규화하여 Raycaster에 적용한다.
- intersectObjects: Raycaster의 intersectObjects 메서드를 사용해 교차된 객체를 배열로 반환하며, 첫 번째 객체의 색상을 랜덤하게 변경한다.
위 예제에서는 마우스를 클릭할 때마다 큐브의 색상이 무작위로 변경된다.
3. 애니메이션과 인터랙션을 결합한 예제
이제 애니메이션과 상호작용을 결합하여, 사용자가 클릭할 때마다 회전 속도가 증가하는 애니메이션을 만들어 보자. 사용자가 클릭할 때마다 객체의 회전 속도가 빠르게 변한다.
import * as THREE from 'three';
function init() {
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);
const geometry = new THREE.BoxGeometry();
const material = new THREE.MeshStandardMaterial({ color: 0x0077ff });
const cube = new THREE.Mesh(geometry, material);
scene.add(cube);
const light = new THREE.DirectionalLight(0xffffff, 1);
light.position.set(5, 10, 7.5);
scene.add(light);
camera.position.z = 5;
let rotationSpeed = 0.01; // 초기 회전 속도
function onMouseClick() {
rotationSpeed += 0.01; // 클릭할 때마다 회전 속도 증가
}
window.addEventListener('click', onMouseClick);
function animate() {
requestAnimationFrame(animate);
cube.rotation.x += rotationSpeed;
cube.rotation.y += rotationSpeed;
renderer.render(scene, camera);
}
animate();
}
init();
- rotationSpeed 변수: 큐브의 회전 속도를 결정하는 변수로, 초기값은 0.01로 설정되어 있다.
- 클릭 이벤트로 회전 속도 증가: 사용자가 클릭할 때마다 rotationSpeed가 0.01씩 증가하여, 큐브가 점점 더 빠르게 회전한다.
이 예제는 사용자가 상호작용할 때 애니메이션 속도가 변화하는 인터랙티브한 애니메이션을 구현하는 좋은 방법이다.
결론
Three.js는 애니메이션과 상호작용을 통해 3D 장면에 생동감을 더할 수 있는 기능을 제공한다. 애니메이션 루프를 사용해 객체의 속성을 지속적으로 업데이트하고, Raycaster와 이벤트를 통해 사용자와 상호작용을 구현할 수 있다. 이러한 기능들을 활용하여, 더욱 풍부하고 몰입감 있는 3D 장면을 구현해 보자.
'개발자일기 > 3D 웹 세상' 카테고리의 다른 글
react-three-rapier로 물리 엔진 연동하기 (0) | 2024.11.14 |
---|---|
3D 물리 엔진 개요와 Three.js에서의 사용 (0) | 2024.11.12 |
Three.js에서 조명과 재질을 사용해보자! (0) | 2024.11.10 |
react-three-fiber로 간단한 3D 객체 렌더링하기 (0) | 2024.11.09 |
React와 Three.js의 결합: react-three-fiber (1) | 2024.11.08 |