type="nal"

[Three.js] 웹사이트에 3D 모델 추가하기 본문

Web Development/Front

[Three.js] 웹사이트에 3D 모델 추가하기

nalmi 2024. 12. 14. 12:37

1. 우선 3D 모델을 준비해준다.

1. 블렌더로 직접 깎거나

2. 웹사이트 에서 다운 받아준다(ex: https://sketchfab.com/feed)

나는 위 사이트에서 동물 검색해서 무료팩을 다운 받았다.

(동물들 하나하나 분리 되는지 궁금함,,)

 

다운 받을 땐 Download3D를 누르고

glTF 형식으로 다운받아준다. (gltf: JSON 형식의 텍스트 파일)

일단 압축 풀어서 작업폴더에 넣어주면 되는데 이 gltf파일이 3D 모델이다

 

2. Three.js 라이브러리 설치

우선 canvas 태그를 이용하고, 크기를 지정해준다.

<canvas id="canvas" width="300" height="300"> </canvas>

 

3D 모델을 가져올 때는 Three.js라는 유용한 라이브러리를 이용하면 된다. https://threejs.org/

  • 리액트나 뷰 프로젝트라면 npm install three 명령어를 사용한다.
  • 일반 html 파일이라면 문서에 있는 해당 설치 코드를 넣어준다.

<script type="importmap">
  {
    "imports": {
      "three": "https://cdn.jsdelivr.net/npm/three@<version>/build/three.module.js",
      "three/addons/": "https://cdn.jsdelivr.net/npm/three@<version>/examples/jsm/"
    }
  }
</script>

 

3. 3D 모델 가져오기 위한 코드 작성

우선 본격적인 코드 작성 전에 두가지를 추가해준다.

      <script type="module">
        import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
        import * as THREE from 'three';

      </script>

 

3D 모델을 브라우저에 보여주려면

1. 장면을 하나만들고,

2. 브라우저에 렌더링해야한다.

 

1. 우선 장면을 만드는 방법은

	// 1. 장면 만들기
        let scene = new THREE.Scene();
        scene.add(도형);

위처럼 new THREE.Scene();으로 장면을 생성하고

add로 넣고 싶은 도형같은 걸 넣을 수 있다.

 

2. 만든 그림을 보여주고 싶으면

	// 2. 브라우저에 띄우기
        let renderer = new THREE.WebGLRenderer();
        renderer.render(scene);

브라우저에 내가 만든 장면을 보여준다는 뜻

 

근데 gltf 파일을 바로 가져올 수 없고 import 했던 로더를 이용 해줌

        // 3D 모델 추가 - gltf 파일 가져오기
        let loader = new GLTFLoader();
        loader.load('src/scene.gltf', function(gltf) {
            scene.add(gltf.scene);
            renderer.render(scene);
        });

src는 해당 gltf 파일이 저장된 경로.

그리고 로드가 완료된 후 실행될 콜백함수를 작성해주면 되는데 매개변수로 3D 모델을 전달하고,

여기에 장면에 gltf.scene을 추가하고(실제 3D 오브젝트가 있는 위치)

장면을 렌더하는 코드도 넣어준다.

 

4. 3D 모델을 보여주기 위해 필요한 것들

1. 카메라 2. 조명 3. 배경

 

1. 먼저 카메라에는 두 종류가 있는데

  • PerspectiveCamera - 원근법 적용
  • OrthographicCamera - 원근법 무시

이렇게 카메라까지 렌더링해주면

	 // 카메라
        let camera = new THREE.PerspectiveCamera(30, 1);

        // 3D 모델 추가 - gltf 파일 가져오기
        let loader = new GLTFLoader();
        loader.load('src/scene.gltf', function(gltf) {
            scene.add(gltf.scene);
            renderer.render(scene, camera);
        });

에러가 발생했다..

크롬에서는 안뜨고 사파리에는 뜸.

hook.js:608 THREE.WebGLRenderer: A WebGL context could not be created. Reason: Could not create a WebGL context, VENDOR = 0xffff, DEVICE = 0xffff, GL_VENDOR = Google Inc. (Google), GL_RENDERER = ANGLE (Google, Vulkan 1.3.0 (SwiftShader Device (LLVM 10.0.0) (0x0000C0DE)), SwiftShader driver-5.0.0), GL_VERSION = 5.0.0, Sandboxed = yes, Optimus = no, AMD switchable = no, Reset notification strategy = 0x8252, ErrorMessage = BindToCurrentSequence failed: .

머 이런...

지피티가 방법을 몇 개 제안해줬는데

 

 

1. 하드웨어 가속 비활성화

  • Chrome에서 하드웨어 가속이 꺼져 있을 수 있습니다.

확인 및 수정 방법:

  1. 설정 > 고급 > 시스템 메뉴로 이동
  2. "가능한 경우 하드웨어 가속 사용" 옵션을 활성화
  3. 설정 후 Chrome 재시작
  • 설정 URL로 바로 가기: chrome://settings/?search=hardware+acceleration

2. WebGL 차단 (Chrome 플래그)

  • WebGL 기능이 실수로 비활성화되었을 수 있습니다.

확인 및 수정 방법:

  1. chrome://flags 페이지에 접속
  2. WebGLWebGL2 검색
  3. 옵션을 Enabled로 변경
  4. Chrome 재시작

1번은 효과가 없었고, 

2번 사이트로 들어가서 다 허용해줬다.

이제 성공적으로 화면에 발가락이 보임.

발가락만 보이는 이유는 카메라의 위치를 조정 안해줘서 그럼.

	// 카메라
        let camera = new THREE.PerspectiveCamera(30, 1);
        camera.position.set(0,0,10);

이런 식으로 x, y, z 축 좌표를 조절한다.

 

배경색과 조명은 아래처럼 설정해준다.

 	// 배경색
        scene.background = new THREE.Color('white');
        // 조명
        let light = new THREE.DirectionalLight(0xffff00, 2);
        scene.add(light);

조명은 여러 종류가 있는데,

  • AmbientLight: 전체 장면에 부드러운 빛. 그림자 없음
  • PointLight: 점 광원에서 퍼져 나가며 물체의 위치에 따라 빛과 어둠이 생김.
  • DirectionalLight: 직선으로 한 방향에 비춰지며, 그림자가 선명하고 명확함.

표면 재질에 따라 조금씩.. 조금 많이 다르다.

순서대로 비교를 해봤다.

그리고 지금은 테두리에 계단 현상이 심해서 픽셀이 막 보이는데

이렇게 앨리어싱을 없애줄 수 있다.

	// 2. 브라우저에 띄우기
        let renderer = new THREE.WebGLRenderer({
            canvas : document.querySelector('#canvas'),
            antialias : true
        });

 

 

다시 쫜

그리고 기존이랑 색이 어둡고 다르게 보이면 gltf 파일의 경우 아래처럼 인코딩 방식을 지정해주면 된다는데, 나는 별 차이가 없었다.

renderer.outputEncoding = THREE.sRGBEncoding;

 

5. 애니메이션

애니메이션을 추가하고 싶으면

아래처럼 함수를 추가로 만들고 requestAnimationFrame을 이용하면 1초에 60번 정도 움직이고 rener도 함수 안으로 옮겨야 프레임마다 렌더링이 된다.

loader.load('src/scene.gltf', function(gltf) {
            scene.add(gltf.scene);
            function animate() {
                requestAnimationFrame(animate)
                gltf.scene.rotation.y += 0.001;
                renderer.render(scene, camera);
            }
            animate();
        });

-> y 축으로 회전

 

비슷하게 사용자가 마우스로 장면을 회전시키고 줌도 가능하게 할 수 있다.
OrbitControls를 추가해주면 된다.

오브젝트 여러개 넣는거나.. 장면 꾸미는 거는 더 많이 공부해야겠다..

 

최종 코드는 아래와 같음

최종 코드
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Threejs</title>
</head>
<body>
    <p>3D 모델입니다</p>
    <canvas id="canvas" width="700" height="700"> </canvas>
    <script type="importmap">
        {
          "imports": {
            "three": "https://cdn.jsdelivr.net/npm/three@0.171.0/build/three.module.js",
            "three/addons/": "https://cdn.jsdelivr.net/npm/three@0.171.0/examples/jsm/"
          }
        }
      </script>
      <script type="module">
        import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
        import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
        import * as THREE from 'three';

        // 1. 장면 만들기
        let scene = new THREE.Scene();

        // 2. 브라우저에 띄우기
        let renderer = new THREE.WebGLRenderer({
            canvas : document.querySelector('#canvas'),
            antialias : true
        });
        renderer.outputEncoding = THREE.sRGBEncoding;

        // 카메라
        let camera = new THREE.PerspectiveCamera(30, 1);
        camera.position.set(0,1,10);
        // 배경색
        scene.background = new THREE.Color('white');
        // 조명
        let light = new THREE.PointLight(0xffff00, 3);
        scene.add(light);

        // OrbitControls 추가
        const controls = new OrbitControls(camera, renderer.domElement);
        controls.enableDamping = true; // 부드러운 감속 효과
        controls.dampingFactor = 0.05; // 감속 강도 설정
        controls.enableZoom = true;    // 줌 활성화

        // 3D 모델 추가 - gltf 파일 가져오기
        let loader = new GLTFLoader();
        loader.load('src/scene.gltf', function(gltf) {
            scene.add(gltf.scene);
            function animate() {
                requestAnimationFrame(animate)
                controls.update(); // OrbitControls 업데이트
                renderer.render(scene, camera);
            }
            animate();
        });



      </script>
</body>
</html>