bramz' diary : Fixing transformations and local geometry

April 20th, 2006 by bramz

Today, I noticed there was something seriously wrong with the way local differential geometry was treated by transformation objects.

Basically, rendering goes like this: find intersection, find geometry of intersection, get shader at intersection, shade using the geometry. However, currently, if the object being intersected is a transformed one (by scenery::Transformation), all local geometry (3D point, normal, …) was transformed to global space, the top level of the transformations. So, all shading was done in global space. Is that bad? Yes. Imagine a sphere that uses a 3D texture like CheckerVolume, and this sphere moves from the left to the right. Because the value of the texture is looked up in global space, this means that the sphere will move while the checkerboard pattern is stuck to its global position. This is not what is wanted. The pattern should be fixed to the object!

OK, seems easy to solve that: don’t transform local geometry! Instead, when shading, transform all global information (eye rays, light rays, …) to local space. Well, not exactly … There’s a bit of a problem to this approach: suppose you create a complex object using CSG and some transformations, then every part of that object will have its own local space. If you apply one 3D texture to the complex object, you’ll notice that you won’t get a continuous texture: it will jump from one local space to another.

So, we need a combination of both. Basically, from the observation above, we want to do the shading in the coordinate space of the (compound) object the shader was attached to (let’s call it shader space). The untransformed sphere in the first case, the complete CSG object in the latter. When retrieving local geometry, transform it up (towards global space) until you get to the object with the shader attached. From there, keep track of a single transformation from shader to global space.

Using this approach, we get the following result. One sphere with radius 1 is instanced three times: once without transformation, and two times scaled up by a factor 2.

  • The middle sphere is the untransformed sphere and a shader attached with a standard CheckerVolume texture. For this one, local space = global space = shader space.
  • The left sphere is a second instance of the middle sphere, but scaled up by a factor of two. The shader space is still the local space of the untransformed sphere. As result the texture is scaled up together with the object.
  • The right sphere is a third instance of the same sphere, however this time, the shader is attached to the transformed sphere. This means that the shader space = global space. As result, the pattern has the same size of the untransformed sphere.

Transformations and shader space

script: examples/scenery/transformation.py

bramz' diary : shaders or BSDFs?

April 18th, 2006 by bramz

I’m in a bit of a design dilemma right now … Currently, materials are implemented as shaders. This is similar to the RenderMan Interface. Each material is a piece of code that gets executed when the ray tracer hits the surface, and yields the outgoing radiance (the colour to be rendered). That’s great, we have maximum flexibility, and we keep open the possibility to be somewhat, more-or-less compatible to the RenderMan Interface.

Add photon mapping to the mix (or another GI thingy like path tracing, radiosity, … though radiosity might still do with the shaders above?). Suddenly, those shaders aren’t so cute anymore. Since photon mapping basically shoots a photon at a surface, and wants to know in what direction that photon will be scattered. This is very BRDF oriented. We can’t really do that with shaders, or can we?

So here’s the dilemma … abandon shaders, or come up with a solution that fits both? What solution?

bramz' diary : cornell box (direct lighting only)

April 17th, 2006 by bramz

Today, I’ve being translating the ever-famous Cornell box to a python module. Of course, I also had to make some render, so here it is. Since I still only have direct lighting (ok ok, I really need to fix that =), the result is not so terrific. But there’s at least soft shadows ;)

Cornell box (direct lighting only)

The scripts are available in the examples/cornell_box directory.

bramz' diary : area lights

April 16th, 2006 by bramz

Today, I’ve been playing a bit with area lights … They are implemented as a scene object scenery.LightArea that takes another scene object as light surface. I’m not entirely happy with it, but here’s some tests …

The first one is the good ol’ red sphere with a spherical area light. The entire scene is also illuminated by a blueish sky. 9 samples per pixel, 16 light samples for the sphere and 36 for the sky.

area light ...

Happy Buddha under a bright white sky … 9 samples per pixel, 64 light samples

happy buddha under a white sky

The sky surface is a bit troublesome because it LiAR isn’t exactly designed to cope with points at infinity. Currently, it’s just a giant normal sphere, but it should be examined how we can improve that.

We also need to be able to texture map the area lights so that we can use a nice HDR image as sky =)

news : Subversion

April 16th, 2006 by bramz

We’re glad to announce that we’ve migrated the LiAR source code from the CVS to a Subversion (SVN) repository. SVN is generally available on sourceforge since February, and by making this move, we’ll allow for more flexible code management.

You can grab the latest code from the repository by the following command:
svn co https://svn.sourceforge.net/svnroot/liar/trunk/liar/

