Three.js Geometry와 Primitives (왕사탕 토성 만들기를 곁들인)

date
Nov 9, 2024
slug
three-js-geometry-and-primitives
author
status
Public
tags
Three.js
summary
type
Post
thumbnail
planet.jpg
category
updatedAt
Nov 10, 2024 01:13 PM
 

Primitives란?


Three.js는 개발자들이 쉽게 3D 도형을 만들 수 있도록 다양한 기본 도형들을 제공합니다. 이러한 미리 정의된 3D 도형들을 'Primitives'라고 부릅니다.

Geometry의 이해


Geometry는 3D 공간에서 물체의 형태를 정의하는 정점(vertices)들의 집합입니다. Primitives보다 더 기본적인 개념으로, 3D 물체의 뼈대라고 할 수 있죠. 예를 들어, 하나의 박스를 만들 때 두 가지 방법으로 접근할 수 있습니다.
1. Primitives 사용 (간단한 방법)
const boxGeometry = new THREE.BoxGeometry(1, 1, 1);
2. BufferGeometry로 직접 정의 (세밀한 제어 가능)
const geometry = new THREE.BufferGeometry(); // 정점 데이터를 더 읽기 쉽게 구조화 const vertices = new Float32Array([ // Front face -1.0, -1.0, 1.0, // v0: 좌하단 1.0, -1.0, 1.0, // v1: 우하단 1.0, 1.0, 1.0, // v2: 우상단 -1.0, 1.0, 1.0, // v3: 좌상단 ]); // 각 정점당 x, y, z 3개의 값을 사용 geometry.setAttribute( 'position', new THREE.BufferAttribute(vertices, 3) );
 

BufferGeometry? 너 누군데


BufferGeometry는 Three.js에서 3D 모델의 기하학적 데이터를 효율적으로 저장하고 처리하기 위한 컨테이너입니다. 여러 BufferAttribute들의 집합으로 구성되며, 각 속성은 정점(vertex)의 특정 특성을 정의합니다. *모든 기본 제공 Geometry들이 이를 기반으로 만들어집니다.

핵심 특징

  • ⚡ GPU 직접 처리: 데이터가 GPU가 바로 처리할 수 있는 형태로 저장됨
  • 📦 효율적인 메모리 관리: TypedArray를 사용하여 메모리 최적화
  • 🔧 높은 유연성: 사용자가 필요에 따라 속성을 추가/수정 가능
 

기본 구성 요소

각 정점(vertex)은 다음과 같은 속성들을 가질 수 있습니다.
속성
설명
용도
Position
3차원 좌표 (x, y, z)
정점의 위치 정의
Normal
법선 벡터
조명 계산, 표면 방향 정의
Color
RGB 색상 값
정점별 색상 지정
UV
2차원 좌표 (u, v)
텍스처 매핑
Index
정점 참조 번호
면(삼각형) 구성
 
데이터 구조의 이해
// 정점 데이터 예시 const positions = new Float32Array([ // x, y, z // 설명 -1.0, -1.0, 1.0, // 정점 0 1.0, -1.0, 1.0, // 정점 1 1.0, 1.0, 1.0 // 정점 2 ]); const normals = new Float32Array([ 0, 0, 1, // 정점 0의 법선 0, 0, 1, // 정점 1의 법선 0, 0, 1 // 정점 2의 법선 ]);
 
💡 정육면체 구성의 이해
정육면체를 만들 때 필요한 정점 수는 다음과 같이 계산됩니다.
총 정점 수 = 면 개수 × 삼각형/면 × 정점/삼각형 = 6 × 2 × 3 = 36개
  • 면 6개: 앞, 뒤, 좌, 우, 위, 아래
  • 각 면은 2개의 삼각형으로 구성
  • 각 삼각형은 3개의 정점 필요
 
🔍 왜 36개나 필요할까?
정육면체는 실제로 8개의 꼭지점만 있지만, OpenGL/WebGL에서는 각 정점이 법선 벡터나 UV 좌표와 같은 고유한 속성을 가져야 하기 때문에, 같은 위치의 정점이라도 다른 면에서 사용될 때는 별도의 정점으로 처리해야 합니다.
 

Three.js가 제공하는 주요 Geometry들


기본 도형 - BoxGeometry (상자) - SphereGeometry (구) - CylinderGeometry (원통) - PlaneGeometry (평면) - TorusGeometry (도넛) 고급 도형 - ExtrudeGeometry (돌출) - TextGeometry (텍스트) - TubeGeometry (관)
 
다면체 - IcosahedronGeometry (20면체) - OctahedronGeometry (8면체)
*이보다 더 많은 Geometry와 예제 코드는 Three.js docs에서 살펴보실 수 있습니다.
 

실전 예제: 토성 만들기 (Feat. 왕사탕 토성)


실제 예제를 통해 Geometry의 활용법을 살펴보겠습니다.
토성 데모 보기 - https://threejs-saturn.vercel.app/ github - https://github.com/reeseo3o/threejs-saturn
 

토성 분체 만들기 - SphereGeometry

const saturnGeometry = new THREE.SphereGeometry(1.5, 128, 128);
*SphereGeometry는 구체를 만드는 기하학적 도형입니다.
매개변수
  • 1.5: 구체의 반지름
  • 128: 가로 세그먼트 수 (경도 방향 분할)
  • 128: 세로 세그먼트 수 (위도 방향 분할)
*세그먼트가 많을수록 더 부드러운 구체가 생성됩니다.
 

토성의 고리 만들기 - (RingGeometry)

const ringGeometry = new THREE.RingGeometry(innerRad, outerRad, 256);
*RingGeometry는 2D 원형 디스크 모양을 생성합니다.
매개변수
  • innerRad: 내부 반지름 (2.0 ~ 3.5 범위로 설정)
  • outerRad: 외부 반지름 (2.3 ~ 3.7 범위로 설정)
  • 256: 세그먼트 수 (원의 둘레를 몇 개의 삼각형으로 분할할지)
 

고리 세부 구현

const rings = [ createRing(2.0, 2.3, 0x3c3c3c, 0.9), // 가장 안쪽 고리 createRing(2.3, 2.8, 0xb0a89b, 0.8), createRing(2.8, 3.2, 0x8b7355, 0.7), createRing(3.2, 3.5, 0x6d6152, 0.6), createRing(3.5, 3.7, 0x4a4a4a, 0.4) // 가장 바깥쪽 고리 ];
5개의 서로 다른 고리를 생성하여 실제 토성의 고리와 비슷한 모양을 구현했습니다.
각 고리마다 반지름 범위, 색상, 투명도를 다르게 했습니다.
 

회전과 기울기 설정

const tilt = (15 * Math.PI) / 180; // 15도 기울기 rings.forEach((ring) => { ring.rotation.x = Math.PI / 2; // 90도 회전 (수평 배치) ring.rotation.z = tilt; // 15도 기울기 적용 });
실제 토성의 고리와 유사한 모습을 연출하기 위해서 고리들을 수평으로 배치하고 15도 기울어진 형태로 구현했습니다.
 

마치며

Three.js의 Geometry 시스템을 살펴보면서 실습까지 해보니 기본 제공되는 도형들에 감사함을 느낄 수 있었습니다. BufferGeometry를 직접 만져보려니 상당히 어지러웠거든요.
실습 예제 토성의 왕사탕… 무늬는 얼떨결에 작업해보다가 만들어 낸 것인데 귀여운 맛도 있고… 좀 두었다가 틈틈이 개선해보려고합니다. 이유는 귀여워서 입니다. 👻
 
notion image
 
글 작성 시 참고한 자료: https://threejs.org/manual/#ko/primitives