본문 바로가기
Three.js/Class techniques

[threejs-journey 2-1] Lights

by SL123 2025. 7. 15.

개요

3D 그래픽에서 조명은 단순히 Scene을 밝히는 것을 넘어, 객체의 재질감, 깊이, 그리고 전체적인 분위기를 결정하는 핵심 요소입니다. Three.js는 다양한 시나리오에 맞춰 사용할 수 있는 풍부한 조명 컴포넌트를 제공합니다. 본 포스트에서는 Three.js의 주요 조명들의 특징과 사용법을 알아보고, 사실적인 Scene을 구성하기 위한 성능 고려사항과 최적화 기법까지 다뤄보겠습니다.

 

테스트를 위해 MeshStandardMaterial이 적용된 여러 기하학 객체(Sphere, Cube, Torus, Plane)를 Scene에 배치한 상태를 가정하고 시작하겠습니다. 이 재질은 물리적으로 반응하므로, 각 조명의 효과를 명확하게 관찰하기에 적합합니다. 

 

AmbientLight(전역광)

AmbientLight는 Scene의 모든 객체에 대해 방향성 없이 균일한 빛을 더합니다. 그림자를 생성하지는 않지만, 빛이 직접 닿지 않아 완전히 검게 표현될 수 있는 부분의 최소한의 밝기를 보정하는 역할을 합니다.

// new THREE.AmbientLight(color, intensity)
const ambientLight = new THREE.AmbientLight(0xffffff, 0.5);
scene.add(ambientLight);

실제 환경에서는 빛이 여러 표면에 반사되어 간접광을 형성합니다. Three.js는 실시간 렌더링 성능을 위해 복잡한 간접광 계산(Global Illumination)을 기본적으로 지원하지 않습니다. 이때 약한 강도의 AmbientLight를 사용하면 이 간접광 효과를 근사하여 Scene의 전반적인 현실감을 높일 수 있습니다.

 

DirectionalLight(평행광)

DirectionalLight는 태양광 같이 무한히 먼 광원에서 오는 평행한 빛을 시뮬레이션합니다. 광원의 위치는 빛의 '방향'을 정의할 뿐, 객체와 광원 사이의 거리는 빛의 강도에 영향을 주지 않습니다.

// new THREE.DirectionalLight(color, intensity)
const directionalLight = new THREE.DirectionalLight(0xffffff, 1.0); 
// 빛의 위치를 설정하여 방향을 지정 (position에서 원점을 향해 빛이 발사됨)
directionalLight.position.set(2, 5, 3);
scene.add(directionalLight);

기존 상태
방향 이동

 

이 조명은 명확한 방향성을 가지므로, 객체의 입체감을 표현하고 그림자를 생성하는 데 가장 핵심적은 역할을 수행합니다.

 

 

HemisphereLight (반구광)

HemisphereLight는 Scene의 상단(하늘)과 하단(지면)에서 오는 빛을 각각 다른 색으로 지정하여, 보다 자연스러운 야외 환경의 빛을 표현하는 데 특화된 조명입니다.

// new THREE.HemisphereLight(skyColor, groundColor, intensity)
const hemisphereLight = new THREE.HemisphereLight(0xb1e1ff, 0x4a4a4a, 0.8);
scene.add(hemisphereLight);

다른 Light도 킨 상태
HemisphereLight만 킨 상태

 

메쉬의 법선(Normal) 벡터 방향에 따라 하늘색과 땅 색 사이의 색상이 보간되어 적용됩니다. DirectionalLight와 함께 사용하면 직접광과 간접광을 효과적으로 분리하여 표현할 수 있으며, AmbientLight에 비해 적은 비용으로 풍부한 색감의 장면을 연출할 수 있습니다.

 

 

PointLight (점광원)

PointLight는 특정 지점에서 모든 방향으로 빛이 퍼져나가는 광원을 시뮬레이션합니다. 백열전구나 촛불과 같은 효과를 만드는 데 사용됩니다.

// new THREE.PointLight(color, intensity, distance, decay)
const pointLight = new THREE.PointLight(0xff9000, 1.5, 50, 2);
pointLight.position.set(-5, 3, 2);
scene.add(pointLight);

주요 파라미터는 다음과 같습니다:

  • distance: 빛이 최대로 도달하는 거리입니다. 0일 경우 무한대를 의미합니다.
  • decay: 거리에 따른 빛의 감쇠율입니다. 물리적으로 정확한 렌더링을 위해서는 기본값인 2를 사용하는 것이 권장됩니다. 

빛 이동
빛 이동
빛 감쇠
PointLight만 킨 상태

 

 

RectAreaLight (사각형 영역광)

