/// <summary> /// Directly evaluate the winding number inside the marching cubes, /// instead of sampling onto a grid. More precise, basically. /// </summary> protected virtual void update_winding_exact() { DMesh3 meshIn = MeshSource.GetDMeshUnsafe(); if (spatialPro == null || spatial_timestamp != meshIn.ShapeTimestamp) { spatialPro = new DMeshAABBTreePro(meshIn, true); spatialPro.FastWindingNumber(Vector3d.Zero); spatial_timestamp = meshIn.ShapeTimestamp; } if (is_invalidated()) { return; } MarchingCubesPro c = new MarchingCubesPro(); c.Implicit = new WindingNumberImplicit(spatialPro, winding_iso); c.IsoValue = 0.0; c.Bounds = meshIn.CachedBounds; c.CubeSize = mesh_cell_size; c.Bounds.Expand(3 * c.CubeSize); c.RootMode = MarchingCubesPro.RootfindingModes.Bisection; c.RootModeSteps = 5; c.CancelF = is_invalidated; c.GenerateContinuation(meshIn.Vertices()); if (is_invalidated()) { return; } Reducer r = new Reducer(c.Mesh); r.FastCollapsePass(c.CubeSize * 0.5, 3, true); if (is_invalidated()) { return; } if (min_component_volume > 0) { MeshEditor.RemoveSmallComponents(c.Mesh, min_component_volume, min_component_volume); } if (is_invalidated()) { return; } if (is_invalidated()) { return; } ResultMesh = c.Mesh; }
protected virtual DMesh3 compute_blend() { cache_input_sdfs(); if (is_invalidated()) { return(null); } ImplicitBlend3d blend = new ImplicitBlend3d() { A = cached_isos[0], B = cached_isos[1], Blend = blend_power, WeightA = 1.0, WeightB = 1.0 }; MarchingCubes c = new MarchingCubes(); c.Implicit = blend; c.IsoValue = 0; c.Bounds = blend.Bounds(); c.CubeSize = mesh_cell_size; c.Bounds.Expand(3 * c.CubeSize); c.RootMode = MarchingCubes.RootfindingModes.Bisection; c.RootModeSteps = 5; c.CancelF = is_invalidated; c.Generate(); if (is_invalidated()) { return(null); } Reducer r = new Reducer(c.Mesh); r.FastCollapsePass(c.CubeSize / 2, 3, true); if (is_invalidated()) { return(null); } if (min_component_volume > 0) { MeshEditor.RemoveSmallComponents(c.Mesh, min_component_volume, min_component_volume); } if (is_invalidated()) { return(null); } return(c.Mesh); }
protected virtual void update_level_set() { double unsigned_offset = Math.Abs(offset_distance); if (cached_sdf == null || unsigned_offset > cached_sdf_max_offset || grid_cell_size != cached_sdf.CellSize) { DMesh3 meshIn = MeshSource.GetDMeshUnsafe(); int exact_cells = (int)(unsigned_offset / grid_cell_size) + 1; // only use spatial DS if we are computing enough cells DMeshAABBTree3 use_spatial = GenerateClosedMeshOp.MeshSDFShouldUseSpatial( input_spatial, exact_cells, grid_cell_size, input_mesh_edge_stats.z); MeshSignedDistanceGrid sdf = new MeshSignedDistanceGrid(meshIn, grid_cell_size, use_spatial) { ExactBandWidth = exact_cells }; if (use_spatial != null) { sdf.NarrowBandMaxDistance = unsigned_offset + grid_cell_size; sdf.ComputeMode = MeshSignedDistanceGrid.ComputeModes.NarrowBand_SpatialFloodFill; } sdf.CancelF = is_invalidated; sdf.Compute(); if (is_invalidated()) { return; } cached_sdf = sdf; cached_sdf_max_offset = unsigned_offset; cached_sdf_bounds = meshIn.CachedBounds; } var iso = new DenseGridTrilinearImplicit(cached_sdf.Grid, cached_sdf.GridOrigin, cached_sdf.CellSize); MarchingCubes c = new MarchingCubes(); c.Implicit = iso; c.IsoValue = offset_distance; c.Bounds = cached_sdf_bounds; c.CubeSize = mesh_cell_size; c.Bounds.Expand(offset_distance + 3 * c.CubeSize); c.RootMode = MarchingCubes.RootfindingModes.LerpSteps; c.RootModeSteps = 5; c.CancelF = is_invalidated; c.Generate(); if (is_invalidated()) { return; } Reducer r = new Reducer(c.Mesh); r.FastCollapsePass(c.CubeSize * 0.5, 3, true); if (is_invalidated()) { return; } if (min_component_volume > 0) { MeshEditor.RemoveSmallComponents(c.Mesh, min_component_volume, min_component_volume); } if (is_invalidated()) { return; } ResultMesh = c.Mesh; }
/// <summary> /// this variant use a lazy-evaluation version of the grid, and continuation-MC, /// so the marching cubes pulls values from the grid that are evaluated on-the-fly. /// In theory this should be comparable or faster than the narrow-band version, /// practice it is 10-20% slower...?? possible reasons: /// - spinlock contention /// - lots of duplicate grid evaluations because CachingDenseGridTrilinearImplicit does not use locking /// /// However, because it can re-use grid values, changing the isovalue is /// *much* faster and so it makes sense if the mesh is not closed... /// </summary> protected virtual void update_winding_fast() { DMesh3 meshIn = MeshSource.GetDMeshUnsafe(); if (spatialPro == null || spatial_timestamp != meshIn.ShapeTimestamp) { spatialPro = new DMeshAABBTreePro(meshIn, true); spatialPro.FastWindingNumber(Vector3d.Zero); spatial_timestamp = meshIn.ShapeTimestamp; } if (is_invalidated()) { return; } if (cached_lazy_mwn_grid == null || grid_cell_size != cached_lazy_mwn_grid.CellSize) { // figure out origin & dimensions AxisAlignedBox3d bounds = meshIn.CachedBounds; float fBufferWidth = 2 * (float)grid_cell_size; Vector3d origin = (Vector3f)bounds.Min - fBufferWidth * Vector3f.One; Vector3f max = (Vector3f)bounds.Max + fBufferWidth * Vector3f.One; int ni = (int)((max.x - origin.x) / (float)grid_cell_size) + 1; int nj = (int)((max.y - origin.y) / (float)grid_cell_size) + 1; int nk = (int)((max.z - origin.z) / (float)grid_cell_size) + 1; var grid = new CachingDenseGridTrilinearImplicit(origin, grid_cell_size, new Vector3i(ni, nj, nk)); grid.AnalyticF = new WindingField(spatialPro); cached_lazy_mwn_grid = grid; cached_mwn_bounds = meshIn.CachedBounds; } WindingFieldImplicit iso = new WindingFieldImplicit(cached_lazy_mwn_grid, winding_iso); MarchingCubesPro c = new MarchingCubesPro(); c.Implicit = iso; c.Bounds = cached_mwn_bounds; c.CubeSize = mesh_cell_size; c.Bounds.Expand(3 * c.CubeSize); c.RootMode = MarchingCubesPro.RootfindingModes.Bisection; c.RootModeSteps = 10; c.CancelF = is_invalidated; c.GenerateContinuation(meshIn.Vertices()); if (is_invalidated()) { return; } Reducer r = new Reducer(c.Mesh); r.FastCollapsePass(c.CubeSize * 0.5, 3, true); if (is_invalidated()) { return; } if (min_component_volume > 0) { MeshEditor.RemoveSmallComponents(c.Mesh, min_component_volume, min_component_volume); } if (is_invalidated()) { return; } // reproject - if we want to do this, we need to create spatial and meshIn above! gParallel.ForEach(c.Mesh.VertexIndices(), (vid) => { if (is_invalidated()) { return; } Vector3d v = c.Mesh.GetVertex(vid); int tid = spatialPro.FindNearestTriangle(v, grid_cell_size * MathUtil.SqrtTwo); if (tid != DMesh3.InvalidID) { var query = MeshQueries.TriangleDistance(meshIn, tid, v); if (v.Distance(query.TriangleClosest) < grid_cell_size) { c.Mesh.SetVertex(vid, query.TriangleClosest); } } }); if (is_invalidated()) { return; } ResultMesh = c.Mesh; }
/// <summary> /// Sample analytic winding number into grid in narrow-band around target isovalue, /// and then extract using marching cubes. /// /// TODO: don't need to discard current grid when isovalue changes, just need to /// re-run the front propagation part of mwn.Compute()! /// If this is done, then use this instead of update_winding_fast() for open meshes /// </summary> protected virtual void update_winding() { DMesh3 meshIn = MeshSource.GetDMeshUnsafe(); if (spatialPro == null || spatial_timestamp != meshIn.ShapeTimestamp) { spatialPro = new DMeshAABBTreePro(meshIn, true); spatialPro.FastWindingNumber(Vector3d.Zero); spatial_timestamp = meshIn.ShapeTimestamp; } if (is_invalidated()) { return; } if (cached_mwn_grid == null || grid_cell_size != cached_mwn_grid.CellSize || (float)winding_iso != cached_mwn_grid.IsoValue) { Func <Vector3d, double> fastWN = (q) => { return(spatialPro.FastWindingNumber(q)); }; var mwn = new MeshScalarSamplingGrid(meshIn, grid_cell_size, fastWN) { IsoValue = (float)winding_iso }; mwn.CancelF = is_invalidated; mwn.Compute(); if (is_invalidated()) { return; } cached_mwn_grid = mwn; cached_mwn_bounds = meshIn.CachedBounds; } MarchingCubes c = new MarchingCubes(); c.Implicit = new SampledGridImplicit(cached_mwn_grid); c.IsoValue = 0.0; c.Bounds = cached_mwn_bounds; c.CubeSize = mesh_cell_size; c.Bounds.Expand(3 * c.CubeSize); c.RootMode = MarchingCubes.RootfindingModes.Bisection; c.RootModeSteps = 10; c.CancelF = is_invalidated; c.Generate(); if (is_invalidated()) { return; } Reducer r = new Reducer(c.Mesh); r.FastCollapsePass(c.CubeSize * 0.5, 3, true); if (is_invalidated()) { return; } if (min_component_volume > 0) { MeshEditor.RemoveSmallComponents(c.Mesh, min_component_volume, min_component_volume); } if (is_invalidated()) { return; } // reproject - if we want to do this, we need to create spatial and meshIn above! gParallel.ForEach(c.Mesh.VertexIndices(), (vid) => { if (is_invalidated()) { return; } Vector3d v = c.Mesh.GetVertex(vid); int tid = spatialPro.FindNearestTriangle(v, grid_cell_size * MathUtil.SqrtTwo); if (tid != DMesh3.InvalidID) { var query = MeshQueries.TriangleDistance(meshIn, tid, v); if (v.Distance(query.TriangleClosest) < grid_cell_size) { c.Mesh.SetVertex(vid, query.TriangleClosest); } } }); if (is_invalidated()) { return; } ResultMesh = c.Mesh; }
protected virtual DMesh3 compute_blend_analytic() { bool profile = true; LocalProfiler p = null; if (profile) { p = new LocalProfiler(); p.Start("bvtree"); } compute_cache_lazy_sdfs(); if (is_invalidated()) { return(null); } if (profile) { p.Stop("bvtree"); p.Start("mc"); } List <BoundedImplicitFunction3d> inputs = new List <BoundedImplicitFunction3d>(); foreach (CachingMeshSDF sdf in cached_lazy_sdfs) { var skel_field = new DistanceFieldToSkeletalField() { DistanceField = new CachingMeshSDFImplicit(sdf), FalloffDistance = blend_falloff }; inputs.Add(skel_field); } SkeletalRicciNaryBlend3d blend = new SkeletalRicciNaryBlend3d() { Children = inputs, BlendPower = this.blend_power, FieldShift = -DistanceFieldToSkeletalField.ZeroIsocontour }; AxisAlignedBox3d use_bounds = source_bounds; source_bounds.Expand(blend_falloff); MarchingCubesPro c = lazy_mc; c.Implicit = blend; //c.IsoValue = DistanceFieldToSkeletalField.ZeroIsocontour; c.Bounds = use_bounds; c.CubeSize = mesh_cell_size; c.Bounds.Expand(3 * c.CubeSize); c.RootMode = MarchingCubesPro.RootfindingModes.LerpSteps; c.RootModeSteps = 3; //c.ParallelCompute = false; c.CancelF = is_invalidated; c.GenerateContinuation(input_mesh_seeds()); if (is_invalidated()) { return(null); } if (profile) { p.Stop("mc"); p.Start("reduce"); } c.Mesh.ReverseOrientation(); Reducer r = new Reducer(c.Mesh); r.FastCollapsePass(c.CubeSize / 2, 3, true); if (is_invalidated()) { return(null); } if (min_component_volume > 0) { MeshEditor.RemoveSmallComponents(c.Mesh, min_component_volume, min_component_volume); } if (is_invalidated()) { return(null); } if (profile) { p.Stop("reduce"); #if G3_USING_UNITY UnityEngine.Debug.Log("ANALYTIC BLEND TIME: " + p.AllTimes()); #endif } return(c.Mesh); }
protected virtual DMesh3 compute_blend_bounded() { bool profile = true; LocalProfiler p = null; if (profile) { p = new LocalProfiler(); p.Start("sdf"); } cache_input_sdfs_bounded(); if (is_invalidated()) { return(null); } if (profile) { p.Stop("sdf"); p.Start("mc"); } List <BoundedImplicitFunction3d> inputs = new List <BoundedImplicitFunction3d>(); foreach (var sdf in cached_bounded_sdfs) { var dist_field = new DenseGridTrilinearImplicit(sdf); var skel_field = new DistanceFieldToSkeletalField() { DistanceField = dist_field, FalloffDistance = blend_falloff }; inputs.Add(skel_field); } SkeletalRicciNaryBlend3d blend = new SkeletalRicciNaryBlend3d() { Children = inputs, BlendPower = this.blend_power }; MarchingCubesPro c = new MarchingCubesPro(); c.Implicit = blend; c.IsoValue = DistanceFieldToSkeletalField.ZeroIsocontour; c.Bounds = blend.Bounds(); c.CubeSize = mesh_cell_size; c.Bounds.Expand(3 * c.CubeSize); c.RootMode = MarchingCubesPro.RootfindingModes.LerpSteps; c.RootModeSteps = 3; c.CancelF = is_invalidated; //c.Generate(); c.GenerateContinuation(input_mesh_seeds()); if (is_invalidated()) { return(null); } if (profile) { p.Stop("mc"); p.Start("reduce"); } c.Mesh.ReverseOrientation(); Reducer r = new Reducer(c.Mesh); r.FastCollapsePass(c.CubeSize / 2, 3, true); if (is_invalidated()) { return(null); } if (min_component_volume > 0) { MeshEditor.RemoveSmallComponents(c.Mesh, min_component_volume, min_component_volume); } if (is_invalidated()) { return(null); } if (profile) { p.Stop("reduce"); #if G3_USING_UNITY UnityEngine.Debug.Log("BLEND TIME: " + p.AllTimes()); #endif } return(c.Mesh); }
protected virtual void compute_shell_distancefield() { if (cached_is_closed == false) { compute_shell_distancefield_unsigned(); return; } double offset_distance = shell_thickness; Interval1d shell_range = new Interval1d(0, offset_distance); if (shell_direction == ShellDirections.Symmetric) { shell_range = new Interval1d(-offset_distance / 2, offset_distance / 2); } else if (shell_direction == ShellDirections.Inner) { shell_range = new Interval1d(-offset_distance, 0); offset_distance = -offset_distance; } if (cached_sdf == null || shell_thickness > cached_sdf_max_offset || grid_cell_size != cached_sdf.CellSize) { DMesh3 meshIn = MeshSource.GetDMeshUnsafe(); int exact_cells = (int)((shell_thickness) / grid_cell_size) + 1; // only use spatial DS if we are computing enough cells DMeshAABBTree3 use_spatial = GenerateClosedMeshOp.MeshSDFShouldUseSpatial(input_spatial, exact_cells, grid_cell_size, input_mesh_edge_stats.z); MeshSignedDistanceGrid sdf = new MeshSignedDistanceGrid(meshIn, grid_cell_size, use_spatial) { ExactBandWidth = exact_cells }; if (use_spatial != null) { sdf.NarrowBandMaxDistance = shell_thickness + grid_cell_size; sdf.ComputeMode = MeshSignedDistanceGrid.ComputeModes.NarrowBand_SpatialFloodFill; } sdf.CancelF = is_invalidated; sdf.Compute(); if (is_invalidated()) { return; } cached_sdf = sdf; cached_sdf_max_offset = shell_thickness; cached_sdf_bounds = meshIn.CachedBounds; } var iso = new DenseGridTrilinearImplicit(cached_sdf.Grid, cached_sdf.GridOrigin, cached_sdf.CellSize); BoundedImplicitFunction3d shell_field = (shell_direction == ShellDirections.Symmetric) ? (BoundedImplicitFunction3d) new ImplicitShell3d() { A = iso, Inside = shell_range } : (BoundedImplicitFunction3d) new ImplicitOffset3d() { A = iso, Offset = offset_distance }; //var shell_field = new ImplicitShell3d() { A = iso, Inside = shell_range }; //BoundedImplicitFunction3d shell_field = (signed_field) ? // (BoundedImplicitFunction3d)new ImplicitShell3d() { A = iso, Inside = shell_range } : // (BoundedImplicitFunction3d)new ImplicitOffset3d() { A = iso, Offset = offset_distance }; //ImplicitOffset3d offset = new ImplicitOffset3d() { A = iso, Offset = offset_distance }; MarchingCubes c = new MarchingCubes(); c.Implicit = shell_field; c.IsoValue = 0; c.Bounds = cached_sdf_bounds; c.CubeSize = mesh_cell_size; c.Bounds.Expand(offset_distance + 3 * c.CubeSize); c.RootMode = MarchingCubes.RootfindingModes.LerpSteps; c.RootModeSteps = 5; c.CancelF = is_invalidated; c.Generate(); if (is_invalidated()) { return; } Reducer r = new Reducer(c.Mesh); r.FastCollapsePass(c.CubeSize * 0.5, 3, true); if (is_invalidated()) { return; } if (min_component_volume > 0) { MeshEditor.RemoveSmallComponents(c.Mesh, min_component_volume, min_component_volume); } if (is_invalidated()) { return; } if (shell_surface_only) { if (shell_direction == ShellDirections.Inner || shell_direction == ShellDirections.Outer) { c.Mesh.AttachMetadata("is_partial", new object()); } } ResultMesh = c.Mesh; }
protected virtual void compute_shell_distancefield_unsigned() { double offset_distance = shell_thickness * 0.5; if (cached_sdf == null || offset_distance > cached_sdf_max_offset || grid_cell_size != cached_sdf.CellSize) { DMesh3 meshIn = MeshSource.GetDMeshUnsafe(); int exact_cells = (int)((offset_distance) / grid_cell_size) + 1; MeshSignedDistanceGrid sdf = new MeshSignedDistanceGrid(meshIn, grid_cell_size) { ExactBandWidth = exact_cells, ComputeSigns = false }; sdf.CancelF = is_invalidated; sdf.Compute(); if (is_invalidated()) { return; } cached_sdf = sdf; cached_sdf_max_offset = offset_distance; cached_sdf_bounds = meshIn.CachedBounds; } var iso = new DenseGridTrilinearImplicit(cached_sdf.Grid, cached_sdf.GridOrigin, cached_sdf.CellSize); MarchingCubes c = new MarchingCubes(); c.Implicit = iso; c.IsoValue = offset_distance; c.Bounds = cached_sdf_bounds; c.CubeSize = mesh_cell_size; c.Bounds.Expand(offset_distance + 3 * c.CubeSize); c.RootMode = MarchingCubes.RootfindingModes.LerpSteps; c.RootModeSteps = 5; c.CancelF = is_invalidated; c.Generate(); if (is_invalidated()) { return; } Reducer r = new Reducer(c.Mesh); r.FastCollapsePass(c.CubeSize * 0.5, 3, true); if (is_invalidated()) { return; } if (min_component_volume > 0) { MeshEditor.RemoveSmallComponents(c.Mesh, min_component_volume, min_component_volume); } if (is_invalidated()) { return; } ResultMesh = c.Mesh; }
protected virtual DMesh3 update_step_2(DMesh3 meshIn) { double unsigned_offset = Math.Abs(distance); int exact_cells = (int)(unsigned_offset / grid_cell_size) + 1; // only use spatial DS if we are computing enough cells bool compute_spatial = GenerateClosedMeshOp.MeshSDFShouldUseSpatial( input_spatial, exact_cells, grid_cell_size, input_mesh_edge_stats.z) != null; DMeshAABBTree3 use_spatial = (compute_spatial) ? new DMeshAABBTree3(meshIn, true) : null; MeshSignedDistanceGrid sdf = new MeshSignedDistanceGrid(meshIn, grid_cell_size, use_spatial) { ExactBandWidth = exact_cells }; if (use_spatial != null) { sdf.NarrowBandMaxDistance = unsigned_offset + grid_cell_size; sdf.ComputeMode = MeshSignedDistanceGrid.ComputeModes.NarrowBand_SpatialFloodFill; } sdf.CancelF = is_invalidated; sdf.Compute(); if (is_invalidated()) { return(null); } var iso = new DenseGridTrilinearImplicit(sdf.Grid, sdf.GridOrigin, sdf.CellSize); MarchingCubes c = new MarchingCubes(); c.Implicit = iso; if (op_type == OperationTypes.Close) { c.IsoValue = -distance; } else { c.IsoValue = distance; } c.Bounds = cached_sdf_bounds; c.CubeSize = mesh_cell_size; c.Bounds.Expand(distance + 3 * c.CubeSize); c.RootMode = MarchingCubes.RootfindingModes.LerpSteps; c.RootModeSteps = 5; c.CancelF = is_invalidated; c.Generate(); if (is_invalidated()) { return(null); } Reducer r = new Reducer(c.Mesh); r.FastCollapsePass(c.CubeSize * 0.5, 3, true); if (is_invalidated()) { return(null); } if (min_component_volume > 0) { MeshEditor.RemoveSmallComponents(c.Mesh, min_component_volume, min_component_volume); } if (is_invalidated()) { return(null); } return(c.Mesh); }
protected virtual DMesh3 compute_inset(DMesh3 meshIn) { double unsigned_offset = Math.Abs(distance); DMeshAABBTree3 use_spatial = new DMeshAABBTree3(meshIn, true); if (is_invalidated()) { return(null); } CachingMeshSDF sdf = new CachingMeshSDF(meshIn, grid_cell_size, use_spatial); sdf.MaxOffsetDistance = (float)unsigned_offset; sdf.CancelF = is_invalidated; sdf.Initialize(); if (is_invalidated()) { return(null); } var sdf_iso = new CachingMeshSDFImplicit(sdf); // currently MCPro-Continuation does not work w/ non-zero // isovalues, so we have to shift our target offset externally ImplicitOffset3d iso = new ImplicitOffset3d() { A = sdf_iso, Offset = -distance }; MarchingCubesPro c = new MarchingCubesPro(); c.Implicit = iso; c.Bounds = cached_sdf_bounds; c.CubeSize = mesh_cell_size; c.Bounds.Expand(distance + 3 * c.CubeSize); c.CancelF = is_invalidated; c.GenerateContinuation(offset_seeds(meshIn, -distance)); if (is_invalidated()) { return(null); } Reducer r = new Reducer(c.Mesh); r.FastCollapsePass(c.CubeSize * 0.5, 3, true); if (is_invalidated()) { return(null); } if (min_component_volume > 0) { MeshEditor.RemoveSmallComponents(c.Mesh, min_component_volume, min_component_volume); } if (is_invalidated()) { return(null); } return(c.Mesh); }
protected virtual DMesh3 compute_wrap() { DMesh3 meshIn = MeshSource.GetDMeshUnsafe(); double unsigned_offset = Math.Abs(distance); if (cached_sdf == null || unsigned_offset > cached_sdf_max_offset || grid_cell_size != cached_sdf.CellSize) { DMeshAABBTree3 use_spatial = input_spatial; CachingMeshSDF sdf = new CachingMeshSDF(meshIn, grid_cell_size, use_spatial); sdf.MaxOffsetDistance = 2 * (float)unsigned_offset; sdf.CancelF = is_invalidated; sdf.Initialize(); if (is_invalidated()) { return(null); } cached_sdf = sdf; cached_sdf_max_offset = unsigned_offset; cached_sdf_bounds = meshIn.CachedBounds; } var grid_iso = new CachingMeshSDFImplicit(cached_sdf); // currently MCPro-Continuation does not work w/ non-zero // isovalues, so we have to shift our target offset externally var iso = new ImplicitOffset3d() { A = grid_iso, Offset = distance }; MarchingCubesPro c = new MarchingCubesPro(); c.Implicit = iso; c.Bounds = cached_sdf_bounds; c.CubeSize = mesh_cell_size; c.Bounds.Expand(distance + 3 * c.CubeSize); c.CancelF = is_invalidated; c.GenerateContinuation(offset_seeds(meshIn, distance)); if (is_invalidated()) { return(null); } Reducer r = new Reducer(c.Mesh); r.FastCollapsePass(c.CubeSize * 0.5, 3, true); if (is_invalidated()) { return(null); } if (min_component_volume > 0) { MeshEditor.RemoveSmallComponents(c.Mesh, min_component_volume, min_component_volume); } if (is_invalidated()) { return(null); } DMesh3 offsetMesh = c.Mesh; MeshConnectedComponents comp = new MeshConnectedComponents(offsetMesh); comp.FindConnectedT(); if (is_invalidated()) { return(null); } DSubmesh3Set subMeshes = new DSubmesh3Set(offsetMesh, comp); if (is_invalidated()) { return(null); } MeshSpatialSort sort = new MeshSpatialSort(); foreach (var subMesh in subMeshes) { sort.AddMesh(subMesh.SubMesh, subMesh); } sort.Sort(); if (is_invalidated()) { return(null); } DMesh3 outerMesh = new DMesh3(); foreach (var solid in sort.Solids) { DMesh3 outer = solid.Outer.Mesh; //if (is_outward_oriented(outer) == false) // outer.ReverseOrientation(); MeshEditor.Append(outerMesh, outer); } if (is_invalidated()) { return(null); } return(compute_inset(outerMesh)); }
protected virtual DMesh3 compute_wrap() { cache_input_sdfs(); if (is_invalidated()) { return(null); } BoundedImplicitFunction3d iso = null; if (op_type == OpTypes.Union) { iso = new ImplicitNaryUnion3d() { Children = new List <BoundedImplicitFunction3d>(cached_isos) }; } else if (op_type == OpTypes.Intersection) { iso = new ImplicitNaryIntersection3d() { Children = new List <BoundedImplicitFunction3d>(cached_isos) }; } else if (op_type == OpTypes.Difference) { iso = new ImplicitNaryDifference3d() { A = cached_isos[0], BSet = new List <BoundedImplicitFunction3d>(cached_isos.Skip(1)) }; } MarchingCubes c = new MarchingCubes(); c.Implicit = iso; c.IsoValue = 0; c.Bounds = iso.Bounds(); c.CubeSize = mesh_cell_size; c.Bounds.Expand(3 * c.CubeSize); c.RootMode = MarchingCubes.RootfindingModes.Bisection; c.RootModeSteps = 5; c.CancelF = is_invalidated; c.Generate(); if (is_invalidated()) { return(null); } Reducer r = new Reducer(c.Mesh); r.FastCollapsePass(c.CubeSize / 2, 3, true); if (is_invalidated()) { return(null); } if (min_component_volume > 0) { MeshEditor.RemoveSmallComponents(c.Mesh, min_component_volume, min_component_volume); } if (is_invalidated()) { return(null); } return(c.Mesh); }
protected virtual void compute_hollow() { double offset_distance = -wall_thickness; if (cached_sdf == null || wall_thickness > cached_sdf_max_offset || grid_cell_size != cached_sdf.CellSize) { DMesh3 meshIn = MeshSource.GetDMeshUnsafe(); int exact_cells = (int)((wall_thickness) / grid_cell_size) + 1; // only use spatial DS if we are computing enough cells DMeshAABBTree3 use_spatial = GenerateClosedMeshOp.MeshSDFShouldUseSpatial(input_spatial, exact_cells, grid_cell_size, input_mesh_edge_stats.z); MeshSignedDistanceGrid sdf = new MeshSignedDistanceGrid(meshIn, grid_cell_size, use_spatial) { ExactBandWidth = exact_cells }; if (use_spatial != null) { sdf.NarrowBandMaxDistance = wall_thickness + grid_cell_size; sdf.ComputeMode = MeshSignedDistanceGrid.ComputeModes.NarrowBand_SpatialFloodFill; } sdf.CancelF = is_invalidated; sdf.Compute(); if (is_invalidated()) { return; } cached_sdf = sdf; cached_sdf_max_offset = wall_thickness; cached_sdf_bounds = meshIn.CachedBounds; } var iso = new DenseGridTrilinearImplicit(cached_sdf.Grid, cached_sdf.GridOrigin, cached_sdf.CellSize); ImplicitOffset3d shell_field = new ImplicitOffset3d() { A = iso, Offset = offset_distance }; ImplicitFunction3d use_iso = shell_field; if (enable_infill) { GridDistanceField grid_df = new GridDistanceField() { CellSize = infill_spacing, Radius = infill_thickness * 0.5, Origin = cached_sdf.GridOrigin }; ImplicitDifference3d diff = new ImplicitDifference3d() { A = shell_field, B = grid_df }; use_iso = diff; } MarchingCubes c = new MarchingCubes(); c.Implicit = use_iso; c.IsoValue = 0; c.Bounds = cached_sdf_bounds; c.CubeSize = mesh_cell_size; c.Bounds.Expand(offset_distance + 3 * c.CubeSize); c.RootMode = MarchingCubes.RootfindingModes.LerpSteps; c.RootModeSteps = 5; c.CancelF = is_invalidated; c.Generate(); if (is_invalidated()) { return; } Reducer r = new Reducer(c.Mesh); r.FastCollapsePass(c.CubeSize * 0.5, 3, true); if (is_invalidated()) { return; } //r.ReduceToTriangleCount(c.Mesh.TriangleCount / 5); //if (is_invalidated()) // return; if (min_component_volume > 0) { MeshEditor.RemoveSmallComponents(c.Mesh, min_component_volume, min_component_volume); } if (is_invalidated()) { return; } c.Mesh.AttachMetadata("is_partial", new object()); ResultMesh = c.Mesh; }