본문 바로가기
개발/Unity

유니티 - 절차적 메시 기준점 설정하기 (Setting Offset with Procedural Mesh)

by 피로물든딸기 2022. 10. 30.
반응형

Unity 전체 링크

 

절차적 메시로 삼각형을 그렸는데, 유니티에서 제공하는 쿼드와 다르게 기즈모의 중심이 다르다.

 

먼저 삼각형의 중심을 기준으로 메시를 만들도록 좌표를 수정해보자.

정삼각형의 중점의 높이 g를 구해보자.

 

정삼각형이기 때문에 위의 파란색은 30º, 60º의 각도를 가지는 삼각형이 되므로, 길이가 긴 선분은 2g가 된다.

따라서 피타고라스 정리에 의해 아래의 방정식을 만족한다.

 

g에 대해서 정리하면 아래와 같다.

 

이제 g를 알았으니 세 점의 좌표를 다시 바꿔보자. 

 

마찬가지로 h의 높이도 피타고라스 공식으로 구할 수 있다.


정삼각형의 중심을 기준으로 메시 생성

 

이제 setMeshData에서 좌표를 고쳐보자.

    void setMeshData()
    {
        float g = Mathf.Sqrt(3.0f) / 6.0f;
        vertices = new Vector3[] {
            new Vector3(-0.5f, 0, -g),
            new Vector3(0, 0, Mathf.Sqrt(3.0f) / 2.0f - g),
            new Vector3(0.5f, 0, -g)};

        triangles = new int[] { 0, 1, 2 };
    }

 

게임을 실행하면 삼각형의 중심에 기즈모가 생긴 것을 알 수 있다.


삼각형의 크기와 기준점 변경하기

 

크기가 1인 삼각형이 아니라 크기가 a인 삼각형을 만들 수 있도록 size를 조절해보자.

public 변수인 size가 변화될 때 마다 확인하도록 OnValidate를 이용한다.

size와 관련된 부분을 수정하고 createProceduralMesh에서는 콜라이더를 삭제하고 다시 추가하도록 한다.

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

[RequireComponent(typeof(MeshRenderer), typeof(MeshFilter))]
public class ProceduralTriangle : MonoBehaviour
{
    public float size = 1.0f;

    Mesh mesh;
    Vector3[] vertices;
    int[] triangles;

    void OnValidate()
    {
        if (mesh == null) return;

        if(size > 0)
        {
            setMeshData(size);
            createProceduralMesh();
        }
    }

    void Start()
    {
        mesh = GetComponent<MeshFilter>().mesh;

        setMeshData(size);
        createProceduralMesh();
    }

    void setMeshData(float size)
    {
        float g = Mathf.Sqrt(3.0f) / 6.0f * size;
        vertices = new Vector3[] {
            new Vector3(-0.5f * size, 0, -g),
            new Vector3(0, 0, Mathf.Sqrt(3.0f) / 2.0f * size - g),
            new Vector3(0.5f * size, 0, -g)};

        triangles = new int[] { 0, 1, 2 };
    }

    void createProceduralMesh()
    {
        mesh.Clear();
        mesh.vertices = vertices;
        mesh.triangles = triangles;
        mesh.RecalculateNormals();

        Destroy(this.GetComponent<MeshCollider>());
        this.gameObject.AddComponent<MeshCollider>();
    }
}

 

그리고 메시를 만들 때 중점을 기준으로 만들고 싶지 않은 경우도 있으므로 offset을 추가하여 조정하도록 하자.

 

참고로 아래의 경고창은 Collider가 삭제, 생성이 반복되면서 나타나는 현상이다.

현재는 Test를 위해 OnValidate에서 Size를 변경하였지만, 실제 코드를 적용할 때는 방어 코드를 추가할 필요가 있다.

 

이제 offset을 추가하여 중심 좌표도 변경할 수 있도록 해보자.

    void setMeshData(float size)
    {
        float g = Mathf.Sqrt(3.0f) / 6.0f * size;
        vertices = new Vector3[] {
            new Vector3(-0.5f * size, 0, -g) + offset,
            new Vector3(0, 0, Mathf.Sqrt(3.0f) / 2.0f * size - g) + offset,
            new Vector3(0.5f * size, 0, -g) + offset};

        triangles = new int[] { 0, 1, 2 };
    }

 

게임을 실행하면 원하는 offset을 변경할 수 있다.

 

최종 코드는 다음과 같다.

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

[RequireComponent(typeof(MeshRenderer), typeof(MeshFilter))]
public class ProceduralTriangle : MonoBehaviour
{
    public float size = 1.0f;
    public Vector3 offset = new Vector3(0, 0, 0);

    Mesh mesh;
    Vector3[] vertices;
    int[] triangles;

    void OnValidate()
    {
        if (mesh == null) return;

        if(size > 0 || offset.magnitude > 0)
        {
            setMeshData(size);
            createProceduralMesh();
        }
    }

    void Start()
    {
        mesh = GetComponent<MeshFilter>().mesh;

        setMeshData(size);
        createProceduralMesh();
    }

    void setMeshData(float size)
    {
        float g = Mathf.Sqrt(3.0f) / 6.0f * size;
        vertices = new Vector3[] {
            new Vector3(-0.5f * size, 0, -g) + offset,
            new Vector3(0, 0, Mathf.Sqrt(3.0f) / 2.0f * size - g) + offset,
            new Vector3(0.5f * size, 0, -g) + offset};

        triangles = new int[] { 0, 1, 2 };
    }

    void createProceduralMesh()
    {
        mesh.Clear();
        mesh.vertices = vertices;
        mesh.triangles = triangles;
        mesh.RecalculateNormals();

        Destroy(this.GetComponent<MeshCollider>());
        this.gameObject.AddComponent<MeshCollider>();
    }
}

 

위의 실행결과는 아래의 unitypackage에서 확인 가능하다.

ProceduralTriangle_Size_Offset.unitypackage
0.00MB

 

Unity Plus:

 

Easy 2D, 3D, VR, & AR software for cross-platform development of games and mobile apps. - Unity Store

Have a 2D, 3D, VR, or AR project that needs cross-platform functionality? We can help. Take a look at the easy-to-use Unity Plus real-time dev platform!

store.unity.com

 

Unity Pro:

 

Unity Pro

The complete solutions for professionals to create and operate.

unity.com

 

Unity 프리미엄 학습:

 

Unity Learn

Advance your Unity skills with live sessions and over 750 hours of on-demand learning content designed for creators at every skill level.

unity.com

반응형

댓글