RectAreaLight는 사각형 평면의 형태를 가진 광원으로, 창문을 통해 들어오는 빛이나 스튜디오의 소프트박스 조명 효과를 시뮬레이션 합니다. 면적을 가진 광원이기에 부드럽고 사실적인 반사광을 표현합니다.

// new THREE.RectAreaLight(color, intensity, width, height)
const rectAreaLight = new THREE.RectAreaLight(0x4e00ff, 5, 2, 2);
rectAreaLight.position.set(0, 2, 3);
rectAreaLight.lookAt(0, 0, 0); // 조명이 (0,0,0)을 향하도록 설정
scene.add(rectAreaLight);

주의할 점은 RectAreaLight는 PBR 재질인 MeshStandardMaterial과 MeshPhysicalMaterial에서만 정상적으로 작동하며, 다른 조명에 비해 계산비용이 높다는 것입니다.

 

RectAreaLioght만 킨 경우
위치 조정

 

 

SpotLight (스포트라이트)

SpotLight는 원뿔 형태의 빛을 한 방향으로 집중하여 비추는 조명입니다. 무대 조명이나 손전등처럼 특정 영역을 강조하는 데 효과적입니다.

// new THREE.SpotLight(color, intensity, distance, angle, penumbra, decay)
const spotLight = new THREE.SpotLight(0x78ff00, 4.0, 40, Math.PI * 0.1, 0.2, 1);
spotLight.position.set(0, 5, 3);
scene.add(spotLight);

// SpotLight의 방향은 target 객체의 위치에 의해 결정됩니다.
// target의 위치를 변경하려면 target 객체를 씬에 추가해야 합니다.
scene.add(spotLight.target);
spotLight.target.position.set(1, 0, 0);

  • angle: 빛의 원뿔 각도입니다.
  • penumbra: 빛의 가장자리 부분의 부드러운 감쇠(반그림자) 효과를 조절합니다. 0에서 1사이의 값을 가집니다.

위치 이동(Target 변경)

 

 

 

성능 고려사항 및 최적화

실시간 렌더링에서 조명은 성능에 직접적인 영향을 미칩니다. 조명의 계산 복잡도에 따른 비용은 일반적으로 다음과 같습니다.

  • 저비용(Low Cost): AmbientLight, HemisphereLight
  • 중간 비용(Medium Cost): DirectionalLight, PointLight
  • 고비용 (High Cost): SpotLight, RectAreaLight

프로젝트의 요구사항과 타겟 환경에 맞춰 최소한의 조명을 사용하고, 가능하면 저비용 조명을 우선적으로 활용하는 것이 성능 관리에 유리합니다.

 

성능 최적화 기법: 라이트 베이킹(Light Baking) 

고품질의 그래픽을 유지하면서 성능을 확보하기 위한 가장 효과적인 기법 중 하나는 라이트 베이킹입니다. 이는 복잡한 조명 연산의 결과를 미리 계산하여 텍스처에 '구워내는(bake)' 방식입니다.

 

렌더링 시에는 실시간 조명 계싼 대신 이 텍스처를 사용하므로, 매우 높은 성능을 확보할 수 있습니다. 정적인(static) 조명과 객체로 구성된 Scene에 특히 효과적입니다.

 

 

디버깅을 위한 Helpers

Three.js는 각 조명의 위치, 방향, 범위를 시각적으로 디버깅할 수 있도록 헬퍼(Helper) 클래스를 제공합니다.

const hemisphereLightHelper = new THREE.HemisphereLightHelper(hemisphereLight, 0.2)
scene.add(hemisphereLightHelper);

const directionalLightHelper = new THREE.DirectionalLightHelper(directionalLight, 0.2)
scene.add(directionalLightHelper)


const pointLightHelper = new THREE.PointLightHelper(pointLight, 0.2)
scene.add(pointLightHelper)


const spotLightHelper = new THREE.SpotLightHelper(spotLight)
scene.add(spotLightHelper)

HemisphereHelper
DirectionalHelper
PointHelper
SpotHepler

 

 

 

RectAreaLightHelper는 import 해서 사용해야 합니다.

import { RectAreaLightHelper } from 'three/examples/jsm/helpers/RectAreaLightHelper.js'

const rectAreaLightHelper = new RectAreaLightHelper(rectAreaLight)
scene.add(rectAreaLightHelper)

개발 과정에서 헬퍼를 활용하면 조명의 배치와 설정을 훨씬 직관적으로 수행할 수 있습니다.

 

 

결론

Three.js에서 제공하는 주요 조명들의 개념과 활용법, 그리고 성능 관련 고려사항을 살펴보았습니다. 각 조명의 특성을 정확히 이해하고 조합하여, 의도에 맞는 풍부하고 효율적인 3D 장면을 구축하는 데 이 내용이 도움이 되기를 바랍니다.