static void TestSlices() { Console.WriteLine("Hello World!"); VoxelSet <Vec4b> colors = new VoxelSet <Vec4b>(32); colors.Set(new Vec4b(0)); colors.Slice(new Vec3i(1), new Vec3i(30)).Set(new Vec4b(255)); colors.Slice(new Vec3i(3), new Vec3i(28)).Set(new Vec4b(0)); colors.Slice(new Vec3i(5), new Vec3i(26)).Set(new Vec4b(255)); for (int i = 0; i < 32; ++i) { if (colors[16, i, 16].x == 0) { Console.Write("."); } else { Console.Write("#"); } } Console.Write("\nPress any key to continue ... "); Console.ReadKey(); }
public static List <Box> MakeBoxes(VoxelSet <bool> shape) { List <Box> boxes = new List <Box>(); // Directions to explore Vec3i[] dirs = new[] { new Vec3i(1, 0, 0), new Vec3i(0, 1, 0), new Vec3i(0, 0, 1) }; // TODO: Iteration order may need to be reversed for (int z = 0; z < shape.Size.z; z++) { for (int y = 0; y < shape.Size.y; y++) { for (int x = 0; x < shape.Size.x; x++) { if (!shape[x, y, z]) { continue; } Vec3i idx = new Vec3i(x, y, z); Vec3i endIdx = new Vec3i(x, y, z); // Expand box in each cardinal direction as much as possible foreach (var dir in dirs) { Vec3i checkFromIdx = idx; // Expand as much as possible in the current direction while (shape.IsValid(endIdx + dir)) { checkFromIdx += dir; // Create a slice for the next layer in the current dir and make sure it's solid var slice = shape.Slice(checkFromIdx, endIdx + dir); if (!slice.IsAllSolid(b => b)) { break; } slice.Set(false); endIdx += dir; } } Box box = new Box(); box.origin = new Vec3i(x, y, z); box.extents = new Vec3i(endIdx.x + 1 - idx.x, endIdx.y + 1 - idx.y, endIdx.z + 1 - idx.z); boxes.Add(box); } } } return(boxes); }
public void GetMesh(VoxelSet <Vec4b> voxels, out int[] indices, out Vec3f[] points, out Vec3f[] normals, out Vec2f[] uvs, out VoxelSet <Vec4b> textureAtlas) { List <int> indicesList = new List <int>(); List <Vec3f> pointsList = new List <Vec3f>(); List <Vec3f> normalsList = new List <Vec3f>(); List <Vec2f> uvsList = new List <Vec2f>(); Dictionary <int, int> vertIdxRemap = new Dictionary <int, int>(); List <Bin> bins = new List <Bin>(); foreach (var poly in AllPolygons()) { // For each connected polygon vertIdxRemap.Clear(); Vec3f normal = Normal(poly.First()); Vec3f maxP = new Vec3f(-1); Vec3f minP = new Vec3f(1024 * 1024); AtlasEntry atlasEntry = new AtlasEntry(); atlasEntry.startVertIdx = pointsList.Count; atlasEntry.normal = new Vec3i( (int)Math.Round(normal.x), (int)Math.Round(normal.y), (int)Math.Round(normal.z) ); foreach (var baseEdge in poly) { // Each triangle that makes up the polygon foreach (var e in new int[] { baseEdge, Next(baseEdge), Prev(baseEdge) }) { // Each vertex of each triangle int vertIdx = Edges[e].vertexIdx; if (!vertIdxRemap.ContainsKey(vertIdx)) { vertIdxRemap.Add(vertIdx, pointsList.Count); pointsList.Add(Points[vertIdx]); normalsList.Add(normal); maxP = Max3f(maxP, Points[vertIdx]); minP = Min3f(minP, Points[vertIdx]); // TODO: Add UV here } indicesList.Add(vertIdxRemap[vertIdx]); } } atlasEntry.vertCount = pointsList.Count - atlasEntry.startVertIdx; // TODO: Add to texture atlas here Vec3f deltaP = maxP - minP; // Determine which dimension is flat int flatIdx = -1; for (int i = 0; i < 3; ++i) { if (deltaP[i] == 0) { if (flatIdx >= 0) { throw new Exception("Two or more flat dimensions found"); } flatIdx = i; } } Vec2i size; if (flatIdx == 0) { size = new Vec2i((int)Math.Round(deltaP.y), (int)Math.Round(deltaP.z)); } else if (flatIdx == 1) { size = new Vec2i((int)Math.Round(deltaP.x), (int)Math.Round(deltaP.z)); } else { size = new Vec2i((int)Math.Round(deltaP.x), (int)Math.Round(deltaP.y)); } atlasEntry.flatDimension = flatIdx; atlasEntry.max = new Vec3i(maxP + new Vec3f(0.5f)); atlasEntry.min = new Vec3i(minP + new Vec3f(0.5f)); Bin b = new Bin(); b.Size = size; b.UserData = atlasEntry; bins.Add(b); } indices = indicesList.ToArray(); points = pointsList.ToArray(); normals = normalsList.ToArray(); //BinPacker bp = new BinPacker(512); BinPacker bp = new BinPacker(512); bp.BinPadding = new Vec2i(2); bp.Pack(bins); bp.MakePow2(); textureAtlas = new VoxelSet <Vec4b>(bp.Width, bp.Height, 1); for (int y = 0; y < textureAtlas.Size.y; ++y) { for (int x = 0; x < textureAtlas.Size.x; ++x) { textureAtlas[x, y, 0] = new Vec4b(0, 255, 0, 255); } } uvs = new Vec2f[points.Length]; foreach (var bin in bp.Bins) { var atlasEntry = (AtlasEntry)bin.UserData; // Copy to atlas var toSlice = textureAtlas.Slice(new Vec3i(bin.Position, 0), new Vec3i(bin.Position + bin.Size - 1, 0)); Vec3i voxelOffset = new Vec3i(0); if (atlasEntry.normal.Dot(new Vec3i(1)) > 0) { voxelOffset = atlasEntry.normal * -1; } else { //voxelOffset = atlasEntry.normal * -1; voxelOffset = new Vec3i(0); } var fromSlice = voxels.Slice( atlasEntry.min + voxelOffset, atlasEntry.max - atlasEntry.min + atlasEntry.Basis() * new Vec3i(0, 0, 1), atlasEntry.Basis() ); if (toSlice.Size.x != fromSlice.Size.x || toSlice.Size.y != fromSlice.Size.y || toSlice.Size.z != fromSlice.Size.z) { throw new Exception(); } /*for (int y = 0; y < toSlice.Size.y; ++y) { * for (int x = 0; x < toSlice.Size.x; ++x) { * toSlice[x, y, 0] = fromSlice[x, y, 0]; * } * }*/ for (int y = 0; y < toSlice.Size.y; ++y) { for (int x = 0; x < toSlice.Size.x; ++x) { if (Vec4b.Dot(toSlice[x, y, 0], new Vec4b(1)) != 0) { ////throw new Exception(); } toSlice[x, y, 0] = voxels[atlasEntry.To3d(new Vec2i(x, y)) + voxelOffset]; //toSlice[x, y, 0] = c; } } // Compute UVs for (int i = atlasEntry.startVertIdx; i < atlasEntry.startVertIdx + atlasEntry.vertCount; ++i) { Vec2f uv = new Vec2f(atlasEntry.To2d(new Vec3i(points[i]))); //uv *= new Vec2f(bin.Size - 1) / new Vec2f(bin.Size); //uv += 0.5f; uv *= (new Vec2f(bin.Size) - 0.01f) / new Vec2f(bin.Size); uv += 0.005f; ///////// //uv *= 0.998f; //uv += 0.01f; uv += new Vec2f(bin.Position); /////// //uv += 0.25f; uv.x /= bp.Width; uv.y /= bp.Height; uvs[i] = uv; } } Console.WriteLine("Total size: {0} x {1}", bp.Width, bp.Height); }