Ejemplo n.º 1
0
 /// <summary>
 /// Initialize function. Called from VoxelTerrain when a new VTPart gameobject is instantiated
 /// </summary>
 /// <param name="v">VoxelTerrain parent</param>
 /// <param name="i"> Index of this part in x direction </param>
 /// <param name="j"> Index of this part in y direction </param>
 /// <param name="k"> Index of this part in z direction </param>
 public void Init(VoxelTerrain v, int i, int j, int k)
 {
     this.v = v;
     px     = i; py = j; pz = k;
     // Init chunks array
     _chunks = new VTChunk[nchunk * nchunk * nchunk];
 }
Ejemplo n.º 2
0
    private void PaintAtPoint(VoxelTerrain terrain, int x, int y, int z)
    {
        if (paintOnlyBlank)
        {
            var voxel = terrain.GetVoxel(x, y, z);
            if (voxel.MeshShape != Voxel.MeshShapeType.None)
            {
                return;
            }
        }

        if (!paintBlockType && paintShape)
        {
            var currentVoxel = terrain.GetVoxel(x, y, z);
            if (currentVoxel.MeshShape != Voxel.MeshShapeType.None)
            {
                terrain.SetVoxel(x, y, z, currentVoxel.ChangeShape(selectedMeshShape, selectedRotation, selectedUpsideDown));
            }
        }
        else if (paintBlockType && !paintShape)
        {
            var currentVoxel = terrain.GetVoxel(x, y, z);
            if (currentVoxel.MeshShape != Voxel.MeshShapeType.None)
            {
                terrain.SetVoxel(x, y, z, currentVoxel.ChangeBlockType(selectedBlockType));
            }
        }
        else
        {
            terrain.SetVoxel(x, y, z, new Voxel(selectedMeshShape, selectedRotation, selectedUpsideDown, selectedBlockType));
        }
    }
Ejemplo n.º 3
0
 public override void OnInspectorGUI()
 {
     v = target as VoxelTerrain;
     DrawDefaultInspector();
     v.blockSize = Mathf.NextPowerOfTwo((int)v.blockSize);
     v.size      = Mathf.RoundToInt(v.size / v.npart / v.blockSize) * v.blockSize * v.npart;
     EditorGUILayout.BeginHorizontal();
     if (GUILayout.Button("Init"))
     {
         v.Init();
         List <Material> mat = new List <Material>();
         foreach (string f in System.IO.Directory.GetFiles(Application.dataPath + "/Materials/VT", "*.mat"))
         {
             mat.Add(AssetDatabase.LoadAssetAtPath(f.Substring(f.IndexOf("Assets")), typeof(Material)) as Material);
         }
         v.mat = mat[Random.Range(0, mat.Count)];
     }
     EditorGUILayout.EndHorizontal();
     if (GUILayout.Button("Make Part"))
     {
         Undo.RegisterSceneUndo("Make VT");
         long t0 = System.DateTime.Now.Ticks / System.TimeSpan.TicksPerMillisecond;
         MakePart(v.edx, v.edy, v.edz);
         last = (System.DateTime.Now.Ticks / System.TimeSpan.TicksPerMillisecond - t0) / 1000;
     }
     EditorGUILayout.LabelField("Time taken in last Make operation:" + last);
     EditorStyles.label.wordWrap = true;
     EditorGUILayout.LabelField("Use the arrow keys, keypad 8 and keypad 2 to select a part of the Voxel Terrain. Once selected, it will" +
                                "be highlighted. Then click on 'Make Part' to generate terrain in that region.");
 }
