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)); } }
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(); } }