XRT is a raytracing based programmable rendering system for photo-realistic image synthesis built around a plug-in architecture design.


Misc gallery updates

Posted: 24 Dec 2010 15:05
Tags: gallery


With the latest XRT release, not only ambient occlusion is a lot faster thanks to caching, but the image quality has improved due to the better statistical properties of the samples distribution. Visually speaking, a jittered stratified distribution requires approximately half the number of samples compared to a purely random distribution for the same result.

This is best examplified in the Structure Synth gallery which has been extended and updated.


I have also started a new gallery to illustrate color bleeding. Have a look here.

The BMRT gallery layout have been revised and a few examples have been updated.

Comments: 0, Rating: 0

XRT 1.1.0 released

Posted: 08 Dec 2010 22:47
Tags: caching downloads irradiance


XRT 1.1.0 major new feature is the support of indirect lighting between diffuse surfaces (also called color bleeding). Indirect lighting is the phenomenon in which objects or surfaces are colored by reflection of light from nearby surfaces. For instance, a red carpet next to a white wall gives a pink tint to the wall.

Computing indirect lighting is really simple: sample the hemisphere centered on the intersection point and oriented according to the surface normal by firing rays, shade each intersection and average the results. Because sampling is a random process, it produces noise which can only be smoothed out by taking many samples: 256 samples at a single location is a common number. Even worse, shading the intersected surfaces may as well spawn a new batch of rays for reflection, refraction, shadows or … indirect lighting, and so on recursively. It only stops when a ray reaches a light source or a perfectly diffuse surface. One can easily figure out that the number of rays can grow out of control.

Fortunately, there are a number of techniques to limit this exponential growth. One of them, irradiance caching, is based on the fact that diffuse lighting varies much more slowly than specular lighting and is a prevalent effect for most scenes (yes, a swimming pool is a perfect counter example). Therefore, there is no need to spawn specular rays when shading a surface hit by a diffuse ray and it is not necessary to compute diffuse lighting at every hit point: interpolating between results from sparsely distributed locations is enough. For that purpose, you need a caching mechanism.

XRT implementation of irradiance caching is based on "Practical Global Illumination with Irradiance Caching" from Jaroslav Krivánek and Pascal Gautron, available here, with (nearly) all bells and whistles1. Some restrictions apply:

  • neighbour clamping is implemented but disabled because it is currently much too slow.
  • last query reuse is not implemented
  • multiple bounces caching is not implemented
  • motion blur is not handled

Finally, XRT is now linked against libtcmalloc, Google replacement for Microsoft memory allocator (link). Without changing a single line of code, I have seen an average 20% performance improvement on rendering times. Not too bad …

As usual, the goods are available in the Downloads section.

Comments: 0, Rating: 0

Geek gift or Greek gift?

Posted: 28 Aug 2010 14:06
Tags: implicit surface


Most renderers deal only with a very limited subset of primitives: points, curves, polygons, nurbs, subdivision surfaces. Beyond this tiny set, there exists an almost ignored mathematical realm: implicit surfaces.

An implicit surface in 3D is defined as the set of solutions of an equation $f(x,y,z) = 0$ where $f$ can be any algebraic or non algebraic expression. It is called implicit because you cannot compute explicitely points on the surface: you have to solve for the equation first. The fact that $f$ can be pretty much anything you want lets you guess the variety of shapes that can be explored. As you can see in the implicit surfaces section of the gallery, most of them are of little practical use but have real aesthetic value.

Intersection algorithm

XRT implicit surface plugin implementation is based on a publication by Knoll et al. [1] where the inclusion property of interval arithmetic is used to define an efficient rejection algorithm briefly summarized below1.

A fundamental theorem of interval arithmetic states that, for any function f defined by an arithmetical expression, the corresponding interval evaluation function F is an inclusion function of f. In other words, if you define X, Y, Z as three intervals containing respectively the bounding values for x, y, z and evaluate $f(X, Y, Z)$ using interval arithmetic, the resulting interval is guaranteed to contain all possible values of $f(x, y, z)$ for any combination of (x, y, z) within the bounding box defined by (X, Y, Z). Using bounding boxes defined by ray segments and a recursive bisection algorithm (a binary search), it is possible to compute an intersection:

  • if a interval evaluation does not contain 0, the input ray segment is discarded.
  • if it does, the input ray segment is subdivided in two halves which are in turn evaluated.