Ejemplo n.º 4
0
        /// <summary>
        /// Load a chunk into the terrain object.
        /// </summary>
        /// <param name="terrain">The terrain.</param>
        /// <param name="chunkIndex">The chunk index.</param>
        /// <returns>The chunk.</returns>
        public Chunk LoadChunk(VoxelTerrain terrain, Position chunkIndex)
        {
            // Deserialize or generate the chunk
            Chunk chunk;
            if (!this.serializer.TryDeserialiseChunk(chunkIndex, out chunk))
            {
                // Get the surface heights of the chunk
                float[] surfaceHeights;
                if (!terrain.SurfaceHeights.TryGetValue(chunkIndex.X, out surfaceHeights))
                {
                    surfaceHeights = this.voxelGenerator.GenerateSurfaceHeights(chunkIndex.X);
                    terrain.SurfaceHeights.Add(chunkIndex.X, surfaceHeights);
                }

                // The chunk doesn't yet exist, so generate a new one
                chunk = new Chunk();
                this.voxelGenerator.Generate(chunk.Voxels, surfaceHeights, chunkIndex);

                // Serialize the generated chunk
                this.serializer.SerialiseChunk(chunk, chunkIndex);
            }

            // Add the chunk to the terrain object
            terrain.Chunks.Add(chunkIndex, chunk);

            return chunk;
        }
        private void InitForTerrain(VoxelTerrain terrain)
        {
            if (terrain == null)
            {
                m_initTerrain = null; return;
            }
            if (terrain.readable == null)
            {
                return;
            }
            if (terrain.writeable == null)
            {
                return;
            }

            m_initTerrain = terrain;

            if (terrain == null)
            {
                return;
            }

            m_rectBrush        = new RectBrush(terrain.voxelSize, terrain.readable.min, terrain.readable.max, terrain.readable.Sample, terrain.SetValue);
            m_rectBrush.width  = 1.0f;
            m_rectBrush.height = 1.0f;

            m_circleBrush        = new CircleBrush(terrain.voxelSize, terrain.readable.min, terrain.readable.max, terrain.readable.Sample, terrain.SetValue);
            m_circleBrush.radius = 0.5f;
        }
Ejemplo n.º 6
0
 private void OnValidate()
 {
     if (terrain == null)
     {
         terrain = GetComponent <VoxelTerrain>();
     }
     terrain.UpdateMesh();
 }
Ejemplo n.º 7
0
    void OnSceneGUI()
    {
        v = target as VoxelTerrain;
        if (!v.initialized)
        {
            return;
        }
        VTPart part = v.getPart(v.edx, v.edy, v.edz);
        Event  e    = Event.current;

        if (e.type == EventType.keyDown)
        {
            if (e.control)
            {
                if (e.keyCode == KeyCode.RightArrow)
                {
                    v.edx++;
                }
                if (e.keyCode == KeyCode.LeftArrow)
                {
                    v.edx--;
                }
                if (e.keyCode == KeyCode.UpArrow)
                {
                    v.edz++;
                }
                if (e.keyCode == KeyCode.DownArrow)
                {
                    v.edz--;
                }
                if (e.keyCode == KeyCode.Keypad8)
                {
                    v.edy++;
                }
                if (e.keyCode == KeyCode.Keypad2)
                {
                    v.edy--;
                }
                v.edx = Mathf.Clamp(v.edx, 0, v.npart - 1);
                v.edy = Mathf.Clamp(v.edy, 0, v.npart - 1);
                v.edz = Mathf.Clamp(v.edz, 0, v.npart - 1);

                Vector3 cp = Camera.current.transform.position;
                v.LoadMeshes(cp);
            }
        }
        Vector3 p = new Vector3(v.edx + 0.5f, v.edy + 0.5f, v.edz + 0.5f) * v.partSize;

        partCube.transform.position   = p;
        partCube.transform.localScale = v.partSize * Vector3.one;

        /*
         * int l=v.getPart (v.edx,v.edy,v.edz).getLOD (Camera.current.transform.position);
         * Handles.BeginGUI ();
         * GUI.Label(new Rect(10,10,100,100),"LOD: "+l);
         * Handles.EndGUI ();
         */
    }
Ejemplo n.º 8
0
    void Start()
    {
        _previousLocation = null;
        _parentTerrain    = GetComponent <VoxelTerrain>();

        if (_parentTerrain == null)
        {
            throw new System.Exception("VoxelTerrain component not found!");
        }
    }
Ejemplo n.º 9
0
    void CreatePlanes(VoxelTerrain terrain)
    {
        if (createPlane)
        {
            var normal = planeNormals[alignment];
            plane = new Plane(normal, tileCursorPosition);

            createPlane = false;
        }
    }
Ejemplo n.º 10
0
    void Start()
    {
        player = GameObject.FindGameObjectWithTag("Player").transform;

        v = GameObject.FindObjectOfType(typeof(VoxelTerrain)) as VoxelTerrain;

        Vector3 cp = Camera.main.transform.position;

        v.LoadMeshes(cp);
    }
