MNMesh Note on Debugging

The functions MNVert::MNDebugPrint(), MNEdge::MNDebugPrint(), MNFace::MNDebugPrint(), MNMesh::MNDebugPrint(), and MNMeshBorder::MNDebugPrint() print out detailed ASCII summaries of the component or mesh, which can be an invaluable aid in tracking bugs.

Here is the MNMesh::MNDebugPrint output from a standard 3ds Max box, after applying MakePolyMesh. Mapping coordinates, vertex colors, and face triangulation may also be included.

MNMesh Debug Output: 8 verts, 12 edges, 6 faces
Vertex 0:( -17.185, -26.798, 0.000) Edges:(0 3 9 ) Faces:(0 2 5 )
Vertex 1:( 17.185, -26.798, 0.000) Edges:(2 3 8 ) Faces:(0 2 3 )
Vertex 2:( -17.185, 26.798, 0.000) Edges:(0 1 11 ) Faces:(0 4 5 )
Vertex 3:( 17.185, 26.798, 0.000) Edges:(1 2 10 ) Faces:(0 3 4 )
Vertex 4:( -17.185, -26.798, 24.984) Edges:(4 7 9 ) Faces:(1 2 5 )
Vertex 5:( 17.185, -26.798, 24.984) Edges:(4 5 8 ) Faces:(1 2 3 )
Vertex 6:( -17.185, 26.798, 24.984) Edges:(6 7 11 ) Faces:(1 4 5 )
Vertex 7:( 17.185, 26.798, 24.984) Edges:(5 6 10 ) Faces:(1 3 4 )
Edge 0: verts(0 2), face 0, rev-face 5
Edge 1: verts(2 3), face 0, rev-face 4
Edge 2: verts(3 1), face 0, rev-face 3
Edge 3: verts(1 0), face 0, rev-face 2
Edge 4: verts(4 5), face 1, rev-face 2
Edge 5: verts(5 7), face 1, rev-face 3
Edge 6: verts(7 6), face 1, rev-face 4
Edge 7: verts(6 4), face 1, rev-face 5
Edge 8: verts(1 5), face 2, rev-face 3
Edge 9: verts(4 0), face 2, rev-face 5
Edge 10: verts(3 7), face 3, rev-face 4
Edge 11: verts(2 6), face 4, rev-face 5
Face 0: verts(0 2 3 1 ) edges(0v 1v 2v 3v )
Face 1: verts(4 5 7 6 ) edges(4v 5v 6v 7v )
Face 2: verts(0 1 5 4 ) edges(3v 8v 4v 9v )
Face 3: verts(1 3 7 5 ) edges(2v 10v 5v 8v )
Face 4: verts(3 2 6 7 ) edges(1v 11v 6v 10v )
Face 5: verts(2 0 4 6 ) edges(0v 9v 7v 11v )

MNMeshes have a complex, interlinked topology. Without frequent assertions, a mistake in one part of the code can result in a failure much further down the line. Since an assertion failure in itself provides little diagnostic information, each assertion failure in MNMath.dll is accompanied by a DebugPrint() message that gives more information in the visual studio output pane about the problesm. If this information does not immediately lead to a solution, try using assert to verify MNMesh::CheckAllData() is true between each of your MNMesh operations.

If you call an MNMesh function that produces an inexplicable error after your MNMesh has successfully had all its data checked with MNMesh::CheckAllData(), please contact SDK support.

To give a simple example, suppose you had an application which created an MNMesh from a Mesh , made it into a polygonal mesh, split a single face, and returned.

SplitUp(Mesh & mesh) {
   MNMesh mm(mesh);
  mm.MakePolyMesh();
  mm.SplitTriEdge(0, .5f);
  mm.OutToTri(mesh);
}

You try it out on a geosphere, and it works fine. But then you try it out on a box, and for some reason you get an assertion failure somewhere in the MNMath.dll source. By running 3ds Max under the debugger, you can reproduce the error. If you check the debug output pane in Visual Studio, you’ll find the message:

MNMesh::SplitTriEdge error: edge’s face 1(0) not a triangle.

So you check with the documentation and realize that MNMesh::SplitTriEdge is an edge-splitting function that only works on triangulated meshes. To do the same thing to a PolyMesh, you need to use one of the variants of the method SplitEdge. So you can fix your code by either removing MNMesh::MakePolyMesh(), triangulating with a call to MNMesh::Triangulate(), or just calling MNMesh::SplitEdge() with the values 0.0f and 0.5f instead of MNMesh::SplitTriEdge().

Imagine a more complicated case: in the middle of a series of complex MNMesh modifications made by your program, you need to recompute the triangulation of one of the higher-degree faces with a call to MNMesh::RetriangulateFace. For some reason, this generates an assertion failure. Checking the Debug output, you find the cryptic message:

MNMesh::RetriangulateFace internal error.

This could mean one of two things. First of all, the MNMesh could have had some of its data scrambled before the call to RetriangulateFace. You can check this by adding an assertion that verifies CheckAllData() is true, immediately before the call to RetriangulateFace. CheckAllData performs a time-intensive series of checks on the mesh structure, checking each mesh component against the components it’s supposed to be linked to, checking that nothing references a dead component, and so on. If any errors are found, the check will fail, and CheckAllData will print diagnostic information to the Debug output.

If CheckAllData() gives your mesh a clean bill of health, but you’re still getting an "internal error", or just an "error" with no further info, you may have found a bug. Please contact SDK support.

While during your debugging phase, frequent calls to MNMesh::CheckAllData() can be very useful, but the MNDebugPrint() and MNMEsh::CheckAllData() functions are highly time intensive and serve no useful purpose for a released plug-in, you should check to remove them all before release.

See Also