(5) 큐브

1. 개요

Unity에는 자체 큐브 모델이 있지만 이 기사에서는 이를 구현하며 기본 버전과 퍼펙트 버전으로 나뉩니다. 기본 버전은 정점 정상 계산을 수행하지 않지만 완벽한 버전은 정상 계산을 수행하며 결과는 내장 큐브에 더 가깝습니다.

2. 기본 큐브

2.1 기본 클래스

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

[RequireComponent(typeof(MeshFilter),typeof(MeshRenderer))]
public class CreateMeshBase : MonoBehaviour
{
    MeshFilter meshFilter;

    protected Mesh mesh;

    protected virtual Vector3[] Vertices { get; }
    protected virtual int[] Triangles { get; }
    protected virtual Vector3[] Normals { get; }
    protected virtual Vector2[] Uvs { get; }
    protected virtual string MeshName { get; }

    protected virtual void Start()
    {
        GetMeshFilter();
    }

    protected virtual void Reset()
    {
        GetMeshFilter();
    }

    protected virtual void OnValidate()
    {
        GetMeshFilter();
    }

    void GetMeshFilter()
    {
        if (meshFilter == null)
        {
            meshFilter = GetComponent<MeshFilter>();
            mesh = new Mesh();            
        }

        mesh.triangles = null;
        mesh.uv = null;
        mesh.vertices = null;

        mesh.name = MeshName;
        mesh.vertices = Vertices;
        mesh.triangles = Triangles;
        mesh.uv = Uvs;

        meshFilter.mesh = mesh;
    }

    private void OnDrawGizmos()
    {
        if (Vertices == null) return;

        Gizmos.color = Color.red;
        Gizmos.DrawSphere(Vector3.zero, 0.5f);

        Gizmos.color = Color.blue;

        for (int i = 0; i < Vertices.Length; i++)
        {
            Gizmos.DrawSphere(Vertices[i], 0.3f);
        }
    }
}

2.2 큐브 코드

코드는 8개의 정점을 정의한 다음 삼각형을 차례로 설정하는 것입니다.

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

public class CreateCube : CreateMeshBase
{
    public float halfLength = 5;

    protected override string MeshName
    {
        get
        {
            return "Cube Mesh";
        }
    }

    protected override Vector3[] Vertices
    {
        get
        {
            Vector3[] vertices = new Vector3[8];
            vertices[0] = new Vector3(-halfLength, -halfLength, -halfLength);
            vertices[1] = new Vector3(halfLength, -halfLength, -halfLength);
            vertices[2] = new Vector3(halfLength, -halfLength, halfLength);
            vertices[3] = new Vector3(-halfLength, -halfLength, halfLength);

            vertices[4] = new Vector3(-halfLength, halfLength, -halfLength);
            vertices[5] = new Vector3(halfLength, halfLength, -halfLength);
            vertices[6] = new Vector3(halfLength, halfLength, halfLength);
            vertices[7] = new Vector3(-halfLength, halfLength, halfLength);

            return vertices;
        }
    }

    protected override int[] Triangles
    {
        get
        {
            int[] triangles = new int[36]
            {
                0,1,3,
                3,1,2,
                4,6,5,
                4,7,6,
                1,6,2,
                1,5,6,
                0,3,4,
                4,3,7,
                0,4,1,
                1,4,5,
                3,2,6,
                3,6,7
            };

            return triangles;
        }
    }
}

3. 퍼펙트 큐브

3.1 큐브 기본 버전의 문제점

큐브의 기본 버전에서는 세 면이 하나의 정점을 공유하므로 이 정점에서 법선과 접선을 정의할 수 없으므로 정점을 분리해야 합니다. 이와 같이 정점 위치에는 3개의 겹치는 점이 있고 각 점은 해당 평면과만 관계가 있습니다.

3.2 완벽한 정육면체 정점

새로운 정육면체 생성 방식은 기본 버전을 기준으로 하지만 고정점 수가 8개에서 36개로 변경되어 기본 버전의 삼각형 배열에 따라 생성된다. 다음과 같이

    protected override Vector3[] Vertices
    {
        get
        {
            Vector3[] vertices = new Vector3[8];
            vertices[0] = new Vector3(-halfLength, -halfLength, -halfLength);
            vertices[1] = new Vector3(halfLength, -halfLength, -halfLength);
            vertices[2] = new Vector3(halfLength, -halfLength, halfLength);
            vertices[3] = new Vector3(-halfLength, -halfLength, halfLength);

            vertices[4] = new Vector3(-halfLength, halfLength, -halfLength);
            vertices[5] = new Vector3(halfLength, halfLength, -halfLength);
            vertices[6] = new Vector3(halfLength, halfLength, halfLength);
            vertices[7] = new Vector3(-halfLength, halfLength, halfLength);

            int[] triangles = new int[36]
            {
                0,3,1,
                3,2,1,
                4,5,6,
                4,6,7,
                1,2,6,
                1,6,5,
                0,4,3,
                4,7,3,
                0,1,4,
                1,5,4,
                3,6,2,
                3,7,6
            };

            cubeVertices = new Vector3[36];

            for (int i = 0; i < cubeVertices.Length; i++)
            {
                cubeVertices[i] = vertices[triangles[i]];
            }

            return cubeVertices;
        }
    }