Ejemplo n.º 11
0
 public static void Save(VoxelTerrain terrain, string path)
 {
     using (var output = new System.IO.StreamWriter(LevelPath(path), false, System.Text.Encoding.UTF8))
     {
         output.WriteLine("# Level terrain data for {0}", path);
         output.WriteLine("# X, Y, Z, MeshShape, Rotation, IsUpsideDown, BlockType");
         foreach (var chunk in terrain.Chunks.Values)
         {
             SaveChunk(chunk, output);
         }
     }
 }
Ejemplo n.º 12
0
 void OnEnable()
 {
     v = target as VoxelTerrain;
     if (v.transform.FindChild("partCube") == null)
     {
         partCube      = GameObject.CreatePrimitive(PrimitiveType.Cube); partCube.transform.parent = v.transform;
         partCube.name = "partCube";
         partCube.renderer.sharedMaterial = AssetDatabase.LoadAssetAtPath("Assets/Materials/Highlight.mat", typeof(Material)) as Material;
     }
     partCube = v.transform.FindChild("partCube").gameObject;
     partCube.SetActive(true);
 }
Ejemplo n.º 13
0
    public VoxelTerrain GetParentTerrain()
    {
        if (_parentTerrain != null)
        {
            return(_parentTerrain);
        }

        if (transform.parent != null)
        {
            _parentTerrain = transform.parent.GetComponent <VoxelTerrain>();
        }

        return(_parentTerrain);
    }
Ejemplo n.º 14
0
    public static void Load(VoxelTerrain terrain)
    {
        foreach (var file in Directory.GetFiles(LevelPath(terrain.LevelName), "*.chunk"))
        {
            Debug.Log("Related files: " + file);
            Vector3 chunkPosition;
            if (!ChunkSerializer.GetChunkPosition(file, out chunkPosition))
            {
                return;
            }

            var chunk = terrain.GetChunk((int)chunkPosition.x, (int)chunkPosition.y, (int)chunkPosition.z);
            ChunkSerializer.Deserialize(chunk, file);
        }
    }
Ejemplo n.º 15
0
    public static void Save(VoxelTerrain terrain, bool onlyDirty)
    {
        var baseFolder = LevelPath(terrain.LevelName);

        Directory.CreateDirectory(baseFolder);
        foreach (var chunk in terrain.Chunks.Values)
        {
            if (onlyDirty && !chunk.IsDataDirty)
            {
                continue;
            }

            var pos      = chunk.ChunkPosition;
            var filename = Path.Combine(baseFolder, string.Format("{0}.{1}.{2}.chunk", pos.x, pos.y, pos.z));
            Debug.Log("Saving chunk: " + filename);
            ChunkSerializer.Serialize(chunk, filename);
            chunk.IsDataDirty = false;
        }
    }
Ejemplo n.º 16
0
    public static void Load(VoxelTerrain terrain, string path)
    {
        foreach (var line in System.IO.File.ReadAllLines(LevelPath(path)))
        {
            if (line.Length == 0 || line[0] == '#')
            {
                continue;
            }

            var split = line.Split(',');
            var x     = int.Parse(split[0]);
            var y     = int.Parse(split[1]);
            var z     = int.Parse(split[2]);

            var meshShape    = ParseMeshShape(split[3]);
            var rotation     = ParseRotation(split[4]);
            var isUpsideDown = split[5] == "true";
            var blockType    = ushort.Parse(split[6]);

            terrain.SetVoxel(x, y, z, new Voxel(meshShape, rotation, isUpsideDown, blockType));
        }
    }
Ejemplo n.º 17
0
    /// <summary>
    /// Creates voxel terrain object
    /// </summary>
    public static VoxelTerrain New(int Y)
    {
        GameObject obj = new GameObject("Layer " + Y);

        obj.isStatic           = true;
        obj.transform.position = new Vector3(0, VoxelChunk.ChunkHeight * Y, 0) * WorldManager.VoxelToUnitScale;


        VoxelTerrain terrain = obj.AddComponent <VoxelTerrain>();

        terrain.Y = Y;
        terrain.mTerrainGenerator = new TerrainGen_Overworld(123);


        // Create chunk pool
        for (int i = 0; i < 30; ++i)
        {
            terrain.mChunkPool.Enqueue(VoxelChunk.NewPoolObj(terrain));
        }


        return(terrain);
    }
