유니티 도로 만들기 Spline-3(완)

박성준·2025년 3월 26일

유니티 복습용

목록 보기
21/23

정점을 얻는 메서드를 구현했으니 이제 이용해보자.
새로운 클래스를 선언
에디터 모드에서 실행.

[ExecuteInEditMode()]
public class SplineRoad : MonoBehaviour
{

}

먼저 정점들을 보관해줄 리스트,
얼마나 스플라인을 쪼갤지,
업벡터에 영향을 받을지 안 받을지 정하는 변수를 선언.

private SplineSampler m_splineSampler;
[SerializeField] private int resolution;
[SerializeField] private bool EffectByUpVector;
MeshFilter m_meshFilter;

List<Vector3> m_vertsP1;
List<Vector3> m_vertsP2;

전체 길이가 1이니 1을 resolution만큼 나눈다.
그럼 도로의 양쪽 정점들을 배열에 넣을 수 있다.

void GetVerts()
{
    m_vertsP1 = new List<Vector3>();
    m_vertsP2 = new List<Vector3>();

    float step = 1f / (float)resolution;
    for (int i = 0; i <= resolution; i++)
    {
        float t = step * i;
        Math.Round(t, 4);
        m_splineSampler.SamplerWidth(t, out Vector3 p1, out Vector3 p2, EffectByUpVector);
        m_vertsP1.Add(p1);
        m_vertsP2.Add(p2);
    }
}

이제 메쉬를 만드는 메서드를 구현해야한다.
메쉬를 간략하게 설명하면 메쉬를 구성하는 정점들을 갖고있는 Vertices와
정점들을 잇는 순서를 나타내는 Triangles로 구성되어있다.
보통 정점은 반 시계 방향으로 잇는다. 이래야 메쉬가 위를 바라보기때문(빛 반사를 표현할 때 필요함)
예를 들자면

이렇게 정점이 4개 있고 옆에 숫자가 정점의 index라고 생각하자.
메쉬는 삼각형 혹은 사각형으로 이루는데 Triangles이므로 삼각형임.
즉 3개씩 끊어서 순서를 주어야한다.

이러한 순서로 정점을 잇는다면 Triangles에는 어떤 값이 들어갈까.
단순하게 생각하면 0-2-3-1-0 이다.
하지만 위에 말한 걸 고려해보자. 3개씩 끊어서 정점을 이어야한다.
즉 0-2-3으로 끊고 3-1-0으로 끊어야한다. 합치면 0-2-3-3-1-0.
이를 메서드에 적용한다.

private void BuildMesh()
{
    Mesh m = new Mesh();
    List<Vector3> verts = new List<Vector3>();
    List<int> tris = new List<int>();

    int length = m_vertsP2.Count;

    for (int i = 0; i < length; i++)
    {

        // 현재 인덱스 i와 다음 인덱스 (순환하도록)
        int nextIndex = (i + 1) % length;

        // 현재 사각형을 구성하는 네 개의 정점
        Vector3 p1 = transform.InverseTransformPoint(m_vertsP1[i]);
        Vector3 p2 = transform.InverseTransformPoint(m_vertsP2[i]);
        Vector3 p3 = transform.InverseTransformPoint(m_vertsP1[nextIndex]);
        Vector3 p4 = transform.InverseTransformPoint(m_vertsP2[nextIndex]);

        // 정점 추가
        int offset = verts.Count; // 현재 추가된 정점 개수 기반으로 오프셋 계산

        verts.Add(p1);
        verts.Add(p2);
        if (nextIndex != 0)
        {
            verts.Add(p3);
            verts.Add(p4);
        }

        tris.Add(offset + 0);
        if (nextIndex != 0)
        {
            tris.Add(offset + 2);
            tris.Add(offset + 3);
            tris.Add(offset + 3);
        }
        tris.Add(offset + 1);
        tris.Add(offset + 0);
    }

    m.SetVertices(verts);
    m.SetTriangles(tris, 0);

    m_meshFilter.mesh = m;
}

정점 4개만이 아닌 여러개를 이어야하므로 반복문 마지막에는 정점이 마무리지어지도록 조건을 건다.
그리고 결과값이 예상값과 같은지 확인해야하므로 기즈모도 생성.

private void OnDrawGizmos()
{
    for (int i = 0; i < m_vertsP1.Count; i++)
    {
        Handles.SphereHandleCap(0, m_vertsP1[i], Quaternion.identity, 1f, EventType.Repaint);
        Handles.SphereHandleCap(0, m_vertsP2[i], Quaternion.identity, 1f, EventType.Repaint);
        Gizmos.DrawLine(m_vertsP1[i], m_vertsP2[i]);
    }
}


메쉬 필터와 메쉬 렌더러는 필수.

도로 완성.

profile
GameDeveloper

0개의 댓글