3.3 삼각형 배열

3.2에서 생성된 새로운 정점 배열에 따르면 삼각형 배열 값은 이때 인덱스가 됩니다.

   protected override int[] Triangles
    {
        get
        {
            /*int[] triangles = new int[36]
            {
                0,1,3,
                3,1,2,
                4,6,5,
                4,7,6,
                1,6,2,
                1,5,6,
                0,3,4,
                4,3,7,
                0,4,1,
                1,4,5,
                3,2,6,
                3,6,7
            };*/

            int[] triangles = new int[36];

            for (int i = 0; i < triangles.Length; i++)
            {
                triangles[i] = i;
            }

            return triangles;
        }
    }

3.4 일반 배열

큐브의 기본 버전은 Unity와 함께 제공되는 것과 비교하여 이상하게 보입니다. 이는 정점 법선이 설정되지 않았기 때문입니다. 기본 버전의 공통 정점으로 인해 법선을 정의할 수 없으므로 새 버전의 법선이 더 쉽습니다. 다음과 같이:

    protected override Vector3[] Normals
    {
        get
        {
            Vector3[] normals = new Vector3[36];

            for (int i = 0; i < normals.Length - 2; i+=3)
            {
                Vector3 normal = Vector3.Cross(cubeVertices[i + 1] - cubeVertices[i], cubeVertices[i + 2] - cubeVertices[i]);

                for (int j = 0; j < 3; j++)
                {
                    normals[i + j] = normal;
                }
            }

            return normals;
        }
    }

3.5 완전한 코드

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

public class CreateNewCube : CreateMeshBase
{
    public float halfLength = 5;

    private Vector3[] cubeVertices = new Vector3[36];

    protected override string MeshName
    {
        get
        {
            return "Cube Mesh";
        }
    }

    protected override Vector3[] Vertices
    {
        get
        {
            Vector3[] vertices = new Vector3[8];
            vertices[0] = new Vector3(-halfLength, -halfLength, -halfLength);
            vertices[1] = new Vector3(halfLength, -halfLength, -halfLength);
            vertices[2] = new Vector3(halfLength, -halfLength, halfLength);
            vertices[3] = new Vector3(-halfLength, -halfLength, halfLength);

            vertices[4] = new Vector3(-halfLength, halfLength, -halfLength);
            vertices[5] = new Vector3(halfLength, halfLength, -halfLength);
            vertices[6] = new Vector3(halfLength, halfLength, halfLength);
            vertices[7] = new Vector3(-halfLength, halfLength, halfLength);

            int[] triangles = new int[36]
            {
                0,3,1,
                3,2,1,
                4,5,6,
                4,6,7,
                1,2,6,
                1,6,5,
                0,4,3,
                4,7,3,
                0,1,4,
                1,5,4,
                3,6,2,
                3,7,6
            };

            cubeVertices = new Vector3[36];

            for (int i = 0; i < cubeVertices.Length; i++)
            {
                cubeVertices[i] = vertices[triangles[i]];
            }

            return cubeVertices;
        }
    }

    protected override int[] Triangles
    {
        get
        {
            /*int[] triangles = new int[36]
            {
                0,1,3,
                3,1,2,
                4,6,5,
                4,7,6,
                1,6,2,
                1,5,6,
                0,3,4,
                4,3,7,
                0,4,1,
                1,4,5,
                3,2,6,
                3,6,7
            };*/

            int[] triangles = new int[36];

            for (int i = 0; i < triangles.Length; i++)
            {
                triangles[i] = i;
            }

            return triangles;
        }
    }

    protected override Vector3[] Normals
    {
        get
        {
            Vector3[] normals = new Vector3[36];

            for (int i = 0; i < normals.Length - 2; i+=3)
            {
                Vector3 normal = Vector3.Cross(cubeVertices[i + 1] - cubeVertices[i], cubeVertices[i + 2] - cubeVertices[i]);

                for (int j = 0; j < 3; j++)
                {
                    normals[i + j] = normal;
                }
            }

            return normals;
        }
    }

    //override 
}

4. 결론

큐브의 완벽한 버전조차도 uv 정의와 탄젠트 정의가 없습니다. 접선은 일반적으로 Vector4 유형이며 값은 해당 접선 또는 (-1, 0, 0, -1)입니다. uv 문제는 더 책임이 있기 때문이고, 각 표면이 동일한지 또는 다른 uv인지에 관한 것이므로 여기서는 확장하지 않겠습니다.

추천

출처blog.csdn.net/ttod/article/details/130300262