Ejemplo n.º 18
0
    void Start()
    {
        if (Main == null)
        {
            Main = this;
            Debug.Log("World Manager created.");


            // Make sure library is initialized
            ResourceLoader.AttemptImport();
            mWorker = GetComponent <WorldWorker>();

            mCurrentTerrain = VoxelTerrain.New(-1);

            Entity_Player player = Resources.Load <Entity_Player>("Entities/Human/Player/Player Prefab");
            Instantiate(player.gameObject);
        }
        else
        {
            Debug.LogError("Cannot have multiple world managers active at once.");
            Destroy(gameObject);
        }
    }
Ejemplo n.º 19
0
        public override void OnInspectorGUI()
        {
            DrawDefaultInspector();

            m_Terrain = (VoxelTerrain)target;

            EditorGUILayout.BeginHorizontal();

            if (GUILayout.Button("Generate"))
            {
                m_Terrain.Generate();

                m_Terrain.Reset();
            }

            if (GUILayout.Button("Delete"))
            {
                m_Terrain.Eliminate();
                m_Terrain.Reset();
            }

            EditorGUILayout.EndHorizontal();
        }
        public FirstPersonCameraSimulator()
        {
            info    = TW.Data.GetSingleton <CameraInfo>();
            cam     = new SpectaterCamera();
            terrain = TW.Data.GetSingleton <VoxelTerrain>();
            camData = TW.Data.GetSingleton <FirstPersonCamera>();

            cam.CameraPosition  = camData.Position;
            camData.LookDir    -= Vector3.UnitX * camData.LookDir.X * 2;
            cam.CameraDirection = camData.LookDir;
            cam.UpdateCameraInfo();

            cam.AngleHorizontal = cam.AngleHorizontal;


            points = new List <Vector3>();
            points.Add(Vector3.UnitX * 0.5f);
            points.Add(Vector3.UnitY * 0.5f);
            points.Add(Vector3.UnitZ * 0.5f);
            points.Add(-Vector3.UnitX * 0.5f);
            points.Add(-Vector3.UnitY * 0.5f);
            points.Add(-Vector3.UnitY * 1.5f);
            points.Add(-Vector3.UnitZ * 0.5f);
        }
Ejemplo n.º 21
0
 public TerrainAStar()
 {
     terrain = TW.Data.GetSingleton <VoxelTerrain>();
 }
Ejemplo n.º 22
0
 void Awake()
 {
     m_terrain = GetComponent <VoxelTerrain>();
 }
Ejemplo n.º 23
0
        public static void ReduceMesh(Chunk chunk, MeshData meshData)
        {
            if (chunk.IsEmpty())
            {
                return;
            }

            List <Vector3> vertices  = new List <Vector3>();
            List <int>     triangles = new List <int>();

            int size = Chunk.CHUNK_SIZE;

            // Sweep over 3-axes
            for (int d = 0; d < 3; d++)
            {
                int i, j, k, l, w, h, u = (d + 1) % 3, v = (d + 2) % 3;

                int[] x    = new int[3];
                int[] q    = new int[3];
                int[] mask = new int[(size + 1) * (size + 1)];

                q[d] = 1;

                for (x[d] = -1; x[d] < size;)
                {
                    // Compute the mask
                    int n = 0;
                    for (x[v] = 0; x[v] < size; ++x[v])
                    {
                        for (x[u] = 0; x[u] < size; ++x[u], ++n)
                        {
                            int a = 0; if (0 <= x[d])
                            {
                                a = (int)VoxelTerrain.GetBlock(chunk, x[0], x[1], x[2]).type;
                            }
                            int b = 0; if (x[d] < size - 1)
                            {
                                b = (int)VoxelTerrain.GetBlock(chunk, x[0] + q[0], x[1] + q[1], x[2] + q[2]).type;
                            }

                            if (a != -1 && b != -1 && a == b)
                            {
                                mask[n] = 0;
                            }
                            else if (a > 0)
                            {
                                a       = 1;
                                mask[n] = a;
                            }
                            else
                            {
                                b       = 1;
                                mask[n] = -b;
                            }
                        }
                    }

                    // Increment x[d]
                    ++x[d];

                    // Generate mesh for mask using lexicographic ordering
                    n = 0;
                    for (j = 0; j < size; ++j)
                    {
                        for (i = 0; i < size;)
                        {
                            var c = mask[n]; if (c > -3)
                            {
                                // Compute width
                                for (w = 1; c == mask[n + w] && i + w < size; ++w)
                                {
                                }

                                // Compute height
                                bool done = false;
                                for (h = 1; j + h < size; ++h)
                                {
                                    for (k = 0; k < w; ++k)
                                    {
                                        if (c != mask[n + k + h * size])
                                        {
                                            done = true; break;
                                        }
                                    }
                                    if (done)
                                    {
                                        break;
                                    }
                                }
                                // Add quad
                                bool flip = false;
                                x[u] = i; x[v] = j;
                                int[] du = new int[3];
                                int[] dv = new int[3];
                                if (c > -1)
                                {
                                    du[u] = w;
                                    dv[v] = h;
                                }
                                else
                                {
                                    flip  = true;
                                    c     = -c;
                                    du[u] = w;
                                    dv[v] = h;
                                }

                                Vector3 v1 = new Vector3(x[0], x[1], x[2]);
                                Vector3 v2 = new Vector3(x[0] + du[0], x[1] + du[1], x[2] + du[2]);
                                Vector3 v3 = new Vector3(x[0] + du[0] + dv[0], x[1] + du[1] + dv[1], x[2] + du[2] + dv[2]);
                                Vector3 v4 = new Vector3(x[0] + dv[0], x[1] + dv[1], x[2] + dv[2]);

                                if (c > 0 && !flip)
                                {
                                    AddFace(v1, v2, v3, v4, vertices, triangles, 0);
                                }

                                if (flip)
                                {
                                    AddFace(v4, v3, v2, v1, vertices, triangles, 0);
                                }

                                // Zero-out mask
                                for (l = 0; l < h; ++l)
                                {
                                    for (k = 0; k < w; ++k)
                                    {
                                        mask[n + k + l * size] = 0;
                                    }
                                }

                                // Increment counters and continue
                                i += w; n += w;
                            }

                            else
                            {
                                ++i;
                                ++n;
                            }
                        }
                    }
                }
            }

            meshData.ColliderVertices  = vertices;
            meshData.ColliderTriangles = triangles;
        }
Ejemplo n.º 24
0
    /// <summary>
    /// Create a new object to be using in object pool for a terrain
    /// </summary>
    public static VoxelChunk NewPoolObj(VoxelTerrain Terrain)
    {
        // Create inactive game object
        GameObject obj = new GameObject();

        obj.isStatic         = true;
        obj.transform.parent = Terrain.transform;
        obj.layer            = LayerMask.NameToLayer("Terrain");


        // Add (Initialize) component
        VoxelChunk chunk = obj.AddComponent <VoxelChunk>();

        chunk.mTerrain = Terrain;


        // Init data
        chunk.mVoxelData = new VoxelInstance[ChunkWidth, ChunkHeight, ChunkWidth];
        // Fill with air
        ushort air = VoxelLibrary.GetID("air");

        for (int x = 0; x < ChunkWidth; ++x)
        {
            for (int y = 0; y < ChunkHeight; ++y)
            {
                for (int z = 0; z < ChunkWidth; ++z)
                {
                    chunk.mVoxelData[x, y, z] = new VoxelInstance(air);
                }
            }
        }


        // Setup rendering
        {
            GameObject subObj = new GameObject("Terrain");
            subObj.isStatic         = true;
            subObj.transform.parent = obj.transform;

            chunk.mMeshTerrainFilter = subObj.AddComponent <MeshFilter>();
            MeshRenderer renderer = subObj.AddComponent <MeshRenderer>();
            renderer.sharedMaterial    = VoxelLibrary.mTerrainMaterial;
            renderer.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off;
            {
                Mesh mesh = new Mesh();
                mesh.name = "Terrain Mesh";
                mesh.MarkDynamic();
                chunk.mMeshTerrainFilter.sharedMesh = mesh;
            }
        }
        {
            GameObject subObj = new GameObject("Liquid");
            subObj.isStatic         = true;
            subObj.transform.parent = obj.transform;

            chunk.mMeshLiquidFilter = subObj.AddComponent <MeshFilter>();
            MeshRenderer renderer = subObj.AddComponent <MeshRenderer>();
            renderer.sharedMaterial    = VoxelLibrary.mLiquidMaterial;
            renderer.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off;
            {
                Mesh mesh = new Mesh();
                mesh.name = "Liquid Mesh";
                mesh.MarkDynamic();
                chunk.mMeshLiquidFilter.sharedMesh = mesh;
            }
        }


        // Setup collision
        chunk.mMeshCollider = obj.AddComponent <MeshCollider>();
        chunk.mMeshCollider.sharedMaterial = Resources.Load <PhysicMaterial>("World/Phys_Terrain");
        {
            Mesh mesh = new Mesh();
            mesh.name = "Physics Mesh";
            mesh.MarkDynamic();
            chunk.mMeshCollider.sharedMesh = mesh;
        }


        // Flag as inactive
        obj.name = "Chunk (Inactive)";
        obj.transform.position = Vector3.zero;
        obj.SetActive(false);

        return(chunk);
    }
Ejemplo n.º 25
0
 private void SaveAllDataDirty(VoxelTerrain terrain)
 {
     VoxelLoader.Save(terrain, true);
 }
Ejemplo n.º 26
0
 void OnEnable()
 {
     _target = (VoxelTerrain)target;
 }
 /// <summary>
 /// Initialises a new instance of the MarchingCubesGenerator class.
 /// </summary>
 /// <param name="terrain">The terrain.</param>
 /// <param name="isoLevel">The isolevel, which is the density at which the mesh surface lies.</param>
 public MarchingCubesGenerator(VoxelTerrain terrain, byte isoLevel)
     : base(terrain)
 {
     this.IsoLevel = isoLevel;
 }
Ejemplo n.º 28
0
        /// <summary>
        /// Unload a chunk from the terrain object.
        /// </summary>
        /// <param name="terrain">The terrain.</param>
        /// <param name="chunkIndex">The chunk index.</param>
        /// <returns>The chunk that was unloaded; Null if the chunk was never loaded.</returns>
        public Chunk UnloadChunk(VoxelTerrain terrain, Position chunkIndex)
        {
            // Get the chunk
            Chunk chunk;
            if (!terrain.Chunks.TryGetValue(chunkIndex, out chunk))
            {
                // The chunk isn't loaded so do nothing
                return null;
            }

            // Serialize the chunk
            this.serializer.SerialiseChunk(chunk, chunkIndex);

            // Remove the chunk from the Terrain object
            terrain.Chunks.Remove(chunkIndex);

            return chunk;
        }
Ejemplo n.º 29
0
    public IEnumerator GenerateMesh(VoxelTerrain voxelTerrain)
    {
        MeshFilter        meshFilter      = GetComponent <MeshFilter>();
        PolygonCollider2D polygonCollider = GetComponent <PolygonCollider2D>();

        // Mesh info
        List <Vector3> points  = new List <Vector3>();
        List <int>     indices = new List <int>();

        Vector3 offsetPoint = Vector3.zero;
        int     indexOffset = 0;

        // Track which voxel configurations have edges
        //Dictionary<Vector2Int, int> edgePoints = new Dictionary<Vector2Int, int>();
        // Remember the configuration(lookup) for each voxel square
        int[,] lookupGrid        = new int[Size, Size];
        float[,] expandedTerrain = new float[Size, Size];
        int[,] chunkEdgeLookup   = new int[Size, Size];

        for (int y = 0; y < Size; y++)
        {
            for (int x = 0; x < Size; x++)
            {
                int lookup = 0;

                if (x < Size - 1 && y < Size - 1)
                {
                    for (int offset = 0; offset < 4; offset++)
                    {
                        var o = offsets[offset];
                        var v = Terrain[x + o.x, y + o.y];
                        expandedTerrain[x, y] = v;
                        lookup += v > 0f ? (1 << offset) : 0;
                    }
                }
                else
                {
                    for (int offset = 0; offset < 4; offset++)
                    {
                        var o = offsets[offset];
                        var v = voxelTerrain.GetVoxel(
                            ChunkCoord.x * Size + x + o.x,
                            ChunkCoord.y * Size + y + o.y
                            );
                        expandedTerrain[x, y] = v;
                        lookup += v > 0f ? (1 << offset) : 0;
                    }
                }

                lookupGrid[x, y] = lookup;
                int chunkEdge = ChunkEdgeIndex(x, y);
                chunkEdgeLookup[x, y] = chunkEdge;

                if (lookup > 0 && lookup < 15 || chunkEdge != 0)
                {
                    edgePoints.Add(new Vector2Int(x, y), chunkEdge == 0 && (lookup == 5 || lookup == 10) ? 2 : 1);
                }
            }
        }


        for (int y = 0; y < Size; y++)
        {
            for (int x = 0; x < Size; x++)
            {
                offsetPoint.x = x;
                offsetPoint.y = y;

                int lookup    = lookupGrid[x, y];
                int chunkEdge = chunkEdgeLookup[x, y];

                // Add points
                int tempIndexOffset = 0;
                for (int i = 0; i < 6; i++)
                {
                    int p = pointLookup[lookup, i];
                    if (p < 0)
                    {
                        break;
                    }
                    points.Add(basePoints[p] + offsetPoint);
                    tempIndexOffset++;
                }

                // Add indices
                for (int i = 0; i < 12; i++)
                {
                    int index = indexLookup[lookup, i];
                    if (index < 0)
                    {
                        break;
                    }
                    indices.Add(index + indexOffset);
                }
                indexOffset += tempIndexOffset;
            }
        }

        var mesh = meshFilter.mesh;

        mesh.Clear();
        mesh.vertices  = points.ToArray();
        mesh.triangles = indices.ToArray();
        mesh.RecalculateNormals();
        mesh.RecalculateBounds();

        // Calculate polygon collider
        polygonCollider.pathCount = 0;

        while (edgePoints.Any())
        {
            // List<Vector2> pathPoints = new List<Vector2>();

            // Starting at the first point in the queue
            var point         = edgePoints.Keys.First();
            var startingPoint = point;

            int lookup         = lookupGrid[point.x, point.y];
            int nextConnection = -1;

            edgePoints[point] = edgePoints[point] - 1;
            if (edgePoints[point] <= 0)
            {
                edgePoints.Remove(point);
            }

            // Find the first valid edge for the point
            for (int i = 0; i < 4; i++)
            {
                int chunkEdge  = ChunkEdgeIndex(point.x, point.y);
                int connection = edgeConnections[chunkEdge, lookup, i];
                // Valid connection that leads to another edge
                if (connection >= 0 && edgePoints.ContainsKey(point + edgeOffset[connection]))
                {
                    pathPoints.Add(basePoints[i + 4] + (Vector3Int)point);
                    var extraPoints = extraEdgePoint[chunkEdge][lookup];
                    for (int e = 0; e < extraPoints.Length; e++)
                    {
                        pathPoints.Add(basePoints[extraPoints[e]] + (Vector3Int)point);
                    }
                    nextConnection = connection;
                    break;
                }
            }

            // If no valid connection, ignore this point
            if (nextConnection == -1)
            {
                continue;
            }

            point += edgeOffset[nextConnection];

            // Keep following the edges that are connected to our starting point
            // until we reach our starting again
            while (point != startingPoint)
            {
                int chunkEdge = ChunkEdgeIndex(point.x, point.y);
                edgePoints[point] = edgePoints[point] - 1;
                if (edgePoints[point] <= 0)
                {
                    edgePoints.Remove(point);
                }

                // The 'up' edge from the voxel below us is our 'down' edge. Same with left/right, etc.
                // This is a nice trick to do this conversion
                int incomingEdge = 3 - nextConnection;

                // Add 4 to get the cardinal points instead of diagonals
                pathPoints.Add(basePoints[incomingEdge + 4] + (Vector3Int)point);
                var extraPoints = extraEdgePoint[chunkEdge][lookup];
                for (int e = 0; e < extraPoints.Length; e++)
                {
                    pathPoints.Add(basePoints[extraPoints[e]] + (Vector3Int)point);
                }

                yield return(new WaitForSeconds(0.1f));

                lookup         = lookupGrid[point.x, point.y];
                nextConnection = edgeConnections[chunkEdge, lookup, incomingEdge];
                var nextPoint = point + edgeOffset[nextConnection];

                point = nextPoint;
            }

            polygonCollider.SetPath(polygonCollider.pathCount++, pathPoints);
            pathPoints.Clear();
        }
    }