When an interval evaluation contains 0 and the desired precision is reached, an intersection is returned. If no interval evaluation contains 0, there is no intersection.

XRT implementation is using GOAL for interval arithmetic computations.


Shape( "implicit") instantiates the "implicit" shape plugin and creates a new implicit surface. Accepted parameters are:

  • "string name": the name of the surface. This parameter is required.
  • "string function": the arithmetic expression in C code that defines the implicit surface. Using this C code, the "implicit" plugin generates a function plugin that provides a floating point evaluation function and an interval evaluation function. This parameter is required.
  • "float[6] bounds": the domain [xmin, xmax, ymin, ymax, zmin, zmax] where the surface is defined. This parameter is required because most implicit surfaces have an infinite domain. It also serves as a starting point for the bisection algorithm.
  • "float precision": the bisection algorithm stops recursing when an interval containing 0 with this width is met. This parameter is optional. The default value is 0.001 and is small enough for most functions.

Pyg format example:

Shape("implicit", "string name", "dingdong", 
    "string function", "sqr(x) + sqr(y) + z * (1 - sqr(z))", 
    "float[6] bounds", (-3, 3, -3, 3, -3, 3))

defines a implicit surface "dingdong" whose equation is $x^2 + y^2 + z(1 -z^2) = 0$ over the domain [ -3, 3 -3, 3 -3, 3].

This surface (and many more) is available in the implicit surfaces section of the gallery.

Optimizing render times

There are two main rules to decrease render times:

  • provide tight bounding boxes. Interval evaluation is a costly operation. Computing these evaluations for void space wastes CPU cycles.
  • provide optimized code for function evaluation. Minimizing the number of operations when evaluating a function interval is a key point which will yield huge savings:
    1. Try to factorize expressions.
    2. Remember that pow() is a very expensive operation and that sqr() or * are not.
    3. Use Horner's rule to rewrite polynomial expressions.

Let's provide two significant examples with Chmutov surfaces:

  • The Chmutov surface of order 6 is defined by the equation $T{_6}(x)+T{_6}(y)+T{_6}(z)=0$ where $T{_6}(x) = 32x^6-48x^4+18x^2-1$. Using rule 1, this expression can be rewritten as $T{_6}(x) = 2x^2(3-4x^2)^2-1$.
  • The Chmutov surface of order 7 is defined by the equation $T{_7}(x)+T{_7}(y)+T{_7}(z)+1=0$ where $T{_7}(x) = 64x^7-112x^5 +56x^3-7x$. Combining rules 2 and 3, this expression can be rewritten as $T{_7}(x) = x(x^2 (x^2(64x^2-112)+56)-7)$.

In both cases, rendering times with these optimized expressions are decreased by an order of magnitude over "naive" expressions.


To generate a function plugin, you need to have a C++ compiler installed (see Downloads section for more details). However, the implicit shape plugin will not rebuild an already generated function plugin.

1. A. Knoll, Y. Hijazi, C. D. Hansen, I. Wald, and H. Hagen. "Interactive ray tracing of arbitrary implicit functions". In Proceedings of the 2007 Eurographics/IEEE Symposium on Interactive Ray Tracing, 2007.
2. Jag Mohan Singh and P. J. Narayanan, "Real-Time Ray-Tracing of Implicit Surfaces on the GPU". Tech Rep. IIIT/TR/2007/72. July 2007

Rendering implicit surfaces is a bit addictive. Internet ressources are so numerous that you end up filling your hard drive with pictures, rising your CPU to insane temperatures and depriving you from sleep without ever paying attention.

"Abandon all hope, ye who enter here."

Comments: 0, Rating: 0

XRT 1.0.3 released

Posted: 28 Aug 2010 13:26
Tags: downloads implicit surface


XRT 1.0.3 exports a new Shape API call that loads a shape plugin at run-time. This way, the renderer can be extended to handle new primitives without changing the core. Actually, all primitives in XRT are implemented this way: the many primitives calls provided by the API are just convenient shortcuts using Shape.

As an example, I have implemented an implicit surface plugin (an implicit surface is the set of points that obeys to the equation $f(x,y,z) =$0 where $f$ can be any arithmetic expression). The thumbnail on the left is a rendering of such a surface1. The next post will fully document this primitive.

This release also fixes the flawed implementation of LookAt introduced in the 1.0.1 release. It was not working correctly with multiple cameras. All the generators that make use of this call have been updated, including the Structure Synth exporter.

The Reference Guide, along with a few layout changes, documents the Shape call and explains how to properly use LooKAt.

The goods are available in the Downloads section.

Comments: 0, Rating: 0

XRT 1.0.2 released

Posted: 22 Jul 2010 14:16
Tags: downloads luxrender ply


XRT 1.0.2 features a new generator plugin for PLY files loading. It is based on the RPly library from Diego Nehab (available here).

To stress the generator, I have hand translated some test scenes from LuxRays1 to Pyg. I have also updated XRT Python binding to enable object instancing within Pyg and redesigned a bit area lights to use geometry sets.

PLY geometry import works flawlessly but, given that XRT has no support for global illumination, the result is sometimes not convincing. Surface shaders could also be improved. Nevertheless, a few preliminary pictures are available here.

As usual, this new release along with the updated documentation is available in the Downloads section.

Comments: 0, Rating: 0

XRT 1.0.1 released

Posted: 07 Jul 2010 21:17
Tags: downloads gallery structure_synth


Structure Synth is a tool for generating 3D structures by specifying a design grammar (something akin to L-systems: a script with rewriting rules). Using simple rule sets, you can create very complex objects which looks like futuristic buildings, organic structures or abstract sculptures. It features a flexible template based export system for integration with third-party renderers. I believe this capability combined with SunFlow stunning renderings contributed a lot to its fame.

Of course, I could not resist writing a similar export template for XRT. It exports Structure Synth camera settings and shades the geometry with an ambient occlusion shader. To ease the process, I have added a Python binding for XRT LookAt API call bumping XRT version to 1.0.1.

This new release along with the exporter, the shader and the updated documentation is available in the Downloads section.

A new section of the gallery dedicated to Structure Synth is now available here.

Comments: 0, Rating: 0

What's next?

Posted: 28 Jun 2010 16:55
Tags: roadmap

Here is what I plan to do for version 2.0.

The most important added features will be:

  • Catmull-Clark subdivision surfaces
  • multi-threaded rendering
  • OpenImageIO library integration
  • deformation blur
  • occlusion cache for faster ambient occlusion
  • color bleeding (and of course irradiance caching)

I also want to add lesser (in terms of development effort but nevertheless useful) features:

  • primitive variables
  • imagers
  • file format support: PLY, OBJ
  • shader message passing
  • shadeops
  • geometry sets
  • shadow bias support
  • nurbs curves
  • Python bindings for XRT extensions to Gelato
  • any other fancy stuff that allows me to render a nice picture

The third major topic will target optimisation:

  • run a profiler to identify architectural and implementation bottlenecks
  • review existing acceleration structures and possibly implement new ones (sbvh, bih, qbvh)

My ultimate goal for this release is to able to render scenes exported from Blender by Eric Back's MOSAIC.

I guess it's probably going to take me 18 to 24 months to complete all these tasks but most of them are really incremental changes. Now that packaging the software and the documentation is a lot quicker, I intend to issue releases much more frequently (when I complete new features).

Comments: 0, Rating: 0

XRT 1.0.0 released!

Posted: 07 Jun 2010 17:28
Tags: downloads

After months of exhaustive testing, the first release of the XRT renderer is finally available for public consumption here. Despite the time spent, there are a few bugs remaining and important features like subdivision surfaces or global illumination are still missing. Therefore, you should not probably rely on it for mission critical duties.

However, the gallery is large enough to testify that you can already do a lot with XRT. If you render something nice with it, drop me a message on the Forum. If you have troubles, find something that does not work as expected (the Overview page should give you a good idea of XRT current feature set) or want to ask a question, the Forum is also the place to go.

Hope you will enjoy it!

Comments: 0, Rating: 0

The RenderMan Companion

Posted: 23 Mar 2010 22:59
Tags: arman gallery rc rfb


Since the beginning of the year, I have entered a fairly intensive bug-fixing phase: pick a set of scenes, compute reference renderings, compare the results with XRT output and hack the code until it gets right. Lather, rince, repeat …

This is rather tedious and will probably last a few more months but I am making good progress. Of course, because there are features that I have not yet implemented, some scenes cannot look right but I have decided to halt any further development until I am confident that the current code base is solid enough.

Less bugs means also more new pictures for the galllery. Their number has steadily increased and is now over 200.

I am just done with the examples of the RenderMan Companion. This is a fairly old book (1989), so old that, at the time of its writing, the RIB file format was not yet defined and all examples were provided as C programs. These are good test cases for XRT RIB client library.

