Reese-log
  • About
  • Blog

© 2025 Reese. All rights reserved.

2024년 11월 9일

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

#Three.js

Primitives란?


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

Geometry의 이해


Geometry는 3D 공간에서 물체의 형태를 정의하는 정점(vertices)들의 집합입니다. Primitives보다 더 기본적인 개념으로, 3D 물체의 뼈대라고 할 수 있죠. 예를 들어, 하나의 박스를 만들 때 두 가지 방법으로 접근할 수 있습니다.

1. Primitives 사용 (간단한 방법)

javascript
const boxGeometry = new THREE.BoxGeometry(1, 1, 1);

2. BufferGeometry로 직접 정의 (세밀한 제어 가능)

javascript
1const geometry = new THREE.BufferGeometry();
2
3// 정점 데이터를 더 읽기 쉽게 구조화
4const vertices = new Float32Array([
5  // Front face
6  -1.0, -1.0,  1.0,  // v0: 좌하단
7   1.0, -1.0,  1.0,  // v1: 우하단
8   1.0,  1.0,  1.0,  // v2: 우상단
9  -1.0,  1.0,  1.0,  // v3: 좌상단
10]);
11
12// 각 정점당 x, y, z 3개의 값을 사용
13geometry.setAttribute(
14  'position', 
15  new THREE.BufferAttribute(vertices, 3)
16);

BufferGeometry? 너 누군데


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

이미지 출처:
이미지 출처:

핵심 특징

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

    각 정점(vertex)은 다음과 같은 속성들을 가질 수 있습니다.

    속성설명용도
    Position3차원 좌표 (x, y, z)정점의 위치 정의
    Normal법선 벡터조명 계산, 표면 방향 정의
    ColorRGB 색상 값정점별 색상 지정
    UV2차원 좌표 (u, v)텍스처 매핑
    Index정점 참조 번호면(삼각형) 구성

    데이터 구조의 이해
    javascript
    1// 정점 데이터 예시
    2const positions = new Float32Array([
    3    // x,   y,   z    // 설명
    4    -1.0, -1.0, 1.0,  // 정점 0
    5     1.0, -1.0, 1.0,  // 정점 1
    6     1.0,  1.0, 1.0   // 정점 2
    7]);
    8
    9const normals = new Float32Array([
    10    0, 0, 1,  // 정점 0의 법선
    11    0, 0, 1,  // 정점 1의 법선
    12    0, 0, 1   // 정점 2의 법선
    13]);
    14

    💡 정육면체 구성의 이해

    정육면체를 만들 때 필요한 정점 수는 다음과 같이 계산됩니다.

    plain text
    총 정점 수 = 면 개수 × 삼각형/면 × 정점/삼각형
               = 6 × 2 × 3
               = 36개
  • 면 6개: 앞, 뒤, 좌, 우, 위, 아래
  • 각 면은 2개의 삼각형으로 구성
  • 각 삼각형은 3개의 정점 필요
  • 🔍 왜 36개나 필요할까?

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


    기본 도형 - BoxGeometry (상자) - SphereGeometry (구) - CylinderGeometry (원통) - PlaneGeometry (평면) - TorusGeometry (도넛) 고급 도형 - ExtrudeGeometry (돌출) - TextGeometry (텍스트) - TubeGeometry (관)

    다면체 - IcosahedronGeometry (20면체) - OctahedronGeometry (8면체)

    *이보다 더 많은 Geometry와 예제 코드는 Three.js docs에서 살펴보실 수 있습니다.

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


    실제 예제를 통해 Geometry의 활용법을 살펴보겠습니다.

    토성 분체 만들기 - SphereGeometry

    javascript
    const saturnGeometry = new THREE.SphereGeometry(1.5, 128, 128);

    *SphereGeometry는 구체를 만드는 기하학적 도형입니다.

    매개변수

  • 1.5: 구체의 반지름
  • 128: 가로 세그먼트 수 (경도 방향 분할)
  • 128: 세로 세그먼트 수 (위도 방향 분할)
  • *세그먼트가 많을수록 더 부드러운 구체가 생성됩니다.

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

    javascript
    const ringGeometry = new THREE.RingGeometry(innerRad, outerRad, 256);

    *RingGeometry는 2D 원형 디스크 모양을 생성합니다.

    매개변수

  • innerRad: 내부 반지름 (2.0 ~ 3.5 범위로 설정)
  • outerRad: 외부 반지름 (2.3 ~ 3.7 범위로 설정)
  • 256: 세그먼트 수 (원의 둘레를 몇 개의 삼각형으로 분할할지)
  • 고리 세부 구현

    javascript
    1const rings = [
    2    createRing(2.0, 2.3, 0x3c3c3c, 0.9), // 가장 안쪽 고리
    3    createRing(2.3, 2.8, 0xb0a89b, 0.8),
    4    createRing(2.8, 3.2, 0x8b7355, 0.7),
    5    createRing(3.2, 3.5, 0x6d6152, 0.6),
    6    createRing(3.5, 3.7, 0x4a4a4a, 0.4)  // 가장 바깥쪽 고리
    7];

    5개의 서로 다른 고리를 생성하여 실제 토성의 고리와 비슷한 모양을 구현했습니다.

    각 고리마다 반지름 범위, 색상, 투명도를 다르게 했습니다.

    회전과 기울기 설정

    javascript
    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를 직접 만져보려니 상당히 어지러웠거든요.

    실습 예제 토성의 왕사탕… 무늬는 얼떨결에 작업해보다가 만들어 낸 것인데 귀여운 맛도 있고… 좀 두었다가 틈틈이 개선해보려고합니다. 이유는 귀여워서 입니다. 👻

    글 작성 시 참고한 자료: https://threejs.org/manual/#ko/primitives