본문 바로가기
개발/Unity

Unity)보로노이 다이어그램 (Voronoi diagram)

by 테샤르 2024. 10. 19.

보로노이 다이어그램 (Voronoi diagram)

 

보로노이 다이어그램은 주어진 평면 위의 점 집합에서, 

각 점에 대해 해당 점과 가장 가까운 영역을 나누는 공간 분할 방법으로 여러가지 과학적 및 공학적 분야에서 자주 사용된다. 특정 전체를 기준으로 분할되기 때문에 어느정도의 일정구역을 차지하게 된다.

 

반응형

 

< Voronoi Diagram >

Map Size 에서 Point Count 만큼 영역을 생성하는 로직이다.

 

 

 

< Voronoi Diagram > 

using System.Collections.Generic;
using UnityEngine;

public class VoronoiDiagram : MonoBehaviour
{
	public int pointCount = 10;
	public Vector2 mapSize = new Vector2(10, 10);
	private List<Vector2> points;
	private Texture2D voronoiTexture;

	void Start()
	{
		// 카메라 설정
		Camera.main.transform.position = new Vector3(mapSize.x / 2, mapSize.y / 2, -10);
		Camera.main.orthographic = true;
		Camera.main.orthographicSize = mapSize.y / 2;

		// 랜덤 점들 생성
		points = GenerateRandomPoints(pointCount);

		// Voronoi 다이어그램을 위한 텍스처 생성
		voronoiTexture = new Texture2D((int)mapSize.x * 100, (int)mapSize.y * 100);

		// 다이어그램 생성
		GenerateVoronoiDiagram();

		// 텍스처를 적용할 Quad 생성
		GameObject quad = GameObject.CreatePrimitive(PrimitiveType.Quad);
		quad.transform.SetParent(transform);

		// Quad의 위치를 가운데로 설정 (Gizmos와 맞춤)
		quad.transform.position = new Vector3(mapSize.x / 2, mapSize.y / 2, 0) + transform.position;
		quad.transform.localScale = new Vector3(mapSize.x, mapSize.y, 1);
		quad.GetComponent<Renderer>().material.mainTexture = voronoiTexture;
	}

	List<Vector2> GenerateRandomPoints(int count)
	{
		List<Vector2> result = new List<Vector2>();
		for (int i = 0; i < count; i++)
		{
			result.Add(new Vector2(Random.Range(0, mapSize.x), Random.Range(0, mapSize.y)));
		}
		return result;
	}

	void GenerateVoronoiDiagram()
	{
		for (int y = 0; y < voronoiTexture.height; y++)
		{
			for (int x = 0; x < voronoiTexture.width; x++)
			{
				// 픽셀 좌표를 월드 좌표로 변환 (Gizmos와 일치)
				Vector2 pixelPosition = new Vector2(
					(float)x / voronoiTexture.width * mapSize.x,
					(float)y / voronoiTexture.height * mapSize.y
				) + (Vector2)transform.position; // Transform 적용

				int closestPointIndex = GetClosestPoint(pixelPosition);
				voronoiTexture.SetPixel(x, y, GetColorForPoint(closestPointIndex));
			}
		}
		voronoiTexture.Apply();
	}

	int GetClosestPoint(Vector2 position)
	{
		int closestIndex = 0;
		float closestDistance = Vector2.Distance(position, points[0] + (Vector2)transform.position); // Transform 적용

		for (int i = 1; i < points.Count; i++)
		{
			float distance = Vector2.Distance(position, points[i] + (Vector2)transform.position); // Transform 적용
			if (distance < closestDistance)
			{
				closestDistance = distance;
				closestIndex = i;
			}
		}
		return closestIndex;
	}

	Color GetColorForPoint(int pointIndex)
	{
		int hash = pointIndex.GetHashCode();
		Random.InitState(hash);
		return new Color(Random.value, Random.value, Random.value);
	}

	void OnDrawGizmos()
	{
		if (points == null)
			return;

		Gizmos.color = Color.red;
		foreach (var point in points)
		{
			// Transform 좌표를 반영하여 Gizmos에서 점을 그리기
			Gizmos.DrawSphere(new Vector3(point.x, point.y, 0) + transform.position, 0.1f);
		}
	}
}

 

★★★☆☆

 

반응형

댓글