The repository is also browsable. More info can be found on the project page

bramz' diary : RenderTarget with PixelToaster

March 13th, 2006 by bramz

I’ve just implemented a RenderTarget called Display which shows the image on screen while being rendered. I’ve used the almighty PixelToaster to accomplish this, which turned out to be pretty easy. Here’s the recurring red sphere on a blue checkerboard plane being rendered in a window:

Scene rendered to Display RenderTarget (using PixelToaster)

One lesson learned: you should never update a PixelToaster display in another thread than in the one you’ve opened it. Upon the first call of update(), somewhere deep inside the function, there’s a call to the Win32 ShowWindow function (the window still is hidden when you open it). However, that call will block when it’s called from a different thread than the one to create the window …

Things to do: currently, the window closes the moment the render is finished … We’ll need the “press any key” feature!

bramz' diary : blender export!

February 18th, 2006 by bramz

It’s been a while since my last update. Two months to be exact. What have I been doing in that time? Not that much … I’ve been struggling with lights … How do lights fit in the grand design of a ray tracer? Are they objects? Are they shaders? Or even something completely different? I’ve settled with the first option: lights are objects. I don’t know if that’s the best decision, but you have to make one to get on, don’t you? Anyway, that’s not the subject of this post. I’ve also been working on a script to export scenes in Blender to a LiAR script.

You can’t continue crafting your scenes in raw Python code forever. One day, you want to use a real modeling program. And what program better suits this need than Blender? First of all, it’s free and open source. But secondly (and perhaps more interesting for LiAR), it has an embedded Python environment. So, we can write our export script in pure Python, which is of course great.

It takes a while to get the hang of their Python API, but once you get the feeling, it’s fairly easy. And so here’s the first result. I’ve managed to export the default scene (the one you get when you start Blender) to a LiAR script, and to actually render it. It’s not exactly spectacular (it’s rather dull even), but it works. A lot of features are still missing, but that’s not so important. The important thing is that the export works. Here it is (model courtesy blender.org =) …

I can’t link to the code, because it’s not in the CVS yet, but when it is commited, you’ll find it in extras/blender_scripts/liar_export.py

default scene of Blender rendered by LiAR isn't a raytracer ...

bramz' diary : PHD-Motorsports FZR

December 15th, 2005 by bramz

A render of the new PHD-Motosports skin for the FZR. Wimz is doing an amazing job on those skins. There’s a nice detail you can’t see from this point of view: the driver’s name with a little Belgian flag. Great!

The cars are rendered with depth of field for a more realistic image …

FZR with new skin and DOF.  Model by liveforspeed.com, skin by phd-motorsports.com

Model by Live for Speed, custom skin by PHD-Motorsports.

bramz' diary : depth of field

December 4th, 2005 by bramz

Some time ago, I mentioned I was implementing depth of field in LiAR. Well, I finally managed to code and test it. The following image illustrates the depth of field effect. The left part is rendered by a pinhole camera, the right part by a camera with a circular lens. You can find the script on the CVS: examples/cameras/depth_of_field.py

illustration of depth of field on a grid of spheres.  render script: examples/cameras/depth_of_field.py

Adding depth of field to a ray tracer is rather easy once you’re familiar to the concepts of distributed ray tracing (which isn’t too hard either). First, you generate a primary ray as usual and you determine it’s intersection with the focal plane. This is a (virtual) plane orthogonal to the camera direction and al points on this plane will be in focus. Then you generate a new origin of the primary ray. This is done by picking a random point on the camera “lens”, which is a disk orthogonal to the camera direction and with the camera position as center. The best way to do this is by generating stratified \left(u,v\right) samples in the range \left[0,1\right]\times\left[0,1\right] and to transform them to a disk (Peter Shirley has written a paper on how exactly to do this). Finally, you generate the new ray direction from the point on the lens to the intersection on the focal plane. This makes sure everything on the focal plane is indeed in focus. Voila, that’s it!

bramz' diary : renders of LX6

December 3rd, 2005 by bramz

This week, I’ve been mostly rendering … cars.

Front view of the LX6 cars with team skin.  Model courtesy

It’s been a while since my last update. I’ve been rendering cars for PHD-Motorsports. The setup is rather simple. The same triangle mesh is instantiated three times with a different skin. There are three point lights: a pure white key light in the front left corner, a blueish fill light in the front right corner, and as last a blueish back light.

side view with motion blur

Of course, we also had to render some “action”, so we added a bit of motion blur to the side view of the cars. A checker board is added a floor to have a fixed object as reference.

Model and skin by Live for Speed and PHD-Motorsports.