Although RenderMan Companion image content cannot really be considered any longer as cutting edge (its follow-ups, Advanced RenderMan or Renderings for Beginners, are a bit more challenging), you will find some nice pictures here.

Comments: 0, Rating: 0

Constructive Solid Geometry

Posted: 20 Feb 2010 12:35
Tags: csg


The most widely known algorithms for rendering constructive solid geometry (CSG) require finding all intersections of a line with a primitive and then computing the intersections by examining the intervals. This is clearly inefficient because you need to store and compute all the intersections for all the sub-objects of the CSG tree. Not only you don't really need to know all intersections to find the nearest one but the storage/deletion of many hits within a rendering loop is a real performance killer. Another issue is that you must rewrite all your primitive intersection routines to support CSG which increases the code bloat.

Therefore, CSG support within XRT is based on a different algorithm described in a short paper from Andrew Kensler: Ray Tracing CSG Objects Using Single Hit Intersections. This paper is no longer available on the web but you can find a local copy here.

As the author states in his introduction:

"The [algorithm] computes intersections with binary CSG objects using the [nearest] intersection. Though it may need to do several of these per sub-object, the usual number needed is quite low. The only limitation of this algorithm is that the sub-objects must be closed, non-self-intersecting and have consistently oriented normals."1

Algorithm outline

A ray is shot at each sub-object to find the nearest intersection, then the intersection with the sub-object is classified as one of entering, exiting or missing it. Based upon the combination of the two classifications, one of several actions is taken:

  • returning a hit
  • returning a miss
  • changing the starting point of the ray for one of the objects and then shooting this ray, classifying the intersection. In this case, the state machine enters a new loop.

The paper finally describes the state machine and the 3 different state tables (one for each CSG operation Union, Intersection and Difference) needed to raytrace a CSG tree. This a very neat idea expressed clearly and concisely: the paper is 3 pages long, 2/3 of it made of diagrams, state tables and pseudo code ready to be translated into C++. A real programmer's heaven.

But it doesn't work.

The state table for Union is OK but the state tables for Intersection and Difference are not. Even with very simple cases, when you run the routine with pen and paper, it fails. The good news are that it can be fixed with a few minor changes:

  • create two other actions
  • change the result of one combination in the Difference and Intersection tables
  • update the state machine

My changes are given below in bold.

List of actions

ReturnMiss Exit, reporting no intersection
ReturnAIfCloser Return the intersection with A if it is closer
ReturnAIfFarther Return the intersection with A if it is farther
ReturnA Always return the intersection with A
ReturnBIfCloser Return the intersection with B if it is closer
ReturnBIfFarther Return the intersection with B if it is farther
ReturnB Always return the intersection with B
FlipB If returning an intersection with B, flip its normal
AdvanceAAndLoop Continue with the next intersection with A
AdvanceBAndLoop Continue with the next intersection with B
AdvanceAAndLoopIfCloser Continue with the next intersection with A if the current intersection with A is closer
AdvanceBAndLoopIfCloser Continue with the next intersection with B if the current intersection with B is closer

Action tables

Union Enter B Exit B Miss B
Enter A ReturnAIfCloser, ReturnBIfCloser ReturnBIfCloser, AdvanceAAndLoop ReturnA
Exit A ReturnAIfCloser, AdvanceBAndLoop ReturnAIfFarther, ReturnBIfFarther ReturnA
Miss A ReturnB ReturnB ReturnMiss
Difference Enter B Exit B Miss B
Enter A ReturnAIfCloser, AdvanceBAndLoop AdvanceAAndLoopIfCloser, AdvanceBAndLoopIfCloser ReturnA
Exit A ReturnAIfCloser, ReturnBIfCloser, FlipB ReturnBIfCloser, FlipB, AdvanceAAndLoop ReturnA
Miss A ReturnMiss ReturnMiss ReturnMiss
Intersection Enter B Exit B Miss B
Enter A AdvanceAAndLoopIfCloser, AdvanceBAndLoopIfCloser ReturnAIfCloser, AdvanceBAndLoop ReturnMiss
Exit A ReturnBIfCloser, AdvanceAAndLoop ReturnAIfCloser, ReturnBIfCloser ReturnMiss
Miss A ReturnMiss ReturnMiss ReturnMiss

State machine pseudo-code

The algorithm is slightly modified to take into account the new actions. Please note that minA and minB must not be initialized to 0.

