Three.js GLTF Loader

강정우·2025년 1월 8일
0

three.js

목록 보기
12/24
post-thumbnail

GLTF Loader

GLTF Loader 는 Scene 에 glTF 모델을 로드하기 위해 존재하는 로더이다.

  • glTF 는 Scene 과 모델의 효츌적인 전송 및 로딩을 위해 특화되어있다.
    glTF 는 3D 에셋의 크기와 해당 에셋의 압축을 풀고 사용하는 데 필요한 런타임 처리를 최소화한다.
    glTF 파일에는 하나 이상의 scenes, meshes, materials, textures, skins, skeletons, morph targets, animations, lights and cameras 가 포함될 수 있다.

에셋은 JSON(.gltf) 또는 바이너리(.glb) 형식으로 제공될 수 있다.
그럼 glTF 와 glb 의 차이점은 무엇일까?
glb 는 all in 1 인데 반해 glTF 는 때때로 외부 파일을 참조하므로 모든 리소스를 기본 에셋과 같은 폴더에 넣지 않으면 많은 문제가 발생할 수 있다.

Group 객체

Group 객체는 Object3D와 거의 동일하다. 다만, 오브젝트 그룹 작업을 구문적으로 더 명확하게 하기 위해 분리하였다.
속성 값도 isGroup 밖에 없다.
즉, glTF 파일은 Group 객체인 것이다.

glTF 생성하기 (feat. blender)

우선 blender 를 설치해준다.
설치하면 기본적인 프롭들이 존재하는데 a 를 눌러서 모두 선택한 후 삭제해주고 이제 마우스 wheel 버튼으로 시야를 욺직일 수 있다.

shfit + a: 추가 메뉴 단축키
numpad 1~9: 카메라 프리 셋 (e.g. 7번 머리에서 수직으로 내려보는 카메라)
Mesh 선택 후 + s: 사이즈 조절
n: x, y, z 위치 조절
g+z: 마우스로 높이 조절 가능

그래서 이것저것 만져본 후 export 를 한 다음 프로젝트에서 불러오면

// ... renderer, camera, controller 추가 코드

const light = new THREE.SpotLight(undefined, Math.PI * 1000)
light.position.set(7, 7, 7)
light.angle = Math.PI / 3
light.castShadow = true
scene.add(light)

new GLTFLoader().load('models/suzanne_the_monkey.gltf', (gltf) => {
    console.log(gltf)
    scene.add(gltf.scene)
})

여기서 중요한 점은 하나의 glTF 로 내보낸 Group 객체는 동일한 Material 을 공유하여 하나의 Material 을 바꾸면 모두 적용된다는 것을 알아야한다.

new GLTFLoader().load('models/suzanne_the_monkey.gltf', (gltf) => {
    const rootScene = gltf.scene;

    const shadowSettings = {
        cast: ['수잔', '구체', '구체001', '구체002', '구체003'],
        receive: ['평면'],
    };

    rootScene.traverse((object) => {
        if (object instanceof THREE.Mesh) {
            if (shadowSettings.cast.includes(object.name)) {
                object.castShadow = true;
            }
            if (shadowSettings.receive.includes(object.name)) {
                object.receiveShadow = true;
            }
        }
    });

    scene.add(rootScene);
})
  • light(1000) + environment map

  • light(1000) + environment map(ACESFilmicToneMapping + toneMappingExposure 10%) (더 자연스러운 모습)

blender, three.js

우리는 앞서 blender 에서 생성한 glTF 파일을 three.js 에 import 해봤다.
하지만 역시 blender 는 전문적인 툴로 훨씬 더 다양한 옵션을 제공한다. 하지만 그 옵션 중 몇개는 three.js 에서 인식할 수 있는 옵션이 존재한다. 그것들을 살펴보자.

1. Material

오브젝트를 클릭 후 내려보면 Material 을 볼 수 있다. 여기서 기본 표면은 Principled BSDF 이다. 이 surface 를 three.js 로 import 해올 시 밑에있는 color, Matalic, Roughness 까지 three.js 에서 적용이 가능하다. 이제 이를 설정하면 아무것도 변경되는 것이 없는데 이는 지금 블렌더가 덩어리만 보여주고 있기 때문이다. 따라서 오른쪽 상단 viewport shader 를 눌러주면 수정한 값이 반영되어 표출된다.

2. transmission

transmission 속성은 MeshPhysicalMaterial 이었다.
자, 그럼 일단 이 투명도 속성없이 한번 가보자.

보면 MeshStandardMaterial 인 것을 알 수 있다. 하지만 여기에 블렌더에 transmission 속성을 넣는다면?

투명도 속성 때문에 타입이 MeshPhysicalMaterial 로 바뀐 것을 알 수 있다.

하지만 중요한 것은 blender 와 three.js 는 동작 엔진도 다르고 옵션, 사용 목적, 대상도 모두 다르기 때문에 blender 에 나오는 모습이 three.js 에서 그래도 나올 것이라는 기대를 하면 안 된다. 따라서 blender 에서 대충 모양을 잡고 three.js 로 가져와서 gui 를 통하여 본인이 원하는 모습을 만들어야 할 것이다.

3. Light

블렌더에는 총 4가지의 광원이 준비되어있다.
1. point: point light 와 같다. 광원에서 모든 방향으로 빛이 나가는
2. sun: directional Light 와 같다. 모든 방향이 같은 방향으로 parellel 하게 들어옴
3. spot: spot light 와 같다. 손전등 같은거
4. area: RectAreaLight 와 같다. (아직 살펴본 적 없음.)

대충 spot light 를 만들어주고 export 할 때 이제 Include 에서 Punctual lights 를 체크해주면 된다.

여기서 light 를 켜주고 power 를 5000 으로 설정하면

블랜더와 다르게 intensity 가 너무너무 강렬하게 설정되어 색이 다 날아간 것을 확인할 수 있다. 따라서 우리는

new GLTFLoader().load('models/suzanne_the_monkey.gltf', (gltf) => {
    const spotLight =  gltf.scene.getObjectByName("스폿") as THREE.SpotLight
    spotLight.castShadow = true
    spotLight.intensity /= 5000
    scene.add(gltf.scene)
})

위 코드를 통하여 아래와 같은 결과를 얻을 수 있다.

4. texture

블렌더에는 굉장히 다양한 텍스쳐를 확인할 수 있다. 하지만 이 모든 텍스쳐가 three.js 에서 동작하진 않는다.

우선 이미지 텍스쳐를 넣어보자. 저장하고 three.js 와 블렌더를 비교해보면 상당히 다른 모습인 것을 확인할 수 있는데 이는 역시 블렌더와 three.js 의 이미지 렌러딩 형식이 달라서 그렇다. 이는 코드를 통해 맞춰줄 수 있다.

new GLTFLoader().load('models/suzanne_the_monkey.gltf', (gltf) => {
    console.log(gltf)

    const suzanne = gltf.scene.getObjectByName('수잔') as THREE.Mesh
    suzanne.castShadow = true;
    ((suzanne.material as THREE.MeshStandardMaterial).map as THREE.Texture).colorSpace = THREE.LinearSRGBColorSpace;
  	...

Lensflare (dev mode)

아직 정식적으로 나온 것은 아니다.
앞서 작성한 Light 객체에 .add() 메서드로 Lensflare 객체를 추가하면 광원 효과를 얻을 수 있다.

const light = new THREE.SpotLight(undefined, Math.PI * 1000)
...
scene.add(light)

const textureLoader = new THREE.TextureLoader()
const textureFlare0 = textureLoader.load('https://cdn.jsdelivr.net/gh/Sean-Bradley/First-Car-Shooter@main/dist/client/img/lensflare0.png')

const lensflare = new Lensflare()
lensflare.addElement(new LensflareElement(textureFlare0, 1000, 0))
light.add(lensflare)
profile
智(지)! 德(덕)! 體(체)!

0개의 댓글