[Three.js] Environt map

JINBOK LEE·2023년 8월 21일
0

Three.js

목록 보기
1/2
post-thumbnail

0. 들어가기 앞서

그동안 배운 Three.js의 기능들을 사용해보며 기술 수준을 높여보고자 개인 프로젝트를 진행해 보았다.

아직 배울 내용들이 많이 남았지만, 개인적인 중간 점검 차원이랄까..

이를 위해 과거 3D 모델링을 공부할 때 영감을 얻기 위해 애용했던 Sketchfab 이라는 사이트에서 3D 모델을 다운로드 받았다. (직접 모델링을 하지 않고도 다른 디자이너들의 3D 에셋들을 활용할 수 있다는 점이 너무나 좋다.)

다운로드 받은 3D 모델을 three.js에 임포트 하고, 웹뷰에 띄우는 것까지 성공했으나.. 역시나 맞닥뜨리게 된 문제점이 있었다. 이번 포스팅은 이러한 문제점의 원인을 파악하고 해결한 과정을 공유 해보고자 한다.


1. 파악한 문제점

1-1. Sketchfab 3D View

먼저, 아래는 내가 Sketchfab에서 다운로드 받은 3D 모델의 렌더링 샷이다.
Sketchfab의 3D뷰어 상에서 본 모습이며, 의자의 다리 부분이나 쓰레기통 부분의 메탈릭한 재질이 잘 표현되어 있는 것을 확인할 수 있다.

1-2. Three.js WebGLRenderer View

그리고 아래는, three.js로 임포트한 뒤 WebGLRenderer를 통해 브라우저에서 렌더한 모습이다.
위 사진과는 다르게 메탈릭한 재질의 텍스쳐들이 모두 까맣게 표현되는 것을 볼 수 있다.

포스트 프로세스와 광원량의 차이로 인한 전체적인 밝기 차이는 후에 잡아주면 될 것 이라고 생각했으나, 이렇게 재질 자체가 다르게 표현되는 경우는 생각하지 못했었기 때문에 무엇이 문제인지 파악하는 것이 관건이었다.


2. 문제 발생 원인 파악하기

2-1. 광원의 문제인가

원인을 파악하기 위해 먼저 광원을 모두 조정해 보았었다. Ambient Light와 Directional Light를 사용하고 있었으며, lil-gui를 이용하여 이들의 위치와 광량을 조절하며 실시간으로 확인해 보았다.

2-1-a. Ambient Light만 적용

아무런 반사 표현 없이 까맣게 표현된 모습이다.

2-1-b. Ambient Light + Directional Light 적용

여전히 까맣지만, 금속 재질의 특성인 스펙큘러 반사는(반짝거림) 표현이 되고 있는 것을 알 수 있었다.

이러한 부분이 의아해서 조금 더 찾아보니,

Ambient Light
특정한 방향이에서 오는 빛이 아니다. 빛의 근원은 있지만 방 혹은 장면 주위에서 반사되어 들어오기 때문에 방향이 없는 광선이다. Ambient light에 의해서 조명되는 물체는 전체적으로 모든 방향으로부터 빛이 비추어진다. 물체를 회전시켜도 Ambient Light에 의해서 색이 변하지 않는다. 즉, 방향을 갖고 있지 않은 Ambient Light가 그 물체를 비추고 있었기 때문에, 어느 각도에서도 같은 색으로 보여지는 것이다.

Diffuse Light
특정한 방향으로 비춰지지만, 그 빛의 반사는 여러 방향으로 이루어진다. 빛이 골고루 반사된다 하더라도, 물체를 비스듬히 비출 때보다 바로 위에서 비출 때가 물체 표면을 더 밝게 보인다. 예로써 형광등의 빛이나 오후에 창을 통해 들어오는 햇빛을 생각하면 된다.

Specular Light
역시 방향을 가지는 빛이다. 하지만 사방으로 밫을 반사시키는 Diffuse Light와는 달리 특정 방향으로만 뚜렷하게 빛을 반사시킨다. 강한 Specular Light이 물체에 닿으면 그 표면에 Spot가 생기는데 이것을 Specular Highlight라고 한다.

Ambient Light는 방향성이 없는 빛이기 때문에 디푸즈 반사에만 영향을 주며 스펙큘러 반사에는 영향을 주지 않고, Directional Light, Point Light, Spot Light 등은 방향성이 있는 빛이기 때문에 스펙큘러 반사에 영향을 주어 이러한 현상이 발생한다는 것을 알 수 있었다.

다시 말하자면, 스펙큘러 반사란 반사된 광원이 내 눈에 직접 쏘아지게 되며 반짝거림을 보게되는 것인데, Ambient Light처럼 반사되는 빛이 방향성을 가지지 않으면 내 눈에 들어오는 방향성 조차 없기 때문에 반짝거리는 스펙큘러 반사가 일어나지 않는다는 것이다.

자 그럼, 일단 광원에도 문제가 있었음을 알 수 있었다. 그런데 왜 여전히 텍스쳐는 까맣게 표현되는 것일까?


2-2. Material의 문제인가

