Advanced Displacement in Arnold (Patreon)
Content
Most great renders require great displacement. The fine details you get from a high resolution displacement map are crucial for photorealism. The downside that comes along with this is that it's easy to run out of memory fast if you have to subdivide meshes a lot. Thankfully, there are a number of settings in Arnold that can make the process of subdividing for displacement much smoother.
I'm using Maya for all these examples, but they should apply to Arnold in any DCC. In fact, the principles will translate to pretty much any renderer, although the terminology and specifics will be different.
Max Subdivisions
The first thing to do on any project is to set the Max. Subdivisions override. We've all been there: instead of 5 you type 55 when setting the subdivisions on a mesh. Too late, you realize the render was still running, so goodbye Maya. By setting the global maximum you can easily avoid this.
Frustum Culling
For those who don't know, "frustum" in this case basically means "everything in the camera's field of view." If you enable Frustum Culling you're telling Arnold to not subdivide any meshes that are outside the camera's view, or any that are on camera but hidden behind something else.
To test what this setting does is in practice, I measured time to first pixel (TTFP) on this closeup from my recent butterfly project. The eye is highly subdivided to capture the detailed displacement.
Without frustum culling TTFP is 1m7s. Turning it on, TTFP is 22s, a massive improvement.
One caveat here is that any displaced or subdivided mesh off camera that creates reflections or shadows on camera will not render as desired with culling on. In this case you can either increase the padding to try to capture the objects, or you just won't be able to use culling in that situation.
Adaptive Subdivision
Another way to significantly improve Arnold's performance is to enable Adaptive Subdivision on a per-mesh basis.
Here I've set the subdivision on the butterfly head to "catclark" with 7 iterations to capture maximum detail. I arrived at 7 after testing various levels. Below 7 lost some detail, above 7 showed no visual difference and quickly got too memory intensive.
Adaptive Metric is fine to leave at "auto." Arnold will use the appropriate method depending whether a displacement shader is connected to the mesh. The "flatness" option will create a smooth mesh at rendertime, but might sacrifice displacement detail. The other option, "edge_length," will retain detail at the expense of a heavier mesh.
Adaptive Error determines how finely detailed subdivision and, by extension, displacement is. The default is zero, which disables adaptive subdivision and brute forces the number of iterations you have set.
In this test I set the error to 1 and Adaptive Space to "raster." This means that Arnold will subdivide the mesh not until max iterations are reached, but until the subdivided edges reach a resolution of 1 pixel or less. This can vastly increase performance as there is no need to subdivide a mesh that is further from the camera when doing so would result in details smaller than a single pixel.
To test this I simply compared the butterfly eye closeup, above, with a wide shot:
You would expect a much faster TTFP in the wide shot using adaptive subdivision as the details never need to be smaller than one pixel. By using non-adaptive subdivision you're demanding that Arnold crank out details that are actually invisible in the render.
And this is exactly what happens. Using adaptive subdivision TTFP is 4 seconds. (Actually, call it TTFBP, time to first butterfly pixel. The background begins to render regardless, but the hangups start happening when the render buckets get to the butterfly's head.)
Turn off adaptive subdivision and the TTFBP shoots up to 2m44s. A workaround might be to drop the iterations to 5 or lower. While this indeed works, it's a pain since you would have to manually set the iterations based on how far objects are from the camera. It's much easier to use adaptive subdivision and let Arnold take care of the rest.
One final note: Adaptive Space can be set to either "raster" or "object." The Arnold docs recommend object when instancing as instances might be varying distances from the camera and so one raster setting might not be optimal. I find that object is a bit annoying to use in practice since the values can often be very small. For example, with this small butterfly I had to set the error to something like 0.0004, versus 1 for raster. You can determine which is best on a scene by scene basis.
Conclusion
As you can see, it's possible to get big performance improvements by making some small changes to how Arnold handles subdivision. Especially when doing lookdev this can be a lifesaver: you'll get much faster TTFP and more responsive feedback as you move around your scene.