About
XRT is a raytracing based programmable rendering system for photo-realistic image synthesis built around a plug-in architecture design.
Blog
Geek gift or Greek gift?
Posted: 1283004403|%e %B %Y, %H:%M|agohover
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
where
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
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
using interval arithmetic, the resulting interval is guaranteed to contain all possible values of
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.
Usage
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
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:
- Try to factorize expressions.
- Remember that pow() is a very expensive operation and that sqr() or * are not.
- 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
where
. Using rule 1, this expression can be rewritten as
. - The Chmutov surface of order 7 is defined by the equation
where
. Combining rules 2 and 3, this expression can be rewritten as
.
In both cases, rendering times with these optimized expressions are decreased by an order of magnitude over "naive" expressions.
Requirements
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.
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
Posted: 1283002007|%e %B %Y, %H:%M|agohover
Tags: implicit release 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
0 where
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
Posted: 1279808178|%e %B %Y, %H:%M|agohover
Tags: luxrays 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
Posted: 1278537439|%e %B %Y, %H:%M|agohover
Tags: 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: 1277744127|%e %B %Y, %H:%M|agohover
Tags: roadmap
Here is what I plan to do for the next release.
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 is out!
Posted: 1275931694|%e %B %Y, %H:%M|agohover
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: 1269385159|%e %B %Y, %H:%M|agohover
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: 1266669347|%e %B %Y, %H:%M|agohover
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 )
loop
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: 1264200022|%e %B %Y, %H:%M|agohover
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: 1263665541|%e %B %Y, %H:%M|agohover
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
Motion blur (the end?)
Posted: 1261243165|%e %B %Y, %H:%M|agohover
Tags: blur motion transformation
After a long struggle with my laziness, I finally found the energy to complete (sort of) motion blur. I have left deformation blur and attributes blur (see here for an explanation of these terms) aside for the moment and focused on transformation blur.
It turned out that my first implementation was at the same time partly buggy and awfully slow. To take motion into account, I was enlarging any affected primitive bounding box before inserting them into my acceleration structure. It was therefore no big surprise that it was really inefficient. A(nother) complete overhaul was needed. Pfff …
Back to the drawing board, I figured out that, usually, motion is applied to a group of static primitives for which an efficient acceleration structure can be computed. Therefore, I have redesigned the scene parser to output a hierarchy of acceleration structures (aggregate) instead of a single one. Motion blur is applied only at the aggregate level. Underneath, everything has tight and efficient bounding boxes. As a result, I got a 60x speedup compared to my first naive implementation and it also cured magically my bugs!
I have added a page in the gallery to demonstrate these new features.
Comments: 0, Rating: 0
Motion blur again
Posted: 1253050001|%e %B %Y, %H:%M|agohover
Tags: blur motion transformation
I am finally done with a first implementation of transformation motion blur (for some examples, go here). As expected, extensive changes to transformation and intersection routines were needed. However, this is not the end of it. Let me explain why in a few words.
Motion blurred transformations are created by giving a sequence of transformations at different times and can be concatenated and nested hierarchically. The number of time samples may be different for each transformation. When a ray is fired, it is given a random time. When a primitive is tested for intersection by a ray, this time is used to retreive the corresponding motion segment and to interpolate the current transformation between the two ends of the segment.
Right now, I am using linear interpolation between transformations. This works well for scales, translations and small rotations but is obviously wrong for large rotations. It's just an faster path to get a feel on motion blur. I know there is a much better solution: quaternions and spherical interpolation. This will be the next step.
Comments: 0, Rating: 0
Gelato gallery updated
Posted: 1252858132|%e %B %Y, %H:%M|agohover
Tags: gallery gelato
I have added new examples and updated some others because they really benefited from the last features I have implemented: improved sampling and blurred shadows. I have also completely changed the gallery layout to display full resolution pictures. It's less straightforward than to use Wikidot builtin gallery but one cannot see anything worthwhile on a confetti. Have a look here.
Comments: 0, Rating: 0
Improved sampling
Posted: 1252448776|%e %B %Y, %H:%M|agohover
Tags: pbrt sampler stratified
If you are serious about raytracing, give yourself a favor and buy Physically Based Rendering from Matt Pharr & Malcolm Humphreys. It's huge, it's thick, it weighs a ton and will not fit in your pocket but this is definitely the reference book on the subject. Because I felt bad sampling was possibly responsible for my noisy motion blur images (see my previous post), I have opened it once again and reread chapter 7 which deals with sampling and reconstruction (by the way, this chapter is available for downloading here). This led me to conclude it was time to ditch the current "uniform" sampler and to add a brand new sampler plugin: the "stratified jittered" sampler. It was quite straightforward to adapt PBRT implementation to XRT.
| Camera motion blur |
![]() |
| rendered with uniform sampling |
| Camera motion blur |
![]() |
| rendered with stratified sampling |
This is still not as good as the 3Delight reference image but a lot closer to it. The PBRT book describes other samplers:"low discrepancy" and "best candidate" which should give even better results.
Comments: 0, Rating: 0
Motion blur: first steps
Posted: 1251843631|%e %B %Y, %H:%M|agohover
Tags: 3delight blur motion
I am currently adding motion blur support to XRT.
Actually, motion blur designates four different features:
- camera motion blur, where blur occurs when the camera moves
- transformation motion blur, where blur occurs when the transformation attached to a scene object changes
- deformation blur, where the actual object geometry changes
- attributes blur, where the surface properties of objects changes over time
Camera motion blur is the easiest to implement because it affects only the camera world transformation and therefore does not require extensive changes. Here is a first rendering. The camera turns from right to left while aiming a green matte sphere.
| Camera motion blur |
![]() |
| rendered with XRT |
I am not completely happy with the result because it is way too noisy. The same scene rendered with 3Delight is a lot smoother.
| Camera motion blur |
![]() |
| rendered with 3Delight |
A possible explanation for this noise is that XRT sampling strategy is a bit crude: a regular grid is used with no jitter. I'll try smarter schemes in the future.
Comments: 0, Rating: 0
More Wikidot lore
Posted: 1248957167|%e %B %Y, %H:%M|agohover
Tags: website
- added autonumbering to posts not to worry any more about page names
- renamed existing posts to fit with autonumbering
- updated blog template and main page to improve tags display
- changed the CSS theme of the blog to a fixed width to get a more consistent page layout across different screen sizes
- slightly updated the layout of some of my previous posts (bigger pictures with a nice border)
Comments: 0, Rating: 0
New RenderMan repository gallery
Posted: 1248271617|%e %B %Y, %H:%M|agohover
Tags: gallery rmr shader
I have started a new gallery with examples from the RenderMan repository. This is a very good demonstration of the power of programmable shading. Most of these examples feature very simplistic geometrical content (just one sphere or one square): the real image content comes from the shaders.
Comments: 0, Rating: 0
Hairy monster
Posted: 1247213523|%e %B %Y, %H:%M|agohover
Tags: fur gallery gelato
There is a new creature in the Gelato gallery that demonstrates XRT fur rendering capabilities. Frightening, isn't it ?
The rendering times are frightening too (more than 10 hours on my PC). Because the fur is made of tiny little curves, sampling has been set to 6x6 subsamples. Otherwise, aliasing starts to appear as tiny holes in the individual hairs. The other issue that explains long rendering times is the fact that, in a given volume, there are lots of primitives. The BVH acceleration structure that I am using is obviously having a hard time choosing a sufficiently small set of candidates for intersection testing. This is a problem that I have already noticed while benchmarking with other simpler scenes but for which I haven't yet found a solution (improved implementation or better algorithm ?).
Comments: 0, Rating: 0
New Rendering for Beginners shader gallery
Posted: 1246913205|%e %B %Y, %H:%M|agohover
Tags: gallery rfb shader
I have built a shader gallery with examples from the Rendering for Beginners book
Comments: 0, Rating: 0
Improving the gallery (part 3)
Posted: 1246570585|%e %B %Y, %H:%M|agohover
Tags: arman gallery
The Advanced RenderMan gallery is now up to date.
































