안녕하세요, 이번 포스팅에서는 Unity에서 C#을 사용해 깎은 정이십면체(Truncated Icosahedron)를 생성하는 방법을 소개하겠습니다. 깎은 정이십면체는 축구공 모양으로 잘 알려진 다면체로, 정오각형 12개와 정육각형 20개로 구성됩니다. 이 글에서는 정점 데이터와 폴리곤 인덱스를 활용해 Unity의 Mesh 클래스로 이를 구현해 보겠습니다.
준비
- Unity: 최신 버전 설치 (2021.3 이상 권장).
- 기본 C# 지식: Unity 스크립팅에 대한 이해.
- 데이터: 정점 60개, 오각형 12개, 육각형 20개의 인덱스 데이터.
데이터
우리가 사용할 데이터는 다음과 같습니다:
- 정점 (vdata): 60개의 3D 좌표 (x, y, z).
- 오각형 (pentagons): 12개의 오각형 폴리곤을 정의하는 정점 인덱스 배열.
- 육각형 (hexagons): 20개의 육각형 폴리곤을 정의하는 정점 인덱스 배열.
Unity는 폴리곤을 삼각형 단위로만 렌더링하므로, 오각형과 육각형을 삼각형으로 분해(triangulation)해야 합니다.
코드 작성
아래는 Unity에서 깎은 정이십면체를 생성하는 전체 코드입니다. GameObject에 붙여 실행하면 메시가 렌더링됩니다.
using UnityEngine;
public class TruncatedIcosahedronMesh : MonoBehaviour
{
void Start()
{
CreateMesh();
}
void CreateMesh()
{
Mesh mesh = new Mesh();
gameObject.AddComponent<MeshFilter>().mesh = mesh;
gameObject.AddComponent<MeshRenderer>().material = new Material(Shader.Find("Standard"));
// 정점 데이터 (60개)
Vector3[] vertices = new Vector3[60]
{
new Vector3(0, 0, 1.021f), new Vector3(0.4035482f, 0, 0.9378643f), new Vector3(-0.2274644f, 0.3333333f, 0.9378643f),
new Vector3(-0.1471226f, -0.375774f, 0.9378643f), new Vector3(0.579632f, 0.3333333f, 0.7715933f), new Vector3(0.5058321f, -0.375774f, 0.8033483f),
new Vector3(-0.6020514f, 0.2908927f, 0.7715933f), new Vector3(-0.05138057f, 0.6666667f, 0.7715933f), new Vector3(0.1654988f, -0.6080151f, 0.8033483f),
new Vector3(-0.5217096f, -0.4182147f, 0.7715933f), new Vector3(0.8579998f, 0.2908927f, 0.4708062f), new Vector3(0.3521676f, 0.6666667f, 0.6884578f),
new Vector3(0.7841999f, -0.4182147f, 0.5025612f), new Vector3(-0.657475f, 0.5979962f, 0.5025612f), new Vector3(-0.749174f, -0.08488134f, 0.6884578f),
new Vector3(-0.3171418f, 0.8302373f, 0.5025612f), new Vector3(0.1035333f, -0.8826969f, 0.5025612f), new Vector3(-0.5836751f, -0.6928964f, 0.4708062f),
new Vector3(0.8025761f, 0.5979962f, 0.2017741f), new Vector3(0.9602837f, -0.08488134f, 0.3362902f), new Vector3(0.4899547f, 0.8302373f, 0.3362902f),
new Vector3(0.7222343f, -0.6928964f, 0.2017741f), new Vector3(-0.8600213f, 0.5293258f, 0.1503935f), new Vector3(-0.9517203f, -0.1535518f, 0.3362902f),
new Vector3(-0.1793548f, 0.993808f, 0.1503935f), new Vector3(0.381901f, -0.9251375f, 0.2017741f), new Vector3(-0.2710537f, -0.9251375f, 0.3362902f),
new Vector3(-0.8494363f, -0.5293258f, 0.2017741f), new Vector3(0.8494363f, 0.5293258f, -0.2017741f), new Vector3(1.007144f, -0.1535518f, -0.06725804f),
new Vector3(0.2241935f, 0.993808f, 0.06725804f), new Vector3(0.8600213f, -0.5293258f, -0.1503935f), new Vector3(-0.7222343f, 0.6928964f, -0.2017741f),
new Vector3(-1.007144f, 0.1535518f, 0.06725804f), new Vector3(-0.381901f, 0.9251375f, -0.2017741f), new Vector3(0.1793548f, -0.993808f, -0.1503935f),
new Vector3(-0.2241935f, -0.993808f, -0.06725804f), new Vector3(-0.8025761f, -0.5979962f, -0.2017741f), new Vector3(0.5836751f, 0.6928964f, -0.4708062f),
new Vector3(0.9517203f, 0.1535518f, -0.3362902f), new Vector3(0.2710537f, 0.9251375f, -0.3362902f), new Vector3(0.657475f, -0.5979962f, -0.5025612f),
new Vector3(-0.7841999f, 0.4182147f, -0.5025612f), new Vector3(-0.9602837f, 0.08488134f, -0.3362902f), new Vector3(-0.1035333f, 0.8826969f, -0.5025612f),
new Vector3(0.3171418f, -0.8302373f, -0.5025612f), new Vector3(-0.4899547f, -0.8302373f, -0.3362902f), new Vector3(-0.8579998f, -0.2908927f, -0.4708062f),
new Vector3(0.5217096f, 0.4182147f, -0.7715933f), new Vector3(0.749174f, 0.08488134f, -0.6884578f), new Vector3(0.6020514f, -0.2908927f, -0.7715933f),
new Vector3(-0.5058321f, 0.375774f, -0.8033483f), new Vector3(-0.1654988f, 0.6080151f, -0.8033483f), new Vector3(0.05138057f, -0.6666667f, -0.7715933f),
new Vector3(-0.3521676f, -0.6666667f, -0.6884578f), new Vector3(-0.579632f, -0.3333333f, -0.7715933f), new Vector3(0.1471226f, 0.375774f, -0.9378643f),
new Vector3(0.2274644f, -0.3333333f, -0.9378643f), new Vector3(-0.4035482f, 0, -0.9378643f), new Vector3(0, 0, -1.021f)
};
// 삼각형 인덱스 생성
int[] triangles = GenerateTriangles();
// Mesh 설정
mesh.vertices = vertices;
mesh.triangles = triangles;
mesh.RecalculateNormals();
}
int[] GenerateTriangles()
{
// 오각형과 육각형을 삼각형으로 분해
int[] pentagons = new int[]
{
0,3,8,5,1, 2,7,15,13,6, 4,10,18,20,11, 9,14,23,27,17, 12,21,31,29,19,
16,26,36,35,25, 22,32,42,43,33, 24,30,40,44,34, 28,39,49,48,38, 37,47,55,54,46,
41,45,53,57,50, 51,52,56,59,58
};
int[] hexagons = new int[]
{
0,1,4,11,7,2, 0,2,6,14,9,3, 1,5,12,19,10,4, 3,9,17,26,16,8, 5,8,16,25,21,12,
6,13,22,33,23,14, 7,11,20,30,24,15, 10,19,29,39,28,18, 13,15,24,34,32,22, 17,27,37,46,36,26,
18,28,38,40,30,20, 21,25,35,45,41,31, 23,33,43,47,37,27, 29,31,41,50,49,39, 32,34,44,52,51,42,
35,36,46,54,53,45, 38,48,56,52,44,40, 42,51,58,55,47,43, 48,49,50,57,59,56, 53,54,55,58,59,57
};
int totalTriangles = 12 * 3 + 20 * 4; // 116개 삼각형
int[] triangles = new int[totalTriangles * 3];
int index = 0;
// 오각형 분해 (12개, 각 3개 삼각형)
for (int i = 0; i < 12; i++)
{
int base = i * 5;
int v0 = pentagons[base];
triangles[index++] = v0; triangles[index++] = pentagons[base + 1]; triangles[index++] = pentagons[base + 2];
triangles[index++] = v0; triangles[index++] = pentagons[base + 2]; triangles[index++] = pentagons[base + 3];
triangles[index++] = v0; triangles[index++] = pentagons[base + 3]; triangles[index++] = pentagons[base + 4];
}
// 육각형 분해 (20개, 각 4개 삼각형)
for (int i = 0; i < 20; i++)
{
int base = i * 6;
int v0 = hexagons[base];
triangles[index++] = v0; triangles[index++] = hexagons[base + 1]; triangles[index++] = hexagons[base + 2];
triangles[index++] = v0; triangles[index++] = hexagons[base + 2]; triangles[index++] = hexagons[base + 3];
triangles[index++] = v0; triangles[index++] = hexagons[base + 3]; triangles[index++] = hexagons[base + 4];
triangles[index++] = v0; triangles[index++] = hexagons[base + 4]; triangles[index++] = hexagons[base + 5];
}
return triangles;
}
}
코드 설명
- 정점 설정:
- vertices 배열에 60개의 정점 좌표를 직접 입력했습니다. 이는 깎은 정이십면체의 3D 위치를 정의합니다.
- 삼각형 분해:
- 오각형: 각 오각형(5개 정점)을 3개의 삼각형으로 분해합니다. 첫 번째 정점을 기준으로 "팬(fan)" 방식 사용.
- 예: {0, 3, 8, 5, 1} → (0, 3, 8), (0, 8, 5), (0, 5, 1).
- 육각형: 각 육각형(6개 정점)을 4개의 삼각형으로 분해합니다.
- 예: {0, 1, 4, 11, 7, 2} → (0, 1, 4), (0, 4, 11), (0, 11, 7), (0, 7, 2).
- 총 삼각형 개수: 12 × 3 + 20 × 4 = 116개.
- 오각형: 각 오각형(5개 정점)을 3개의 삼각형으로 분해합니다. 첫 번째 정점을 기준으로 "팬(fan)" 방식 사용.
- Mesh 생성:
- MeshFilter와 MeshRenderer를 추가해 메시를 렌더링합니다.
- mesh.vertices와 mesh.triangles로 데이터 설정 후, RecalculateNormals()로 법선 벡터를 계산합니다.
실행 방법
- Unity에서 새 프로젝트를 엽니다.
- 빈 GameObject를 생성하고 이름을 "TruncatedIcosahedron"으로 설정합니다.
- 위 코드를 TruncatedIcosahedronMesh.cs로 저장 후 GameObject에 추가합니다.
- 플레이 버튼을 누르면 씬에 깎은 정이십면체가 나타납니다!
팁과 주의사항
- 크기 조정: 정점이 작게 보일 경우, vertices[i] *= 5f처럼 스케일을 키워보세요.
- 방향 문제: 메시가 뒤집혀 보인다면, 삼각형 인덱스 순서를 반대로(예: v0, v2, v1) 조정하세요.
- 최적화: 더 정교한 삼각분할(예: Delaunay)을 원한다면 별도 알고리즘을 적용할 수 있습니다.
마무리
이 튜토리얼을 통해 Unity에서 복잡한 다면체를 생성하는 방법을 배워보았습니다. 깎은 정이십면체는 3D 그래픽스 학습이나 게임 오브젝트 제작에 유용하게 활용될 수 있습니다. 질문이나 개선 아이디어가 있다면 댓글로 남겨주세요!
'Unity' 카테고리의 다른 글
Unity에서 GPGS v2와 Firebase 연동 후 발생한 ClassNotFoundException 해결기 (0) | 2025.03.19 |
---|---|
Unity 2022.3.20f1 에서 빌드 시 에러 (0) | 2024.03.12 |
CommandInvokationFailure: Failed to update Android SDK package list. (0) | 2024.02.23 |
경고 메시지 : androidx.fragment:fragment (androidx.fragment:fragment) (0) | 2023.12.16 |
[UNITY] Animator Controller - 8방향 이동 애니메이션 블랜딩 (1) | 2022.09.12 |