public static void printVoxelizedRepresentation(Bitmap3 bmp, String outputPath) { VoxelSurfaceGenerator voxGen = new VoxelSurfaceGenerator(); voxGen.Voxels = bmp; voxGen.Generate(); DMesh3 voxMesh = voxGen.Meshes[0]; Util.WriteDebugMesh(voxMesh, outputPath); }
public static void test_voxel_surface() { //DMesh3 mesh = TestUtil.LoadTestInputMesh("bunny_solid.obj"); DMesh3 mesh = TestUtil.LoadTestInputMesh("holey_bunny_2.obj"); DMeshAABBTree3 spatial = new DMeshAABBTree3(mesh, autoBuild: true); AxisAlignedBox3d bounds = mesh.CachedBounds; int numcells = 64; double cellsize = bounds.MaxDim / numcells; MeshSignedDistanceGrid levelSet = new MeshSignedDistanceGrid(mesh, cellsize); levelSet.UseParallel = true; levelSet.Compute(); Bitmap3 bmp = new Bitmap3(levelSet.Dimensions); foreach (Vector3i idx in bmp.Indices()) { float f = levelSet[idx.x, idx.y, idx.z]; bmp.Set(idx, (f < 0) ? true : false); } //AxisAlignedBox3d bounds = mesh.CachedBounds; //int numcells = 32; //double cellsize = bounds.MaxDim / numcells; //ShiftGridIndexer3 indexer = new ShiftGridIndexer3(bounds.Min-2*cellsize, cellsize); //Bitmap3 bmp = new Bitmap3(new Vector3i(numcells, numcells, numcells)); //foreach (Vector3i idx in bmp.Indices()) { // Vector3d v = indexer.FromGrid(idx); // bmp.Set(idx, spatial.IsInside(v)); //} //spatial.WindingNumber(Vector3d.Zero); //Bitmap3 bmp = new Bitmap3(new Vector3i(numcells+3, numcells+3, numcells+3)); //gParallel.ForEach(bmp.Indices(), (idx) => { // Vector3d v = indexer.FromGrid(idx); // bmp.SafeSet(idx, spatial.WindingNumber(v) > 0.8); //}); VoxelSurfaceGenerator voxGen = new VoxelSurfaceGenerator(); voxGen.Voxels = bmp; voxGen.ColorSourceF = (idx) => { return(new Colorf((float)idx.x, (float)idx.y, (float)idx.z) * (1.0f / numcells)); }; voxGen.Generate(); DMesh3 voxMesh = voxGen.Meshes[0]; Util.WriteDebugMesh(voxMesh, "c:\\scratch\\temp.obj"); TestUtil.WriteTestOutputMesh(voxMesh, "voxel_surf.obj", true, true); }
protected override void SolveInstance(IGH_DataAccess DA) { int num_cells = 128; DMesh3_goo dMsh_goo = null; DA.GetData(0, ref dMsh_goo); DA.GetData(1, ref num_cells); DMesh3 dMsh_copy = new DMesh3(dMsh_goo.Value); double cell_size = dMsh_copy.CachedBounds.MaxDim / num_cells; DMeshAABBTree3 spatial = new DMeshAABBTree3(dMsh_copy, autoBuild: true); AxisAlignedBox3d bounds = dMsh_copy.CachedBounds; double cellsize = bounds.MaxDim / num_cells; ShiftGridIndexer3 indexer = new ShiftGridIndexer3(bounds.Min, cellsize); Bitmap3 bmp = new Bitmap3(new Vector3i(num_cells, num_cells, num_cells)); foreach (Vector3i idx in bmp.Indices()) { g3.Vector3d v = indexer.FromGrid(idx); bmp.Set(idx, spatial.IsInside(v)); } VoxelSurfaceGenerator voxGen = new VoxelSurfaceGenerator(); voxGen.Voxels = bmp; voxGen.Generate(); DMesh3 voxMesh = voxGen.Meshes[0]; var vecSize = dMsh_copy.CachedBounds.Extents; var box = dMsh_copy.GetBounds(); // Scale voxel mesh //MeshTransforms.Scale(voxMesh,) DA.SetData(0, voxMesh); }
public static DMesh3 MineCraft(DMesh3 mesh, int num_cells, out double scalefactor) { DMeshAABBTree3 spatial = new DMeshAABBTree3(mesh, autoBuild: true); AxisAlignedBox3d bounds = mesh.CachedBounds; double cellsize = bounds.MaxDim / num_cells; scalefactor = cellsize; ShiftGridIndexer3 indexer = new ShiftGridIndexer3(bounds.Min, cellsize); Bitmap3 bmp = new Bitmap3(new Vector3i(num_cells, num_cells, num_cells)); foreach (Vector3i idx in bmp.Indices()) { g3.Vector3d v = indexer.FromGrid(idx); if (spatial.IsInside(v)) { bmp.Set(idx, true); } else { bmp.Set(idx, false); } } VoxelSurfaceGenerator voxGen = new VoxelSurfaceGenerator(); voxGen.Voxels = bmp; voxGen.Generate(); DMesh3 voxMesh = voxGen.Meshes[0]; return(voxMesh); }
void process_version2(DenseGrid3f supportGrid, DenseGridTrilinearImplicit distanceField) { int ni = supportGrid.ni, nj = supportGrid.nj, nk = supportGrid.nk; float dx = (float)CellSize; Vector3f origin = this.GridOrigin; // sweep values down layer by layer DenseGrid2f prev = supportGrid.get_slice(nj - 1, 1); DenseGrid2f tmp = new DenseGrid2f(prev); Bitmap3 bmp = new Bitmap3(new Vector3i(ni, nj, nk)); for (int j = nj - 2; j >= 0; j--) { // skeletonize prev layer DenseGrid2i prev_skel = binarize(prev, 0.0f); skeletonize(prev_skel, null, 2); //dilate_loners(prev_skel, null, 2); if (j == 0) { dilate(prev_skel, null, true); dilate(prev_skel, null, true); } for (int k = 1; k < nk - 1; ++k) { for (int i = 1; i < ni - 1; ++i) { bmp[new Vector3i(i, j, k)] = (prev_skel[i, k] == 1) ? true : false; } } smooth(prev, tmp, 0.5f, 5); DenseGrid2f cur = supportGrid.get_slice(j, 1); cur.set_min(prev); for (int k = 1; k < nk - 1; ++k) { for (int i = 1; i < ni - 1; ++i) { float skelf = prev_skel[i, k] > 0 ? -1.0f : int.MaxValue; cur[i, k] = Math.Min(cur[i, k], skelf); if (cur[i, k] < 0) { Vector3d cell_center = new Vector3f(i * dx, j * dx, k * dx) + origin; if (distanceField.Value(ref cell_center) < -CellSize) { cur[i, k] = 1; } } } } for (int k = 1; k < nk - 1; ++k) { for (int i = 1; i < ni - 1; ++i) { if (is_loner(prev_skel, i, k)) { foreach (Vector2i d in gIndices.GridOffsets8) { float f = 1.0f / (float)Math.Sqrt(d.x * d.x + d.y * d.y); cur[i + d.x, k + d.y] += -0.25f * f; } } } } for (int k = 1; k < nk - 1; ++k) { for (int i = 1; i < ni - 1; ++i) { supportGrid[i, j, k] = cur[i, k]; } } prev.swap(cur); } VoxelSurfaceGenerator gen = new VoxelSurfaceGenerator() { Voxels = bmp }; gen.Generate(); Util.WriteDebugMesh(gen.Meshes[0], "c:\\scratch\\binary.obj"); }
void update_mesh() { clear_mesh(); AxisAlignedBox3i bounds = grid.Extents; Vector3i minCorner = bounds.Min; Vector3f cornerXYZ = grid.ToXYZ(minCorner); Bitmap3d bmp; try { bmp = new Bitmap3d(bounds.Diagonal + Vector3i.One); } catch (Exception e) { Debug.Log("update_mesh: exception allocating grid of size " + bounds.Diagonal); throw e; } foreach (Vector3i idx in grid.GridIndices(MinSamples)) { Vector3i bidx = idx - minCorner; try { bmp.Set(bidx, true); } catch (Exception e) { Debug.Log("bad index is " + bidx + " grid dims " + bmp.Dimensions); throw e; } } // get rid of one-block tubes, floaters, etc. // todo: use a queue instead of passes? or just descend into // nbrs when changing one block? one pass to compute counts and // then another to remove? (yes that is a good idea...) bmp.Filter(2); bmp.Filter(2); bmp.Filter(2); bmp.Filter(2); bmp.Filter(2); bmp.Filter(2); VoxelSurfaceGenerator gen = new VoxelSurfaceGenerator() { Voxels = bmp, Clockwise = false, MaxMeshElementCount = 65000, ColorSourceF = (idx) => { idx = idx + minCorner; return(grid.GetColor(idx)); } }; gen.Generate(); List <DMesh3> meshes = gen.Meshes; List <fMeshGameObject> newMeshGOs = new List <fMeshGameObject>(); foreach (DMesh3 mesh in meshes) { MeshTransforms.Scale(mesh, grid.GridStepSize); MeshTransforms.Translate(mesh, cornerXYZ); Mesh m = UnityUtil.DMeshToUnityMesh(mesh, false); fMeshGameObject meshGO = GameObjectFactory.CreateMeshGO("gridmesh", m, false, true); meshGO.SetMaterial(MaterialUtil.CreateStandardVertexColorMaterialF(Colorf.White)); newMeshGOs.Add(meshGO); } CurrentMeshGOs = newMeshGOs; }