void update_curvature(int vid) { double angle_sum = 0; exterior_angle_sums.TryGetValue(vid, out angle_sum); foreach (int tid in fillmesh.VtxTrianglesItr(vid)) { Index3i et = fillmesh.GetTriangle(tid); int idx = IndexUtil.find_tri_index(vid, ref et); angle_sum += fillmesh.GetTriInternalAngleR(tid, idx); } curvatures[vid] = angle_sum - MathUtil.TwoPI; }
// TODO: // - (in merge coincident) don't merge tris with same/opposite normals (option) // - after orienting components, try to find adjacent open components and // transfer orientation between them // - orient via nesting public void OrientComponents() { Components = new List <Component>(); HashSet <int> remaining = new HashSet <int>(Mesh.TriangleIndices()); List <int> stack = new List <int>(); while (remaining.Count > 0) { Component c = new Component(); c.triangles = new List <int>(); stack.Clear(); int start = remaining.First(); remaining.Remove(start); c.triangles.Add(start); stack.Add(start); while (stack.Count > 0) { int cur = stack[stack.Count - 1]; stack.RemoveAt(stack.Count - 1); Index3i tcur = Mesh.GetTriangle(cur); Index3i nbrs = Mesh.GetTriNeighbourTris(cur); for (int j = 0; j < 3; ++j) { int nbr = nbrs[j]; if (remaining.Contains(nbr) == false) { continue; } int a = tcur[j]; int b = tcur[(j + 1) % 3]; Index3i tnbr = Mesh.GetTriangle(nbr); if (IndexUtil.find_tri_ordered_edge(b, a, ref tnbr) == DMesh3.InvalidID) { Mesh.ReverseTriOrientation(nbr); } stack.Add(nbr); remaining.Remove(nbr); c.triangles.Add(nbr); } } Components.Add(c); } }
protected override void update_vertices(FScene s) { if (Target.Timestamp == target_timestamp) { return; } target_timestamp = Target.Timestamp; DMesh3 Mesh = Target.Mesh; for (int i = 0; i < VertexCount; ++i) { SurfaceVertexRef r = SurfacePoints[i]; Vector3d vSum = Vector3d.Zero; Frame3f f = Mesh.GetTriFrame(r.tid); Index3i tv = Mesh.GetTriangle(r.tid); for (int j = 0; j < 3; ++j) { f.Origin = (Vector3f)Mesh.GetVertex(tv[j]); Vector3d v = f.FromFrameP(r.offsets[j]); vSum += v; } vSum /= 3; this[i] = SceneTransforms.ObjectToSceneP(Target, vSum); } }
public override void AppendVertex(Vector3d v) { base.AppendVertex(v); // map v to mesh v = SceneTransforms.SceneToObjectP(Target, v); // TODO encode vertices by normals ?? DMesh3 Mesh = Target.Mesh; DMeshAABBTree3 Spatial = Target.Spatial; SurfaceVertexRef r = new SurfaceVertexRef(); r.tid = Spatial.FindNearestTriangle(v); Frame3f f = Mesh.GetTriFrame(r.tid); Index3i tv = Mesh.GetTriangle(r.tid); for (int j = 0; j < 3; ++j) { f.Origin = (Vector3f)Mesh.GetVertex(tv[j]); Vector3d dv = f.ToFrameP(v); r.offsets[j] = dv; } SurfacePoints.Add(r); if (Curve.VertexCount != SurfacePoints.Count) { throw new Exception("SurfaceCurvePreview: counts are out of sync!!"); } }
public static Mesh ToMesh(this DMesh3 mesh) { var outMesh = new Mesh(); int[] mapV = new int[mesh.MaxVertexID]; int nAccumCountV = 0; foreach (int vi in mesh.VertexIndices()) { mapV[vi] = nAccumCountV++; Vector3d v = mesh.GetVertex(vi); outMesh.Vertices.Add(new Vector3(v[0], v[1], v[2])); } foreach (int ti in mesh.TriangleIndices()) { Index3i t = mesh.GetTriangle(ti); t[0] = mapV[t[0]]; t[1] = mapV[t[1]]; t[2] = mapV[t[2]]; outMesh.Faces.Add(t[0], t[1], t[2], outMesh.Vertices); } return(outMesh); }
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)); }
protected override void SolveInstance(IGH_DataAccess DA) { DMesh3_goo goo = null; DA.GetData(0, ref goo); DMesh3 mesh = new DMesh3(goo.Value); List <Point3d> vertices = new List <Point3d>(); List <MeshFace> faces = new List <MeshFace>(); List <Color> cols = new List <Color>(); List <int> v_i = new List <int>(); List <int> f_i = new List <int>(); foreach (var ind in mesh.VertexIndices()) { v_i.Add(ind); vertices.Add(mesh.GetVertex(ind).ToRhinoPt()); var col = mesh.GetVertexColor(ind); cols.Add(Color.FromArgb((int)(col.x * 255), (int)(col.y * 255), (int)(col.z * 255))); } foreach (var ind in mesh.TriangleIndices()) { f_i.Add(ind); var tri = mesh.GetTriangle(ind); faces.Add(new MeshFace(tri.a, tri.b, tri.c)); } DA.SetDataList(0, v_i); DA.SetDataList(1, vertices); DA.SetDataList(2, f_i); DA.SetDataList(3, faces); DA.SetDataList(4, cols); }
// [RMS] this only tests some basic cases... public static void test_Laplacian_deformer() { // compact version DMesh3 mesh = new DMesh3(TestUtil.MakeRemeshedCappedCylinder(1.0), true); Debug.Assert(mesh.IsCompact); AxisAlignedBox3d bounds = mesh.GetBounds(); TestUtil.WriteTestOutputMesh(mesh, "laplacian_deformer_before.obj"); List <IMesh> result_meshes = new List <IMesh>(); LaplacianMeshDeformer deformer = new LaplacianMeshDeformer(mesh); int ti = MeshQueries.FindNearestTriangle_LinearSearch(mesh, new Vector3d(2, 5, 2)); int v_pin = mesh.GetTriangle(ti).a; List <int> constraints = new List <int>() { v_pin }; double consPin = 10; double consBottom = 10; foreach (int vid in constraints) { result_meshes.Add(TestUtil.MakeMarker(mesh.GetVertex(vid), (vid == 0) ? 0.2f : 0.1f, Colorf.Red)); } foreach (int vid in mesh.VertexIndices()) { Vector3d v = mesh.GetVertex(vid); bool bottom = (v.y - bounds.Min.y) < 0.01f; if (constraints.Contains(vid)) { deformer.SetConstraint(vid, v + Vector3f.AxisY, consPin, false); } if (bottom) { deformer.SetConstraint(vid, v, consBottom, false); } } deformer.SolveAndUpdateMesh(); result_meshes.Add(mesh); TestUtil.WriteTestOutputMeshes(result_meshes, "laplacian_deformer_after.obj"); }
public void Precompute_NearestTriangleNormals() { int N = DisplaceMesh.MaxTriangleID; TriVtxNormalDisplacements = new TriVtxNormalsDisplace[N]; update_vertex_frames(); //foreach ( int vid in DisplaceMesh.VertexIndices() ) { gParallel.ForEach <int>(DisplaceMesh.VertexIndices(), (vid) => { Vector3f pos = (Vector3f)DisplaceMesh.GetVertex(vid); int tid = BaseSpatial.FindNearestTriangle(pos); Index3i tri = BaseMesh.GetTriangle(tid); Vector3f dv0 = VtxFrames[tri.a].ToFrameP(pos); Vector3f dv1 = VtxFrames[tri.b].ToFrameP(pos); Vector3f dv2 = VtxFrames[tri.c].ToFrameP(pos); TriVtxNormalDisplacements[vid] = new TriVtxNormalsDisplace() { tID = tid, dv0 = dv0, dv1 = dv1, dv2 = dv2 }; }); }
public static void test_local_param() { //DMesh3 mesh = TestUtil.LoadTestInputMesh("plane_250v.obj"); //DMesh3 mesh = TestUtil.LoadTestInputMesh("hemisphere_nicemesh_3k.obj"); DMesh3 mesh = TestUtil.LoadTestInputMesh("bunny_open_base.obj"); mesh.EnableVertexUVs(Vector2f.Zero); DMeshAABBTree3 spatial = new DMeshAABBTree3(mesh); spatial.Build(); //int tid = spatial.FindNearestTriangle(Vector3d.Zero); //Frame3f seedF = new Frame3f(Vector3d.Zero, Vector3d.AxisY); int tid = 3137; Frame3f seedF = mesh.GetTriFrame(tid); Index3i seedNbrs = mesh.GetTriangle(tid); MeshLocalParam param = new MeshLocalParam(mesh.MaxVertexID, mesh.GetVertexf, mesh.GetVertexNormal, mesh.VtxVerticesItr); param.ComputeToMaxDistance(seedF, seedNbrs, float.MaxValue); float fR = param.MaxUVDistance; param.TransformUV(0.5f / fR, 0.5f * Vector2f.One); param.ApplyUVs((vid, uv) => { mesh.SetVertexUV(vid, uv); }); TestUtil.SetColorsFromScalarF(mesh, (vid) => { return(param.GetUV(vid).Distance(0.5f * Vector2f.One)); }, new Vector2f(0, 0.5f)); OBJWriter writer = new OBJWriter(); var s = new System.IO.StreamWriter(Program.TEST_OUTPUT_PATH + "mesh_local_param.obj", false); List <WriteMesh> wm = new List <WriteMesh>() { new WriteMesh(mesh) }; WriteOptions opt = new WriteOptions() { bCombineMeshes = false, bWriteGroups = false, bPerVertexColors = true, bPerVertexUVs = true, AsciiHeaderFunc = () => { return("mttllib checkerboard.mtl\r\nusemtl checkerboard\r\n"); } }; writer.Write(s, wm, opt); s.Close(); }
protected override Result RunCommand(RhinoDoc doc, RunMode mode) { DMesh3 mesh = new DMesh3(MakeRemeshedCappedCylinder(1.0), true); AxisAlignedBox3d bounds = mesh.GetBounds(); List <IMesh> result_meshes = new List <IMesh>(); LaplacianMeshDeformer deformer = new LaplacianMeshDeformer(mesh); // constrain bottom points foreach (int vid in mesh.VertexIndices()) { g3.Vector3d v = mesh.GetVertex(vid); bool bottom = (v.y - bounds.Min.y) < 0.01f; if (bottom) { deformer.SetConstraint(vid, v, 10); } } // constrain one other vtx int ti = MeshQueries.FindNearestTriangle_LinearSearch(mesh, new g3.Vector3d(2, 5, 2)); int v_pin = mesh.GetTriangle(ti).a; g3.Vector3d cons_pos = mesh.GetVertex(v_pin); cons_pos += new g3.Vector3d(0.5, 0.5, 0.5); deformer.SetConstraint(v_pin, cons_pos, 10); deformer.Initialize(); g3.Vector3d[] resultV = new g3.Vector3d[mesh.MaxVertexID]; deformer.Solve(resultV); foreach (int vid in mesh.VertexIndices()) { mesh.SetVertex(vid, resultV[vid]); } var rhinoMesh = GopherUtil.ConvertToRhinoMesh(mesh); doc.Objects.AddMesh(rhinoMesh); return(Result.Success); }
// [RMS] this only tests some basic cases... public static void test_LaplacianDeformation() { // compact version DMesh3 mesh = new DMesh3(TestUtil.MakeRemeshedCappedCylinder(1.0), true); Debug.Assert(mesh.IsCompact); AxisAlignedBox3d bounds = mesh.GetBounds(); List <IMesh> result_meshes = new List <IMesh>(); LaplacianMeshDeformer deformer = new LaplacianMeshDeformer(mesh); // constrain bottom points foreach (int vid in mesh.VertexIndices()) { Vector3d v = mesh.GetVertex(vid); bool bottom = (v.y - bounds.Min.y) < 0.01f; if (bottom) { deformer.SetConstraint(vid, v, 10); } } // constrain one other vtx int ti = MeshQueries.FindNearestTriangle_LinearSearch(mesh, new Vector3d(2, 5, 2)); int v_pin = mesh.GetTriangle(ti).a; Vector3d cons_pos = mesh.GetVertex(v_pin); cons_pos += new Vector3d(0.5, 0.5, 0.5); deformer.SetConstraint(v_pin, cons_pos, 10); result_meshes.Add(TestUtil.MakeMarker(mesh.GetVertex(v_pin), 0.2f, Colorf.Red)); deformer.Initialize(); Vector3d[] resultV = new Vector3d[mesh.MaxVertexID]; deformer.Solve(resultV); foreach (int vid in mesh.VertexIndices()) { mesh.SetVertex(vid, resultV[vid]); } result_meshes.Add(mesh); TestUtil.WriteDebugMeshes(result_meshes, "___LAPLACIAN_result.obj"); }
private bool IsInRange(DMesh3 mesh, int triIndexOriginal, int triIndex, double rangeSquared) { var triOriginal = mesh.GetTriCentroid(triIndexOriginal); var tri = mesh.GetTriangle(triIndex); var v1 = mesh.GetVertex(tri.a); var v2 = mesh.GetVertex(tri.b); var v3 = mesh.GetVertex(tri.c); if (v1.DistanceSquared(triOriginal) < rangeSquared) { return(true); } if (v2.DistanceSquared(triOriginal) < rangeSquared) { return(true); } if (v3.DistanceSquared(triOriginal) < rangeSquared) { return(true); } return(false); }
IntrRay3Triangle3 find_added_hit(ref Ray3d ray, out int hit_tid) { hit_tid = DMesh3.InvalidID; IntrRay3Triangle3 nearest = null; double dNearT = double.MaxValue; Triangle3d tri = new Triangle3d(); foreach (int tid in AddedT) { Index3i tv = EditMesh.GetTriangle(tid); tri.V0 = EditMesh.GetVertex(tv.a); tri.V1 = EditMesh.GetVertex(tv.b); tri.V2 = EditMesh.GetVertex(tv.c); IntrRay3Triangle3 intr = new IntrRay3Triangle3(ray, tri); if (intr.Find() && intr.RayParameter < dNearT) { dNearT = intr.RayParameter; hit_tid = tid; nearest = intr; } } return(nearest); }
int[] insert_points(Vector3d[] points, DMesh3 mesh) { int[] MapV = new int[points.Length]; HashSet <int> newV = new HashSet <int>(); for (int i = 0; i < points.Length; ++i) { MapV[i] = DMesh3.InvalidID; Vector3d pt = points[i]; pt.Normalize(); Ray3d ray = new Ray3d(Vector3d.Zero, pt); int hit_tid = MeshQueries.FindHitTriangle_LinearSearch(mesh, ray); if (hit_tid == DMesh3.InvalidID) { continue; } Index3i hit_tri = mesh.GetTriangle(hit_tid); IntrRay3Triangle3 intr = MeshQueries.TriangleIntersection(mesh, hit_tid, ray); Vector3d bary = intr.TriangleBaryCoords; bool done = false; for (int j = 0; j < 3 && done == false; ++j) { if (bary[j] > 0.9) { // hit-vertex case if (newV.Contains(hit_tri[j]) == false) { MapV[i] = hit_tri[j]; newV.Add(MapV[i]); done = true; } } else if (bary[j] < 0.1) { // hit-edge case DMesh3.EdgeSplitInfo split_info; MeshResult splitResult = mesh.SplitEdge(hit_tri[(j + 1) % 3], hit_tri[(j + 2) % 3], out split_info); if (splitResult == MeshResult.Ok) { MapV[i] = split_info.vNew; newV.Add(MapV[i]); mesh.SetVertex(split_info.vNew, points[i]); done = true; } } } if (done) { continue; } DMesh3.PokeTriangleInfo poke_info; MeshResult result = mesh.PokeTriangle(hit_tid, out poke_info); if (result == MeshResult.Ok) { MapV[i] = poke_info.new_vid; newV.Add(MapV[i]); mesh.SetVertex(poke_info.new_vid, points[i]); } } return(MapV); }
// [RMS] this only tests some basic cases... public static void test_Laplacian() { // compact version DMesh3 mesh = new DMesh3(TestUtil.MakeRemeshedCappedCylinder(1.0), true); Debug.Assert(mesh.IsCompact); AxisAlignedBox3d bounds = mesh.GetBounds(); TestUtil.WriteDebugMesh(mesh, "___CG_before.obj"); List <IMesh> result_meshes = new List <IMesh>(); // make uniform laplacian matrix int N = mesh.VertexCount; SymmetricSparseMatrix M = new SymmetricSparseMatrix(); //DenseMatrix M = new DenseMatrix(N, N); double[] Px = new double[N], Py = new double[N], Pz = new double[N]; int[] nbr_counts = new int[N]; for (int vid = 0; vid < N; ++vid) { nbr_counts[vid] = mesh.GetVtxEdgeCount(vid); } int ti = MeshQueries.FindNearestTriangle_LinearSearch(mesh, new Vector3d(2, 5, 2)); int v_pin = mesh.GetTriangle(ti).a; List <int> constraints = new List <int>() { v_pin }; double consW = 10; double consBottom = 10; foreach (int vid in constraints) { result_meshes.Add(TestUtil.MakeMarker(mesh.GetVertex(vid), (vid == 0) ? 0.2f : 0.1f, Colorf.Red)); } for (int vid = 0; vid < N; ++vid) { int n = nbr_counts[vid]; Vector3d v = mesh.GetVertex(vid), c = Vector3d.Zero; Px[vid] = v.x; Py[vid] = v.y; Pz[vid] = v.z; bool bottom = (v.y - bounds.Min.y) < 0.01f; double sum_w = 0; foreach (int nbrvid in mesh.VtxVerticesItr(vid)) { int n2 = nbr_counts[nbrvid]; // weight options //double w = -1; double w = -1.0 / Math.Sqrt(n + n2); //double w = -1.0 / n; M.Set(vid, nbrvid, w); c += w * mesh.GetVertex(nbrvid); sum_w += w; } sum_w = -sum_w; M.Set(vid, vid, sum_w); // add soft constraints if (constraints.Contains(vid)) { M.Set(vid, vid, sum_w + consW); } else if (bottom) { M.Set(vid, vid, sum_w + consBottom); } } // compute laplacians double[] MLx = new double[N], MLy = new double[N], MLz = new double[N]; M.Multiply(Px, MLx); M.Multiply(Py, MLy); M.Multiply(Pz, MLz); DiagonalMatrix Preconditioner = new DiagonalMatrix(N); for (int i = 0; i < N; i++) { Preconditioner.Set(i, i, 1.0 / M[i, i]); } MLy[v_pin] += consW * 0.5f; MLx[v_pin] += consW * 0.5f; MLz[v_pin] += consW * 0.5f; bool useXAsGuess = true; // preconditioned SparseSymmetricCG SolverX = new SparseSymmetricCG() { B = MLx, X = Px, MultiplyF = M.Multiply, PreconditionMultiplyF = Preconditioner.Multiply, UseXAsInitialGuess = useXAsGuess }; // initial solution SparseSymmetricCG SolverY = new SparseSymmetricCG() { B = MLy, X = Py, MultiplyF = M.Multiply, UseXAsInitialGuess = useXAsGuess }; // neither of those SparseSymmetricCG SolverZ = new SparseSymmetricCG() { B = MLz, MultiplyF = M.Multiply }; bool bx = SolverX.Solve(); bool by = SolverY.Solve(); bool bz = SolverZ.Solve(); for (int vid = 0; vid < mesh.VertexCount; ++vid) { Vector3d newV = new Vector3d(SolverX.X[vid], SolverY.X[vid], SolverZ.X[vid]); mesh.SetVertex(vid, newV); } result_meshes.Add(mesh); TestUtil.WriteDebugMeshes(result_meshes, "___CG_result.obj"); }
public static fMesh DMeshToUnityMesh(DMesh3 m, bool bSwapLeftRight, bool bAllowLargeMeshes = false) { if (bSwapLeftRight) { throw new Exception("[RMSNOTE] I think this conversion is wrong, see MeshTransforms.SwapLeftRight. Just want to know if this code is ever hit."); } if (bAllowLargeMeshes == false) { if (m.MaxVertexID > 65000 || m.MaxTriangleID > 65000) { Debug.Log("[UnityUtil.DMeshToUnityMesh] attempted to import object larger than 65000 verts/tris, not supported by Unity!"); return(null); } } Mesh unityMesh = new Mesh(); Vector3[] vertices = dvector_to_vector3(m.VerticesBuffer); Vector3[] normals = (m.HasVertexNormals) ? dvector_to_vector3(m.NormalsBuffer) : null; unityMesh.vertices = vertices; if (m.HasVertexNormals) { unityMesh.normals = normals; } if (m.HasVertexColors) { unityMesh.colors = dvector_to_color(m.ColorsBuffer); } if (m.HasVertexUVs) { unityMesh.uv = dvector_to_vector2(m.UVBuffer); } if (bAllowLargeMeshes && (m.MaxVertexID > 65000 || m.TriangleCount > 65000)) { unityMesh.indexFormat = UnityEngine.Rendering.IndexFormat.UInt32; } if (m.IsCompactT) { unityMesh.triangles = dvector_to_int(m.TrianglesBuffer); } else { int[] triangles = new int[m.TriangleCount * 3]; int ti = 0; for (int k = 0; k < m.MaxTriangleID; ++k) { if (m.IsTriangle(k)) { Index3i t = m.GetTriangle(k); int j = 3 * ti; triangles[j] = t.a; triangles[j + 1] = t.b; triangles[j + 2] = t.c; ti++; } } unityMesh.triangles = triangles; } if (m.HasVertexNormals == false) { unityMesh.RecalculateNormals(); } return(new fMesh(unityMesh)); }
public static UnityMesh ToUnityMesh(this DMesh3 dMesh, bool bNorm = true, bool bUV = false, bool bCol = false) { bNorm &= dMesh.HasVertexNormals; bUV &= dMesh.HasVertexUVs; bCol &= dMesh.HasVertexColors; int[] vertexMap = new int[dMesh.VerticesBuffer.Length]; int[] triangleMap = new int[dMesh.TrianglesBuffer.Length]; int[] triangles = new int[dMesh.TriangleCount * 3]; List <Vector3d> vertices = new List <Vector3d>(); List <Vector3f> normals = new List <Vector3f>(); List <Vector2f> uv = new List <Vector2f>(); List <Colorf> colors = new List <Colorf>(); List <int> vertexUseCount = new List <int>(); NewVertexInfo vInfo = new NewVertexInfo(new Vector3d(), new Vector3f(), new Vector3f(), new Vector2f()); IEnumerator e = dMesh.TrianglesRefCounts.GetEnumerator(); int ti = 0; while (e.MoveNext()) { int iRef = (int)e.Current; Index3i triangle = dMesh.GetTriangle(iRef); triangleMap[iRef] = ti; for (int i = 0; i < 3; i++) { int vertIndex = triangle[i]; if (vertexMap[vertIndex] == 0) { vertexUseCount.Add(1); dMesh.GetVertex(vertIndex, ref vInfo, bNorm, bCol, bUV); vertices.Add(new Vector3f((float)vInfo.v.x, (float)vInfo.v.y, (float)vInfo.v.z)); vertexMap[vertIndex] = vertices.Count - 1; if (bNorm) { normals.Add(vInfo.n); } if (bUV) { uv.Add(vInfo.uv); } if (bCol) { colors.Add(new Colorf(vInfo.c.x, vInfo.c.y, vInfo.c.z)); } } else { vertexUseCount[vertexMap[vertIndex]]++; } triangles[ti * 3 + i] = vertexMap[vertIndex]; } ti++; } UnityMesh uMesh = new UnityMesh(vertexUseCount.ToArray(), triangles, vertices, normals, uv, colors); // Triangle normals and neighbors. e = dMesh.TrianglesRefCounts.GetEnumerator(); while (e.MoveNext()) { int iRef = (int)e.Current; int[] nb = dMesh.GetTriNeighbourTris(iRef).array; int[] neighbors = new int[3]; for (int i = 0; i < 3; i++) { neighbors[i] = (nb[i] != -1) ? triangleMap[nb[i]] : -1; } uMesh.AddTriangleInfo(triangleMap[iRef], (Vector3f)dMesh.GetTriNormal(iRef), neighbors); } return(uMesh); }
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); }
public bool Insert() { Func <int, bool> is_contained_v = (vid) => { Vector3d v = Mesh.GetVertex(vid); Vector2f vf2 = ProjectFrame.ToPlaneUV((Vector3f)v, 2); return(Polygon.Contains(vf2)); }; MeshVertexSelection vertexROI = new MeshVertexSelection(Mesh); Index3i seedT = Mesh.GetTriangle(SeedTriangle); // if a seed vert of seed triangle is containd in polygon, we will // flood-fill out from there, this gives a better ROI. // If not, we will try flood-fill from the seed triangles. List <int> seed_verts = new List <int>(); for (int j = 0; j < 3; ++j) { if (is_contained_v(seedT[j])) { seed_verts.Add(seedT[j]); } } if (seed_verts.Count == 0) { seed_verts.Add(seedT.a); seed_verts.Add(seedT.b); seed_verts.Add(seedT.c); } // flood-fill out from seed vertices until we have found all vertices // contained in polygon vertexROI.FloodFill(seed_verts.ToArray(), is_contained_v); // convert vertex ROI to face ROI MeshFaceSelection faceROI = new MeshFaceSelection(Mesh, vertexROI, 1); faceROI.ExpandToOneRingNeighbours(); faceROI.FillEars(true); // this might be a good idea... // construct submesh RegionOperator regionOp = new RegionOperator(Mesh, faceROI); DSubmesh3 roiSubmesh = regionOp.Region; DMesh3 roiMesh = roiSubmesh.SubMesh; // save 3D positions of unmodified mesh Vector3d[] initialPositions = new Vector3d[roiMesh.MaxVertexID]; // map roi mesh to plane MeshTransforms.PerVertexTransform(roiMesh, roiMesh.VertexIndices(), (v, vid) => { Vector2f uv = ProjectFrame.ToPlaneUV((Vector3f)v, 2); initialPositions[vid] = v; return(new Vector3d(uv.x, uv.y, 0)); }); // save a copy of 2D mesh and construct bvtree. we will use // this later to project back to 3d // [TODO] can we use a better spatial DS here, that takes advantage of 2D? DMesh3 projectMesh = new DMesh3(roiMesh); DMeshAABBTree3 projecter = new DMeshAABBTree3(projectMesh, true); MeshInsertUVPolyCurve insertUV = new MeshInsertUVPolyCurve(roiMesh, Polygon); //insertUV.Validate() bool bOK = insertUV.Apply(); if (!bOK) { throw new Exception("insertUV.Apply() failed"); } if (SimplifyInsertion) { insertUV.Simplify(); } int[] insertedPolyVerts = insertUV.CurveVertices; // grab inserted loop, assuming it worked EdgeLoop insertedLoop = null; if (insertUV.Loops.Count == 1) { insertedLoop = insertUV.Loops[0]; } // find interior triangles List <int> interiorT = new List <int>(); foreach (int tid in roiMesh.TriangleIndices()) { Vector3d centroid = roiMesh.GetTriCentroid(tid); if (Polygon.Contains(centroid.xy)) { interiorT.Add(tid); } } if (RemovePolygonInterior) { MeshEditor editor = new MeshEditor(roiMesh); editor.RemoveTriangles(interiorT, true); InteriorTriangles = null; } else { InteriorTriangles = interiorT.ToArray(); } // map back to 3d Vector3d a = Vector3d.Zero, b = Vector3d.Zero, c = Vector3d.Zero; foreach (int vid in roiMesh.VertexIndices()) { // [TODO] somehow re-use exact positions from regionOp maps? // construct new 3D pos w/ barycentric interpolation Vector3d v = roiMesh.GetVertex(vid); int tid = projecter.FindNearestTriangle(v); Index3i tri = projectMesh.GetTriangle(tid); projectMesh.GetTriVertices(tid, ref a, ref b, ref c); Vector3d bary = MathUtil.BarycentricCoords(ref v, ref a, ref b, ref c); Vector3d pos = bary.x * initialPositions[tri.a] + bary.y * initialPositions[tri.b] + bary.z * initialPositions[tri.c]; roiMesh.SetVertex(vid, pos); } bOK = BackPropagate(regionOp, insertedPolyVerts, insertedLoop); return(bOK); }
public override void Selected(SelectionType button) { nullifyHitPos = true; transform.parent.SendMessage("Selected", button, SendMessageOptions.DontRequireReceiver); if (button == SelectionType.SELECTALL) { BlockMove = true; } else { MeshFilter mf = GetComponent <MeshFilter>(); Mesh mesh = mf.sharedMesh; currentHit = transform.InverseTransformPoint(AppState.instance.lastHitPosition); Vector3d target = currentHit; System.Random rand = new System.Random(); int count = 0; // // The algorithm will find local optima - repeat until you get the tru optima // but limit the interation using a count // Int32 current = 0; while (count < dmesh.VertexCount) { count++; // // choose a random starting point // current = rand.Next(0, dmesh.VertexCount); Vector3d vtx = dmesh.GetVertex(current); double currentDist = vtx.DistanceSquared(target); // // find the ring of triangles around the current point // int iter = 0; while (true) { iter++; // throw new InvalidOperationException("Meh One Ring operation invalid : " + res.ToString()); // // Interate through the vertices in the one Ring and find the clost to the target point // bool flag = false; foreach (Int32 v in dmesh.VtxVerticesItr(current)) { Vector3d thisVtx = dmesh.GetVertex(v); double thisDist = thisVtx.DistanceSquared(target); if (thisDist < currentDist) { flag = true; current = v; vtx = thisVtx; currentDist = thisDist; } } // // if the current point as closest - then have a local optima // if (!flag) { break; } } // // we now have a local optima // to check for a global optima look to see if hit is contained by one of the triangles in the one ring // bool f2 = false; foreach (Int32 t in dmesh.VtxTrianglesItr(current)) { Index3i tri = dmesh.GetTriangle(t); Triangle3d triangle = new Triangle3d( dmesh.GetVertex(tri.a), dmesh.GetVertex(tri.b), dmesh.GetVertex(tri.c) ); double[] xs = new double[3] { triangle.V0.x, triangle.V1.x, triangle.V2.x }; double[] ys = new double[3] { triangle.V0.y, triangle.V1.y, triangle.V2.y }; double[] zs = new double[3] { triangle.V0.z, triangle.V1.z, triangle.V2.z }; if ( target.x >= xs.Min() && target.x <= xs.Max() && target.y >= ys.Min() && target.y <= ys.Max() && target.z >= zs.Min() && target.z <= zs.Max() ) { f2 = true; currentHitTri = tri; } } // // if we found on triamgle that contain the current hit then we have finished // if (f2) { break; } } if (count >= dmesh.VertexCount) { // // This is the unoptimized verion but it is guaranteed to find a solution if one exits // current = -1; float currentDist = float.MaxValue; if (currentHit != null) { for (int i = 0; i < mesh.vertices.Length; i++) { Vector3 vtx = mesh.vertices[i]; float dist = (currentHit - vtx).sqrMagnitude; if (dist < currentDist) { current = i; currentDist = dist; } } } // // Check that the closet vertex to the point is an actual solution // bool f2 = false; foreach (Int32 t in dmesh.VtxTrianglesItr(current)) { Index3i tri = dmesh.GetTriangle(t); Triangle3d triangle = new Triangle3d( dmesh.GetVertex(tri.a), dmesh.GetVertex(tri.b), dmesh.GetVertex(tri.c) ); double[] xs = new double[3] { triangle.V0.x, triangle.V1.x, triangle.V2.x }; double[] ys = new double[3] { triangle.V0.y, triangle.V1.y, triangle.V2.y }; double[] zs = new double[3] { triangle.V0.z, triangle.V1.z, triangle.V2.z }; if ( target.x >= xs.Min() && target.x <= xs.Max() && target.y >= ys.Min() && target.y <= ys.Max() && target.z >= zs.Min() && target.z <= zs.Max() ) { f2 = true; currentHitTri = tri; } } // // if we found on triamgle that contain the current hit then we have finished // if (!f2) { Debug.LogError(" Mesh Vertex Search : No Solution Found"); return; } } selectedVertex = current; sphere = GameObject.CreatePrimitive(PrimitiveType.Sphere); sphere.transform.position = transform.TransformPoint(mesh.vertices[current]); sphere.transform.localScale = new Vector3(0.1f, 0.1f, 0.1f); sphere.transform.parent = transform; } }
public MeshData(DMesh3 _mesh) : this() { _mesh = new DMesh3(_mesh, true); vertices = _mesh.VertexIndices().Select(vID => { var vertex = _mesh.GetVertexf(vID); return(new Vector3(vertex.x, vertex.y, vertex.z)); }).ToArray(); triangles = _mesh.TriangleIndices().SelectMany(tID => _mesh.GetTriangle(tID).array).ToArray(); }
// [RMS] This doesn't work because I did something stupid when // making unwrap meshes. The set of triangles aren't the same. argh. public static DMesh3 ConvertUnwrapToUVs(RemoteControl rc, out DenseMeshUVSet UVSet, string mainName = "main") { int mainID = rc.FindObjectByName(mainName); rc.CompactMesh(mainID); DMesh3 mainMesh = ReadMeshFromMM(rc, mainID); Debug.Assert(mainMesh.IsCompact); List <int> all = rc.ListObjects(); List <int> unwrapIDs = new List <int>(); foreach (int id in all) { string sName = rc.GetObjectName(id); if (sName.StartsWith("unwrap", StringComparison.OrdinalIgnoreCase)) { unwrapIDs.Add(id); } } int[] AllGroups = FaceGroupUtil.FindAllGroups(mainMesh).ToArray(); Dictionary <int, DMesh3> Unwraps = new Dictionary <int, DMesh3>(); foreach (int id in unwrapIDs) { DMesh3 mesh = ReadMeshFromMM(rc, id); HashSet <int> subGroups = FaceGroupUtil.FindAllGroups(mesh); Debug.Assert(subGroups.Count == 1); int gid = subGroups.ToArray()[0]; Unwraps[gid] = mesh; } UVSet = new DenseMeshUVSet(); UVSet.TriangleUVs.resize(mainMesh.TriangleCount); Dictionary <Index2i, int> UVSetMap = new Dictionary <Index2i, int>(); Dictionary <int, int> GroupCounters = new Dictionary <int, int>(); for (int i = 0; i < AllGroups.Length; ++i) { GroupCounters[AllGroups[i]] = 0; } for (int ti = 0; ti < mainMesh.TriangleCount; ++ti) { Index3i main_tri = mainMesh.GetTriangle(ti); int gid = mainMesh.GetTriangleGroup(ti); int sub_tid = GroupCounters[gid]; GroupCounters[gid]++; DMesh3 SubMesh = Unwraps[gid]; Index3i sub_tri = SubMesh.GetTriangle(sub_tid); for (int j = 0; j < 3; ++j) { int sub_vid = sub_tri[j]; Index2i key = new Index2i(gid, sub_vid); int uvset_idx; if (UVSetMap.TryGetValue(key, out uvset_idx) == false) { Vector3d v = SubMesh.GetVertex(sub_vid); Vector2f uv = new Vector2f((float)v.x, (float)v.z); uvset_idx = UVSet.AppendUV(uv); UVSetMap[key] = uvset_idx; } sub_tri[j] = uvset_idx; } UVSet.TriangleUVs[ti] = sub_tri; } return(mainMesh); }