/// <summary> /// Set the position of the object frame for this SO without moving the mesh in the scene. /// The input frame is the new object frame. So, this is a frame "in scene coordinates" unless /// this object has a parent SceneObject (ie is not a child of Scene directly). In that case /// the frame needs to be specified relative to that SO. An easy way to do this is to via /// obj_pivot = GetLocalFrame(Object).FromFrame( SceneTransforms.SceneToObject(pivot_in_scene) ) /// TODO: specify frame coordpace as input argument? /// </summary> public void RepositionPivot(Frame3f objFrame) { //if (Parent is FScene == false) // throw new NotSupportedException("DMeshSO.RepositionMeshFrame: have not tested this!"); Frame3f curFrame = this.GetLocalFrame(CoordSpace.ObjectCoords); bool bNormals = mesh.HasVertexNormals; // map vertices to new frame foreach (int vid in mesh.VertexIndices()) { Vector3f v = (Vector3f)mesh.GetVertex(vid); v = curFrame.FromFrameP(ref v); v = objFrame.ToFrameP(ref v); mesh.SetVertex(vid, v); if (bNormals) { Vector3f n = mesh.GetVertexNormal(vid); n = curFrame.FromFrameV(ref n); n = objFrame.ToFrameV(ref n); mesh.SetVertexNormal(vid, n); } } // set new object frame SetLocalFrame(objFrame, CoordSpace.ObjectCoords); fast_mesh_update(bNormals, false); post_mesh_modified(); }
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(); }
public static void test_mesh_builders() { // test mesh builder DMesh3 origMesh = TestUtil.LoadTestMesh(Program.TEST_FILES_PATH + "bunny_open_base.obj"); float[] Vf = new float[origMesh.VertexCount * 3]; List <Vector3f> Vl = new List <Vector3f>(); int k = 0; foreach (Vector3d v in origMesh.Vertices()) { Vf[k++] = (float)v.x; Vf[k++] = (float)v.y; Vf[k++] = (float)v.z; Vl.Add((Vector3f)v); } double[] Nd = origMesh.NormalsBuffer.GetBufferCast <double>(); Vector3d[] Nl = new Vector3d[origMesh.VertexCount]; foreach (int vid in origMesh.VertexIndices()) { Nl[vid] = origMesh.GetVertexNormal(vid); } int[] Ti = origMesh.TrianglesBuffer.GetBuffer(); Index3i[] Tl = new Index3i[origMesh.TriangleCount]; foreach (int tid in origMesh.TriangleIndices()) { Tl[tid] = origMesh.GetTriangle(tid); } DMesh3 m1 = DMesh3Builder.Build(Vf, Ti, Nd); DMesh3 m2 = DMesh3Builder.Build(Vl, Tl, Nl); Util.gDevAssert(origMesh.IsSameMesh(m1, true)); Util.gDevAssert(origMesh.IsSameMesh(m2, true)); }
public void FastUpdateVertices(DMesh3 source, int[] source_vertices, bool bCopyNormals = false, bool bCopyColors = false) { int NV = source_vertices.Length; Vector3[] vertices = new Vector3[NV]; for (int i = 0; i < NV; ++i) { vertices[i] = (Vector3)source.GetVertex(source_vertices[i]); } mesh.vertices = vertices; if (bCopyNormals && source.HasVertexNormals) { Vector3[] normals = new Vector3[NV]; for (int i = 0; i < NV; ++i) { normals[i] = (Vector3)source.GetVertexNormal(source_vertices[i]); } mesh.normals = normals; } if (bCopyColors && source.HasVertexColors) { Color[] colors = new Color[NV]; for (int i = 0; i < NV; ++i) { colors[i] = (Color)source.GetVertexColor(source_vertices[i]); } mesh.colors = colors; } }
public fMesh(int[] triangles, DMesh3 source, int[] source_vertices, bool bCopyNormals = false, bool bCopyColors = false, bool bCopyUVs = false) { int NV = source_vertices.Length; Vector3[] vertices = new Vector3[NV]; for (int i = 0; i < NV; ++i) { vertices[i] = (Vector3)source.GetVertex(source_vertices[i]); } Mesh m = new Mesh(); m.vertices = vertices; if (NV > 65000 || triangles.Length / 3 > 65000) { m.indexFormat = UnityEngine.Rendering.IndexFormat.UInt32; } m.triangles = triangles; if (bCopyNormals && source.HasVertexNormals) { Vector3[] normals = new Vector3[NV]; for (int i = 0; i < NV; ++i) { normals[i] = (Vector3)source.GetVertexNormal(source_vertices[i]); } m.normals = normals; } else { m.RecalculateNormals(); } if (bCopyColors && source.HasVertexColors) { Color[] colors = new Color[NV]; for (int i = 0; i < NV; ++i) { colors[i] = (Color)source.GetVertexColor(source_vertices[i]); } m.colors = colors; } if (bCopyUVs && source.HasVertexUVs) { Vector2[] uvs = new Vector2[NV]; for (int i = 0; i < NV; ++i) { uvs[i] = source.GetVertexUV(source_vertices[i]); } m.uv = uvs; } mesh = m; }
public IEnumerator RunMainThreadProcessing(bool bSpawnBackgroundWrite = true) { int N = ExportMeshSOs.Count; ExportMeshes = new DMesh3[N]; MeshFrames = new Frame3f[N]; for (int k = 0; k < N; ++k) { DMeshSO so = ExportMeshSOs[k]; DMesh3 copy = new DMesh3(so.Mesh, false, MeshComponents.VertexColors | MeshComponents.VertexNormals); // if we have scaling or parent hierarchy, need to transform to scene in main // thread, because we have no way of storing transform stack currently if (so.GetLocalScale() != Vector3f.One || so.Parent != so.GetScene()) { foreach (int vid in copy.VertexIndices()) { Vector3d v = copy.GetVertex(vid); Vector3f n = copy.GetVertexNormal(vid); Frame3f f = new Frame3f(v, n); f = SceneTransforms.ObjectToScene(so, f); copy.SetVertex(vid, f.Origin); copy.SetVertexNormal(vid, f.Z); } MeshFrames[k] = Frame3f.Identity; } else { MeshFrames[k] = ExportMeshSOs[k].GetLocalFrame(CoordSpace.ObjectCoords); } ExportMeshes[k] = copy; yield return(null); } if (MainThreadWorkCompletedF != null) { MainThreadWorkCompletedF(); } DebugUtil.Log("MeshExporter: completed main thread processing"); if (bSpawnBackgroundWrite) { ThreadPool.QueueUserWorkItem((state) => { var result = RunBackgroundWrite(); if (OnCompletedF != null) { OnCompletedF(result); } }); } }
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); }
virtual public void Apply() { TargetSO.EditAndUpdateMesh((mesh) => { DMesh3 fromMesh = PreviewSO.Mesh; foreach (int vid in mesh.VertexIndices()) { mesh.SetVertex(vid, fromMesh.GetVertex(vid)); mesh.SetVertexNormal(vid, fromMesh.GetVertexNormal(vid)); } }, GeometryEditTypes.VertexDeformation); }
public void SaveCurrentNormals() { if (ActiveChange.NewNormals != null) { foreach (var pair in ModifiedV) { Vector3f normal = Mesh.GetVertexNormal(pair.Key); ActiveChange.NewNormals[pair.Value] = normal; } } }
public static void AppendMeshSO(DMeshSO appendTo, DMeshSO append) { FScene scene = appendTo.GetScene(); if (scene.IsSelected(appendTo)) { scene.Deselect(appendTo); } if (scene.IsSelected(append)) { scene.Deselect(append); } Frame3f f1 = appendTo.GetLocalFrame(CoordSpace.ObjectCoords); Vector3f scale1 = appendTo.GetLocalScale(); Frame3f f2 = append.GetLocalFrame(CoordSpace.ObjectCoords); Vector3f scale2 = append.GetLocalScale(); DMesh3 mesh1 = appendTo.Mesh; DMesh3 mesh2 = append.Mesh; foreach (int vid in mesh2.VertexIndices()) { // convert point in mesh2 to scene coords Vector3f v2 = (Vector3f)mesh2.GetVertex(vid); v2 *= scale2; Vector3f v2s = f2.FromFrameP(v2); // transfer that scene coord into local coords of mesh1 Vector3f v2in1 = f1.ToFrameP(v2s); v2in1 /= scale1; mesh2.SetVertex(vid, v2in1); if (mesh1.HasVertexNormals && mesh2.HasVertexNormals) { Vector3f n = mesh2.GetVertexNormal(vid); Vector3f ns = f2.FromFrameV(n); Vector3f ns2 = f1.ToFrameV(ns); mesh2.SetVertexNormal(vid, ns2); } } MeshEditor editor = new MeshEditor(mesh1); editor.AppendMesh(mesh2); appendTo.NotifyMeshEdited(); // [TODO] change record! scene.RemoveSceneObject(append, false); }
public static void test_points() { string filename = "c:\\scratch\\bunny_solid.obj"; DMesh3 mesh = StandardMeshReader.ReadMesh(filename); PointSplatsGenerator pointgen = new PointSplatsGenerator() { PointIndices = IntSequence.Range(mesh.VertexCount), PointF = mesh.GetVertex, NormalF = (vid) => { return((Vector3d)mesh.GetVertexNormal(vid)); }, Radius = mesh.CachedBounds.DiagonalLength * 0.01 }; DMesh3 pointMesh = pointgen.Generate().MakeDMesh(); StandardMeshWriter.WriteMesh("c:\\scratch\\POINTS.obj", pointMesh, WriteOptions.Defaults); }
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"); } } } }
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); }
public fMesh(int[] triangles, DMesh3 source, int[] source_vertices, bool bCopyNormals = false, bool bCopyColors = false) { int NV = source_vertices.Length; Vector3[] vertices = new Vector3[NV]; for (int i = 0; i < NV; ++i) { vertices[i] = (Vector3)source.GetVertex(source_vertices[i]); } Mesh m = new Mesh(); m.vertices = vertices; m.triangles = triangles; if (bCopyNormals && source.HasVertexNormals) { Vector3[] normals = new Vector3[NV]; for (int i = 0; i < NV; ++i) { normals[i] = (Vector3)source.GetVertexNormal(source_vertices[i]); } m.normals = normals; } else { m.RecalculateNormals(); } if (bCopyColors && source.HasVertexColors) { Color[] colors = new Color[NV]; for (int i = 0; i < NV; ++i) { colors[i] = (Color)source.GetVertexColor(source_vertices[i]); } m.colors = colors; } unitymesh = m; }
/// <summary> /// copy vertex positions from sourceMesh. /// [TODO] perhaps can refactor into a call to EditAndUpdateMesh() ? /// </summary> public void UpdateVertices(DMesh3 sourceMesh, bool bNormals = true, bool bColors = true) { if (sourceMesh.MaxVertexID != mesh.MaxVertexID) { throw new Exception("DMeshSO.UpdateVertexPositions: not enough positions provided!"); } bNormals &= sourceMesh.HasVertexNormals; if (bNormals && mesh.HasVertexNormals == false) { mesh.EnableVertexNormals(Vector3f.AxisY); } bColors &= sourceMesh.HasVertexColors; if (bColors && mesh.HasVertexColors == false) { mesh.EnableVertexColors(Colorf.White); } lock (mesh_write_lock) { foreach (int vid in mesh.VertexIndices()) { Vector3d sourceV = sourceMesh.GetVertex(vid); mesh.SetVertex(vid, sourceV); if (bNormals) { Vector3f sourceN = sourceMesh.GetVertexNormal(vid); mesh.SetVertexNormal(vid, sourceN); } if (bColors) { Vector3f sourceC = sourceMesh.GetVertexColor(vid); mesh.SetVertexColor(vid, sourceC); } } } fast_mesh_update(bNormals, bColors); post_mesh_modified(); }
protected override void SolveInstance(IGH_DataAccess DA) { DMesh3_goo goo = null; DA.GetData(0, ref goo); DMesh3 mesh = new DMesh3(goo.Value); List <Rhino.Geometry.Vector3d> vecs = new List <Rhino.Geometry.Vector3d>(); if (!mesh.HasVertexNormals) { var normals = new MeshNormals(mesh); normals.Compute(); } foreach (var ind in mesh.VertexIndices()) { vecs.Add(mesh.GetVertexNormal(ind).ToRhinoVec()); } DA.SetDataList(0, vecs); }
public virtual void Update() { if (MeshSource == null) { throw new Exception("PlaneBandExpansionOp: must set valid MeshSource to compute!"); } IMesh imesh = MeshSource.GetIMesh(); if (imesh.HasVertexNormals == false) { throw new Exception("PlaneBandExpansionOp: input mesh does not have surface normals..."); } if (imesh is DMesh3 == false) { throw new Exception("RegionOffsetOp: in current implementation, input mesh must be a DMesh3. Ugh."); } DMesh3 mesh = imesh as DMesh3; IList <int> faces = IndexSource.GetIndices(); // [RMS] this is all f'n ugly! MeshVertexSelection selection = new MeshVertexSelection(mesh); selection.SelectTriangleVertices(faces); // ugly List <Vector2d> seeds = new List <Vector2d>(); foreach (int vid in selection) { foreach (int nbrvid in mesh.VtxVerticesItr(vid)) { if (selection.IsSelected(nbrvid) == false) { seeds.Add(new Vector2d(vid, 0)); break; } } } Func <int, int, float> distanceF = (a, b) => { return((float)mesh.GetVertex(a).Distance(mesh.GetVertex(b))); }; Func <int, bool> nodeF = (vid) => { return(selection.IsSelected(vid)); }; DijkstraGraphDistance dijkstra = new DijkstraGraphDistance(mesh.MaxVertexID, true, nodeF, distanceF, mesh.VtxVerticesItr, seeds); dijkstra.Compute(); float maxDist = dijkstra.MaxDistance; Displacement.Clear(); Displacement.Resize(mesh.MaxVertexID); // todo: can do this in parallel... foreach (int vid in selection) { //Vector3d v = mesh.GetVertex(vid); // [TODO]... double dist = maxDist - dijkstra.GetDistance(vid); double falloff = MathUtil.WyvillFalloff(dist, maxDist * 0.0, maxDist); Vector3d n = mesh.GetVertexNormal(vid); n = n - n.Dot(normal) * normal; n.Normalize(); Displacement[vid] = falloff * offset_distance * n; } // smooth it? result_valid = true; }
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(); } } } DMeshAABBTree3 spatial = (Spatial != null && testAgainstMesh == Mesh) ? Spatial : new DMeshAABBTree3(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); }
protected override void Update_GenerateMap() { base.begin_update(); if (MeshSource == null) { throw new Exception("EnclosedRegionOffsetOp: must set valid MeshSource to compute!"); } if (MeshSource.HasSpatial == false) { throw new Exception("EnclosedRegionOffsetOp: MeshSource must have spatial data structure!"); } IMesh imesh = MeshSource.GetIMesh(); if (imesh.HasVertexNormals == false) { throw new Exception("EnclosedRegionOffsetOp: input mesh does not have surface normals..."); } if (imesh is DMesh3 == false) { throw new Exception("EnclosedRegionOffsetOp: in current implementation, input mesh must be a DMesh3. Ugh."); } DMesh3 mesh = imesh as DMesh3; ISpatial spatial = MeshSource.GetSpatial(); DCurve3 curve = new DCurve3(CurveSource.GetICurve()); MeshFacesFromLoop loop = new MeshFacesFromLoop(mesh, curve, spatial); // [RMS] this is all f'n ugly! MeshVertexSelection selection = new MeshVertexSelection(mesh); selection.SelectTriangleVertices(loop.InteriorTriangles); // [TODO] do this inline w/ loop below? but then no maxdist! Dictionary <int, double> dists = new Dictionary <int, double>(); double max_dist = 0; foreach (int vid in selection) { Vector3d v = mesh.GetVertex(vid); int inearseg; double nearsegt; double min_dist_sqr = curve.DistanceSquared(v, out inearseg, out nearsegt); min_dist_sqr = Math.Sqrt(min_dist_sqr); max_dist = Math.Max(min_dist_sqr, max_dist); dists[vid] = min_dist_sqr; } lock (Displacement) { Displacement.Clear(); Displacement.Resize(mesh.MaxVertexID); // todo: can do this in parallel... foreach (int vid in selection) { //Vector3d v = mesh.GetVertex(vid); // [TODO]... double dist = max_dist - dists[vid]; double falloff = Falloff.FalloffT(dist / max_dist); Vector3d n = mesh.GetVertexNormal(vid); n = n - n.Dot(normal) * normal; n.Normalize(); Displacement[vid] = falloff * offset_distance * n; } } // smooth it? base.complete_update(); }
public virtual void Update() { if (MeshSource == null) { throw new Exception("EnclosedRegionOffsetOp: must set valid MeshSource to compute!"); } if (MeshSource.HasSpatial == false) { throw new Exception("EnclosedRegionOffsetOp: MeshSource must have spatial data structure!"); } IMesh imesh = MeshSource.GetIMesh(); if (imesh.HasVertexNormals == false) { throw new Exception("EnclosedRegionOffsetOp: input mesh does not have surface normals..."); } if (imesh is DMesh3 == false) { throw new Exception("RegionOffsetOp: in current implementation, input mesh must be a DMesh3. Ugh."); } DMesh3 mesh = imesh as DMesh3; ISpatial spatial = MeshSource.GetSpatial(); DCurve3 curve = new DCurve3(CurveSource.GetICurve()); MeshFacesFromLoop loop = new MeshFacesFromLoop(mesh, curve, spatial); // extract submesh RegionOperator op = new RegionOperator(mesh, loop.InteriorTriangles); DMesh3 submesh = op.Region.SubMesh; // find boundary verts and nbr ring HashSet <int> boundaryV = new HashSet <int>(MeshIterators.BoundaryEdgeVertices(submesh)); HashSet <int> boundaryNbrs = new HashSet <int>(); foreach (int vid in boundaryV) { foreach (int nbrvid in submesh.VtxVerticesItr(vid)) { if (boundaryV.Contains(nbrvid) == false) { boundaryNbrs.Add(nbrvid); } } } // [TODO] maybe should be not using vertex normal here? // use an averaged normal, or a constant for patch? // offset mesh if requested if (Math.Abs(offset_distance) > 0.0001) { foreach (int vid in submesh.VertexIndices()) { if (boundaryV.Contains(vid)) { continue; } // if inner ring is non-zero, then it gets preserved below, and // creates a crease... //double dist = boundaryNbrs.Contains(vid) ? (offset_distance / 2) : offset_distance; double dist = boundaryNbrs.Contains(vid) ? 0 : offset_distance; submesh.SetVertex(vid, submesh.GetVertex(vid) + (float)dist * submesh.GetVertexNormal(vid)); } } //double t = MathUtil.Clamp(1.0 - SmoothAlpha, 0.1, 1.0); double t = 1.0 - SmoothAlpha; t = t * t; double boundary_t = 5.0; double ring_t = 1.0; // smooth submesh, with boundary-ring constraints LaplacianMeshSmoother smoother = new LaplacianMeshSmoother(submesh); foreach (int vid in submesh.VertexIndices()) { if (boundaryV.Contains(vid)) { smoother.SetConstraint(vid, submesh.GetVertex(vid), boundary_t, true); } else if (boundaryNbrs.Contains(vid)) { smoother.SetConstraint(vid, submesh.GetVertex(vid), ring_t); } else { smoother.SetConstraint(vid, submesh.GetVertex(vid), t); } } smoother.SolveAndUpdateMesh(); // turn into displacement vectors Displacement.Clear(); Displacement.Resize(mesh.MaxVertexID); foreach (int subvid in op.Region.SubMesh.VertexIndices()) { Vector3d subv = op.Region.SubMesh.GetVertex(subvid); int basevid = op.Region.SubToBaseV[subvid]; Vector3d basev = op.Region.BaseMesh.GetVertex(basevid); Displacement[basevid] = subv - basev; } result_valid = true; }
public virtual void Update() { base.begin_update(); if (MeshSource == null) { throw new Exception("MeshVertexDisplacementOp: must set valid MeshSource to compute!"); } if (DisplacementSource == null) { throw new Exception("MeshVertexDisplacementOp: must set valid DisplacementSource to compute!"); } DMesh3 meshIn = MeshSource.GetDMeshUnsafe(); IVectorDisplacement displace = DisplacementSource.GetDisplacement(); if (displace.Count != 0 && displace.Count != meshIn.MaxVertexID) { throw new Exception("MeshVertexDisplacementOp: inconsistent counts " + displace.Count.ToString() + " != " + meshIn.MaxVertexID.ToString()); } DMesh3 mesh = new DMesh3(meshIn, MeshHints.None); //if (!mesh.HasVertexNormals) // MeshNormals.QuickCompute(mesh); if (displace.Count > 0) { gParallel.ForEach(mesh.VertexIndices(), (vid) => { Vector3d dv = displace.GetDisplacementForIndex(vid); //Vector3f n = mesh.GetVertexNormal(vid); Vector3d v = mesh.GetVertex(vid); v += dv; mesh.SetVertex(vid, v); }); if (enable_heat_map) { // compute max displace len ColorMap map = new ColorMap(); map.AddPoint(0, Colorf.CornflowerBlue); float d = (float)HeatMapMaxDistance; map.AddPoint(d, Colorf.Orange); map.AddPoint(2 * d, Colorf.VideoYellow); map.AddPoint(4 * d, Colorf.VideoRed); map.AddPoint(-d, Colorf.VideoMagenta); float max_displace = d; gParallel.ForEach(mesh.VertexIndices(), (vid) => { Vector3f dv = (Vector3f)displace.GetDisplacementForIndex(vid); Vector3f n = mesh.GetVertexNormal(vid); float sign = n.Dot(dv) > 0 ? 1 : -1; Colorf c = map.Linear(dv.Length * sign); Colorf existing_c = mesh.GetVertexColor(vid); float preserve__max = max_displace / 2; float t = MathUtil.Clamp(dv.Length / preserve__max, 0.0f, 1.0f); c = (1.0f - t) * existing_c + (t) * c; mesh.SetVertexColor(vid, c); //float t = MathUtil.Clamp(dv.Length / max_displace, -1.0f, 1.0f); //mesh.SetVertexColor(vid, t * Colorf.Orange); }); } } MeshNormals.QuickCompute(mesh); DisplacedMesh = mesh; base.complete_update(); }