먼저 gltf 파일을 이용해 import 해온 해당 모델의 material에 무언가 문제가 있는지 확인해보고자 했다. 이를 위해 아래 코드와 같이 traverse 메서드를 이용하여 gltf 파일 속 mesh들의 재질을 확인해 보았다.

 new GLTFLoader().load(
    "models/small_office/scene.gltf",
    function (gltf) {
      gltf.scene.traverse((node) => {
        if (node.isMesh) {
          console.log("material : ", node.material);
          console.log("metalness : ", node.material.metalness);
        }
      });
      scene.add(gltf.scene);
    },
    function (xhr) {
      console.log((xhr.loaded / xhr.total) * 100 + "% loaded");
    },
    function (error) {
      console.log("error :", error);
    }
  );

확인 결과, MeshStandardMaterial을 사용하고 있었으며

문제가 될 수 있겠다 싶었던 metalness 값 또한 모델별로 다르게 잘 설정이 되어 있는 것을 알 수 있었다.

그렇다면 도대체 무엇이 문제일까..
더 깊이 찾아보니 해답의 실마리를 찾을 수 있었는데, 그것은 바로 "반사시킬 환경의 부재" 였다.


3. 반사시킬 환경의 부재란?

처음에는 조금 혼란스러웠다. 이미지처럼 주변에 벽돌 재질의 텍스쳐가 입혀진 벽이 있고, 반사 방향성이 있는 Directional Light 또한 적용을 했는데, 왜 스펙큘러 반사만 표현이 되고 텍스쳐는 여전히 까맣게만 표현이 되는 것일까? 벽면의 벽돌들이 반사가 되어 보여야 하는게 정상 아닌가?

여기서 내가 크게 놓친 부분은,

Three.js의 MeshStandardMaterial나 다른 PBR Material들은 실제로 주변의 환경을 "보고" 그것들을 그대로 "반사" 시키는 능력이 없다는 것이다. (실제 주변 환경을 반사하기 위해서는 Ray Tracing과 같은 기술이 필요하다)

따라서 PBR Material들이 "볼 수 있는" 환경을 따로 제공을 해 주어야지만 그것을 통해 반사되는 이미지 또한 연산이 가능하다는 것이다.

그동안 나는 무의식적으로 레이 트레이싱을 기대했던 것이다..

따라서, 나는 프로젝트 씬에 어울릴만한 환경맵 파일을 다운로드하여 곧바로 적용시켜 보았다.


4. Environment map 적용

  new RGBELoader().load(
    "models/small_office/MR_INT-005_WhiteNeons_NAD.hdr",
    (texture) => {
      texture.mapping = THREE.EquirectangularReflectionMapping;
      scene.environment = texture;
    }
  );

적용 전

적용 후

기존의 까맣게 표현되던 의자 다리와 쓰레기통이 원래 의도하던 대로 잘 표현이 되는 것을 확인할 수 있었다. 또한 hdr 환경맵을 사용하면서 전체적인 톤이 밝아지고 디테일이 조금 더 향상된 것을 알 수 있었다.

자세히 들여다보면 실제 주변 환경과는 다르게, 다운로드한 환경맵의 모습이 반사되어 이질감이 들지만 이번 프로젝트에서 직접 환경맵을 만드는 수고는 하지 않도록 하고, 원인을 파악하고 해결하는데 의의를 두도록 하겠다!


5. 마치며

아직 Three.js에 대해 학습해야 할 내용이 많이 남아있다. 남은 내용을 모두 학습한 뒤에 프로젝트를 진행했더라면 아마도 이번에 마주했던 문제점의 원인을 더 빠르게 파악하고 해결했을 것 같다는 생각이 든다.

이전에 3D 모델링도 해본 경험도 있겠다, "이 정도는 할 수 있겠군" 이라는 생각으로 호기롭게 시작했으나 역시나 문제가 생겨버리고 말았고, 앞으로 알아야 할 내용이 정말 산더미겠구나 라는 생각이 들었다. 크루거 효과의 정석이라고 말해도 될 정도로..

언리얼 엔진을 잠깐 다뤄보았던 경험을 떠올려 봤을 때, metalness 값만 설정하고 프리뷰를 해도 주변 환경이 잘 반사 되었던 기억이 있어서 환경맵의 부재로 인한 문제라고는 생각을 못했었는데, 생각해보니 프리뷰 환경 자체에 기본 환경맵이 설정이 되어있었던 것 같다.

우여곡절이 있었지만 그래도 나는 항상 직접 부딪히고 깨지는 것을 선호한다. 강의를 보면서 코드를 따라 작성하며 프로젝트를 완수해도 뒤돌아서면 잊어버리게 되고, 결국엔 '내 머릿속에 남은게 무엇일까' 라는 생각을 자주 했기에 혼자서 직접 해보는 것이 최고의 학습이라고 생각하기 때문이다.

때문에 이번 경험을 통해서도 three.js를 다루는 방법에 대해 조금 더 익숙해졌다는 생각이 들고, 빛과 PBE 재질에 대해 보다 더 깊게 학습할 수 있는 아주 좋은 기회가 되었다.

또한, 이전의 3D 모델링 경험을 통해 얕게나마 학습해둔 여러 개념들이 이번 문제의 해결에 크게 도움이 된 것 같다. 앞으로 3D의 기반지식이 되는 light와 material에 대해 더 깊이 공부해두면 크게 도움이 될 것 같다.


참고

Sketchfab / Small Office by dylanheyes
OpenGL Tutorial / Lighting

profile
깔끔한 비즈니스 로직 설계를 위해 공부하는 FE 개발자

0개의 댓글