Beispiel #1
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));
        }
    }
Beispiel #2
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();
        }
    }