ChunkMeshCreator.cs

 avatar
unknown
csharp
a year ago
10 kB
1
Indexable
using System.Collections;
using System.Collections.Generic;
using System.Threading.Tasks;
using UnityEngine;

public class ChunkMeshCreator
{
    public class CreateMesh
    {
        public int[,,] DataToDraw;
        public System.Action<Mesh> OnComplete;
    }

    public class FaceData
    {
        public FaceData(Vector3[] verts, int[] tris, int[] uvindexorder)
        {
            UVIndexOrder = uvindexorder;
            Vertices = verts;
            Indices = tris;
        }

        public Vector3[] Vertices;
        public int[] Indices;
        public int[] UVIndexOrder;
    }

    #region FaceData

    static readonly Vector3Int[] CheckDirections = new Vector3Int[]
    {
        Vector3Int.right,
        Vector3Int.left,
        Vector3Int.up,
        Vector3Int.down,
        Vector3Int.forward,
        Vector3Int.back
    };

    static readonly Vector3[] RightFace = new Vector3[]
    {
        new Vector3(.5f, -.5f, -.5f),
        new Vector3(.5f, -.5f, .5f),
        new Vector3(.5f, .5f, .5f),
        new Vector3(.5f, .5f, -.5f)
    };

    static readonly int[] RightTris = new int[]
    {
        0,2,1,0,3,2
    };

    static readonly Vector3[] LeftFace = new Vector3[]
    {
                //  Left   Center   Right
        new Vector3(-.25f, -.25f, -.25f), // Right bottom
        new Vector3(-.5f, -.5f, .5f),
        new Vector3(-.5f, .5f, .5f), // Left top
        new Vector3(-.5f, .5f, -.5f)
    };

    static readonly int[] LeftTris = new int[]
    {
        0,1,2,0,2,3
    };

    static readonly Vector3[] UpFace = new Vector3[]
    {
        new Vector3(-.5f, .5f, -.5f),
        new Vector3(-.5f, .5f, .5f),
        new Vector3(.5f, .5f, .5f),
        new Vector3(.5f, .5f, -.5f)
    };

    static readonly int[] UpTris = new int[]
    {
        0,1,2,0,2,3
    };

    static readonly Vector3[] DownFace = new Vector3[]
    {
        new Vector3(-.5f, -.5f, -.5f),
        new Vector3(-.5f, -.5f, .5f),
        new Vector3(.5f, -.5f, .5f),
        new Vector3(.5f, -.5f, -.5f)
    };

    static readonly int[] DownTris = new int[]
    {
        0,2,1,0,3,2
    };

    static readonly Vector3[] ForwardFace = new Vector3[]
    {
        new Vector3(-.5f, -.5f, .5f),
        new Vector3(-.5f, .5f, .5f),
        new Vector3(.5f, .5f, .5f),
        new Vector3(.5f, -.5f, .5f)
    };

    static readonly int[] ForwardTris = new int[]
    {
        0,2,1,0,3,2
    };

    static readonly Vector3[] BackFace = new Vector3[]
    {
        new Vector3(-.5f, -.5f, -.5f),
        new Vector3(-.5f, .5f, -.5f),
        new Vector3(.5f, .5f, -.5f),
        new Vector3(.5f, -.5f, -.5f)
    };

    static readonly int[] BackTris = new int[]
    {
        0,1,2,0,2,3
    };

    #endregion

    #region FaceUVData

    static readonly int[] XUVOrder = new int[]
    {
        2, 3, 1, 0
    };

    static readonly int[] YUVOrder = new int[]
    {
        0, 1, 3, 2
    };


    static readonly int[] ZUVOrder = new int[]
    {
        3, 1, 0, 2
    };

    #endregion

    private Dictionary<Vector3Int, FaceData> CubeFaces = new Dictionary<Vector3Int, FaceData>();
    private TextureLoader TextureLoaderInstance;
    private World world;
    private Queue<CreateMesh> MeshesToCreate;
    public bool Terminate;

    public ChunkMeshCreator(TextureLoader textureLoaderInstance, World world)
    {
        CubeFaces = new Dictionary<Vector3Int, FaceData>();
        TextureLoaderInstance = textureLoaderInstance;
        MeshesToCreate = new Queue<CreateMesh>();
        this.world = world;

        for (int i = 0; i < CheckDirections.Length; i++)
        {
            if (CheckDirections[i] == Vector3Int.up)
            {
                CubeFaces.Add(CheckDirections[i], new FaceData(UpFace, UpTris, YUVOrder));
            }
            else if (CheckDirections[i] == Vector3Int.down)
            {
                CubeFaces.Add(CheckDirections[i], new FaceData(DownFace, DownTris, YUVOrder));
            }
            else if (CheckDirections[i] == Vector3Int.forward)
            {
                CubeFaces.Add(CheckDirections[i], new FaceData(ForwardFace, ForwardTris, ZUVOrder));
            }
            else if (CheckDirections[i] == Vector3Int.back)
            {
                CubeFaces.Add(CheckDirections[i], new FaceData(BackFace, BackTris, ZUVOrder));
            }
            else if (CheckDirections[i] == Vector3Int.left)
            {
                CubeFaces.Add(CheckDirections[i], new FaceData(LeftFace, LeftTris, XUVOrder));
            }
            else if (CheckDirections[i] == Vector3Int.right)
            {
                CubeFaces.Add(CheckDirections[i], new FaceData(RightFace, RightTris, XUVOrder));
            }
        }

        world.StartCoroutine(MeshGenLoop());
    }


