/// <summary> /// compute offset meshes as simple extrusions /// </summary> void compute_offset_meshes_nosdf() { if (cached_inner_sdf_offset != inner_offset) { InnerOffsetMesh = new DMesh3(cachedInputMesh); MeshTransforms.FromFrame(InnerOffsetMesh, cachedInputsTransform); MeshNormals.QuickCompute(InnerOffsetMesh); MeshTransforms.VertexNormalOffset(InnerOffsetMesh, inner_offset); Reducer reducer = new Reducer(InnerOffsetMesh); reducer.ReduceToTriangleCount(5000); InnerOffsetMeshSpatial = new DMeshAABBTree3(InnerOffsetMesh, true); cached_inner_sdf_offset = inner_offset; } double max_offset = inner_offset + thickness; if (cached_outer_sdf_offset != max_offset) { OuterOffsetMesh = new DMesh3(cachedInputMesh); MeshTransforms.FromFrame(OuterOffsetMesh, cachedInputsTransform); MeshNormals.QuickCompute(OuterOffsetMesh); MeshTransforms.VertexNormalOffset(OuterOffsetMesh, max_offset); Reducer reducer = new Reducer(OuterOffsetMesh); reducer.ReduceToTriangleCount(5000); OuterOffsetMeshSpatial = new DMeshAABBTree3(OuterOffsetMesh, true); cached_outer_sdf_offset = max_offset; } //Util.WriteDebugMesh(MeshSource.GetIMesh(), "c:\\scratch\\__OFFESTS_orig.obj"); //Util.WriteDebugMesh(InnerOffsetMesh, "c:\\scratch\\__OFFESTS_inner.obj"); //Util.WriteDebugMesh(OuterOffsetMesh, "c:\\scratch\\__OFFESTS_outer.obj"); }
private static DMesh3 BooleanIntersection(DMesh3 mesh1, DMesh3 mesh2) { BoundedImplicitFunction3d meshA = meshToImplicitF(mesh1, 64, 0.2f); BoundedImplicitFunction3d meshB = meshToImplicitF(mesh2, 64, 0.2f); //take the intersection of the meshes minus the tools ImplicitIntersection3d mesh = new ImplicitIntersection3d() { A = meshA, B = meshB }; //calculate the boolean mesh MarchingCubes c = new MarchingCubes(); c.Implicit = mesh; c.RootMode = MarchingCubes.RootfindingModes.LerpSteps; c.RootModeSteps = 5; c.Bounds = mesh.Bounds(); c.CubeSize = c.Bounds.MaxDim / 128; c.Bounds.Expand(3 * c.CubeSize); c.Generate(); MeshNormals.QuickCompute(c.Mesh); int triangleCount = c.Mesh.TriangleCount / 2; Reducer r = new Reducer(c.Mesh); r.ReduceToTriangleCount(triangleCount); return(c.Mesh); }
protected override void SolveInstance(IGH_DataAccess DA) { DMesh3_goo gooA = null; List <DMesh3_goo> gooB = new List <DMesh3_goo>(); int numCells = 64; DA.GetData(0, ref gooA); DA.GetDataList(1, gooB); DA.GetData(2, ref numCells); DMesh3 A = new DMesh3(gooA.Value); List <DMesh3> B = gooB.Select(x => x.Value).ToList(); ImplicitNaryDifference3d diff2 = new ImplicitNaryDifference3d(); diff2.A = g3ghUtil.MeshToImplicit(A, numCells, 0.2f); diff2.BSet = B.Select(x => g3ghUtil.MeshToImplicit(x, numCells, 0.2f)).ToList(); g3.MarchingCubes c = new g3.MarchingCubes(); c.Implicit = diff2; c.RootMode = g3.MarchingCubes.RootfindingModes.Bisection; c.RootModeSteps = 5; c.Bounds = diff2.Bounds(); c.CubeSize = c.Bounds.MaxDim / numCells; c.Bounds.Expand(3 * c.CubeSize); c.Generate(); MeshNormals.QuickCompute(c.Mesh); DA.SetData(0, c.Mesh); }
private UnityMesh CreateMesh(List <Vector3d> lPath) { DMesh3 dMesh = meshGen.CreateMesh(lPath, qPoly.ToList(), tmpSeam); // Defer normal calculation if we reduce smoothing later. if (triangleReductionFactor > 1f) { dMesh.ReduceTriangles(triangleReductionFactor, !reduceSmoothing); } else if (!reduceSmoothing) { MeshNormals.QuickCompute(dMesh); } UnityMesh uMesh = dMesh.ToUnityMesh(); uMesh.seam = meshGen.Seam; // TODO if (reduceSmoothing) { uMesh.IncreaseVertexCount(smoothingThresholdAngle); } return(uMesh); }
public DMesh3 BooleanUnion(DMesh3 mesh1, DMesh3 mesh2) { BoundedImplicitFunction3d meshA = meshToImplicitF(mesh1, 128, 0.2f); BoundedImplicitFunction3d meshB = meshToImplicitF(mesh2, 128, 0.2f); //take the difference of the bolus mesh minus the tools var mesh = new ImplicitUnion3d() { A = meshA, B = meshB }; //calculate the boolean mesh MarchingCubes c = new MarchingCubes(); c.Implicit = mesh; c.RootMode = MarchingCubes.RootfindingModes.LerpSteps; c.RootModeSteps = 5; c.Bounds = mesh.Bounds(); c.CubeSize = c.Bounds.MaxDim / 96; c.Bounds.Expand(3 * c.CubeSize); c.Generate(); MeshNormals.QuickCompute(c.Mesh); //int triangleCount = c.Mesh.TriangleCount / 2; //Reducer r = new Reducer(c.Mesh); //r.ReduceToTriangleCount(triangleCount); return(c.Mesh); }
void update_warp() { if (warp_dirty == false) { return; } DMesh3 mesh = PreviewSO.Mesh; foreach (int vid in mesh.VertexIndices()) { mesh.SetVertex(vid, VertexPositions[vid]); } Frame3f f = bendPlaneGizmoSO.GetLocalFrame(CoordSpace.SceneCoords); f = SceneTransforms.SceneToObject(PreviewSO, f); BendWarp warp = new BendWarp() { Mesh = mesh, BendPlane = f, BendAngle = bend_angle }; warp.Apply(); MeshNormals.QuickCompute(mesh); PreviewSO.NotifyMeshEdited(true); warp_dirty = false; }
//experimental public List <DMesh3> SliceMold(DMesh3 mesh_to_slice, int number_of_slices) { var meshes = new List <MeshGeometry3D>(); //convert mesh to DMesh DMesh3 mesh = mesh_to_slice; //create cube for slicing double z_height = mesh.GetBounds().Max.z - mesh.GetBounds().Min.z; double slice_interval = (double)(z_height / number_of_slices); double x_size = mesh.GetBounds().Depth; double y_size = mesh.GetBounds().Width; double low_z = mesh.GetBounds().Min.z; //boolean intersection each mesh var sliced_meshes = new List <DMesh3>(); for (int i = 0; i < number_of_slices; i++) { //create box Vector3d centre = new Vector3d(0, 0, low_z + slice_interval / 2 + i * (slice_interval)); Vector3d extend = new Vector3d( x_size, y_size, slice_interval / 2); ImplicitBox3d box = new ImplicitBox3d() { Box = new Box3d(centre, extend) }; //boolean overlap BoundedImplicitFunction3d meshA = meshToImplicitF(mesh, 64, 0.2f); //take the difference of the bolus mesh minus the tools ImplicitIntersection3d mesh_result = new ImplicitIntersection3d { A = meshA, B = box }; //calculate the boolean mesh MarchingCubes c = new MarchingCubes(); c.Implicit = mesh_result; c.RootMode = MarchingCubes.RootfindingModes.LerpSteps; c.RootModeSteps = 5; c.Bounds = mesh_result.Bounds(); c.CubeSize = c.Bounds.MaxDim / 256; c.Bounds.Expand(3 * c.CubeSize); c.Generate(); MeshNormals.QuickCompute(c.Mesh); int triangleCount = c.Mesh.TriangleCount / 3; Reducer r = new Reducer(c.Mesh); r.ReduceToTriangleCount(triangleCount); sliced_meshes.Add(c.Mesh); } return(sliced_meshes); }
protected override void SolveInstance(IGH_DataAccess DA) { List <DMesh3_goo> goo = new List <DMesh3_goo>(); int numCells = 64; DA.GetDataList(0, goo); DA.GetData(1, ref numCells); ImplicitNaryUnion3d diff2 = new ImplicitNaryUnion3d(); diff2.Children = goo.Select(x => g3ghUtil.MeshToImplicit(x.Value, numCells, 0.2f)).ToList(); g3.MarchingCubes c = new g3.MarchingCubes(); c.Implicit = diff2; c.RootMode = g3.MarchingCubes.RootfindingModes.Bisection; c.RootModeSteps = 5; c.Bounds = diff2.Bounds(); c.CubeSize = c.Bounds.MaxDim / numCells; c.Bounds.Expand(3 * c.CubeSize); c.Generate(); MeshNormals.QuickCompute(c.Mesh); DA.SetData(0, c.Mesh); }
// Use this for initialization void Start() { meshGO = GameObject.Find("sample_mesh"); Mesh unityMesh = meshGO.GetComponent <MeshFilter>().mesh; startMesh = g3UnityUtils.UnityMeshToDMesh(unityMesh); double height = startMesh.CachedBounds.Height; // find path to sample file if (LoadSampleMesh) { string curPath = Application.dataPath; string filePath = Path.Combine(curPath, Path.Combine("..\\sample_files", SampleFileName)); // load sample file, convert to unity coordinate system, translate and scale to origin startMesh = StandardMeshReader.ReadMesh(filePath); if (startMesh == null) { startMesh = new Sphere3Generator_NormalizedCube().Generate().MakeDMesh(); } if (FlipLeftRight) { MeshTransforms.FlipLeftRightCoordSystems(startMesh); } MeshTransforms.Scale(startMesh, height / startMesh.CachedBounds.Height); MeshTransforms.Translate(startMesh, -startMesh.CachedBounds.Center); MeshNormals.QuickCompute(startMesh); g3UnityUtils.SetGOMesh(meshGO, startMesh); } }
public override fMesh MakeGeometry(AxisGizmoFlags widget) { switch (widget) { case AxisGizmoFlags.AxisTranslateY: if (MyAxisTranslateY == null) { Radial3DArrowGenerator arrowGen = new Radial3DArrowGenerator() { HeadLength = 2.0f, TipRadius = 0.1f, StickLength = 1.5f, Clockwise = true }; DMesh3 mesh = arrowGen.Generate().MakeDMesh(); MeshNormals.QuickCompute(mesh); MeshTransforms.Translate(mesh, 0.5 * Vector3d.AxisY); DMesh3 flip = new DMesh3(mesh); MeshTransforms.Rotate(flip, Vector3d.Zero, Quaterniond.AxisAngleD(Vector3d.AxisX, 180)); MeshEditor.Append(mesh, flip); MyAxisTranslateY = new fMesh(mesh); } return(MyAxisTranslateY); default: return(null); } }
public virtual void Update() { base.begin_update(); if (MeshSource == null) { throw new Exception("MeshDeformationOp: must set valid MeshSource to compute!"); } IMesh meshIn = MeshSource.GetIMesh(); DMesh3 mesh = new DMesh3(meshIn, MeshHints.None); MeshNormals.QuickCompute(mesh); foreach (int vid in mesh.VertexIndices()) { Vector3d v = mesh.GetVertex(vid); Vector3f n = mesh.GetVertexNormal(vid); Vector3d newPos = deformF(v, n, vid); mesh.SetVertex(vid, newPos); } MeshNormals.QuickCompute(mesh); DisplacedMesh = mesh; base.complete_update(); }
void compute_inner_wall() { if (DebugStep <= 0) { SocketMesh = new DMesh3(TrimmedMesh); return; } InnerMesh = new DMesh3(TrimmedMesh); // compute flare band Func <int, double> flareOffsetF = (vid) => { return(0); }; if (flare_offset > 0 && flare_band_width > 0) { MeshBoundaryLoops loops = new MeshBoundaryLoops(InnerMesh); if (loops.Count != 1) { goto done_inner_wall; } DijkstraGraphDistance dist = DijkstraGraphDistance.MeshVertices(InnerMesh); dist.TrackOrder = true; foreach (int vid in loops[0].Vertices) { dist.AddSeed(vid, 0); } dist.ComputeToMaxDistance(1.25f * (float)flare_band_width); flareOffsetF = (viD) => { float d = dist.GetDistance(viD); if (d < flare_band_width) { double t = d / flare_band_width; t = 1 - t * t; t = t * t * t; return(t * flare_offset); } return(0); }; } gParallel.ForEach(InnerMesh.VertexIndices(), (vid) => { Vector3d v = InnerMesh.GetVertex(vid); Vector3d n = InnerMesh.GetVertexNormal(vid); double offset = inner_offset + flareOffsetF(vid); InnerMesh.SetVertex(vid, v + offset * n); }); done_inner_wall: MeshNormals.QuickCompute(InnerMesh); }
public virtual void BakeDisplacements(DMeshSO so, VertexChangeBuilder changeBuilder) { so.EditAndUpdateMesh((mesh) => { foreach (int vid in ModifiedV) { changeBuilder.SetPosition(vid, Displacements[vid]); } gParallel.ForEach(ModifiedV, (vid) => { MeshNormals.QuickCompute(Mesh, vid); }); }, GeometryEditTypes.VertexDeformation); }
// generateMeshF() meshes the input implicit function at // the given cell resolution, and writes out the resulting mesh DMesh3 generatMeshF(BoundedImplicitFunction3d root, int numcells) { MarchingCubes c = new MarchingCubes(); c.Implicit = root; c.RootMode = MarchingCubes.RootfindingModes.LerpSteps; // cube-edge convergence method c.RootModeSteps = 5; // number of iterations c.Bounds = root.Bounds(); c.CubeSize = c.Bounds.MaxDim / numcells; c.Bounds.Expand(3 * c.CubeSize); // leave a buffer of cells c.Generate(); MeshNormals.QuickCompute(c.Mesh); // generate normals return(c.Mesh); // write mesh }
private DMesh3 GenerateMeshBase(BoundedImplicitFunction3d root, AxisAlignedBox3d filterBox) { MarchingCubes c = new MarchingCubes(); c.Implicit = root; c.RootMode = MarchingCubes.RootfindingModes.LerpSteps; // cube-edge convergence method c.RootModeSteps = 5; // number of iterations c.Bounds = filterBox; //_sideFilterBox; c.CubeSize = _cubeSize / 4.0; c.Generate(); MeshNormals.QuickCompute(c.Mesh); // generate normals return(c.Mesh); }
public override Task Rebuild() { this.DebugDepth("Rebuild"); return(Task.Run(() => { using (RebuildLock()) { using (new CenterAndHeightMaintainer(this)) { #if true ISdf shape = new Sphere() { Radius = Size }; if (Shape == Shapes.Box) { shape = new Box() { Size = new Vector3(Size, Size, Size) }; } var bounds = shape.Bounds; bounds.Expand(.1); if (Iterations > 7) { Iterations = 7; } var root = Octree.BuildOctree(shape.Sdf, bounds.MinXYZ, bounds.Size, Iterations, Threshold); Mesh = Octree.GenerateMeshFromOctree(root); #else var c = new MarchingCubes(); c.Generate(); MeshNormals.QuickCompute(c.Mesh); // generate normals Mesh = c.Mesh.ToMesh(); #endif } } Invalidate(InvalidateType.DisplayValues); Parent?.Invalidate(new InvalidateArgs(this, InvalidateType.Mesh)); return Task.CompletedTask; })); }
public static void test_normals() { // check that frames are ok DMesh3 mesh = TestUtil.LoadTestInputMesh("bunny_solid.obj"); foreach (int tid in mesh.TriangleIndices()) { Vector3f n = (Vector3f)mesh.GetTriNormal(tid); for (int j = 0; j < 3; ++j) { Frame3f f = mesh.GetTriFrame(tid, j); if (Math.Abs(f.X.Dot(f.Y)) > MathUtil.ZeroTolerancef || Math.Abs(f.X.Dot(f.Z)) > MathUtil.ZeroTolerancef || Math.Abs(f.Y.Dot(f.Z)) > MathUtil.ZeroTolerancef) { throw new Exception("argh"); } Vector3f fn = f.Z; if (fn.Dot(n) < 0.99) { throw new Exception("shit"); } } } MeshNormals.QuickCompute(mesh); foreach (int vid in mesh.VertexIndices()) { Vector3f n = mesh.GetVertexNormal(vid); for (int j = 1; j <= 2; ++j) { Frame3f f = mesh.GetVertexFrame(vid, (j == 1) ? true : false); Vector3f fn = f.GetAxis(j); if (Math.Abs(f.X.Dot(f.Y)) > MathUtil.ZeroTolerancef || Math.Abs(f.X.Dot(f.Z)) > MathUtil.ZeroTolerancef || Math.Abs(f.Y.Dot(f.Z)) > MathUtil.ZeroTolerancef) { throw new Exception("argh"); } if (fn.Dot(n) < 0.99) { throw new Exception("shit2"); } } } }
public static DMesh3 GenerateMeshF(BoundedImplicitFunction3d mesh, int num_cells) { MarchingCubes c = new MarchingCubes(); c.Implicit = mesh; c.RootMode = MarchingCubes.RootfindingModes.LerpSteps; // cube-edge convergence method c.RootModeSteps = 5; // number of iterations c.Bounds = mesh.Bounds(); c.CubeSize = c.Bounds.MaxDim / num_cells; c.Bounds.Expand(3 * c.CubeSize); // leave a buffer of cells c.Generate(); MeshNormals.QuickCompute(c.Mesh); // generate normals DMesh3 outputMesh = c.Mesh; return(outputMesh); }
protected override void Recompute(DGArguments args) { OffsetMesh.Copy(CachedValue <DMesh3>(0, args)); double dist = CachedValue <double>(1, args); if (!OffsetMesh.HasVertexNormals) { MeshNormals.QuickCompute(OffsetMesh); } foreach (int vid in OffsetMesh.VertexIndices()) { Vector3d v = OffsetMesh.GetVertex(vid); Vector3d n = OffsetMesh.GetVertexNormal(vid); v += dist * n; OffsetMesh.SetVertex(vid, v); } }
public bool Compute() { DMesh3 copy = new DMesh3(Mesh); //Frame3f PlaneO = SceneTransforms.SceneToObject(TargetSO, PlaneS); Vector3f PlaneNormal = Plane.GetAxis(nPlaneAxis); MeshPlaneCut cut = new MeshPlaneCut(copy, Plane.Origin, PlaneNormal); cut.Cut(); Loops = new DCurve3[cut.CutLoops.Count]; for (int li = 0; li < cut.CutLoops.Count; ++li) { EdgeLoop edgeloop = cut.CutLoops[li]; DCurve3 loop = MeshUtil.ExtractLoopV(copy, edgeloop.Vertices); // [TODO] collapse degenerate points... if (NormalOffset > 0) { for (int i = 0; i < loop.VertexCount; ++i) { Vector3f n = Vector3f.Zero; if (copy.HasVertexNormals) { n = (Vector3f)copy.GetVertexNormal(edgeloop.Vertices[i]); } else { n = (Vector3f)MeshNormals.QuickCompute(Mesh, edgeloop.Vertices[i]); } n -= n.Dot(PlaneNormal) * PlaneNormal; n.Normalize(); loop[i] += NormalOffset * (Vector3d)n; } } Loops[li] = loop; } return(Loops.Length > 0); }
private static DMesh3 GenerateMeshF(BoundedImplicitFunction3d root, int numcells) { var bounds = root.Bounds(); var c = new MarchingCubes() { Implicit = root, RootMode = MarchingCubes.RootfindingModes.LerpSteps, // cube-edge convergence method RootModeSteps = 5, // number of iterations Bounds = bounds, CubeSize = bounds.MaxDim / numcells, }; c.Bounds.Expand(3 * c.CubeSize); // leave a buffer of cells c.Generate(); MeshNormals.QuickCompute(c.Mesh); // generate normals return(c.Mesh); }
void MeshReplace() { Mesh newMesh = new Mesh(); //The triangles tend to come out reversed, so we need to fix them DMesh3 dmesh3 = DMesh3Builder.Build <float, int, float>(verticies, faces); MeshNormals.QuickCompute(dmesh3); dmesh3.ReverseOrientation(false); newMesh.vertices = verticies.ToVectors().ToArray(); newMesh.triangles = dmesh3.TrianglesBuffer.ToArray(); for (int i = 0; i < mesh.uv.Length; i++) { newMesh.uv[i] = mesh.uv[i]; } newMesh.MarkDynamic(); GetComponent <MeshFilter>().mesh = newMesh; }
public static void TestMarchingCubes() { MarchingCubes mc = new MarchingCubes(); LocalProfiler p = new LocalProfiler(); p.Start("GENERATE"); mc.ParallelCompute = true; mc.Generate(); p.Stop("GENERATE"); DebugUtil.Log(2, p.AllTimes()); MeshNormals.QuickCompute(mc.Mesh); DebugUtil.WriteDebugMesh(mc.Mesh, "c:\\scratch\\MARCHING_CUBES.obj"); DMeshSO meshSO = new DMeshSO(); meshSO.Create(mc.Mesh, CC.ActiveScene.DefaultMeshSOMaterial); CC.ActiveScene.AddSceneObject(meshSO, false); }
public static DMesh3 ReduceTriangles(this DMesh3 dMesh, int triangleCount, bool computeNormals = true, bool fixAllBoundaryEdges = true) { Reducer reducer = new Reducer(dMesh); if (fixAllBoundaryEdges) { reducer.SetExternalConstraints(meshConstraints); MeshConstraintUtil.FixAllBoundaryEdges(reducer.Constraints, dMesh); } reducer.ReduceToTriangleCount(triangleCount); if (computeNormals) { MeshNormals.QuickCompute(dMesh); } return(dMesh); }
public static void test_marching_cubes() { MarchingCubes c = new MarchingCubes(); LocalProfiler profiler = new LocalProfiler(); profiler.Start("Generate"); c.ParallelCompute = true; c.Generate(); profiler.Stop("Generate"); System.Console.WriteLine("Tris: {0} Times: {1}", c.Mesh.TriangleCount, profiler.AllTimes()); Reducer r = new Reducer(c.Mesh); r.ReduceToEdgeLength(c.CubeSize * 0.25); System.Console.WriteLine("after reduce: {0}", c.Mesh.TriangleCount); MeshNormals.QuickCompute(c.Mesh); TestUtil.WriteTestOutputMesh(c.Mesh, "marching_cubes.obj"); }
public static void test_marching_cubes_demos() { // generateMeshF() meshes the input implicit function at // the given cell resolution, and writes out the resulting mesh Action <BoundedImplicitFunction3d, int, string> generateMeshF = (root, numcells, path) => { MarchingCubes c = new MarchingCubes(); c.Implicit = root; c.RootMode = MarchingCubes.RootfindingModes.LerpSteps; // cube-edge convergence method c.RootModeSteps = 5; // number of iterations c.Bounds = root.Bounds(); c.CubeSize = c.Bounds.MaxDim / numcells; c.Bounds.Expand(3 * c.CubeSize); // leave a buffer of cells c.Generate(); MeshNormals.QuickCompute(c.Mesh); // generate normals StandardMeshWriter.WriteMesh(path, c.Mesh, WriteOptions.Defaults); // write mesh }; // meshToImplicitF() generates a narrow-band distance-field and // returns it as an implicit surface, that can be combined with other implicits Func <DMesh3, int, double, BoundedImplicitFunction3d> meshToImplicitF = (meshIn, numcells, max_offset) => { double meshCellsize = meshIn.CachedBounds.MaxDim / numcells; MeshSignedDistanceGrid levelSet = new MeshSignedDistanceGrid(meshIn, meshCellsize); levelSet.ExactBandWidth = (int)(max_offset / meshCellsize) + 1; levelSet.Compute(); return(new DenseGridTrilinearImplicit(levelSet.Grid, levelSet.GridOrigin, levelSet.CellSize)); }; // meshToBlendImplicitF() computes the full distance-field grid for the input // mesh. The bounds are expanded quite a bit to allow for blending, // probably more than necessary in most cases Func <DMesh3, int, BoundedImplicitFunction3d> meshToBlendImplicitF = (meshIn, numcells) => { double meshCellsize = meshIn.CachedBounds.MaxDim / numcells; MeshSignedDistanceGrid levelSet = new MeshSignedDistanceGrid(meshIn, meshCellsize); levelSet.ExpandBounds = meshIn.CachedBounds.Diagonal * 0.25; // need some values outside mesh levelSet.ComputeMode = MeshSignedDistanceGrid.ComputeModes.FullGrid; levelSet.Compute(); return(new DenseGridTrilinearImplicit(levelSet.Grid, levelSet.GridOrigin, levelSet.CellSize)); }; // generate union/difference/intersection of sphere and cube ImplicitSphere3d sphere = new ImplicitSphere3d() { Origin = Vector3d.Zero, Radius = 1.0 }; ImplicitBox3d box = new ImplicitBox3d() { Box = new Box3d(new Frame3f(Vector3f.AxisX), 0.5 * Vector3d.One) }; generateMeshF(new ImplicitUnion3d() { A = sphere, B = box }, 128, "c:\\demo\\union.obj"); generateMeshF(new ImplicitDifference3d() { A = sphere, B = box }, 128, "c:\\demo\\difference.obj"); generateMeshF(new ImplicitIntersection3d() { A = sphere, B = box }, 128, "c:\\demo\\intersection.obj"); // generate bunny offset surfaces //double offset = 0.2f; //DMesh3 mesh = TestUtil.LoadTestInputMesh("bunny_solid.obj"); //MeshTransforms.Scale(mesh, 3.0 / mesh.CachedBounds.MaxDim); //BoundedImplicitFunction3d meshImplicit = meshToImplicitF(mesh, 64, offset); //generateMeshF(meshImplicit, 128, "c:\\demo\\mesh.obj"); //generateMeshF(new ImplicitOffset3d() { A = meshImplicit, Offset = offset }, 128, "c:\\demo\\mesh_outset.obj"); //generateMeshF(new ImplicitOffset3d() { A = meshImplicit, Offset = -offset }, 128, "c:\\demo\\mesh_inset.obj"); // compare offset of sharp and smooth union //var smooth_union = new ImplicitSmoothDifference3d() { A = sphere, B = box }; //generateMeshF(smooth_union, 128, "c:\\demo\\smooth_union.obj"); //generateMeshF(new ImplicitOffset3d() { A = smooth_union, Offset = 0.2 }, 128, "c:\\demo\\smooth_union_offset.obj"); //var union = new ImplicitUnion3d() { A = sphere, B = box }; //generateMeshF(new ImplicitOffset3d() { A = union, Offset = offset }, 128, "c:\\demo\\union_offset.obj"); // blending //ImplicitSphere3d sphere1 = new ImplicitSphere3d() { // Origin = Vector3d.Zero, Radius = 1.0 //}; //ImplicitSphere3d sphere2 = new ImplicitSphere3d() { // Origin = 1.5 * Vector3d.AxisX, Radius = 1.0 //}; //generateMeshF(new ImplicitBlend3d() { A = sphere1, B = sphere2, Blend = 1.0 }, 128, "c:\\demo\\blend_1.obj"); //generateMeshF(new ImplicitBlend3d() { A = sphere1, B = sphere2, Blend = 4.0 }, 128, "c:\\demo\\blend_4.obj"); //generateMeshF(new ImplicitBlend3d() { A = sphere1, B = sphere2, Blend = 16.0 }, 128, "c:\\demo\\blend_16.obj"); //generateMeshF(new ImplicitBlend3d() { A = sphere1, B = sphere2, Blend = 64.0 }, 128, "c:\\demo\\blend_64.obj"); //sphere1.Radius = sphere2.Radius = 2.0f; //sphere2.Origin = 1.5 * sphere1.Radius * Vector3d.AxisX; //generateMeshF(new ImplicitBlend3d() { A = sphere1, B = sphere2, Blend = 1.0 }, 128, "c:\\demo\\blend_2x_1.obj"); //generateMeshF(new ImplicitBlend3d() { A = sphere1, B = sphere2, Blend = 4.0 }, 128, "c:\\demo\\blend_2x_4.obj"); //generateMeshF(new ImplicitBlend3d() { A = sphere1, B = sphere2, Blend = 16.0 }, 128, "c:\\demo\\blend_2x_16.obj"); //generateMeshF(new ImplicitBlend3d() { A = sphere1, B = sphere2, Blend = 64.0 }, 128, "c:\\demo\\blend_2x_64.obj"); // mesh blending //DMesh3 mesh1 = TestUtil.LoadTestInputMesh("bunny_solid.obj"); //MeshTransforms.Scale(mesh1, 3.0 / mesh1.CachedBounds.MaxDim); //DMesh3 mesh2 = new DMesh3(mesh1); //MeshTransforms.Rotate(mesh2, mesh2.CachedBounds.Center, Quaternionf.AxisAngleD(Vector3f.OneNormalized, 45.0f)); //var meshImplicit1 = meshToImplicitF(mesh1, 64, 0); //var meshImplicit2 = meshToImplicitF(mesh2, 64, 0); //generateMeshF(new ImplicitBlend3d() { A = meshImplicit1, B = meshImplicit2, Blend = 0.0 }, 256, "c:\\demo\\blend_mesh_union.obj"); //generateMeshF(new ImplicitBlend3d() { A = meshImplicit1, B = meshImplicit2, Blend = 10.0 }, 256, "c:\\demo\\blend_mesh_bad.obj"); //var meshFullImplicit1 = meshToBlendImplicitF(mesh1, 64); //var meshFullImplicit2 = meshToBlendImplicitF(mesh2, 64); //generateMeshF(new ImplicitBlend3d() { A = meshFullImplicit1, B = meshFullImplicit2, Blend = 0.0 }, 256, "c:\\demo\\blend_mesh_union.obj"); //generateMeshF(new ImplicitBlend3d() { A = meshFullImplicit1, B = meshFullImplicit2, Blend = 1.0 }, 256, "c:\\demo\\blend_mesh_1.obj"); //generateMeshF(new ImplicitBlend3d() { A = meshFullImplicit1, B = meshFullImplicit2, Blend = 10.0 }, 256, "c:\\demo\\blend_mesh_10.obj"); //generateMeshF(new ImplicitBlend3d() { A = meshFullImplicit1, B = meshFullImplicit2, Blend = 50.0 }, 256, "c:\\demo\\blend_mesh_100.obj"); //DMesh3 mesh = TestUtil.LoadTestInputMesh("bunny_solid.obj"); //MeshTransforms.Scale(mesh, 3.0 / mesh.CachedBounds.MaxDim); //MeshTransforms.Translate(mesh, -mesh.CachedBounds.Center); //Reducer r = new Reducer(mesh); //r.ReduceToTriangleCount(100); //double radius = 0.1; //List<BoundedImplicitFunction3d> Lines = new List<BoundedImplicitFunction3d>(); //foreach (Index4i edge_info in mesh.Edges()) { // var segment = new Segment3d(mesh.GetVertex(edge_info.a), mesh.GetVertex(edge_info.b)); // Lines.Add(new ImplicitLine3d() { Segment = segment, Radius = radius }); //} //ImplicitNaryUnion3d unionN = new ImplicitNaryUnion3d() { Children = Lines }; //generateMeshF(unionN, 128, "c:\\demo\\mesh_edges.obj"); //radius = 0.05; //List<BoundedImplicitFunction3d> Elements = new List<BoundedImplicitFunction3d>(); //foreach (int eid in mesh.EdgeIndices()) { // var segment = new Segment3d(mesh.GetEdgePoint(eid, 0), mesh.GetEdgePoint(eid, 1)); // Elements.Add(new ImplicitLine3d() { Segment = segment, Radius = radius }); //} //foreach (Vector3d v in mesh.Vertices()) // Elements.Add(new ImplicitSphere3d() { Origin = v, Radius = 2 * radius }); //generateMeshF(new ImplicitNaryUnion3d() { Children = Elements }, 256, "c:\\demo\\mesh_edges_and_vertices.obj"); //double lattice_radius = 0.05; //double lattice_spacing = 0.4; //double shell_thickness = 0.05; //int mesh_resolution = 64; // set to 256 for image quality //var shellMeshImplicit = meshToImplicitF(mesh, 128, shell_thickness); //double max_dim = mesh.CachedBounds.MaxDim; //AxisAlignedBox3d bounds = new AxisAlignedBox3d(mesh.CachedBounds.Center, max_dim / 2); //bounds.Expand(2 * lattice_spacing); //AxisAlignedBox2d element = new AxisAlignedBox2d(lattice_spacing); //AxisAlignedBox2d bounds_xy = new AxisAlignedBox2d(bounds.Min.xy, bounds.Max.xy); //AxisAlignedBox2d bounds_xz = new AxisAlignedBox2d(bounds.Min.xz, bounds.Max.xz); //AxisAlignedBox2d bounds_yz = new AxisAlignedBox2d(bounds.Min.yz, bounds.Max.yz); //List<BoundedImplicitFunction3d> Tiling = new List<BoundedImplicitFunction3d>(); //foreach (Vector2d uv in TilingUtil.BoundedRegularTiling2(element, bounds_xy, 0)) { // Segment3d seg = new Segment3d(new Vector3d(uv.x, uv.y, bounds.Min.z), new Vector3d(uv.x, uv.y, bounds.Max.z)); // Tiling.Add(new ImplicitLine3d() { Segment = seg, Radius = lattice_radius }); //} //foreach (Vector2d uv in TilingUtil.BoundedRegularTiling2(element, bounds_xz, 0)) { // Segment3d seg = new Segment3d(new Vector3d(uv.x, bounds.Min.y, uv.y), new Vector3d(uv.x, bounds.Max.y, uv.y)); // Tiling.Add(new ImplicitLine3d() { Segment = seg, Radius = lattice_radius }); //} //foreach (Vector2d uv in TilingUtil.BoundedRegularTiling2(element, bounds_yz, 0)) { // Segment3d seg = new Segment3d(new Vector3d(bounds.Min.x, uv.x, uv.y), new Vector3d(bounds.Max.x, uv.x, uv.y)); // Tiling.Add(new ImplicitLine3d() { Segment = seg, Radius = lattice_radius }); //} //ImplicitNaryUnion3d lattice = new ImplicitNaryUnion3d() { Children = Tiling }; //generateMeshF(lattice, 128, "c:\\demo\\lattice.obj"); //ImplicitIntersection3d lattice_clipped = new ImplicitIntersection3d() { A = lattice, B = shellMeshImplicit }; //generateMeshF(lattice_clipped, mesh_resolution, "c:\\demo\\lattice_clipped.obj"); //var shell = new ImplicitDifference3d() { // A = shellMeshImplicit, B = new ImplicitOffset3d() { A = shellMeshImplicit, Offset = -shell_thickness } //}; //var shell_cut = new ImplicitDifference3d() { // A = shell, B = new ImplicitAxisAlignedBox3d() { AABox = new AxisAlignedBox3d(Vector3d.Zero, max_dim / 2, 0.4, max_dim / 2) } //}; //generateMeshF(new ImplicitUnion3d() { A = lattice_clipped, B = shell_cut }, mesh_resolution, "c:\\demo\\lattice_result.obj"); }
protected override void SolveInstance(IGH_DataAccess DA) { DMesh3_goo goo = null; double lattice_radius = 0.05; double lattice_spacing = 0.4; double shell_thickness = 0.05; int mesh_resolution = 64; DA.GetData(0, ref goo); DA.GetData(1, ref lattice_radius); DA.GetData(2, ref lattice_spacing); DA.GetData(3, ref shell_thickness); DA.GetData(4, ref mesh_resolution); DMesh3 mesh = new DMesh3(goo.Value); var shellMeshImplicit = g3ghUtil.MeshToImplicit(mesh, 128, shell_thickness); double max_dim = mesh.CachedBounds.MaxDim; AxisAlignedBox3d bounds = new AxisAlignedBox3d(mesh.CachedBounds.Center, max_dim / 2); bounds.Expand(2 * lattice_spacing); AxisAlignedBox2d element = new AxisAlignedBox2d(lattice_spacing); AxisAlignedBox2d bounds_xy = new AxisAlignedBox2d(bounds.Min.xy, bounds.Max.xy); AxisAlignedBox2d bounds_xz = new AxisAlignedBox2d(bounds.Min.xz, bounds.Max.xz); AxisAlignedBox2d bounds_yz = new AxisAlignedBox2d(bounds.Min.yz, bounds.Max.yz); List <BoundedImplicitFunction3d> Tiling = new List <BoundedImplicitFunction3d>(); foreach (g3.Vector2d uv in TilingUtil.BoundedRegularTiling2(element, bounds_xy, 0)) { Segment3d seg = new Segment3d(new g3.Vector3d(uv.x, uv.y, bounds.Min.z), new g3.Vector3d(uv.x, uv.y, bounds.Max.z)); Tiling.Add(new ImplicitLine3d() { Segment = seg, Radius = lattice_radius }); } foreach (g3.Vector2d uv in TilingUtil.BoundedRegularTiling2(element, bounds_xz, 0)) { Segment3d seg = new Segment3d(new g3.Vector3d(uv.x, bounds.Min.y, uv.y), new g3.Vector3d(uv.x, bounds.Max.y, uv.y)); Tiling.Add(new ImplicitLine3d() { Segment = seg, Radius = lattice_radius }); } foreach (g3.Vector2d uv in TilingUtil.BoundedRegularTiling2(element, bounds_yz, 0)) { Segment3d seg = new Segment3d(new g3.Vector3d(bounds.Min.x, uv.x, uv.y), new g3.Vector3d(bounds.Max.x, uv.x, uv.y)); Tiling.Add(new ImplicitLine3d() { Segment = seg, Radius = lattice_radius }); } ImplicitNaryUnion3d lattice = new ImplicitNaryUnion3d() { Children = Tiling }; ImplicitIntersection3d lattice_clipped = new ImplicitIntersection3d() { A = lattice, B = shellMeshImplicit }; g3.MarchingCubes c = new g3.MarchingCubes(); c.Implicit = lattice_clipped; c.RootMode = g3.MarchingCubes.RootfindingModes.LerpSteps; c.RootModeSteps = 5; c.Bounds = lattice_clipped.Bounds(); c.CubeSize = c.Bounds.MaxDim / mesh_resolution; c.Bounds.Expand(3 * c.CubeSize); c.Generate(); MeshNormals.QuickCompute(c.Mesh); DA.SetData(0, c.Mesh); }
public bool Apply() { bool do_checks = false; if (do_checks) { Mesh.CheckValidity(); } /* * Remove parts of the mesh we don't want before we bother with anything else * TODO: maybe we need to repair orientation first? if we want to use MWN... */ do_remove_inside(); if (Cancelled()) { return(false); } int repeat_count = 0; repeat_all: /* * make sure orientation of connected components is consistent * TODO: what about mobius strip problems? */ repair_orientation(false); if (Cancelled()) { return(false); } /* * Do safe close-cracks to handle easy cases */ repair_cracks(true, RepairTolerance); if (Mesh.IsClosed()) { goto all_done; } if (Cancelled()) { return(false); } /* * Collapse tiny edges and then try easy cases again, and * then allow for handling of ambiguous cases */ collapse_all_degenerate_edges(RepairTolerance * 0.5, true); if (Cancelled()) { return(false); } repair_cracks(true, 2 * RepairTolerance); if (Cancelled()) { return(false); } repair_cracks(false, 2 * RepairTolerance); if (Cancelled()) { return(false); } if (Mesh.IsClosed()) { goto all_done; } /* * Possibly we have joined regions with different orientation (is it?), fix that * TODO: mobius strips again */ repair_orientation(false); if (Cancelled()) { return(false); } if (do_checks) { Mesh.CheckValidity(); } // get rid of any remaining single-triangles before we start filling holes remove_loners(); /* * Ok, fill simple holes. */ int nRemainingBowties = 0; int nHoles; bool bSawSpans; fill_trivial_holes(out nHoles, out bSawSpans); if (Cancelled()) { return(false); } if (Mesh.IsClosed()) { goto all_done; } /* * Now fill harder holes. If we saw spans, that means boundary loops could * not be resolved in some cases, do we disconnect bowties and try again. */ fill_any_holes(out nHoles, out bSawSpans); if (Cancelled()) { return(false); } if (bSawSpans) { disconnect_bowties(out nRemainingBowties); fill_any_holes(out nHoles, out bSawSpans); } if (Cancelled()) { return(false); } if (Mesh.IsClosed()) { goto all_done; } /* * We may have a closed mesh now but it might still have bowties (eg * tetrahedra sharing vtx case). So disconnect those. */ disconnect_bowties(out nRemainingBowties); if (Cancelled()) { return(false); } /* * If the mesh is not closed, we will do one more round to try again. */ if (repeat_count == 0 && Mesh.IsClosed() == false) { repeat_count++; goto repeat_all; } /* * Ok, we didn't get anywhere on our first repeat. If we are still not * closed, we will try deleting boundary triangles and repeating. * Repeat this N times. */ if (repeat_count <= ErosionIterations && Mesh.IsClosed() == false) { repeat_count++; MeshFaceSelection bdry_faces = new MeshFaceSelection(Mesh); foreach (int eid in MeshIterators.BoundaryEdges(Mesh)) { bdry_faces.SelectEdgeTris(eid); } MeshEditor.RemoveTriangles(Mesh, bdry_faces, true); goto repeat_all; } all_done: /* * Remove tiny edges */ if (MinEdgeLengthTol > 0) { collapse_all_degenerate_edges(MinEdgeLengthTol, false); } if (Cancelled()) { return(false); } /* * finally do global orientation */ repair_orientation(true); if (Cancelled()) { return(false); } if (do_checks) { Mesh.CheckValidity(); } /* * Might as well compact output mesh... */ Mesh = new DMesh3(Mesh, true); MeshNormals.QuickCompute(Mesh); return(true); }
public static void test_marching_cubes_implicits() { DMesh3 mesh = TestUtil.LoadTestInputMesh("bunny_solid.obj"); MeshTransforms.Translate(mesh, -mesh.CachedBounds.Center); double meshCellsize = mesh.CachedBounds.MaxDim / 32; MeshSignedDistanceGrid levelSet = new MeshSignedDistanceGrid(mesh, meshCellsize); levelSet.ExactBandWidth = 3; levelSet.UseParallel = true; levelSet.ComputeMode = MeshSignedDistanceGrid.ComputeModes.NarrowBandOnly; levelSet.Compute(); var meshIso = new DenseGridTrilinearImplicit(levelSet.Grid, levelSet.GridOrigin, levelSet.CellSize); ImplicitOffset3d offsetMeshIso = new ImplicitOffset3d() { A = meshIso, Offset = 2.0 }; double r = 15.0; ImplicitSphere3d sphere1 = new ImplicitSphere3d() { Origin = Vector3d.Zero, Radius = r }; ImplicitSphere3d sphere2 = new ImplicitSphere3d() { Origin = r * Vector3d.AxisX, Radius = r }; ImplicitAxisAlignedBox3d aabox1 = new ImplicitAxisAlignedBox3d() { AABox = new AxisAlignedBox3d(r * 0.5 * Vector3d.One, r, r * 0.75, r * 0.5) }; ImplicitBox3d box1 = new ImplicitBox3d() { Box = new Box3d(new Frame3f(r * 0.5 * Vector3d.One, Vector3d.One.Normalized), new Vector3d(r, r * 0.75, r * 0.5)) }; ImplicitLine3d line1 = new ImplicitLine3d() { Segment = new Segment3d(Vector3d.Zero, r * Vector3d.One), Radius = 3.0 }; ImplicitHalfSpace3d half1 = new ImplicitHalfSpace3d() { Origin = Vector3d.Zero, Normal = Vector3d.One.Normalized }; ImplicitUnion3d union = new ImplicitUnion3d() { A = sphere1, B = line1 }; ImplicitDifference3d difference = new ImplicitDifference3d() { A = meshIso, B = aabox1 }; ImplicitIntersection3d intersect = new ImplicitIntersection3d() { A = meshIso, B = half1 }; ImplicitNaryUnion3d nunion = new ImplicitNaryUnion3d() { Children = new List <BoundedImplicitFunction3d>() { offsetMeshIso, sphere1, sphere2 } }; ImplicitNaryDifference3d ndifference = new ImplicitNaryDifference3d() { A = offsetMeshIso, BSet = new List <BoundedImplicitFunction3d>() { sphere1, sphere2 } }; ImplicitBlend3d blend = new ImplicitBlend3d() { A = sphere1, B = sphere2 }; BoundedImplicitFunction3d root = intersect; AxisAlignedBox3d bounds = root.Bounds(); int numcells = 64; MarchingCubes c = new MarchingCubes(); c.RootMode = MarchingCubes.RootfindingModes.LerpSteps; c.RootModeSteps = 5; c.Implicit = root; c.Bounds = bounds; c.CubeSize = bounds.MaxDim / numcells; c.Bounds.Expand(3 * c.CubeSize); c.Generate(); MeshNormals.QuickCompute(c.Mesh); TestUtil.WriteTestOutputMesh(c.Mesh, "marching_cubes_implicit.obj"); }
protected virtual void compute_shell_extrude() { DMesh3 mesh = new DMesh3(MeshSource.GetDMeshUnsafe()); MeshNormals.QuickCompute(mesh); if (shell_direction == ShellDirections.Symmetric) { double thickness = shell_thickness * 0.5; DMesh3 outerMesh = new DMesh3(mesh); MeshExtrudeMesh outerExtrude = new MeshExtrudeMesh(outerMesh); outerExtrude.ExtrudedPositionF = (v, n, vid) => { return(v + thickness * (Vector3d)n); }; if (outerExtrude.Extrude() == false) { throw new Exception("MeshShellOp.compute_shell_extrude: outer Extrude() returned false!"); } MeshEditor.RemoveTriangles(outerMesh, outerExtrude.InitialTriangles); MeshExtrudeMesh innerExtrude = new MeshExtrudeMesh(mesh); innerExtrude.IsPositiveOffset = false; innerExtrude.ExtrudedPositionF = (v, n, vid) => { return(v - thickness * (Vector3d)n); }; if (innerExtrude.Extrude() == false) { throw new Exception("MeshShellOp.compute_shell_extrude: inner Extrude() returned false!"); } MeshEditor.RemoveTriangles(mesh, innerExtrude.InitialTriangles); MeshEditor.Append(mesh, outerMesh); if (cached_is_closed == false) { // cheating! MergeCoincidentEdges merge = new MergeCoincidentEdges(mesh); merge.Apply(); } } else { double thickness = (shell_direction == ShellDirections.Outer) ? shell_thickness : -shell_thickness; MeshExtrudeMesh extrude = new MeshExtrudeMesh(mesh); extrude.IsPositiveOffset = (shell_direction == ShellDirections.Outer); extrude.ExtrudedPositionF = (v, n, vid) => { return(v + thickness * (Vector3d)n); }; if (extrude.Extrude() == false) { throw new Exception("MeshShellOp.compute_shell_extrude: Extrude() returned false!"); } if (shell_surface_only && cached_is_closed) { MeshEditor.RemoveTriangles(mesh, extrude.InitialTriangles); if (shell_direction == ShellDirections.Inner) { mesh.ReverseOrientation(); } if (shell_direction == ShellDirections.Inner || shell_direction == ShellDirections.Outer) { mesh.AttachMetadata("is_partial", new object()); } } } if (is_invalidated()) { return; } ResultMesh = mesh; }