Three.js

[Three.js] 1. vue 로 빨간 육각면체 만들기

머지?는 병합입니다 2024. 7. 28. 23:21

 

화면에 무언가를 그리려면 4가지 요소가 필요합니다.

1. 오브젝트를 포함한 scene

2. 오브젝트

3. 카메라

4. 랜더러


1. scene

 

scene은 컨테이너와 같습니다. 

그 안에 오브젝트, 조명, 카메라 등을 배치할 수 있으며, Three.js에 해당 장면을 렌더링하도록 요청합니다

import {
  PerspectiveCamera,
  Scene,
  BoxGeometry,
  MeshBasicMaterial,
  Mesh,
  WebGLRenderer
} from 'three'

const scene = new Scene()

 

특징

  1. 컨테이너: 씬은 다양한 3D 객체들(메쉬, 조명, 카메라 등)을 포함하는 컨테이너로서의 역할을 합니다.
  2. 조직화: 씬 내에서 객체들은 계층적으로 조직될 수 있으며, 이는 복잡한 3D 환경을 효과적으로 관리할 수 있게 해줍니다.
  3. 렌더링 대상: 렌더러는 씬 객체를 입력으로 받아 화면에 그림을 그립니다. 씬에 포함된 모든 요소들이 렌더링 과정을 통해 시각화됩니다.

 


 scene은 Object3D을 상속 받고 있으므로 .add( object ) 메서드를 사용해 객체를 그룹핑해서 오브젝트를 자식으로

추가하는 데에 사용할 수도 있지만, Group를 사용하는 것이 더 낫습니다.
  https://threejs.org/docs/index.html#api/en/objects/Group

 

three.js docs

 

threejs.org

 

 

2. Object

 

object 는 여러 가지가 될 수 있습니다. primitive 지오메트리, import 된 모델, 파티클, 조명 등이 있을 수 있습니다.

 

네모 상자를 그린다고 가정했을 때,

3D 공간에서 렌더링할 수 있는 메쉬 객체를 생성하고 파라미터로 

geometry(기하학적 형태), material(재질)을 설정해야 합니다
이 메쉬는 기하학적 형태와 재질을 결합하여 실제로 보이는 객체를 만듭니다. 

.

 const geometry = new BoxGeometry(1, 1, 1)
 const material = new MeshBasicMaterial({ color: 'red' })

  // Mesh 생성자는 속성 2개만 있다. ( geometry : BufferGeometry, material : Material )
  const mesh = new Mesh(geometry, material)
  
  scene.add(mesh)

 

  • geometry: THREE.Geometry 또는 THREE.BufferGeometry의 인스턴스로, 메쉬의 형태를 정의합니다. 
     예를 들어, BoxGeometry, SphereGeometry 등이 있습니다. 
  • material: THREE.Material의 인스턴스로, 메쉬의 표면 처리 방식을 정의합니다. 
     예를 들어, MeshBasicMaterial, MeshStandardMaterial 등이 있습니다. 

이 코드는 크기가 1x1x1인 정육면체를 생성하고, 빨간색을 적용한 후, 이를 씬에 추가합니다. 
생성된 메쉬는 렌더러를 통해 화면에 그려집니다. 

Mesh 객체는 다양한 속성과 메서드를 가지고 있어, 위치 조정, 크기 변경, 회전 등 다양한 변형을 적용할 수 있습니다. 
또한, 메쉬는 조명, 그림자, 텍스처 등의 다양한 3D 그래픽 효과와 함께 사용될 수 있습니다. 
이러한 기능들을 통해 사용자는 복잡하고 다양한 3D 씬을 구성할 수 있습니다. 

 

 

2-1. BoxGeometry

 

BoxGeometry는 Three.js에서 정육면체 형태의 기하학적 객체를 생성하는 데 사용되는 클래스입니다. 
이 클래스는 각 면이 직사각형인 상자 모양의 메쉬를 생성할 수 있게 해줍니다. 
사용자는 상자의 너비, 높이, 깊이 등을 지정할 수 있으며, 각 면을 구성하는 세그먼트의 수도 조절할 수 있습니다. 

 

BoxGeometry를 사용하면 간단하게 3D 상자 모델을 생성하고, 이를 씬에 추가하여 렌더링할 수 있습니다. 
이는 게임, 시뮬레이션, 시각화 등 다양한 3D 애플리케이션에서 기본적인 형태로 많이 사용됩니다

 

생성자 ) 

const geometry = new BoxGeometry(width, height, depth, widthSegments, heightSegments, depthSegments);

 

width: 상자의 너비(가로, x축)  height: 상자의 높이(세로, y축)  depth: 상자의 깊이(z축) 각각 floot 단위 입니다
widthSegments: 상자의 너비 방향 세그먼트 수입니다. 기본값은 1입니다. integer 단위 입니다
heightSegments: 상자의 높이 방향 세그먼트 수입니다. 기본값은 1입니다. integer 단위 입니다
depthSegments: 상자의 깊이 방향 세그먼트 수입니다. 기본값은 1입니다. integer 단위 입니다

세그먼트  2,2,2 라면 각 면이 2x2 격자로 나뉘어 총 4개의 사각형으로 구성된 정육면체를 생성합니다. 
각 방향으로 세그먼트 수를 늘리면, 정육면체의 각 면은 더 많은 사각형으로 나뉘어 더 세밀하게 표현됩니다. 

세그먼트 1,1,1일때

 

세그먼트 2,2,2 일때
IDE에서 해당 클래스를 ctrl + 클릭하면 나오는 TS 파일이다. 이걸 참고하는데 빠른 경우가 많다.

 

 

2-2. MeshBasicMaterial

 

MeshBasicMaterial은 Three.js에서 가장 기본적인 재질(material) 유형 중 하나로, 

빛의 영향을 받지 않는 단순한 색상이나 텍스처를 물체에 적용할 때 사용됩니다. 
이 재질은 조명이 없는 환경에서도 물체의 색상을 그대로 표현할 수 있고, 빠른 렌더링이 요구되는 상황에서 유용하게 사용됩니다. 예를 들어, 배경 요소, 디버깅 목적의 객체, 또는 빛의 영향을 받지 않는 UI 요소 등에 적합합니다.

 

 

- 특징

  1. 조명 무시: MeshBasicMaterial은 빛을 전혀 반영하지 않으므로, 조명 설정에 관계없이 동일한 색상을 유지합니다.
  2. 색상과 텍스처: color 속성을 통해 색상을 지정할 수 있으며, map 속성을 사용하여 텍스처를 적용할 수 있습니다.
  3. 투명도 지원: transparent와 opacity 속성을 조합하여 재질의 투명도를 조절할 수 있습니다.

 

3. camera

  const sizes = {
    width: 800,
    height: 600
  }

  /* Camera */
  //  PerspectiveCamera : 투영카메라
  // 투영 모드는 사람의 눈으로 보는 방식을 모방하여 설계됨
  
  const camera = new PerspectiveCamera(60, sizes.width / sizes.height)
  /* camera.position.z 값을 주지 않으면 카메라는 객체의 안에 있게 되어 object 가 안보이게 된다 */
  /* 꼭 값을 줄 것*/
  camera.position.z = 3
  scene.add(camera)

 

3-1 . PerspectiveCamera

 

PerspectiveCamera는 Three.js에서 원근 투영 카메라를 나타내는 클래스입니다. 
이 카메라는 사람의 눈이 보는 것과 유사한 방식으로 3D 장면을 렌더링합니다. 
원근 투영은 멀리 있는 객체가 가까이 있는 객체보다 작게 보이는 효과를 만들어 냅니다.

 

생성자

const camera = new PerspectiveCamera(fov, aspect, near, far);

 

파라미터

  1. fov: Field of View(시야각)으로, 카메라가 수직 방향으로 볼 수 있는 범위를 도(degree) 단위로 나타냅니다.
    일반적으로 50에서 75도 사이의 값이 사용됩니다.
  2. aspect: 종횡비(aspect ratio)로, 렌더링되는 화면의 너비를 높이로 나눈 값입니다.
    대부분의 경우 화면의 너비를 높이로 나눈 값이 사용됩니다.
  3. near: 근접 클리핑 평면(near clipping plane)으로, 이 평면 앞의 객체들은 화면에 보이지 않습니다.
    일반적으로 매우 작은 값(예: 0.1)이 사용됩니다.
  4. far: 원거리 클리핑 평면(far clipping plane)으로, 이 평면 뒤의 객체들은 화면에 보이지 않습니다.
    시야에서 멀리 떨어진 객체를 제한하기 위해 사용되며, 값은 장면의 크기에 따라 달라질 수 있습니다.

4. renderer

4-1. WebGLRenderer

3D 그래픽을 렌더링하는 데 사용되는 클래스입니다. 
이 렌더러는 GPU를 활용하여 고성능의 3D 시각화를 가능하게 합니다. 
웹 기반의 3D 애플리케이션에서 널리 사용되며, 다양한 설정 옵션을 제공하여 렌더링 과정을 세밀하게 제어할 수 있습니다. 

 

생성자

const renderer = new WebGLRenderer(options);
// options: 렌더러를 구성하는 다양한 옵션을 설정할 수 있는 객체입니다. 
// 주요 옵션으로는 canvas, antialias, alpha, precision 등이 있습니다.

 

주요옵션들

  • canvas: 렌더링할 HTML canvas 요소를 지정합니다. 지정하지 않으면 자동으로 새 canvas가 생성됩니다.
  • antialias: 안티앨리어싱(계단 현상 감소)을 활성화할지 여부를 지정합니다. 기본값은 false입니다.
  • alpha: 캔버스에 알파(투명도) 버퍼를 사용할지 여부를 지정합니다. 기본값은 false입니다.
  • precision: 셰이더의 정밀도를 설정합니다. highp, mediump, lowp 중 선택할 수 있습니다.

 

 

WebGLRenderer는 씬(scene)과 카메라(camera)를 입력으로 받아 화면에 3D 그래픽을 렌더링합니다

  const renderer = new WebGLRenderer({
    canvas: canvasRef.value
  })
  renderer.setSize(sizes.width, sizes.height)
  // .render ( scene : Object3D, camera : Camera )
  renderer.render(scene, camera)

 

 

 정리하자면

  1. scene.add(new Mesh(geometry, material))
  2. scene.add(camera)
  3. renderer.setSize(sizes.width, sizes.height)
  4. renderer.render(scene, camera)

scene.add 로 담았던 변수들은 children 배열에 담기는 걸 확인할 수 있다

 

<script setup>
import { ref, onMounted } from 'vue'
import {
  PerspectiveCamera,
  Scene,
  BoxGeometry,
  MeshBasicMaterial,
  Mesh,
  WebGLRenderer
} from 'three'

const canvasRef = ref(null)

const initScene = () => {
  const scene = new Scene()
  return scene
}

const initCamera = (sizes) => {
  const camera = new PerspectiveCamera(80, sizes.width / sizes.height)
  camera.position.set(1, 1, 3)
  return camera
}

const initRenderer = (canvas) => {
  const renderer = new WebGLRenderer({ canvas })
  return renderer
}

const createBox = () => {
  const geometry = new BoxGeometry(1, 1, 1)
  const material = new MeshBasicMaterial({ color: 'red' })
  const mesh = new Mesh(geometry, material)
  return mesh
}

const setThree = () => {
  const sizes = { width: 800, height: 600 }
  const scene = initScene()
  const camera = initCamera(sizes)
  const renderer = initRenderer(canvasRef.value)
  renderer.setSize(sizes.width, sizes.height)

  const box = createBox()
  scene.add(box)
  scene.add(camera)

  renderer.render(scene, camera)
}

onMounted(() => {
  setThree()
})
</script>

<template>
  <canvas ref="canvasRef"></canvas>
</template>

<style scoped>
canvas {
  display: block;
  width: 100%;
  height: 100%;
}
</style>

 

 

위 코드 작성시 아래와 같은 사진이 나오면 된다