본문 바로가기

유니티/절차적 생성10

[유니티] 절차적 지형 생성 5 - Nature 목표 바다와 나무를 생성함으로써 절차적 지형 생성을 마무리한다. 기본 준비 먼저 기존에는 공기와 흙, 이렇게 두가지 블록밖에 없었기에 별도의 블록 관리 시스템을 구현하지 않았었지만 지형을 생성함에 따라 필요한 블록들이 늘어나 우선적으로 블록 관리 시스템을 만들었다. 블록에는 아래 사진과 같은 머티리얼 데이터들이 등록되어 있고 이 블록 데이터들을 한데 모아 관리해주는 블록 데이터 매니저 클래스를 만들었다. 나중에 지형을 생성하면서 블록의 머티리얼을 바꿔줘야할 경우가 생길 때 블록 데이터 매니저의 함수를 호출해 머티리얼 데이터들을 참조할 수 있도록 하였다. 이로써 기본적인 준비가 다 되었고 본격적으로 바다를 생성할 단계이다. 바다 바다는 간단하게 구현할 수 있다. 기존의 펄린노이즈를 받아 지형의 높낮이를 조.. 2021. 11. 15.
[유니티] 절차적 지형 생성 4 - 3D Noise 목표 3D 노이즈를 사용하여 지형의 깊이와 동굴을 생성한다. 3D 노이즈 우리가 흔히 노이즈라 하면 2차원 평면상의 형태를 떠올리기 쉽지만 3차원 노이즈 또한 제작하는 것이 가능하다. float perlinValue = Mathf.PerlinNoise(xCoord, yCoord) * 2 - 1; 위 코드는 기존의 평면 노이즈를 제작하는 코드이다. 이 코드를 아래의 코드로 바꿔준다. float xy = Mathf.PerlinNoise(xCoord, yCoord); float yz = Mathf.PerlinNoise(yCoord, zCoord); float xz = Mathf.PerlinNoise(xCoord, zCoord); float yx = Mathf.PerlinNoise(yCoord, xCoord);.. 2021. 11. 15.
[유니티] 절차적 지형 생성 3 - Texture 목표 이전 포스팅에서 생성한 지형에 텍스처를 적용한다. 지형 텍스처는 6면체에서 위, 아래, 옆면 이렇게 총 3가지로 구성된다. 적용될 머티리얼은 다음 사진과 같다. 그리고 이 머티리얼을 단순히 메쉬에 적용하면 될 것 같지만 아니다. 앞서 최적화를 위해 메쉬를 하나로 합쳐놓았기 때문에 각기 다른 머티리얼을 사용하려면 메쉬를 머티리얼에 맞춰 분리해야하며, 분리된 메쉬를 다시 하나의 메쉬로 통합하는 작업이 필요하다. 단일 메쉬 단일 머티리얼 복합 메쉬 복합 머티리얼 단일 메쉬 복합 머티리얼 소스 코드 public void Combine(MeshFilter[] meshFilters, MeshRenderer[] meshRenderers) { //지형 메쉬에서 머티리얼 종류를 가져옴 List materials =.. 2021. 11. 15.
[유니티] 절차적 지형 생성 2 - Chunk 목표 청크라는 단위 개념을 이용해 끝없이 로드되는 지형을 생성한다. 청크란? 하나의 거대한 덩어리라는 뜻으로 끝없는 세계를 구현할 때 맵 데이터를 관리하기 위해 사용된다. 대표적으로 마인크래프트에서 16(가로) * 16(세로) * 256(높이) 단위로 청크를 관리한다. 청크를 사용하는 이유는 무엇인가? 절차적으로 만들어진 세계는 시드가 동일한 이상 언제나 생성되는 결과물은 동일하다. 이러한 점을 이용하여 동적으로 메모리에 맵을 생성하고 지울 수 있는데, 맵을 청크 단위가 아닌 블록 단위(1 * 1 * 1)로 생성하게 되면 메모리에 부하가 생기고 소요되는 시간 또한 길어진다. 그래서 여러 개의 블록을 하나로 묶어 관리하게 되면 맵을 지우거나 로드할 때 빠른 속도로 처리할 수 있다. 청크를 어떻게 활용할 것.. 2021. 11. 15.
[유니티] 절차적 지형 생성 1 - Perlin Noise 목표 펄린 노이즈로 마인크래프트같은 3D 지형을 생성한다. 이전 포스팅에서 학습한 Perlin noise를 이용하여 Height 값에 따라 블록을 배치한 모습 겉보기엔 괜찮은 지형이 생성되었으나 메모리 낭비가 너무 심하다. 아무것도 하지 않았지만 FPS가 약 20으로 현저히 낮은 수치를 기록하고있다. FPS가 낮은 이유는 큐브 오브젝트가 6면을 모두 메쉬로 채우기 때문인데 이를 해결하기 위해서는 보이지 않는 면을 컬링해야한다. 메쉬 생성 Instantiate(cube, new Vector3(x, y, z), Quaternion.identity); 기존의 큐브를 생성하는 코드를 지우고 아래의 메쉬를 생성하는 코드로 바꿔주었다. Vector3[] vertices = { new Vector3 (0, 0, 0).. 2021. 11. 15.
[유니티] 절차적 섬 생성 - Perlin Noise Perlin Noise란? 연속적인 일련의 의사 난수 값을 생성하는 알고리즘으로 유기적인 모양의 노이즈를 생성한다. 왼쪽 노이즈는 랜덤으로 생성된 노이즈로, 유기적인 연결 없이 단절된 형태를 띠기 때문에 지형 생성 노이즈로 적합하지 않다. 펄린 노이즈 파라미터 시드 (seed) 주파수 (frequency) 옥타브 (octave) 시드 : 무작위 생성을 위한 값 주파수 : 노이즈의 간격과 관련된 값. 주파수가 클수록 노이즈가 세밀해진다. 고주파 노이즈 저주파 노이즈 옥타브 : 여러 주파수의 노이즈를 중첩시킬 때 쓰는 값 옥타브가 커질수록 높은 주파수와 낮은 진폭의 노이즈가 중첩된다. 중첩되지 않은 여러 노이즈 중첩된 노이즈 처음 노이즈가 전체적인 형태를 결정하고 이후 다른 노이즈들이 합쳐지면서 디테일한 노.. 2021. 11. 15.
[유니티] 절차적 동굴 생성 - Cellular Automata Cellular Automata란? 격자 구조로 쪼개진 세포(단위)들이 주변에 있는 세포에 따라 자신의 상태를 변화시키는 알고리즘이다. 생성 과정 특정한 비율(ex 50%)로 맵을 벽으로 채운다. 맵의 각 타일을 선택하여 주변 8칸 중 벽이 4칸을 초과할 경우 벽으로, 4칸 미만일 경우 길로 바꾼다. 2번 과정을 정해진 수(ex 5회)만큼 반복한다. 1번 과정 2번 과정 3번 과정 소스 코드 using UnityEngine; using UnityEngine.Tilemaps; public class CaveGeneratorByCellularAutomata : MonoBehaviour { [SerializeField] private int width; [SerializeField] private int he.. 2021. 11. 14.
[유니티] 절차적 동굴 생성 - Binary Space Partitioning Binary Space Partitioning이란? 재귀적으로 공간을 둘로 분할해 트리 형태를 구성하는 알고리즘이다. 생성 과정 임의의 방향(수직, 수평)과 임의의 위치를 선택해 공간을 둘로 분할한다. 정해진 노드만큼 1번 과정을 반복한다. 나누어진 공간에 맞춰 방을 생성한다. 트리를 거슬러 올라가 방과 방을 연결한다. 1번 과정 3번 과정 4번 과정 소스 코드 트리 분할 private void DivideTree(TreeNode treeNode, int n) //재귀 함수 { if (n < maxNode) //0 부터 시작해서 노드의 최댓값에 이를 때 까지 반복 { RectInt size = treeNode.treeSize; //이전 트리의 범위 값 저장, 사각형의 범위를 담기 위해 Rect 사용 in.. 2021. 11. 14.
[유니티] 절차적 미로 생성 - Recursive Backtracking Recursive Backtracking이란? 조건을 만족하는 모든 경우를 탐색하는 알고리즘이다. 탐색 도중 조건에 부합하지 않는 경우가 생길 때 이전 분기로 돌아가 다른 가능성을 탐색한다. 생성 과정 무작위 위치를 시작점으로 삼는다. 길을 만들 수 있는 인접한 벽을 무작위로 선택해 길을 만든다. 선택할 수 있는 벽이 없다면 이전 길로 돌아가 2번 과정을 다시 수행한다. 소스 코드 using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.Tilemaps; enum TILE {ROAD = 0, WALL, CHECK, START}; public class MazeGeneratorByRecurs.. 2021. 11. 14.