    public void QueueDataToDraw(CreateMesh createMeshData)
    {
        MeshesToCreate.Enqueue(createMeshData);
    }

    public IEnumerator MeshGenLoop()
    {
        while (Terminate == false)
        {
            if (MeshesToCreate.Count > 0)
            {
                CreateMesh createMesh = MeshesToCreate.Dequeue();
                yield return world.StartCoroutine(CreateMeshFromData(createMesh.DataToDraw, createMesh.OnComplete));
            }

            yield return null;
        }
    }


    public IEnumerator CreateMeshFromData(int[,,] Data, System.Action<Mesh> callback)
    {
        List<Vector3> Vertices = new List<Vector3>();
        List<int> Indices = new List<int>();
        List<Vector2> UVs = new List<Vector2>();
        Mesh m = new Mesh();

        Task t = Task.Factory.StartNew(delegate
        {
            for (int x = 0; x < world.ChunkSize.x; x++)
            {
                for (int y = 0; y < world.ChunkSize.y; y++)
                {
                    for (int z = 0; z < world.ChunkSize.z; z++)
                    {
                        Vector3Int BlockPos = new Vector3Int(x, y, z);
                        for (int i = 0; i < CheckDirections.Length; i++)
                        {
                            Vector3Int BlockToCheck = BlockPos + CheckDirections[i];

                            try
                            {
                                if (Data[BlockToCheck.x, BlockToCheck.y, BlockToCheck.z] == 0)
                                {
                                    if (Data[BlockPos.x, BlockPos.y, BlockPos.z] != 0)
                                    {
                                        int CurrentBlockID = Data[BlockPos.x, BlockPos.y, BlockPos.z];
                                        TextureLoader.CubeTexture TextureToApply = TextureLoaderInstance.Textures[CurrentBlockID];
                                        FaceData FaceToApply = CubeFaces[CheckDirections[i]];

                                        foreach (Vector3 vert in FaceToApply.Vertices)
                                        {
                                            Vertices.Add(new Vector3(x, y, z) + vert);
                                        }

                                        foreach (int tri in FaceToApply.Indices)
                                        {
                                            Indices.Add(Vertices.Count - 4 + tri);
                                        }

                                        Vector2[] UVsToAdd = TextureToApply.GetUVsAtDirectionT(CheckDirections[i]);
                                        foreach (int UVIndex in FaceToApply.UVIndexOrder)
                                        {
                                            UVs.Add(UVsToAdd[UVIndex]);
                                        }
                                    }
                                }
                            }
                            catch (System.Exception)
                            {
                                //Draws faces towards the outside of the data
                                if (Data[BlockPos.x, BlockPos.y, BlockPos.z] != 0)
                                {
                                    int CurrentBlockID = Data[BlockPos.x, BlockPos.y, BlockPos.z];
                                    TextureLoader.CubeTexture TextureToApply = TextureLoaderInstance.Textures[CurrentBlockID];
                                    FaceData FaceToApply = CubeFaces[CheckDirections[i]];

                                    foreach (Vector3 vert in FaceToApply.Vertices)
                                    {
                                        Vertices.Add(new Vector3(x, y, z) + vert);
                                    }

                                    foreach (int tri in FaceToApply.Indices)
                                    {
                                        Indices.Add(Vertices.Count - 4 + tri);
                                    }

                                    Vector2[] UVsToAdd = TextureToApply.GetUVsAtDirectionT(CheckDirections[i]);
                                    foreach (int UVIndex in FaceToApply.UVIndexOrder)
                                    {
                                        UVs.Add(UVsToAdd[UVIndex]);
                                    }
                                }
                            }
                        }
                    }
                }
            }
        });

        yield return new WaitUntil(() =>
        {
            return t.IsCompleted || t.IsCanceled;
        });

        if (t.Exception != null)
            Debug.LogError(t.Exception);

        m.SetVertices(Vertices);
        m.SetIndices(Indices, MeshTopology.Triangles, 0);
        m.SetUVs(0, UVs);

        m.RecalculateBounds();
        m.RecalculateTangents();
        m.RecalculateNormals();

        callback(m);
    }
}
Leave a Comment