minA = minB = min // current nearest intersection
( tA, NA ) = IntersectWithA( O, D, minA )
( tB, NB ) = IntersectWithB( O, D, minB )
stateA = ClassifyEnterExitOrMiss( tA, NA )
stateB = ClassifyEnterExitOrMiss( tB, NB )
  action = table [stateA, stateB]
  if ReturnMiss ∈ action then
    return miss
  else if ReturnA ∈ action 
    or ( ReturnAIfCloser ∈ action and tA <= tB ) 
    or ( ReturnAIfFarther ∈ action and tA > tB ) then
    return tA, NA
  else if ReturnB ∈ action 
    or ( ReturnBIfCloser ∈ action and tB <= tA ) 
    or ( ReturnBIfFarther ∈ action and tB > tA ) then
    if FlipB ∈ action then
      NB = −NB
    end if
    return tB, NB
  else if AdvanceAAndLoop ∈ action 
    or ( AdvanceAAndLoopIfCloser ∈ action and tA <= tB ) then
    minA = tA
    ( tA, NA ) = IntersectWithA( O, D, minA )
    stateA = ClassifyEnterExitOrMiss( tA, NA )
  else if AdvanceBAndLoop ∈ action 
    or ( AdvanceBAndLoopIfCloser ∈ action and tB <= tA ) then
    minB = tB
    ( tB, NB ) = IntersectWithB( O, D, minB )
    stateB = ClassifyEnterExitOrMiss( tB, NB )
  end if
end loop

You will find some examples of this feature in the gallery

Comments: 0, Rating: 0

Ambient occlusion

Posted: 22 Jan 2010 22:40
Tags: ambient occlusion


Ambient occlusion measures how much of the hemisphere above each surface point is occluded by other objects in the scene. It is computed by tracing rays randomly distributed around the hemisphere above each shaded point. In the example picture, the shader colors pixels white if they have a completely unoccluded view of the hemisphere, and black if the view of the hemisphere is completely occluded: the result looks a bit washed out similar to the way an object would appear on an overcast day.
Because it takes into account other objects for lighting computations, it pretends to be a global illumination solution but is not physically based. Anyway, this is a much better solution for computing the ambient term compared to adding the usual constant to the rendering equation. The only drawback is that you need to fire lots of ray per pixel to get rid of the noise (random distribution of rays = noise).
Implementing ambient occlusion is as simple as its definition: if you already have shadow rays in your renderer, it takes a mere 20 lines of code.
Despite its simplicity, it gives surprisingly convincing results. Therefore, it is part of the toolbox of all major CGI studios: Pixar, DreamWorks, Sony Pictures and the likes. You will find more examples of this feature in the gallery (look here)

Comments: 0, Rating: 0

OSL is out

Posted: 16 Jan 2010 18:12
Tags: compiler langage osl shading


Quoting Sony Pictures Imageworks Open Source Software site: «Open Shading Language (OSL) is a small but rich language for programmable shading in advanced renderers and other applications. OSL is similar to C, as well as other shading languages; however, it is specifically designed for advanced rendering algorithms with features such as radiance closures, BRDFs, and deferred ray tracing as first-class concepts.

The OSL project includes a complete language specification, a compiler from OSL to an intermediate assembly-like bytecode, an interpreter that executes OSL shaders on collections of points in a SIMD manner, and extensive standard shader function library.»

Although the project is not yet production-ready, browsing the source code is very instructive: aside from the fact that the project is a very good demonstration of how to design a langage compiler and byte code interpreter, it features things that I never seen before: automatic differentiation of expressions, symbolic computing. These features allow a raytracer to compute derivatives in a very efficient manner (no need to evaluate three times a shader like BMRT did in its time, once is enough) or to perform fast relighting (running a shader does not return a color but a symbolic expression that can be stored and evaluated later against a different set of light sources). There are many other aspects of OSL that are well thought out and will favor the implementation of global illumination renderers.

For all these reasons, OSL looks like a very worthwhile component to add to the XRT renderer. However, the langage specification is not yet complete and there is currently no way to define the equivalent of RenderMan shading langage "illuminance loops" (except by wiring them into the renderer). This is a long term goal for the project but is not due soon. The roadmap will probably be detailed in the forthcoming months.

One thing I am contemplating is that, given that RSL and OSL already share a lot (keywords, types, function library), it should be possible to transform the OSL compiler into a RSL one without too much hassle. This would allow me to reuse most of OSL.

Comments: 0, Rating: 0