[Unity] Planet Generation [2] - Procedural Planets

suhan0304·2024년 2월 25일
0
post-thumbnail

preview Link : https://velog.io/@suhan0304/Unity-Planet-Generation-The-Sphere
gitHub Link : https://github.com/suhan0304/Planet-Generation
PlanetGeneration


Procedural Planets

생성한 행성의 모양과 색상 설정을 유지하기 위해 여러 속성을 관리할 스크립트를 작성해보자.


모양 설정 및 생성

ShapeSettings.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

[CreateAssetMenu()]
public class ShapeSettings : ScriptableObject
{
    public float planetRadius = 1;
}

ShapeGenerator.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ShapeGenerator 
{
    ShapeSettings settings;

    public ShapeGenerator(ShapeSettings settings)
    {
        this.settings = settings;
    }

    public Vector3 CalculatePoinOnPlanet(Vector3 pointOnUnitSphere)
    {
        return pointOnUnitSphere * settings.planetRadius;
    }
}

ColorSettings.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

[CreateAssetMenu()]
public class ColorSettings : ScriptableObject
{
    public Color planetColor;
}

이제 Planet해서 설정 스크립터블 오브젝트를 불러와서 생성을 처음 생성할 때 해당 설정을 사용한다.

Planet.cs

public ShapeSettings shapeSettings;
public ColorSettings colorSettings;

[HideInInspector]
public bool shapeSettingFoldout;
[HideInInspector]
public bool colorSettingFoldout;

ShapeGenerator shapeGenerator;

private void OnValidate()
{
    GeneratePlanet();
}

public void GeneratePlanet()
{
    Initialize();
    GenerateMesh();
    GenerateColors();
}

public void OnShapeSettingsUpdated()
{
    Initialize();
    GenerateMesh();
}

public void OnColorSettingsUpdated()
{
    Initialize();
    GenerateColors();
}

void GenerateMesh()
{
    foreach (TerrainFace face in terrainFaces)
    {
        face.ConstructMesh();
    }
}

void GenerateColors()
{
    foreach (MeshFilter m in meshFilters)
    {
        m.GetComponent<MeshRenderer>().sharedMaterial.color = colorSettings.planetColor;
    }
}

이후에 Planet의 shapeGnerator를 사용해

TerrainFace.cs

Vector2 percent = new Vector2(x, y) / (resolution - 1);
Vector3 pointOnUnitCube = localUp + (percent.x - .5f) * 2 * axisA + (percent.y - .5f) * 2 * axisB;
Vector3 pointOnUnitSphere = pointOnUnitCube.normalized;
vertices[i] = shapeGenerator.CalculatePoinOnPlanet(pointOnUnitSphere);

스크립터블 오브젝트로 ColorSettings, ShapeSettings를 생성해서 인스펙스 창으로 드래그 드랍해서 Planet의 변수들을 초기화 해준다.


PlanetEditor

행성을 자체적으로 조절할 수 있도록 Planet Editor 스크립트를 추가로 작성한다.

PlanetEditor.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Planet : MonoBehaviour {

    [Range(2,256)]
    public int resolution = 10;
    public bool autoUpdate = true;

    public ShapeSettings shapeSettings;
    public ColorSettings colorSettings;

    [HideInInspector]
    public bool shapeSettingFoldout;
    [HideInInspector]
    public bool colorSettingFoldout;

    ShapeGenerator shapeGenerator;

    [SerializeField, HideInInspector]
    MeshFilter[] meshFilters;
    TerrainFace[] terrainFaces;

    private void OnValidate()
    {
        GeneratePlanet();
    }

	void Initialize()
    {
        shapeGenerator = new ShapeGenerator(shapeSettings);

        if (meshFilters == null || meshFilters.Length == 0)
        {
            meshFilters = new MeshFilter[6];
        }
        terrainFaces = new TerrainFace[6];

        Vector3[] directions = { Vector3.up, Vector3.down, Vector3.left, Vector3.right, Vector3.forward, Vector3.back };

        for (int i = 0; i < 6; i++)
        {
            if (meshFilters[i] == null)
            {
                GameObject meshObj = new GameObject("mesh");
                meshObj.transform.parent = transform;

                meshObj.AddComponent<MeshRenderer>().sharedMaterial = new Material(Shader.Find("Standard"));
                meshFilters[i] = meshObj.AddComponent<MeshFilter>();
                meshFilters[i].sharedMesh = new Mesh();
            }

            terrainFaces[i] = new TerrainFace(shapeGenerator, meshFilters[i].sharedMesh, resolution, directions[i]);
        }
    }

    public void GeneratePlanet()
    {
        Initialize();
        GenerateMesh();
        GenerateColors();
    }

    public void OnShapeSettingsUpdated()
    {
        if (autoUpdate)
        {
            Initialize();
            GenerateMesh();
        }
    }

    public void OnColorSettingsUpdated()
    {
        if (autoUpdate)
        {
            Initialize();
            GenerateColors();
        }
    }
    void GenerateMesh()
    {
        foreach (TerrainFace face in terrainFaces)
        {
            face.ConstructMesh();
        }
    }

    void GenerateColors()
    {
        foreach (MeshFilter m in meshFilters)
        {
            m.GetComponent<MeshRenderer>().sharedMaterial.color = colorSettings.planetColor;
        }
    }
}

이제 인스펙터에 값을 적용하면 자동으로 Planet의 update 함수를 불러오면서 실시간으로 Unity Editor에 적용되는 것을 확인할 수 있다.


이제 행성의 색상과 크기를 인스펙터로 설정하면서 실시간으로 씬 창으로 행성을 확인할 수 있다.

profile
Be Honest, Be Harder, Be Stronger

0개의 댓글