How to represent a tetrahedral mesh nicely in a CRhinoDisplayConduit?

I’m writing a tetrahedral mesher in Rhino from scratch.
The particular application is for heat transfer problems in civil engineering - in particular for physically correct simulation of modernizing insulation of buildings in view of energy efficiency.
I know there are some tetrahedral meshers out there (there’s one based on tetmesh, one based on fTetwild etc). So, I’ll write another post explaining why I write mine from scratch. For now, suffice it to say it’s for accurate and performance-critical meshing of domain boundaries - namely the boundaries between materials modelled as solids in Rhino - by a tight integration with the Rhino C++ SDK. Accurate meshing of material boundaries is the bread and butter of heat transfer simulation - imagine a meshing mismatch between adjacent solids. The computed thermal loss between those materials will be too low. That’s why I’m writing a mesher that immediately works on breps and takes care of the necessary brep splitting steps, nonmanifold breps etc directly with their internal representation.
In broad strokes, the mesher already works:

Here, I’d just like to ask about the best way to draw such a tet mesh from a CRhinoDisplayConduit.
Currently, I throw the triangles into a usual ON_Mesh - which will have very many non-manifold edges, by construction, and draw this with (triangles being a reference to a std::vector<ON_Mesh>)

bool WfConduit::ExecConduit(CRhinoDisplayPipeline& dp, UINT nChannel, bool& bTerminate) {
	if (triangles.empty()) return true;
	if (nChannel == CSupportChannels::SC_POSTDRAWOBJECTS) {
/* as the samples say: "Because we disable Depth Writing and Testing before drawing,
my objects are not obscured by the existing geometry (which was drawn in a channel
previous to PostDrawObjects)" 
		dp.SetupDisplayMaterial(material, color);
		for (int i = 0; i < triangles.size(); i++) {
			dp.DrawShadedMesh(triangles[i], &material);
			dp.DrawWireframeMesh(triangles[i], ON_Color(RGB(255, 0, 0)));
	bTerminate = true;
	return true;

which is more or less like in the developper C++ samples, which looks like in the screenshots above.
Problem: A mesh made just from the triangles of a tet mesh can not have normals, of course. So, it becomes necessary to disable depth writing and testing. But of course, this is just a hack in this context. There is no way to shade the surface of the solid, the conduit will shine through objects in front of it etc.
The problem is that opengl works perfectly with surface meshes with normals but not with extremely non-manifold meshes like the triangles of a tet mesh. That’s why I’d rather like to avoid having to draw this triangle mesh and I was wondering if there are better ways. For instance, would it be possible to use opengl fog for each tetrahedron in the conduit?
If there is no way around the triangle mesh of the tet mesh: Should I just draw the triangle mesh in a double-sided way and give it some transparency? If yes, how should that be done with the attributes of the conduit?
But still, I’d rather avoid having to draw this hacky mesh with all its non-manifold edges.
Hope the questions are clear. Thanks in advance.

1 Like

Create an ON_Mesh surface mesh from the visible faces of the tets and just display that. If you want to view internal tets, create an ON_Mesh surface from a sectioning cutting plane. See for example the TETRA plugin which implements fTetWild.

Thanks for the answer, @Gary .
I mentioned fTetWild and mentioned what motivates me.
The “visible faces” are just a mesh of the boolean union of the input solids. The user knows about their input solids, there is no information for them gained from seeing the meshed surface.
Rather, It’s all about the internal tets. Yes, slicing the whole thing is of course a nice thing to do but it requires user involvement and time.
I need the user to get an immediate non-interactive intuitive visual idea of the presence of a tetrahedral mesh, without them having to initiate some extra functionality. I might write a slicer at some point but that is for users who want to investigate the tet mesh in detail. Before they will want to slice the tet mesh, they need to know it exists in the first place!
So I need something transparent - literally and figuratively.
I asked about opengl fog because it is the way opengl deals with inherently volumetric entities in a transparent way.
The conduits are a very nice wrapper of a lot of opengl functionality, so there would be a chance there is a way to also generate some opengl fog.
If opengl fog is not an option, I’m still seeking the right way to play with transparency settings.

My first step would be to just draw the edges and forget about a shaded mesh. Similar/same as your first picture. This way the user gets an idea about the structure of the mesh as a whole.

Then maybe add an interactive “slice plane” that shows each tet shaded individually if it is sliced by the plane; this is something you see in other volumetric meshing packages as well (e.g. PointWise). Other metrics than a slice plane can be thought of, e.g. based on a tet quality metric, to isolate and show good/bad tets.

Thanks for the answer. Both screenshots show the edges. They’re already drawn by the wireframe command in the code snippet. However, they still need a good way to be semi-transparent in order not to confuse the user. Part of the question is how to achieve this semi-transparency.
As for slicing: See my answer to @Gary .
As for good/bad tets: yes, those will be displayed after a remeshing step.

Thanks to @menno and @gary fro answering.
I’ll do the slicing as soon as I have time.
For now, after some playing, I think I’ll end up doing something like this:

This is achieved with two conduits: One in the CSupportChannels::SC_DRAWOBJECT channel - it draws breps/extrusions itself and disables the m_pChannelAttrs->m_bDrawObject boolean flag.
And another conduit for the shaded “triangle” mesh.
I placed it in a conduit that subscribes to the CSupportChannels::SC_DRAWFOREGROUND channel and does the following:

	if (nChannel == CSupportChannels::SC_POSTDRAWOBJECTS) {
		ON_Color red = ON_Color(RGB(255, 0, 0));
		CDisplayPipelineMaterial m;
		CDisplayAttributeMaterial am;
		m.m_BackMaterial = am;
		m.m_FrontMaterial = am;
		for (const auto& tr : triangles) {
			dp.DrawShadedMesh(tr, &m);
			dp.DrawWireframeMesh(tr, col);
		return true;

This achieves transparency but does not need to disable depths, so the object in front still blocks the view, as it should.
All of this has to conveniently happen in two different conduits because the objects themselves are part of the document but the tet mesh is not.
HOWEVER: in case any McNeel staff stumbles upon this: it still is a makeshift solution. It would be great if there was a way to draw opengl fog from a conduit!

1 Like

Looks nice - I may update my own rendering of tet meshes with this :slight_smile: