void cache_bvtrees(bool bWinding) { gParallel.ForEach(Interval1i.Range(mesh_sources.Count), (k) => { if (cached_bvtrees[k] != null) { return; } if (is_invalidated()) { return; } DMesh3 source_mesh = mesh_sources[k].GetDMeshUnsafe(); cached_bvtrees[k] = new DMeshAABBTreePro(source_mesh, true); }); if (bWinding) { gParallel.ForEach(Interval1i.Range(mesh_sources.Count), (k) => { if (is_invalidated()) { return; } cached_bvtrees[k].FastWindingNumber(Vector3d.Zero); }); } }
public ComponentMesh(DMesh3 mesh, object identifier, DMeshAABBTreePro spatial) { this.Mesh = mesh; this.Identifier = identifier; this.IsClosed = mesh.IsClosed(); this.Spatial = spatial; Bounds = mesh.CachedBounds; }
/// <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; }
public void AddMesh(DMesh3 mesh, object identifier, DMeshAABBTreePro spatial = null) { ComponentMesh comp = new ComponentMesh(mesh, identifier, spatial); if (spatial == null) { if (comp.IsClosed || AllowOpenContainers) { comp.Spatial = new DMeshAABBTreePro(mesh, true); } } Components.Add(comp); }
public virtual void Update() { base.begin_update(); int start_timestamp = this.CurrentInputTimestamp; if (MeshSource == null) { throw new Exception("RemoveHiddenFacesOp: must set valid MeshSource to compute!"); } try { DMesh3 meshIn = MeshSource.GetDMeshUnsafe(); if (cachedSpatial == null || spatial_cache_timstamp != meshIn.ShapeTimestamp) { cachedSpatial = new DMeshAABBTreePro(meshIn, true); cachedSpatial.FastWindingNumber(Vector3d.Zero); spatial_cache_timstamp = meshIn.ShapeTimestamp; } DMesh3 editMesh = new DMesh3(meshIn); RemoveOccludedTriangles remove = new RemoveOccludedTriangles(editMesh, cachedSpatial) { InsideMode = (RemoveOccludedTriangles.CalculationMode)(int) inside_mode, PerVertex = all_hidden_vertices }; remove.Progress = new ProgressCancel(is_invalidated); if (remove.Apply() == false) { ResultMesh = null; RemovedTris = null; RemovedSubmesh = null; } else { ResultMesh = editMesh; RemovedTris = remove.RemovedT; RemovedSubmesh = new DSubmesh3(MeshSource.GetDMeshUnsafe(), RemovedTris); } base.complete_update(); } catch (Exception e) { PostOnOperatorException(e); ResultMesh = base.make_failure_output(MeshSource.GetDMeshUnsafe()); base.complete_update(); } }
public void SetSources(List <DMeshSourceOp> sources) { if (mesh_sources != null) { throw new Exception("MeshVoxelBlendOp.SetSources: handle changing sources!"); } //if (sources.Count != 2) // throw new Exception("MeshVoxelBlendOp.SetSources: only two sources supported!"); mesh_sources = new List <DMeshSourceOp>(sources); foreach (var source in mesh_sources) { source.OperatorModified += on_input_modified; } cached_sdfs = new MeshSignedDistanceGrid[sources.Count]; cached_isos = new BoundedImplicitFunction3d[sources.Count]; cached_bvtrees = new DMeshAABBTreePro[sources.Count]; invalidate(); }
public WindingNumberImplicit(DMeshAABBTreePro spatial, double isoValue) { Spatial = spatial; IsoValue = isoValue; }
public WindingField(DMeshAABBTreePro spatial) { Spatial = spatial; }
/// <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; }
public virtual bool Apply() { DMesh3 testAgainstMesh = Mesh; if (InsideMode == CalculationMode.RayParity) { MeshBoundaryLoops loops = new MeshBoundaryLoops(testAgainstMesh); if (loops.Count > 0) { testAgainstMesh = new DMesh3(Mesh); foreach (var loop in loops) { if (Cancelled()) { return(false); } SimpleHoleFiller filler = new SimpleHoleFiller(testAgainstMesh, loop); filler.Fill(); } } } DMeshAABBTreePro spatial = (Spatial != null && testAgainstMesh == Mesh) ? Spatial : new DMeshAABBTreePro(testAgainstMesh, true); if (InsideMode == CalculationMode.AnalyticWindingNumber) { spatial.WindingNumber(Vector3d.Zero); } else if (InsideMode == CalculationMode.FastWindingNumber) { spatial.FastWindingNumber(Vector3d.Zero); } if (Cancelled()) { return(false); } // ray directions List <Vector3d> ray_dirs = null; int NR = 0; if (InsideMode == CalculationMode.SimpleOcclusionTest) { ray_dirs = new List <Vector3d>(); ray_dirs.Add(Vector3d.AxisX); ray_dirs.Add(-Vector3d.AxisX); ray_dirs.Add(Vector3d.AxisY); ray_dirs.Add(-Vector3d.AxisY); ray_dirs.Add(Vector3d.AxisZ); ray_dirs.Add(-Vector3d.AxisZ); NR = ray_dirs.Count; } Func <Vector3d, bool> isOccludedF = (pt) => { if (InsideMode == CalculationMode.RayParity) { return(spatial.IsInside(pt)); } else if (InsideMode == CalculationMode.AnalyticWindingNumber) { return(spatial.WindingNumber(pt) > WindingIsoValue); } else if (InsideMode == CalculationMode.FastWindingNumber) { return(spatial.FastWindingNumber(pt) > WindingIsoValue); } else { for (int k = 0; k < NR; ++k) { int hit_tid = spatial.FindNearestHitTriangle(new Ray3d(pt, ray_dirs[k])); if (hit_tid == DMesh3.InvalidID) { return(false); } } return(true); } }; bool cancel = false; BitArray vertices = null; if (PerVertex) { vertices = new BitArray(Mesh.MaxVertexID); MeshNormals normals = null; if (Mesh.HasVertexNormals == false) { normals = new MeshNormals(Mesh); normals.Compute(); } gParallel.ForEach(Mesh.VertexIndices(), (vid) => { if (cancel) { return; } if (vid % 10 == 0) { cancel = Cancelled(); } Vector3d c = Mesh.GetVertex(vid); Vector3d n = (normals == null) ? Mesh.GetVertexNormal(vid) : normals[vid]; c += n * NormalOffset; vertices[vid] = isOccludedF(c); }); } if (Cancelled()) { return(false); } RemovedT = new List <int>(); SpinLock removeLock = new SpinLock(); gParallel.ForEach(Mesh.TriangleIndices(), (tid) => { if (cancel) { return; } if (tid % 10 == 0) { cancel = Cancelled(); } bool inside = false; if (PerVertex) { Index3i tri = Mesh.GetTriangle(tid); inside = vertices[tri.a] || vertices[tri.b] || vertices[tri.c]; } else { Vector3d c = Mesh.GetTriCentroid(tid); Vector3d n = Mesh.GetTriNormal(tid); c += n * NormalOffset; inside = isOccludedF(c); } if (inside) { bool taken = false; removeLock.Enter(ref taken); RemovedT.Add(tid); removeLock.Exit(); } }); if (Cancelled()) { return(false); } if (RemovedT.Count > 0) { MeshEditor editor = new MeshEditor(Mesh); bool bOK = editor.RemoveTriangles(RemovedT, true); RemoveFailed = (bOK == false); } return(true); }
public RemoveOccludedTriangles(DMesh3 mesh, DMeshAABBTreePro spatial) { Mesh = mesh; Spatial = spatial; }