After taking a look at the Mobius strip, I noticed its equation is really simple and tried to add it into my Raytracer.

I tried a "naive" way by simply generating N triangles attached to each other to obtain the desired shape. While this approach works, the result it not really pretty:


(By the way I probably have an issue with my normals but I don't know where it comes from.)

I tried it with PovRay and the result was astonishing. Perfectly smooth strip made in a far far FAR smaller time than mine. I'm pretty sure Povray is well optimized but I also think it won't generate triangles like I did.


In case that might help, here is the actual code used (C++) :

float step = .1f;
float halW = 0.5f;


auto lambda = [this] (float v, float t) {
  Vec_t p;

  float cdv = Tools::Cos(2 * v);
  float sdv = Tools::Sin(2 * v);
  float ctv = Tools::Cos(v);
  float stv = Tools::Sin(v);

  float c = 2 + t * ctv;

  p.x = c * cdv;
  p.z = c * sdv;
  p.y = t * stv;

  return p;

for (float v = 0.f; v < Globals::PI; v += step)
  if (v > Globals::PI)
    v = Globals::PI;

  for (float t = -halW; t < halW; t += step)
    if (t > halW)
      t = halW;

    Vec3 p1 = lambda(v, t);
    Vec3 p2 = lambda(v + step, t);
    Vec3 p3 = lambda(v, t + step);
    Vec3 p4 = lambda(v + step, t + step);
    _facets.emplace_back(p1, p2, p3);
    _facets.emplace_back(p3, p2, p4);


How can I handle parametric surfaces like this one in raytracing?

Edit After letting the above algorithm run for about 20 hours, I got a way prettier result (with 3 torsions instead of 1)

Better result

  • $\begingroup$ For the specific problem outlined in red in the first image, it looks like you might need to check which side of the surface you are approaching before deciding which way the normal should point, otherwise some regions will be shaded incorrectly. This shows up in particular for a Möbius strip, since there must be a point at which the normals switch direction due to the twist. There must be some adjacent triangles that have almost opposite normal directions (like the light and dark adjacent triangles in the image). $\endgroup$
    – trichoplax
    Mar 19 '17 at 1:14
  • $\begingroup$ Yes, I thought that as well but I am setting a isInside flag in the triangle intersection method. If it is true I then negate the normal vector. The flag is set if det < 0 using an intersection method I don't recall the name for now $\endgroup$
    – Telokis
    Mar 19 '17 at 2:33
  • $\begingroup$ I am using the Möller–Trumbore intersection algorithm $\endgroup$
    – Telokis
    Mar 19 '17 at 3:04

Many years ago I worked on a ray tracer that handled parametric surfaces, so this is unlikely to be state of the art, but, IIRC, I used a combination of interval arithmetic with (binary?) subdivision and Newton-Rhapson.

The interval arithmetic + subdivision constructed (conservative) bounding boxes which could be used for intersection rejection. I think I may also have used interval arithmetic on the 1st derivative to help determine when it was safe to launch into Newton-Rhapson. Typically the Newton steps converged very rapidly.

You can also pre-dice your parametric surfaces and put them into an acceleration structure (Voxel grid/BVH) to speed up the process.

This work was based on/inspired by Daniel Toth's 1985 paper "On Ray Tracing Parametric Surfaces"

  • $\begingroup$ Thanks for the answer but I have to admit that I don't understand everything. Could you put some concrete example or code so that I can't see more clearly please ? $\endgroup$
    – Telokis
    Mar 14 '17 at 17:30
  • $\begingroup$ Ok. I haven't got time today, but will try to add some more info soon(ish). $\endgroup$
    – Simon F
    Mar 15 '17 at 12:10
  • $\begingroup$ What you do suggest is that I keep using my method of constructing triangles but that I should use a spatial subdivision algorithm to "fasten" the calculation? $\endgroup$
    – Telokis
    Mar 16 '17 at 17:00
  • $\begingroup$ It seems to me you have two basic options though, in some senses, they can both converge to an 'equivalent' result: (a) Interval arithmetic, to weed out regions followed by Newton-Rhapson to solve for the ray intersection or (b) dice (i.e. tessellate) your object into "sufficiently small" triangles that you don't see discontinuity artefacts (as in your first image). In a sense these are "similar" since in (a) each Newton-R iteration approximates the surface locally as a plane (like a small triangle). I suspect b will be much easier to implement but tricky to estimate ideal subdivision level. $\endgroup$
    – Simon F
    Mar 17 '17 at 10:19

In general when doing parametric in a ray tracer you need a solution for

$\begin{cases} P = v * t + C \\ P = f(u,v) \end{cases}$

for the lowest $t$ where $f(u,v)$ is your parametric function $C$ is the camera position and $v$ is the ray direction.

There are a few general ways, for example if you can tell whether 2 points are on the same side or not you can take 2 points on the ray on opposite sides and binary search until you have the depth. You can find the first pair by marching along the ray.

  • $\begingroup$ What do you mean by "the same side"? I know the general idea of "how to do it" but I don't know how it happens in practice. Povray gives such an accurate and pretty result, I don't understand how it can possibly do it. $\endgroup$
    – Telokis
    Mar 14 '17 at 17:36

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.