Three.js/기초튼튼

three.js 조명 시각화, 그림자 잘림 해결 - DirectionalLightHelper, DirectionalLightShadow, OrthographicCamera, CameraHelper

carrotweb 2023. 6. 26. 00:49
728x90
반응형

이전에 방향성 조명인 DirectionalLight(디렉셔널 라이트)를 사용하여 객체를 비추도록 하였습니다.

 

좀 더 조명에 대해 알아보겠습니다.

 

가끔씩 DirectionalLight(디렉셔널 라이트)가 어디에 있는지 헷갈릴 때가 있습니다. 그래서 DirectionalLight(디렉셔널 라이트)를 시각화를 해주는 DirectionalLightHelper(디렉셔널 라이트 헬퍼)를 사용하여 어느 위치에서 어느 방향으로 빛의 비추어지는지 확인해 보겠습니다.

 

DirectionalLightHelper(디렉셔널 라이트 헬퍼)는 빛의 위치를 평면으로 빛의 방향을 선으로 구성하여 시각화를 해줍니다.

DirectionalLightHelper(light : DirectionalLight, size : Number, color : Hex)
  • light(조명) : 시각화할 조명 객체입니다.
  • size(크기) : 평면의 치수(조명의 크기)입니다. 기본값 1 (입력하지 않으면 기본값으로 설정됩니다.)
  • color(색상) : 시각화에 사용할 색상입니다. 기본값 조명의 색상 (입력하지 않으면 기본값으로 설정됩니다.)

 

1. DirectionalLight(디렉셔널 라이트)를 붉은색으로 시각화하기 위해서 DirectionalLightHelper(디렉셔널 라이트 헬퍼)를 생성합니다.

// 방향성 조명을 시각화하여 장면에 표시 
const light1Helper = new THREE.DirectionalLightHelper(light1, 1, 0xff0000);
// 장면에 조명 시각화 객체 추가
scene.add(light1Helper);

 

그러면 DirectionalLight(디렉셔널 라이트)가 시각화되어 보입니다.

현재 DirectionalLight(디렉셔널 라이트)의 위치(position)가 X축 -1, Y축 1, Z축 1이기 때문에 객체 가까이에 있습니다.

 

마우스 왼쪽 버튼을 클릭하고 마우스를 이동해서 보시면 DirectionalLight(디렉셔널 라이트)의 위치(position)를 입체적으로 확인할 수 있습니다.

 

 

2. 색상이 랜덤인 새로운 육면체 객체를 생성하여 Scence(씬, 장면)에 추가합니다.

// 육면체 지오메트리 생성
const box2Geometry = new THREE.BoxGeometry(1, 1, 1);
// 색상 랜덤
const box2Color = THREE.MathUtils.randInt(0, 0xffffff);
// 육면체에 사용할 색상과 질감의 데이터를 생성
const box2Material = new THREE.MeshStandardMaterial({color: box2Color});
// 육면체와 색상과 질감의 데이터를 결합하여 육면체 객체 생성
const box2 = new THREE.Mesh(box2Geometry, box2Material);
// 육면체에 그림자 생성 활성화
box2.castShadow = true;
// 육면체 위치 변경
box2.position.set(2, 0, 5);
// 장면에 육면체 객체 추가
scene.add(box2);

 

그리고 Camera(카메라)의 위치(position)를 조금 멀어지게 변경합니다.

// 카메라 위치 변경
camera.position.set(4, 8, 10);

 

그러면 새로운 육면체가 추가되어 보입니다. 그러나 추가된 육면제에는 그림자가 잘려서 보입니다.

 

마우스 왼쪽 버튼을 클릭하고 마우스를 이동해서 봐도 그림자가 잘려 보이는 것을 확인할 수 있습니다.

 

DirectionalLight(디렉셔널 라이트)의 위치(position)가 객체와 너무 가까이에 있어서 그런 걸까요?

 

DirectionalLight(디렉셔널 라이트)의 위치(position)를 객체로부터 조금 멀어지게 하겠습니다. 그리고 Camera(카메라)의 위치(position)도 변경하여 DirectionalLightHelper(디렉셔널 라이트 헬퍼)가 나오게 하겠습니다.

// 방향성 조명 위치 변경
light1.position.set(-10, 10, 10);

// 카메라 위치 변경
camera.position.set(4, 8, 20);

 

DirectionalLight(디렉셔널 라이트)의 위치(position)가 멀어져도 추가된 육면제의 그림자가 잘려서 보입니다.

 

그럼 무엇이 문제일까요?

 

바로 조명의 그림자를 계산하는 데 사용되는 DirectionalLightShadow(디렉셔널 라이트 쉐도우)에서 사용하는 Camera(카메라) 영역의 크기가 작기 때문입니다.

 

DirectionalLightShadow(디렉셔널 라이트 쉐도우) Camera(카메라)는 OrthographicCamera(오쏘그래픽 카메라)를 사용합니다.

 

OrthographicCamera(오쏘그래픽 카메라)는 원근법이 적용되지 않는 카메라입니다.

