One major endeavour that I undertook this past summer was the creation of a novel displacement mapping system for Maverick Render.

The main motivations behind this have been:

  • Our customers were running out of GPU memory too often when using displacement.
  • Our main goal is that Maverick is an exquisite-quality tool for model visualization. Hence displacement is very important to us.
  • Open the door to some other geometry-generation features beyond displacement itself.

So I undusted the old virtualized geometry solution I implemented for fryrender back in 2008 and re-engineered it for the Maverick core in the GPU.

Say hi to: Micro-Patch Displacement Mapping

Non-affine MPDM in arbitrarily-curved surfaces

Affine MPDM in flat surfaces

Some good properties of Maverick’s displacement:

  • No requirements whatsoever on the base mesh or on the heightmap texture.
  • It costs near 0 in warm-up time.
  • It costs near 0 in memory (only a small payload is appended to the height map).
  • 0 information is lost; every single texel in the heightmap is turned into a displaced micro-patch.
  • Implemented as a custom primitive in Maverick’s OptiX ray-tracing backend.
  • Used every trick in the book to optimize it as much as I could.

MPDM vs. brute-force

MPDM is meant to address some classic problems with the subdivide-and-displace-vertices (brute-force) approach. Using brute-force:

  • There is some (often significant) wait time for warm-up.
  • Memory usage goes through the roof, more than often blowing up all available memory.
  • Height sampling happens at the vertices and not at the heightmap texels.

Points 1-2 are very obvious. It becomes impossible to abuse displacement, or to recklessly use it for large surfaces. Some techniques such as back-face culling or camera culling can be used to work around these difficulties, but such techniques pose problems on their own. Expecting the user to be careful not to exceed his memory budget is always an ill-fated plan.

Point 3 often means that the resulting displacement is smudgy, and not as crisp as it should be. i.e., information is lost, and/or geometry is produced in excess. Some techniques (that Maverick itself has featured in the past) such as autobump can be used to work around this problem by kind-of-restoring the information that is lost in the process. But then again, optimal configuration would become the responsibility of the user.

None of these issues happen with MPDM. :-)

Are there any benefits to the old brute-force approach?

As usual, nothing really good comes without a price. This is often very true in the realm of algorithm optimization.

  • MPDM unfolds virtualized geometry during ray-traversal. The displaced geometry never exists for real in memory (that is why it is said to be virtualized) and this is the reason why MPDM has a near 0-cost in memory usage. However, this virtualization comes at an algorithmic cost. Despite massively optimized, MPDM renders a bit more slowly than the same displaced geometry would if the vertices were pre-displaced during warm-up and entered the ray-tracing BVH as regular geometry.
  • For MPDM, part of the optimization process relies on the fact that the input map is discretized in texels, (as in a regular bitmap). For brute-force displacement the only requirement is that the height map can be evaluated at each geometry vertex, which is true to bitmaps, procedurals, and all map types. So MPDM is a priori limited to filetex maps, but we have added to Maverick a new map type called bakemap so the user can bake any procedural map tree into a filetex to feed MPDM if necessary.

How does MPDM work?

Here’s a very broad explanation on how MPDM in Maverick works:

  • A (rather classic) hierarchical partitioning scheme based in min-max mip-map levels is performed on the input heightmap. As depicted in the images below.
  • Those voxels are efficiently ray-traceable… unless there is curvature in the base mesh. Hell breaks loose as soon as curvature is at play. Maverick does non-affine math here (visualized in a previous post on non-affine triangle sweeps). I’ve tried different approaches for this (non-affine, discretized, and hybrid), and the code allows to flag-switch each mode on and off.
  • Because of the non-affine treatment, at the lowest hierarchy level you no longer have quads or triangles, but bilinear patches (hence the name: Micro-PATCH Displacement Mapping).

Non-affine MPDM in arbitrarily-curved surfaces

Non-affine MPDM in arbitrarily-curved surfaces

The input heightmap used

The input heightmap used

Affine MPDM in flat surfaces (special optimization branch)

Affine MPDM in flat surfaces

The input heightmap used

The input heightmap used

But the devil lies in the details. Efficient implementation of this all was a multi-week hell working with data structures, low-level optimizations, coordinating MPDM with OptiX and the rest of the Maverick core, and dealing with plenty of non-obvious fine-grain issues such as:

  • Avoiding cracks across edges.
  • Dealing with UV mapping projections.
  • Transfer of shading normals.
  • Real-time notifications from the UI.

Youtube 4K videos: