public void GenerateTextureAndUV(VoxelModel model, MeshSlices slices, out Bitmap bitmap) { throw new NotImplementedException(); }
public void GenerateTextureAndUV(VoxelModel model, MeshSlices slices, out Bitmap bitmap, IProgressListener progress) { // Collect colors var colors = new List<int>(); // Marshal.Copy doesn't support uint[] lol int totalSlices = 0; foreach (var slicelist in slices) { totalSlices += slicelist.Length; } int sliceIndex = 0; progress?.Report("Collecting colors"); foreach (var slicelist in slices) { foreach (var slice in slicelist) { ++sliceIndex; progress?.Report((double)sliceIndex / totalSlices); var verts = slice.Positions; Axis3 paxis1, paxis2; GetPerpendicularAxises(slice.Axis, out paxis1, out paxis2); var pt = new IntVector3(); pt[slice.Axis] = slice.Layer; foreach (var face in slice.MeshSliceFaces) { var scoord = FindSliceCoordForFace(slice, face, slice.Axis, paxis1, paxis2); pt[paxis1] = scoord.X; pt[paxis2] = scoord.Y; colors.Add((int) (model[pt] | 0xff000000)); } } } // Determine the dimensions of the texture int texwidth = (int)Math.Ceiling(Math.Sqrt(colors.Count)); int texheight = (colors.Count + texwidth - 1) / texwidth; // And then create the texture bitmap = new Bitmap(texwidth * 2, texheight * 2, System.Drawing.Imaging.PixelFormat.Format32bppRgb); var bmpdata = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), System.Drawing.Imaging.ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format32bppRgb); System.Runtime.InteropServices.Marshal.Copy(Scale2x(colors.ToArray(), texwidth, texheight), 0, bmpdata.Scan0, colors.Count * 4); bitmap.UnlockBits(bmpdata); // Assign UVs int faceu = 0, facev = 0; sliceIndex = 0; progress?.Report("Assigning UV coordinates"); foreach (var slicelist in slices) { foreach (var slice in slicelist) { ++sliceIndex; progress?.Report((double)sliceIndex / totalSlices); var verts = slice.Positions; var uvs = slice.UVs = new Vector2[slice.Positions.Length]; Axis3 paxis1, paxis2; GetPerpendicularAxises(slice.Axis, out paxis1, out paxis2); foreach (var face in slice.MeshSliceFaces) { var scoord = FindSliceCoordForFace(slice, face, slice.Axis, paxis1, paxis2); var uv = new Vector2((float) (faceu << 1) + 0.5f, (float) (facev << 1) + 0.5f); for (int i = face.StartIndex; i < face.EndIndex; ++i) { var vt = verts[i]; float u = uv.X + (float)(vt[paxis1] - scoord.X); float v = uv.Y + (float)(vt[paxis2] - scoord.Y); uvs[i] = new Vector2(u, v); } faceu += 1; if (faceu == texwidth) { faceu = 0; facev += 1; } } } } }
public void Save(MeshSlices slices, Bitmap texture, string path, IProgressListener progress) { var name = System.IO.Path.GetFileNameWithoutExtension(path); var mtlname = name + ".mtl"; var imgname = name + ".png"; var dirname = System.IO.Path.GetDirectoryName(System.IO.Path.GetFullPath(path)); progress?.Report("Opening the output file"); progress?.Report(0); using (var writer = System.IO.File.CreateText(path)) { progress?.Report("Writing headers"); writer.WriteLine($"mtllib {mtlname}"); writer.WriteLine("o Object"); progress?.Report("Writing position"); int numTotalSlices = slices.Select((slicelist) => slicelist.Length).Sum(); int sliceIndex = 0; foreach (var slicelist in slices) { foreach (var slice in slicelist) { foreach (var vt in slice.Positions) { // Usually Y is the upward direction for OBJs writer.WriteLine($"v {vt.X} {-vt.Z} {vt.Y}"); } ++sliceIndex; progress?.Report((double)sliceIndex / numTotalSlices * (1.0 / 3.0)); } } progress?.Report("Writing UV coordinates"); sliceIndex = 0; foreach (var slicelist in slices) { foreach (var slice in slicelist) { foreach (var uv in slice.UVs) { writer.WriteLine($"vt {uv.X / texture.Width} {1f - uv.Y / texture.Height}"); } ++sliceIndex; progress?.Report((double)sliceIndex / numTotalSlices * (1.0 / 3.0) + (1.0 / 3.0)); } } writer.WriteLine("usemtl Material"); writer.WriteLine("s off"); progress?.Report("Writing faces"); int vtxidx = 1; sliceIndex = 0; foreach (var slicelist in slices) { foreach (var slice in slicelist) { foreach (var f in slice.MeshSliceFaces) { writer.Write("f"); for (int i = f.StartIndex; i < f.EndIndex; ++i) { writer.Write($" {vtxidx + i}/{vtxidx + i}"); } writer.WriteLine(); } vtxidx += slice.Positions.Length; ++sliceIndex; progress?.Report((double)sliceIndex / numTotalSlices * (1.0 / 3.0) + (2.0 / 3.0)); } } } // using writer progress?.Report("Saving material"); using (var writer = System.IO.File.CreateText(System.IO.Path.Combine(dirname, mtlname))) { writer.WriteLine("newmtl Material"); writer.WriteLine("Ka 0 0 0"); writer.WriteLine("Kd 1 1 1"); writer.WriteLine("Ks 0.2 0.2 0.2"); writer.WriteLine("Ni 1"); writer.WriteLine("d 1"); writer.WriteLine("illum 2"); writer.WriteLine($"map_Kd {imgname}"); } progress?.Report("Saving texture"); texture.Save(System.IO.Path.Combine(dirname, imgname), System.Drawing.Imaging.ImageFormat.Png); }
public MeshSlices GenerateSlices(VoxelModel model, IProgressListener progress) { var slices = new MeshSlices(); var dims = model.Dimensions; int totalsteps = 2 * (model.Width + model.Height + model.Depth); int step = 0; progress?.Report("Generating slices"); for (int iaxis = 0; iaxis < 3; ++iaxis) { for (int iface = 0; iface < 2; ++iface) { var axis = (Axis3) iaxis; var paxis1 = (Axis3) ((iaxis + 1) % 3); var paxis2 = (Axis3) ((iaxis + 2) % 3); bool face = iface != 0; int dim0 = dims[axis]; int dim1 = dims[paxis1]; int dim2 = dims[paxis2]; var slicelist = new MeshSlice[dim0]; slices[axis, face] = slicelist; for (int layer = 0; layer < dim0; ++layer) { ++step; progress?.Report((double)step / totalsteps); var faces = new List<int>(); var ret = new List<IntVector3>(); var pt1 = new IntVector3(); pt1[axis] = layer; for (int x = 0; x < dim1; ++x) { pt1[paxis1] = x; for (int y = 0; y < dim2; ++y) { pt1[paxis2] = y; bool solid1 = model.IsVoxelSolid(pt1); var pt2 = pt1; bool solid2 = false; if (face) { pt2[axis] += 1; if (pt2[axis] < dim0) { solid2 = model.IsVoxelSolid(pt2); } } else { pt2[axis] -= 1; if (pt2[axis] >= 0) { solid2 = model.IsVoxelSolid(pt2); } } if (!solid1 || solid2) { continue; } // Create quad var qpt1 = pt1; if (face) { qpt1[axis] += 1; qpt1[paxis2] += 1; } var qpt2 = qpt1; qpt2[paxis1] += 1; var qpt3 = qpt1; var qpt4 = qpt2; if (face) { qpt3[paxis2] -= 1; qpt4[paxis2] -= 1; } else { qpt3[paxis2] += 1; qpt4[paxis2] += 1; } // Emit polygons faces.Add(ret.Count); ret.Add(qpt3); ret.Add(qpt4); ret.Add(qpt2); ret.Add(qpt1); } // for y } // for x slicelist[layer] = new MeshSlice() { Positions = ret.ToArray(), Faces = faces.ToArray(), Face = face, Axis = axis, Layer = layer }; } // for slice } // iface } // iaxis return slices; }