Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Converting geometry3Sharp mesh to other mesh #3

Closed
petrasvestartas opened this issue Aug 12, 2017 · 17 comments
Closed

Converting geometry3Sharp mesh to other mesh #3

petrasvestartas opened this issue Aug 12, 2017 · 17 comments

Comments

@petrasvestartas
Copy link

petrasvestartas commented Aug 12, 2017

Hi,

I tried your library and it works:) It is supernice.

I tried to convert your mesh to other type of mesh.
Basically what I am trying to do is to pass all vertices and mesh faces from one mesh type to another.

But I noticed that DMesh3 has vertices with strange indexing. For instance if there are 100 vertices their index id can be something like 2000, 0, 281 and etc, the mesh library I am working with vertex id would go from 0,1,2 to 100 sequentially. Therefore I always have to remap indices.

Is there a better way to do below conversion?

//Remeshed cylinder
g3.DMesh3 g3m = make_good_cylinder();


//Converting DMesh3 to Other mesh
Mesh mesh = new Mesh();

//Add all vertices
var vertices = g3m.Vertices();
foreach(g3.Vector3d vec in vertices)
  mesh.Vertices.Add(vec.x, vec.y, vec.z);

//Add faces
int[] vID = g3m.VertexIndices().ToArray();
var faces = g3m.Triangles();
foreach(g3.Index3i f in faces)
  mesh.Faces.AddFace(Array.IndexOf(vID, f.a), Array.IndexOf(vID, f.b), Array.IndexOf(vID, f.c));
@rms80
Copy link
Contributor

rms80 commented Aug 13, 2017

Does the make_good_cylinder() function do Remeshing internally, or other mesh composition operations?

If you construct a DMesh3 from scratch, it will have the same properties as other indexed meshes, ie dense index space. But if you do things like Remeshing, it will leave 'holes' in the index space as it deletes vertices/triangles.

To get back to a Dense index space you have to compact the mesh. The fastest way to do that is to use the compacting copy constructor. IE you could write:

g3m = new g3.DMesh3(g3m, true);

and now g3m will have dense index spaces.

@petrasvestartas
Copy link
Author

petrasvestartas commented Aug 13, 2017

Thanks it works.

I would like to ask about remeshing part.
I see that after remeshing you apply smoothing. But in this case the original mesh shape changes.

Is it possible to remesh a mesh in such a way that its its edges will be more or less equilateral and output shape would be the same (without smoothing)?

I am using your example file with cylinder:

untitled

public  DMesh3 make_good_cylinder(float fResScale = 1.0f) {

DMesh3 mesh = MakeCappedCylinder(false);
MeshUtil.ScaleMesh(mesh, Frame3f.Identity, new g3.Vector3f(1, 2, 1));
mesh.CheckValidity();

Remesher r = new Remesher(mesh);
r.EnableFlips = r.EnableSplits = r.EnableCollapses = true;
r.MinEdgeLength = 0.1f * fResScale;
r.MaxEdgeLength = 0.2f * fResScale;
r.EnableSmoothing = true;
r.SmoothSpeedT = 0.1f;

r.EnableFlips = r.EnableSmoothing = false;
r.MinEdgeLength = 0.05f * fResScale;
for ( int k = 0; k < 10; ++k ) {
  r.BasicRemeshPass();
  mesh.CheckValidity();
}

r.MinEdgeLength = 0.1f * fResScale;
r.MaxEdgeLength = 0.2f * fResScale;
r.EnableFlips = r.EnableCollapses = r.EnableSmoothing = true;

for ( int k = 0; k < 100; ++k ) {
  r.BasicRemeshPass();
  mesh.CheckValidity();
}

return mesh;

}

@petrasvestartas
Copy link
Author

It seems that this function does what I want:
test_remesh_constraints_fixedverts

remeshing

Would it also work for open meshes? Lets say if cylinder is not capped?

@petrasvestartas
Copy link
Author

Nice works with open one too.

Is this library totally C# ? Or it has dependencies

@rms80
Copy link
Contributor

rms80 commented Aug 13, 2017

it is completely in C# and has no dependencies.

@visose
Copy link

visose commented Aug 17, 2017

Hi Petras,
These are a couple of extension methods I wrote to convert from Dmesh3 to Rhino meshes and back. Only imports vertices and faces (recalculates normals in Rhino) you could also add uvs, colors and so on. Usage would be " var rhinoMesh = mesh.ToRhinoMesh() and var g3Mesh = rhinoMesh.ToDMesh3():

    public static DMesh3 ToDMesh3(this Mesh mesh)
      {
          var dMesh3 = new DMesh3();

          for (int i = 0; i < mesh.Vertices.Count; i++)
          {
              var vertex = mesh.Vertices[i];
              var normal = mesh.Normals[i];

              NewVertexInfo ni = new NewVertexInfo()
              {
                  v = new g3.Vector3d(vertex.X, vertex.Z, vertex.Y),
                  n = new g3.Vector3f(normal.X, normal.Z, normal.Y)
              };

              dMesh3.AppendVertex(ni);
          }

          foreach (var face in mesh.Faces)
          {
              dMesh3.AppendTriangle(face.A, face.B, face.C);
          }

          return dMesh3;
      }

      public static Mesh ToRhinoMesh(this DMesh3 dMesh3)
      {
          dMesh3 = new DMesh3(dMesh3, true, MeshComponents.All);
          var mesh = new Mesh();

          var vertices = dMesh3.Vertices().Select(v => new Point3d(v.x, v.z, v.y));
          var faces = dMesh3.Triangles().Select(f => new MeshFace(f.a, f.b, f.c));

          mesh.Vertices.AddVertices(vertices);
          mesh.Faces.AddFaces(faces);
          mesh.Normals.ComputeNormals();
          mesh.Compact();

          return mesh;
      }

@petrasvestartas
Copy link
Author

petrasvestartas commented Aug 17, 2017

Thanks, maybe you know what is a proper way of checking mesh winding order?

The posts I searched, usually starts with cross product - normal of face. Then there is a construction of transformation matrix.

But what is the proper way of checking the winding if it is clockwise or anti-clockwise?

public bool Triangle(Vector3f v0, Vector3f v1, Vector3f v2)
{
Vector3f axis_x = v1 - v0; // edge v0 -> v1
Vector3f axis_y = v2 - v0; // edge v0 -> v2
Vector3f cross = Vector3f.CrossProduct(axis_x, axis_y);
cross.Unitize();

....

}

This is just normal calculation of mesh face, what it must change if it is clockwise of anti-clockwise.

@visose
Copy link

visose commented Aug 17, 2017

Is that question related to the g3 geometric library or is it a general computer graphics question?
(if it's the second one, i guess Ryan might prefer you ask it in StackOverflow :P)

@petrasvestartas
Copy link
Author

I know...

If there is method in g3 to point me to winding would be preferable.

@petrasvestartas
Copy link
Author

petrasvestartas commented Aug 17, 2017

Probably it boils down to

find the edge that both faces share, and then see if the edges
are reversed in order as you would expect in a well constructed

@visose
Copy link

visose commented Aug 17, 2017

Are you trying to fix a mesh that has faces with different winding or are you trying to figure out which convention this library uses?
If it's the latter, we can check the code to figure out the face normal:

      public static Vector3d Normal(Vector3d v1, Vector3d v2, Vector3d v3) {
            Vector3d edge1 = v2 - v1;
            Vector3d edge2 = v3 - v2;
            edge1.Normalize();
            edge2.Normalize();
            Vector3d vCross = edge1.Cross(edge2);
            vCross.Normalize();
            return vCross;
        }

If you then look at this diagram: https://en.wikipedia.org/wiki/Cross_product#/media/File:Right_hand_rule_cross_product.svg
(assuming he implemented the "Cross" method following the right hand coordinate system)
you can deduce he uses CCW convention for winding.

@petrasvestartas
Copy link
Author

petrasvestartas commented Aug 17, 2017

It is about fixing.

Yap, the directionality define by your function of calculating mesh face normal.

But for checking whole mesh if mesh face windings are correct, you probably need to start from arbitrary mesh face and loop through neighbour faces and swapping their direction if edge direction does not match .

@rms80
Copy link
Contributor

rms80 commented Aug 17, 2017

the Cross Product does not change if you use RHS or LHS coordinate systems. Switching coordinate systems involves switching the basis vectors, which then changes the interpretation of the result of a cross product. But the formula doesn't change.

Most of the library is not specific to a particular coordinate system. For example Unity is LHS but many (perhaps most) other tools are RHS. There are functions in MeshTransform to switch between these two when necessary.

A mesh doesn't have "sides" so any set of vertices and triangles can be oriented such that the normals computed from face-edge-cross-products point outwards or inwards. You switch this just by switching the order of the vertices in the face.

'fixing' a mesh with inconsistent per-triangle orientations can be quite difficult. The process you describe - fix one face and then propagate across neighbour edges - works if the mesh is closed and orientable (ie manifold). The standard process is to do something like a raycast from far away, set the orientation/winding of the face the ray hits to be the orientation/winding you want (ie face normal should point towards ray, under whatever handedness-system you want to use), and then do the propagation.

If the mesh is not closed, this will produce one of the two possible orientations depending on where the ray hits. If the mesh has disjoint regions this can lead to them being "incorrectly" oriented relative to what a human might have been hoping for.

I do intend to eventually implement the fix-and-propagate part of orientation repair in the library, just haven't gotten to it yet.

@petrasvestartas
Copy link
Author

Thanks for the explanation. Fixing winding looks like not a straight forward process.

I have additional question about remeshing.

I am using one of your functions for remeshing, I tried to change angle and other properties, but I corners points of this box are not fixed. How to snap these corner points correctly?

2017-08-18

public DMesh3 test_remesh_constraints_fixedverts(int iterations, DMesh3 mesh, double min, double max,double angle)
        {

            AxisAlignedBox3d bounds = mesh.CachedBounds;

            // construct mesh projection target
            DMesh3 meshCopy = new DMesh3(mesh);
            meshCopy.CheckValidity();
            DMeshAABBTree3 tree = new DMeshAABBTree3(meshCopy);
            tree.Build();
            MeshProjectionTarget target = new MeshProjectionTarget() { Mesh = meshCopy, Spatial = tree };

            // construct constraint set
            MeshConstraints cons = new MeshConstraints();

            //EdgeRefineFlags useFlags = EdgeRefineFlags.NoFlip | EdgeRefineFlags.NoCollapse;
            EdgeRefineFlags useFlags = EdgeRefineFlags.NoFlip;

            foreach (int eid in mesh.EdgeIndices()) {
                double fAngle = MeshUtil.OpeningAngleD(mesh, eid);
                if (fAngle > angle) {
                    cons.SetOrUpdateEdgeConstraint(eid, new EdgeConstraint(useFlags));
                    Index2i ev = mesh.GetEdgeV(eid);
                    int nSetID0 = (mesh.GetVertex(ev[0]).y > bounds.Center.y) ? 1 : 2;
                    int nSetID1 = (mesh.GetVertex(ev[1]).y > bounds.Center.y) ? 1 : 2;
                    cons.SetOrUpdateVertexConstraint(ev[0], new VertexConstraint(true, nSetID0));
                    cons.SetOrUpdateVertexConstraint(ev[1], new VertexConstraint(true, nSetID1));
                }
            }

            Remesher r = new Remesher(mesh);
            r.Precompute();
            r.SetExternalConstraints(cons);
            r.SetProjectionTarget(target);
            r.EnableFlips = r.EnableSplits = r.EnableCollapses = true;
            r.MinEdgeLength = min;
            r.MaxEdgeLength = max;
            r.EnableSmoothing = true;
            r.SmoothSpeedT = 1;


              for (int k = 0; k < iterations; ++k) {
                r.BasicRemeshPass();
                mesh.CheckValidity();
            }


            return mesh;

        }

@visose
Copy link

visose commented Aug 18, 2017

the Cross Product does not change if you use RHS or LHS coordinate systems.

Unity's cross product method follows the LHS. I'm sure the math is the same, but the order of the vector parameters is reversed, which could also be the case in this library if you don't look at the code https://docs.unity3d.com/ScriptReference/Vector3.Cross.html).

A mesh doesn't have "sides"

Well, the direction the face normal are pointing are important for many things, like rendering (back-face culling, refraction) or Boolean operations. I guess the remesher of this library is not affected by this.

@rms80
Copy link
Contributor

rms80 commented Aug 31, 2017

@petrasvestartas This is happening because the Remesher needs to know about the sets of edges you want to preserve. In the sample code the object is a cylinder. Guessing the "sharp" edges is done by the (fAngle > angle) test.

However then in the next few lines I am checking if the vertex is above or below the bounding-box center (the nSetID0 and nSetID1 variables). These values are passed into the VertexConstraint constructor. This is a hacky way to "find" the upper and lower creases on the cylinder.

Basically, the remesher is treating these as "sets" of related vertices/edges. It is allowed to collapse to other vertices in the set, but not across sets. So for your cube it means all the sharp edges in the upper half / lower half are fair game for collapsing, and what is happening is the corner vertices are being lost.

The way to fix this is to tag the corner vertices with their own set ID. However to do that you have to find the corners. One way would be to count the 'sharp' edges coming out of each vertex. If there are more than 2, it is a corner.

(this might be improved in the future because clearly the edge constraints should also have these set IDs, and in that case I could handle these "corner" situations automatically...)

@rms80 rms80 closed this as completed Nov 12, 2017
@petrasvestartas
Copy link
Author

Hello,

Is it possible to know which function prevents vertex from moving (make it fixed)
(I know the vertex ID number)

amakhno referenced this issue in SoftSmile-Inc/geometry3Sharp Jul 23, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants