protected override void on_curve_validated() { if (previewGO != null) { RemoveGO((fGameObject)previewGO); previewGO.Destroy(); } if (EnableRegionOverlay) { if (TargetModelSO == null) { throw new InvalidOperationException("EnclosedPatchSO.on_curve_validated: curve is not connected to a Target"); } if (TransformMode != OutputCurveTransform.ToTargetSO) { throw new InvalidOperationException("EnclosedPatchSO.on_curve_validated: curve is not transformed to TargetSO"); } DCurve3 target_curve = RequestCurveCopyFromMainThread(); MeshFacesFromLoop loop = new MeshFacesFromLoop(TargetModel.SourceMesh, target_curve, TargetModel.SourceSpatial); MeshFaceSelection face_selection = loop.ToSelection(); DSubmesh3 submesh = new DSubmesh3(TargetModel.SourceMesh, face_selection, face_selection.Count); MeshNormals normals = new MeshNormals(submesh.SubMesh); normals.Compute(); foreach (int vid in submesh.SubMesh.VertexIndices()) { Vector3d n = normals.Normals[vid]; Vector3d v = submesh.SubMesh.GetVertex(vid); v += 0.1 * n; v = SceneTransforms.TransformTo(v, TargetModelSO, this); submesh.SubMesh.SetVertex(vid, v); } previewGO = GameObjectFactory.CreateMeshGO("patch", new fMesh(submesh.SubMesh), false, true); previewGO.SetMaterial(previewMaterial, true); previewGO.SetLayer(FPlatform.WidgetOverlayLayer); previewGO.SetIgnoreMaterialChanges(); AppendNewGO(previewGO, root, false); } }
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; }
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(); }