OrthographicCamera(left : Number, right : Number, top : Number, bottom : Number, near : Number, far : Number)
  • left(왼쪽) : 카메라 프러스텀 평면 왼쪽 위치입니다.
  • right(오른쪽) : 카메라 프러스텀 평면 오른쪽 위치입니다.
  • top(위쪽) : 카메라 프러스텀 평면 위쪽 위치입니다.
  • bottom(아래쪽) : 카메라 프러스텀 평면 아래쪽 위치입니다.
  • near(니어) : 카메라부터 가까운 카메라 프러스텀 평면 거리입니다. 기본값 0.1 (입력하지 않으면 기본값으로 설정됩니다.)
  • far(파) : 카메라부터 먼 카메라 프러스텀 평면 거리입니다. 기본값 2000 (입력하지 않으면 기본값으로 설정됩니다.)

 

 

그래서 객체의 그림자가 평면에 평행하게 투영된 형태(정사영)로 촬영할 수 있습니다.

 

원근법이 적용되지 않는 OrthographicCamera(오쏘그래픽 카메라)를 사용하는 이유는 DirectionalLight(디렉셔널 라이트)의 빛이 평행하게 비추기 때문입니다.

 

기본적으로 DirectionalLightShadow(디렉셔널 라이트 쉐도우)에서 사용하는 Camera(카메라)의 영역은 카메라의 중앙을 기준으로 left(왼쪽)은 -5, Right(오른쪽)은 5, Top(위쪽)은 5, Bottom(아래쪽)은 -5, near(니어)는 0.5, far(파)는 500입니다.

 

DirectionalLightShadow(디렉셔널 라이트 쉐도우)는 DirectionalLight(디렉셔널 라이트)의 Shadow(쉐도우) 속성으로 콘솔 로그로 확인해 보면 확인할 수 있습니다.

console.log(light1.shadow);

 

그럼 DirectionalLightShadow(디렉셔널 라이트 쉐도우)의 Camera(카메라)를 시각화하여 그림자가 그려지는 영역의 크기를 확인해 보겠습니다.

 

CameraHelper(카메라 헬퍼)는 카메라의 위치를 평면으로 영역은 선으로 구성하여 시각화를 해줍니다.

CameraHelper(camera : Camera)
  • camera(카메라) : 시각화할 카메라 객체입니다.

 

3. Camera(카메라)를 시각화하기 위해서 CameraHelper(카메라 헬퍼) 생성합니다.

// 방향성 조명의 그림자 카메라를 시각화하여 장면에 표시 
const light1ShadowCameraHelper = new THREE.CameraHelper(light1.shadow.camera);
// 장면에 조명의 그림자 카메라 시각화 객체 추가
scene.add(light1ShadowCameraHelper);

 

그러면 DirectionalLight(디렉셔널 라이트)의 위치(position)에 Camera(카메라)가 시각화되어 나타나고 Camera(카메라)의 영역이 선으로 표시됩니다.

 

마우스 왼쪽 버튼을 클릭하고 마우스를 이동해서 보면 Camera(카메라)의 영역 안에만 그림자가 나타나는 것을 확인할 수 있습니다.

 

DirectionalLightShadow(디렉셔널 라이트 쉐도우)에서 사용하는 Camera(카메라) 영역의 크기가 작아 그림자가 생성되는 부분도 작아져서 그림자가 잘린 겁니다.

 

그럼 DirectionalLightShadow(디렉셔널 라이트 쉐도우)에서 사용하는 Camera(카메라) 영역의 크기를 조절하여 그림자가 나오도록 하겠습니다.

 

4. Camera(카메라) 영역을 변경합니다.

// 방향성 조명의 그림자 카메라 영역 크기 변경
light1.shadow.camera.left = -60;
light1.shadow.camera.right = 60;
light1.shadow.camera.top = 60;
light1.shadow.camera.bottom = -60;

 

그러면 DirectionalLightShadow(디렉셔널 라이트 쉐도우)에서 사용하는 Camera(카메라) 영역이 커져서 나타나고 객채의 그림자가 나타납니다.

(Camera(카메라) 영역은 원하시는 크기만큼 변경하시기 바랍니다.)

 

그렇지만 줌(Zoom)하여 객체를 보면 그림자가 흐릿하게 보이는 것을 확인할 수 있습니다.

 

그 이유는 그림자 맵의 크기(mapSize)가 작기 때문입니다.

 

기본적인 그림자 맵의 넓이(width)와 높이(height)는 각각 512입니다.

console.log(light1.shadow.mapSize);

--> Vector2 {x: 512, y: 512}

 

5. 그림자가 선명하게 처리되게 DirectionalLightShadow(디렉셔널 라이트 쉐도우)의 맵 크기를 크게 변경합니다.

// 방향성 조명의 그림자 맵 크기 변경
light1.shadow.mapSize.width = 3000;
light1.shadow.mapSize.height = 3000;

 

그러면 그림자가 선명하게 보이는 것을 확인할 수 있습니다.

(다만, 맵 크기가 커질수록 랜더링에 필요한 자원이 많이 사용되기 때문에 적절한 크기로 사용하시길 바랍니다.)

728x90
반응형