TIL 120 | Three.js 기본 - Shadows 1

meow·2025년 4월 5일
0

Interactive

목록 보기
10/11
post-thumbnail

Shadow Map

Shadow Map은 3D 그래픽에서 그림자(Shadow)를 표현하기 위한 핵심 기법 중 하나다.

Shadow Map이란?

Shadow Map은 카메라가 아닌 빛(Light)의 시점에서 본 장면의 깊이 정보(depth)를 저장한 텍스처(texture)다. 이걸 이용해서, 어떤 오브젝트가 빛을 가리고 있는지를 판단해서 그림자를 생성할 수 있다.

동작 원리

  1. 빛의 시점에서 씬을 렌더링
    • 깊이(depth)만 렌더링해서 Shadow Map(그림자 맵)을 만든다.
    • 이걸 통해 “어느 부분이 빛에 직접 보이는지”를 파악할 수 있다.
  2. 카메라 시점에서 씬을 렌더링
    • 각 픽셀이 빛의 시점에서 보이는 곳인지 아닌지를 Shadow Map을 보고 판단한다.
    • 보이지 않으면 그림자 영역으로 간주해서 어둡게 처리한다.

Three.js에서의 역할

Three.js에서는 Shadow Map을 자동으로 처리할 수 있다.

  1. 렌더러 설정
const renderer = new THREE.WebGLRenderer();
renderer.shadowMap.enabled = true;
  1. 빛(Light) 설정
const light = new THREE.DirectionalLight(0xffffff, 1);
light.castShadow = true;
scene.add(light);
  1. 오브젝트 설정
mesh.castShadow = true;     // 그림자를 만들 오브젝트
mesh.receiveShadow = true;  // 그림자를 받는 오브젝트

Before

After

💡 참고: 지원하는 빛 종류

•	DirectionalLight ✅
•	SpotLight ✅
•	PointLight (성능 부담 큼) ✅
•	AmbientLight, HemisphereLight ❌ (그림자 지원 안 함)

📌 Shadow Map의 성능 개선

1. 해상도 조절

• Shadow Map의 해상도(shadow.mapSize)를 적절히 조정하면 성능/퀄리티 밸런스를 맞출 수 있다.
• 그림자 품질이 낮게 보일 땐, 해상도를 높이거나 shadow.bias 등을 조정해줘야 한다.
• shadow map의 기본 해상도는 512x512이다.

directionalLight.shadow.mapSize.width = 1024
directionalLight.shadow.mapSize.height = 1024

2. 카메라 범위 조절

Shadow Map도 내부적으로는 카메라로 깊이(depth)를 찍는 것이기 때문에
광원의 shadow camera의 near/far 범위를 조절하면 그림자 품질이 좋아질 수 있다.

const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);

• near: 카메라에서 가장 가까운 렌더링 거리
• far: 카메라에서 가장 먼 렌더링 거리

• far 값이 너무 크면 depth precision이 낮아져서 그림자가 떨리거나 깨져 보인다. (shimmering, acne)
• 적절한 near/far 설정은 shadow map의 depth precision을 최적화해서 품질 향상

directionalLight.shadow.camera.near = 1
directionalLight.shadow.camera.far = 6

const directionalLightCameraHelper = new THREE.CameraHelper(directionalLight.shadow.camera)
scene.add(directionalLightCameraHelper)

• 카메라의 상하좌우 범위까지 지정한 경우.
👆 이 범위 안에 있는 객체만 그림자 계산에 포함되므로,
딱 필요한 범위만 설정하면 성능과 품질 모두 향상된다!

directionalLight.shadow.camera.top = 2
directionalLight.shadow.camera.right = 2
directionalLight.shadow.camera.bottom = -2
directionalLight.shadow.camera.left = -2

radius 값으로 그림자의 테두리를 blurry 하게 처리할 수 있고, cameraHelper도 invisible하게 처리가 가능하다.

directionalLight.shadow.radius = 10

const directionalLightCameraHelper = new THREE.CameraHelper(directionalLight.shadow.camera)
directionalLightCameraHelper.visible = false
scene.add(directionalLightCameraHelper)

3. Shadow Map 타입들

renderer.shadowMap.type = THREE.[타입];

여기서 설정할 수 있는 값들은 다음과 같아:

타입 이름 특징 품질 성능
THREE.BasicShadowMap 기본 섀도우 가장 단순한 그림자 낮음 빠름 (좋음)
THREE.PCFShadowMap Percentage Closer Filtering 가장 많이 쓰이는 평균적인 그림자 중간~좋음 보통
THREE.PCFSoftShadowMap 부드러운 PCF 가장 부드러운 그림자 높음 느림
THREE.VSMShadowMap Variance Shadow Map 부드럽고 다단계 필터링 가능 높음 보통 (WebGL2 필요)

🔍 각 타입 자세히 보기

  1. BasicShadowMap
    • 그림자 맵을 depth-only로 생성하고 단순하게 비교함
    • aliasing이 심함 (경계가 뚜렷하고 깨짐)
    • 성능은 제일 좋음

✅ 추천: 디버깅 용도, 품질보다 속도 우선일 때

  1. PCFShadowMap (기본값)
    • Percentage Closer Filtering
    • 그림자 경계에서 여러 픽셀을 샘플링해서 부드럽게 처리
    • 경계가 살짝 흐려져서 더 자연스러움

✅ 추천: 일반적인 실시간 그림자

  1. PCFSoftShadowMap
    • PCF의 업그레이드 버전
    • 더 부드럽고 그라데이션이 있는 경계를 만듦
    • 성능은 좀 떨어지지만 퀄리티가 좋음
    • radius 프로퍼티가 동작하지 않음

✅ 추천: 부드러운 그림자가 중요한 씬

  1. VSMShadowMap (Variance Shadow Map)
    • WebGL2 필요
    2개의 depth moment (depth, depth²)를 저장해서 통계적으로 그림자 계산
    • 부드러운 블러 처리 가능, self-shadowing도 개선됨
    • 성능은 중간, 단점은 light bleeding이 생기기도 함

renderer.shadowMap.type = THREE.VSMShadowMap;

✅ 추천: 고품질 그림자 & WebGL2 기반 프로젝트

💡 코드 예제

const renderer = new THREE.WebGLRenderer();
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;

🔧 디버깅 팁

Shadow Map이 이상하게 보일 경우:
• light.shadow.bias 조정 (acne 제거)
• mapSize 늘리기 (해상도 증가)
• camera.near/far 조정해서 depth precision 향상

profile
🌙`、、`ヽ`ヽ`、、ヽヽ、`、ヽ`ヽ`ヽヽ` ヽ`、`ヽ`、ヽ``、ヽ`ヽ`、ヽヽ`ヽ、ヽ `ヽ、ヽヽ`ヽ`、``ヽ`ヽ、ヽ、ヽ`ヽ`ヽ 、ヽ`ヽ`ヽ、ヽ、ヽ`ヽ`ヽ 、ヽ、ヽ、ヽ``、ヽ`、ヽヽ 🚶‍♀ ヽ``ヽ``、ヽ`、

0개의 댓글