0

I have a function f defined on a triangle mesh, i.e. for each vertex, I have an associated number. For example, f could be the geodesic distance on the mesh, i.e. f(x)=d(a,x) computed for each point in the mesh, from a specific fixed point a. Clearly, it is easy to "plot" this function on the surface, simply by normalizing the values of f and mapping them to colors on the mesh nodes.

But what if I want to draw isolines (also called contour lines or isoclines) on the surface?

How would I go about this? This does not seem doable easily by simply coloring the mesh as above. Especially since the meshes may have sparse areas with few vertices (i.e. large faces). This suggests (perhaps) that I should compute the isoclines directly as 3D curves on the mesh and use e.g. GL-lines. But computing the isocline curves is not so obvious since the naive approach is to fix a set of target values, and then I will have to check every triangle for whether it reaches the target at some point(s) on the triangle via interpolation, which does not seem ideal. Could anyone point me to any resources that address this?

For reference, I am using python OpenGL.

user3658307
  • 711
  • 1
  • 6
  • 23

2 Answers2

1

if the value is float and you know its range You can try the coloring as you described with fragment shader on top of it that would render only fragment very near your rendered value.

The easiest is to use single rendering pass use something like this in fragment:

float x;
x = (value/10.0)+0.5; // 10 is distance of value you want the lines to render
x = x-floor(x);   // x = value mod distance
if (abs(x-0.5)>0.001) discard; // do not render fragments too far from your line

the code simply decides if you are very near to every distance=10 of the value and throw away any fragments that are not. However the thickness of the lines/curves can vary depending on the value density and triangle size distribution. You must set the constants correctly (distance=10,threshold=0.001) to make this work.

This GLSL animated mesh surface highlight is using very similar technique apart the discard as the stuff there is continuous.

More accurate option is to use the same principle in 2 pass render. Where you render your value as color into some texture in the first pass. And then in second for each fragment you scan the texture around and find the closest position of renderable value and than based on the distance to it either render or not. This provides accurate thickness of the line no matter what. But for that the value must contain specific renderable values. This How to implement 2D raycasting light effect in GLSL might help as it also scans the texture in all the directions (but for different purpose).

If none of the above suits you then only other option that comes into my mind is geometrical approach where you create polylines from your mesh based on value intersection with your mesh (like cross section with plane).

Spektre
  • 45,598
  • 10
  • 100
  • 347
1

Let's say you want to draw contours (isolines) whose Z-coordinate is a multiple of ci (for 'contour interval'). for example, for ci=5 valid values are 25, 30, 35, etc.
A triangle can have none, one, or several contours crossing it. I don't bother with lines. I use points, I examine each fragment in the fragment shader.

The first goal is to get back the world coordinates of the fragment in the fragment shader.
The fragment shader receives gl_FragCoord which has the {x,y,z} in screen coordinates. Or in the vertex shader you can pass a varying with the z. Read this q&a to learn how this transform-back can be done.

Now you have a z in world coordinates, it's time to tell if it belongs to a contour or not:

float maxErr = 0.0001;
float dif = abs(z - (ci * floor(z/ci)));
if ( dif > maxErr )
    color = triangleColor;
else
    color = contourColor;

Because a fragment is not the same as a pixel you may get a not-width-constant line.

Ripi2
  • 6,659
  • 1
  • 13
  • 30