[Three.js journey 강의노트] 09

9rganizedChaos·2022년 9월 26일
1
post-thumbnail

🙌🏻 해당 글은 Three.js Journey의 강의 노트입니다.

09 Geometries

현재까지는 정육면체의 큐브, BoxGeometry 위주로 실습을 진행하였다.
이번 레슨에서는 그 외 다양한 Geometry에 대해서 다룰 것인데, 그에 앞서 Geometry가 무엇인지에 대해서 먼저 짚고 넘어가보자!

ThreeJS에서 Geometry는 3D 공간 상의 점들과 면으로 구성되어있다고 이해할 수 있다. 우리는 Mesh를 만들기 위해서 Geometry를 이용해본 경험이 있다. 물론 Mesh를 만들기 위해서도 Geometry를 활용하지만, 점들을 구성하기 위해서도 Geometry를 이용한다. 또한 Geometry에는 점들의 위치 이상의 정볼르 저장할 수도 있는데, UV coordinatesthe normals가 그 예시이다. 이들에 대해서는 나중에 더 자세히 다룰 것이다.

여러 가지 종류의 내장 Geometries

우리가 알아볼 모든 내장 Geometries는 translate(...), rotateX(...), normalize() 등의 메소드를 가진 BufferGeometry 클래스를 상속받는다.

⚠️ CircleGeometry: 파이차트와 같이, 평면원의 특정 비율도 표현 가능
⚠️ ConeGeometry: 콘의 밑면을 열고 닫을 수 있음 (콘의 밑면이 파이차트와 같은 형태가 될 수 있음)
⚠️ CylinderGeometry: CylinderGeometry 역시 위 둘과 마찬가지

⚠️RingGeometry, TorusGeometry 역시 Geometry의 특정 포션만을 표현하는 것이 가능하다.

⚠️ 각각 사면체, 팔면체, 십이면체, 이십면체를 나타내는데, detail 옵션을 건드려주게 되면, 각 면에 vertex를 추가되고 더 둥글게 변형된다. IcosahedronGeometry의 경우 detail 속성을 늘려주더라도 해당 Geometry를 구성하는 삼각형들의 크기가 서로 거의 같은 크기로 유지되면서 sphere에 가까워진다.

⚠️ SphereGeometry: 작은 사각형(물론 이 역시 두 삼각형의 조합)으로 이루어진 큰 구체
⚠️ ShapeGeometry: path를 기반으로 한 모양의 Geometry
⚠️ TextGeometry: 3D 텍스트 Geometry

물론 위 내장 Geometry들 외에도 원한다면 3D 소프트웨어를 활용해 직접 Geometry를 만들 수도 있다. 이 부분에 대해서는 추후에 다루도록 할 것이다.

Geometry 파라미터와 Segment!

모든 Geometry는 Geometry를 생성하기 위해 파라미터들을 받는데, 이는 각 Geometry마다 서로 달라서 우리는 공식문서를 찾고 해야 한다. 지금까지 다뤄온 BoxGeometry의 파라미터는 총 6 가지인데, 다음과 같다.

  • width: 너비(x축 사이즈)
  • height: 높이(y축 사이즈)
  • depth: 깊이(z축 사이즈)
  • widthSegments: 너비가 몇 개의 구간으로 세분화 되어있는지
  • heightSegments: 높이가 몇 개의 구간으로 세분화 되어있는지
  • depthSegments: 깊이가 몇 개의 구간으로 세분화 되어있는지

위에서 세분화(subdivision)란 해당 면이 몇개의 삼각형으로 구성될 것인가를 의미한다고 이해하면 쉽다. (앞서 언급했듯이 Geometry는 곧 점들의 집합이고, 삼각형들의 집합이다. segment는 이 부분에 대한 설정이라고 이해하면 쉽다.)

const geometry = new THREE.BoxGeometry(1, 1, 1, 2, 2, 2)

삼각형들을 확인할 수 있도록 wireframe 속성의 값을 true로 변경해주자!

이제 좀 더 명확히 segment 파라미터들의 역할을 이해할 수 있을 것이다.

구(SphereGeometry)를 통해 살펴보면 더 흥미로운 결과를 살펴볼 수 있다.

subdivision을 나누면 나눌 수록 우리는 각 삼각형, 즉 face를 구분하기 어려워진다. 그러나 너무 많은 vertices를 추가하면 GPU는 더 많은 연산을 수행해야하기 때문에, 성능에 문제를 줄 수 있으므로 주의하자!

직접 Geometry 만들기!

물론 아주 복잡한 형태의 커스텀 Geometry가 필요하다면 그냥 3D 소프트웨어를 활용하는 편이 훨씬 효율적이다. 그러나 너무 복잡하지 않은 형태하면, 우리는 직접 Geometry를 만들어 볼 수 있을 것이다. BufferGeometry와 함께라면!

const geometry = new THREE.BufferGeometry()
const positionsArray = new Float32Array([
    0, 0, 0, 
    0, 1, 0, 
    1, 0, 0  
])

const positionsAttribute = new THREE.BufferAttribute(positionsArray, 3)
geometry.setAttribute('position', positionsAttribute)

위 코드에 대해 간단히 살펴보자!
1) 먼저 geometry를 만들어 주기 위해서 우리는 new 생성자를 통해 THREE.BufferGeometry를 불러와준다. (이때 Geometry는 비어있는 Geometry이다.)
2) 비어있는 Geomtry에 Vertices를 추가해주기 위해서 우리는 Float32Array를 활용한다. 배열을 인자로 넘겨주게 되는데, 이 배열은 오직 float(실수)만을 요소로 가질 수 있으며, 배열의 길이가 고정되어 있다는 특징을 갖는다. 요소가 셋씩 짝을 이뤄 하나의 vertex의 위치를 결정한다.
3) 이렇게 생성한 배열을 BufferGeometry에 넘겨주기 전에 우리는 해당 배열을 BufferAttirbute 메소드를 통해서 변환해준다. (첫 번째 인자는 위에서 생성해준 Array이고 두번째 인자는 몇 개의 value들이 모여 하나의 vertex를 구성하는지를 의미한다.)
4) 그리고나서 마지막으로 setAttribute 메소드를 활용해 geometry에 해당 Array를 넘겨주게 된다!

위 이미지가 바로 코드의 결과이다!

위 원리를 활용하여, 무작위 삼각형으로 구성된 Geometry를 만들어 볼 수도 있다.

const geometry = new THREE.BufferGeometry()

const count = 10
const positionsArray = new Float32Array(count * 3 * 3)
for (let i = 0; i < count * 3 * 3; i++) {
    positionsArray[i] = (Math.random() - 0.5)
}

const positionsAttribute = new THREE.BufferAttribute(positionsArray, 3)
geometry.setAttribute('position', positionsAttribute)

추가로, 여러 가지 면이 하나의 vertex를 공유하는 경우가 있을 수 있다. 큐브의 꼭지점들을 생각해보자! 그렇다면 우리는 더 적은 attribute 배열을 통해 Geometry를 구성할 수도 있을 것이고 이는 성능을 조금이나마 향상시킬 수 있는 키가 될 것이다. (물론, 이 부분에 대해서까지는 따로 다루지는 않을 것이다.)

profile
부정확한 정보나 잘못된 정보는 댓글로 알려주시면 빠르게 수정토록 하겠습니다, 감사합니다!

0개의 댓글