Three.js 란?

👍·2022년 5월 26일
0

Three.js가 몬가용

  • 3차원 그래픽 및 애니메이션을 위한 js library

  • WebGL 기반
    (WebGL : 2d, 3d 그래픽 렌더링을 위한 로우 레벨 js api)
    - 모던 웹 브라우저
    - No plug-in, Only JS
    - Canvas DOM요소
    - GPU 지원
    - WebGL Wrapper API

  • 공식 사이트
    threejs.org

어디에서 쓰나요?

  • 웹 게임, 인터렉티브 페이지, 지도 서비스, 3d 영상, 저널리즘 등등

기본 구성 요소

Renderer : 장치에 Scene과 Camera를 렌더링 해 줌
│
└─── Scene : 3차원 모델과 빛 등으로 구성된 장면
│    │
│    └─── Light : 장면을 비추는 조명, 재질에 따라 광원이 필요할 때가 있음.
│    │
│    └─── Mesh (Object3D) : 3차원 모델
│         │
│         └─── Geometry : 3차원 모델의 형상을 정의 
│		  │
│      	  └─── Material : 3차원 모델의 색상, 투명도 등, 재질 정의
│
└─── Camera 
		: 장면을 어떤 관점으로 볼 것인지 정의하는 카메라
          Scene 내부에 포함할 수도, 외부에 둘 수도 있다.

뭐 만드나용

결과물

네모네모박스

코드 순서

  • three.js 라이브러리 임포트
  • Class App
    1. DOM요소 참조
    2. Renderer 생성
    3. Scene 생성
    4. Camera 생성
    5. Light 생성 (Mesh가 시야에 보이도록 비춰줌)
    6. Mesh 생성 (3차원 오브젝트, geometrymaterial로 구성되어 있음.)
    7. 2번 Renderer 렌더하기.

기본 코드 작성

1. html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">

    <link rel="stylesheet" href="basic.css">
    <script type="importmap">
        {
            "imports": {
                "three": "../build/three.module.js"
            }
        }
    </script>
    <script type="module" src="basic.js" defer></script>
    <title>Basic</title>
</head>
<body>
    <div id="webgl-container"></div>
</body>
</html>

rederer.domElement 는 canvas를 리턴해준다.
(THREE.WebGLRenderer()로 생성한 rederer객체)
canvas를 동적으로 붙이는 방법도 있지만, 유동적인 대응을 위해 미리 html에 요소를 만들어 놓자.

2. css

	* {
      outline: none;
      margin: 0;
    }

    body {
      /* 한 화면에 들어올 수 있도록 스크롤 없애기 */
      overflow: hidden;
    }

    #webgl-container {
      position: absolute;
      left: 0;
      top: 0;
      width: 100%;
      height: 100%;
    }

3. js

전체 코드)

    import * as THREE from "../build/three.module.js"
    import { OrbitControls } from "../examples/jsm/controls/OrbitControls.js";

    class App {
      #domContainer;
      #renderer;
      #scene;
      #camera;
      #mesh;
      #control;

      constructor() {
        // 1. DOM 요소 참조
        const domContainer = document.querySelector('#webgl-container');
        this.#domContainer = domContainer;  
     
     	// 2. Renderer 설정
        const renderer = new THREE.WebGLRenderer({ antialias: true }); // canvas 생성
        renderer.setPixelRatio(window.devicePixelRatio); // canvas 화소 설정
        domContainer.appendChild(renderer.domElement); 
        this.#renderer = renderer;

        // 3. Scene 설정
        const scene = new THREE.Scene();
        this.#scene = scene;
        
        this.#setupCamera(); // Camera 설정
        this.#setupLight(); // Light: Scene을 비추는 광원
        this.#setupModel(); // Mesh: 3차원 모델 설정
        this.#setupControls(); 

        // resize 업데이트
        window.onresize = this.resize.bind(this);
        this.resize(); // 첫 세팅을 위함.

        requestAnimationFrame(this.render.bind(this));
      }

      resize() {
        const width = this.#domContainer.clientWidth;
        const height = this.#domContainer.clientHeight;

        this.#camera.aspect = width / height;     
        this.#camera.updateProjectionMatrix();
        
        this.#renderer.setSize(width, height);
      }
      
	  // 4. Camera 생성
      #setupCamera() {
        const width = this.#domContainer.clientWidth;
        const height = this.#domContainer.clientHeight;
        const camera = new THREE.PerspectiveCamera(
          75, 
          width / height,
          0.1,
          100
        );

        camera.position.set(0, 0, 2);
        this.#camera = camera;
      }

      // 5. Light 생성
      #setupLight() {
        const color = 0xfffffff;
        const intensity = 1;
        const light = new THREE.DirectionalLight(color, intensity);
        light.position.set(-1, 2, 4); // 광원의 위치를 세팅
        this.#scene.add(light); // 광원은 장면의 구성요소이므로 부챠줌.
      }

      // 6. Mesh 생성
      /**
       * Mesh는 Geometry와 Material로 구성된다.
       */
      #setupModel() {
        // Geometry
        const geometry = new THREE.BoxGeometry(1, 1, 1);
        
        // Material
        const fillMaterial = new THREE.MeshPhongMaterial({ 
          color: 0x44aa88;
          // emissiv: 0xffff00, // mesh의 자체 발광
          // flatShading: true,
          // opacity: 0.1,
          // transparent: true
        });

		// Mesh
        const mesh = new THREE.Mesh(geometry, fillMaterial);

        const lineMaterial = new THREE.LineBasicMaterial({ color: 'red' });
        const line = new THREE.LineSegments(
          new THREE.WireframeGeometry(geometry),
          lineMaterial
        );

	 	// this.#scene에 mesh, line 각각 추가해도 되지만 Three.js에서 Group을 지원해줌.
        const group = new THREE.Group();
        group.add(mesh);
        group.add(line);
        
        this.#scene.add(group);
        
        this.#mesh = group;
      }

      #setupControls() {
        const control = new OrbitControls(this.#camera, this.#domContainer);
        this.#control = control;
      }

      update(time) {
        time *= 0.001; // 'ms' -> 'sec'로 변환

        // control 업데이트 : 딱히 실행 결과가 달라지는 것은 없지만 해줘야 함.
        this.#control.update(); 
      }

      // render : 3차원 요소로 시각화 해줌.
      render(time) {
        this.#renderer.render(this.#scene, this.#camera);
        this.update(time);
        requestAnimationFrame(this.render.bind(this));
      }
    }

    // 3) onload 이벤트 후에 객체 생성해준다.
    window.onload = function () {
      new App();
    }

설명

1. Renderer

Class App {
    constructor () {
        const renderer = new THREE.WebGLRenderer({ antialias: true });
        renderer.setPixelRatio(window.devicePixelRatio); 

        domContainer.appendChild(renderer.domElement); 

        this.#renderer = renderer;   
      }
}
  • antialis
    : (optional) 엘리어싱 제거,
    Default false

  • setPixelRatio
    : 고해상도의 경우 window.devicePixelRatio값이 2 이상이 나옴.
    렌더러에 값을 세팅해줘야 미려하게 렌더됨.

2. Camera

  #setupCamera() {
      const width = this.#domContainer.clientWidth;
      const height = this.#domContainer.clientHeight;

      const camera = new THREE.PerspectiveCamera(
        75, // field of view
        width / height, // aspect
        0.1, // near plane 
        100 // far plane
      );

      camera.position.set(0, 0, 2);

      this.#camera = camera;
  }
  • PerspectiveCamera(fov, aspect, near, far)
    • fov : 시야각
    • aspect : 종횡비, 가로 / 세로 (화면 비율)
    • near : 최소 시야 범위
    • far : 최대 시야 범위

mesh(obejct3d)가 near와 far사이에 있어야 하며, 시야각안에 들어와야 관찰 가능.

3. Light

  #setupLight() {
      const color = 0xfffffff;
      const intensity = 1;
      const light = new THREE.DirectionalLight(color, intensity);
      light.position.set(-1, 2, 4); // 광원의 위치를 세팅
      this.#scene.add(light); // 광원은 장면의 구성요소이므로 부챠줌.
  }
  • intensity
    : (optional) 빛의 강도, numeric value of the light's strength/intensity.
    Default 1

  • DirectionalLight
    : 특정 방향의 빛, 그림자 제공

  • position.set(position.x, position.y, position.z)
    : 축약 가능

4. Mesh

Mesh = Geometry + Material

  #setupModel() {
  	  // geometry
      const geometry = new THREE.BoxGeometry(1, 1, 1);

	  // material
      const fillMaterial = new THREE.MeshPhongMaterial({ color: 0x44aa88 });
      const lineMaterial = new THREE.LineBasicMaterial({ color: "red" });

	  // mesh (mesh)
      const mesh = new THREE.Mesh(geometry, fillMaterial);
	  // mesh (line)
      const line = new THREE.LineSegments(
        new THREE.WireframeGeometry(geometry),
        lineMaterial
      );

      const group = new THREE.Group();
      group.add(mesh);
      group.add(line);

      this.#scene.add(group);

      this.#mesh = group;
  }

5. OrbitControls

#setupControls() {
    const control = new OrbitControls(this.#camera, this.#domContainer);
    // (카메라, 마우스 컨트롤 할 오브젝트)
                                      
    this.#control = control;
  }

6. render

render(time) {
    this.#renderer.render(this.#scene, this.#camera); 
    // 어떤 장면을 어떤 카메라에 렌더를 할 것인지 인자로 넣음
    this.update(time);
  
    requestAnimationFrame(this.render.bind(this));
  }
profile
따봉루피야 힘을내렴

0개의 댓글