레슨 3 / 8·20분
조명과 애니메이션
Light — 장면에 빛 더하기
현실 세계처럼 3D 장면에서도 빛이 있어야 사물을 볼 수 있습니다. Three.js는 여러 종류의 조명을 제공합니다. AmbientLight는 전체를 균일하게 밝히고, DirectionalLight는 태양처럼 평행광을, PointLight는 전구처럼 한 점에서 퍼지는 빛을, SpotLight는 스포트라이트처럼 원뿔 형태의 빛을 만듭니다.
javascript
// AmbientLight — 방향 없이 장면 전체를 균일하게 비춤
const ambient = new THREE.AmbientLight(0xffffff, 0.3); // 색상, 강도
scene.add(ambient);
// DirectionalLight — 태양광처럼 평행한 빛
const dirLight = new THREE.DirectionalLight(0xffffff, 0.8);
dirLight.position.set(5, 10, 7);
dirLight.castShadow = true; // 그림자 활성화
scene.add(dirLight);
// PointLight — 전구처럼 한 점에서 모든 방향으로 퍼지는 빛
const pointLight = new THREE.PointLight(0xff6600, 1, 20); // 색, 강도, 범위
pointLight.position.set(-3, 3, 2);
scene.add(pointLight);
// SpotLight — 원뿔 형태의 집중 조명
const spotLight = new THREE.SpotLight(0x00ff00, 1);
spotLight.position.set(0, 5, 0);
spotLight.angle = Math.PI / 6; // 원뿔 각도
spotLight.penumbra = 0.3; // 경계 부드러움
scene.add(spotLight);Animation — 움직이는 3D 세계
javascript
// requestAnimationFrame을 이용한 애니메이션 루프
const clock = new THREE.Clock();
function animate() {
requestAnimationFrame(animate);
const delta = clock.getDelta(); // 프레임 간 경과 시간(초)
const elapsed = clock.getElapsedTime(); // 시작 이후 총 시간
// 회전 애니메이션
cubeMesh.rotation.x += 0.5 * delta;
cubeMesh.rotation.y += 0.8 * delta;
// 위아래 부유 애니메이션
sphereMesh.position.y = 1 + Math.sin(elapsed * 2) * 0.5;
// 크기 변화 애니메이션
const scale = 1 + Math.sin(elapsed * 3) * 0.2;
cylinderMesh.scale.set(scale, scale, scale);
renderer.render(scene, camera);
}
animate(); // 루프 시작- •AmbientLight — 기본 밝기 확보용, 단독 사용 시 입체감 없음
- •DirectionalLight — 그림자 표현이 가능하며 야외 씬에 적합
- •PointLight — 실내 조명, 불꽃 등 점광원 표현
- •SpotLight — 무대 조명, 손전등 등 집중 조명 표현
- •clock.getDelta() — 프레임 독립적 애니메이션을 위해 경과 시간 사용
javascript
// OrbitControls — 마우스로 카메라를 회전/줌/이동
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
const controls = new OrbitControls(camera, renderer.domElement);
controls.enableDamping = true; // 부드러운 감속
controls.dampingFactor = 0.05;
controls.maxPolarAngle = Math.PI / 2; // 바닥 아래로 못 가게
function animate() {
requestAnimationFrame(animate);
controls.update(); // 매 프레임 업데이트 필수
renderer.render(scene, camera);
}💡
delta 시간을 사용하면 60fps든 30fps든 동일한 속도로 애니메이션이 재생됩니다. rotation.y += 1 * delta처럼 항상 delta를 곱하세요. OrbitControls의 enableDamping을 사용하면 반드시 animate 루프 안에서 controls.update()를 호출해야 합니다.