Archive for the ‘ Blender ’ Category

GSoC: midterm evaluation

Apologies for not having updated my blog recently. There’s quite a lot of stuff I have yet to blog about and I’ll surely do that in the near future. This week is halfway through the Summer of Code and it’s midterm evaluation time. Having been scolded for the lack of coolness of my rendering tests during the last developer meeting, I took the time to grab some better looking model and arrange more interesting tests. You can find my midterm report, together with said renderings, on Blender’s wiki. A warm thank you to the Kino3D guys who helped a lot in the process.

By the way, as a SoCer I got to visit Google’s London office today. I was glad to have my Blender t-shirt handy for the circumstance. During the tour I’m pretty sure I saw a couple of guys editing a video using Blender on an enormous screen. Overall the visit was very inspiring and, you know, a free lunch is always welcome!

Lightcuts: oriented lights

These days I’ve been working on adding support for oriented lights. It’s mostly there, even though there are a couple of missing details and the current code is obviously slower than it could be.

Still, like in my previous post, I can’t resist posting another revisited preliminary test, now rendered with actual lightcuts code.

Indirect lighting

And the corresponding false colour image:

Indirect lighting scene (false colour)

The original test took almost an hour to render, at 400×300 OSA5. This one took ten minutes at 800×600. True, the images don’t look exactly the same, but that’s because I changed the falloff type of the virtual point lights to a more realistic inverse squared. Still, the speed improvement looks pretty good already!

Yes, I am perfectly aware that the shadow from the sun suffers from aliasing problems. This issue will be addressed somehow, so don’t worry about that.

Please note that the virtual point lights have been placed by a custom (and pretty hackish) Python script; generating them automatically is something that I definitely want to do in the future, but is not strictly speaking part of the current GSoC.

My plan in the near future is to complete the basic feature set in time for midterm evaluation — that is, adding support for specularity and for the other diffuse shaders available in Blender. This is holding back some other things I would like to do as soon as possible, such as releasing a couple of Blender scripts to render from environment maps and to do basic indirect lighting, and squashing the bug that is causing this video to flicker like crazy.

Lightcuts: directional lights

I have just added support for directional lights on my branch. Using more than one “sun” light may sound weird, but that’s actually how you transform environment maps in a collection of point lights, as each pixel ideally represents an infinitely distant illumination source.

So I couldn’t resist going back to my preliminary tests, but this time running them with the actual code! Here’s Suzanne again under the Eucalyptus Grove light probe:

Eucalyptus Grove test

Please note that the AO image is there just to give a very rough feeling of how the two could compare — of course energy should be matched more carefully and parameters could be tuned better. Comparison with approximate AO would be useful as well.

Here’s another test using a hand-painted environment map:

Handpainted environment map test

In both tests the average cut size (the number of lights actually evaluated per pixel) is pretty low — see how dark the false color images appear. On the other hand the shadowing doesn’t look entirely convincing; still, it looks like a good starting point to me!

All images were rendered at OSA 5.

Lightcuts: week 2

A quick update from last week that I couldn’t find the time to finalize. I post it now as it discusses a couple of interesting issues. Btw, week numbering refers to the official GSoC timeframe. — UncleZeiv

The scene shown below — an ordinary Suzanne lit by 15000 colored lights — was sent by an early tester (thanks bullx) who found some noticeable artifacts when comparing the Lightcuts rendering to the plain one, despite following the instructions given in my previous post. It was indeed a bug that I finally found after a longish hunt. This is to say that early testing is indeed doable and welcome!

On the other hand, the reference 800×600 rendering using the traditional pipeline, according to the tester, took nothing less than 4 hours (it’s not displayed here). I have to admit, though, that this is not a fair comparison, since you can’t select “pure” single sampled shadows from the UI for the traditional pipeline — you are always forced to use the better quality, but slower, QMC code. [Note: I restored the possibility to select singled sampled lights from the UI in revision 15183.]

I don’t use that because in this context you don’t care if a single light is actually low quality or produces ugly hard shadows: on average the contribution from a single light will be fairly small and will be softened and corrected by the contribution from the other lights. Alas, this may not be the case if a small number of lights is significantly more intense than the average; that situation may require a special treatment.

Error comparison

Finally, I wanted to show an example of false color renderings, which are an invaluable tool to see at a glance how the algorithm is performing behind the scenes. Each color channel bears a different meaning — which is, by the way, liable to change frequently during development (it already has a couple of times).

Right now, the red channel is the most important and is proportional to the ratio between the number of evaluated lights and the maximum number allowed, that is, the maximum cut size. (If this figure is higher than the current number of lights, the latter is used).

As you can see from the picture, more lights get evaluated in darker regions: this may sound counterintuitive but is the direct result of using a relative error metric. The darker the region, the lower the absolute error allowed. This is particularly apparent in the second rendering, where a higher error threshold was selected.

The second picture gives also an idea of how image quality degrades by raising the allowed error.

Playing with a “working” prototype

The Google Summer Of Code has officially started on Monday. I’ve been doing a fair amount of coding  since my last post and it is now possible to see something almost meaningful on my branch.

I finally managed to have all pieces of the puzzle in place. My initial attempt to hook the lightcuts algorithm to the renderer through a “lights iterator” interface turned out to be ill conceived: what I really needed was a callback mechanism to let Blender Internal evaluate the contribution of a single light. In the end this will require more changes to the render engine, but overall this technique remains pretty non-intrusive.

Right now the technique supports omnidirectional lights (“Lamps” in Blender parlance), Lambert shading, only diffuse. Through the UI it’s possible to change the maximum allowed error and the cut size — that is, the maximum number of lights taken into account per sample.

Early tests show that the lightcuts version consistently outperforms the traditional rendering pipeline, even for fairly small amounts of lights. Results are not always correct though, especially when complex occlusions are present.

Let me clarify that although I am already receiving useful feedback from testers, there is a long list of limitations you have to be aware of before playing with my test builds. Here is a minimal and possibly incomplete checklist:

  • raytracing and shadowing must be enabled! This is not a current limitation: Lightcuts doesn’t make sense otherwise
  • all materials should be only diffuse, employing the Lambertian model (current limitation): disable specularity and/or set it to black
  • any other feature is not supported yet; in particular, ensure that the Bias toggle is turned off, or results could differ significantly
  • all lamps should be omnidirectional (“Lamp”), with Inverse Square falloff, and ray shadowing active
  • please ignore QMC settings: I am really using the old “single sample” lamps, not accessible from the UI anymore; fiddling with the settings could lead to inconsisten settings and eventually to crashes
  • it goes without saying: disable AO, SSS, whatever feature doesn’t look like a “plain” feature

I’ve also added a new render layer called “False Color“. It’s a visual debugging tool that shows per-pixel color-coded information. Right now, the red channel shows the ratio between used lights and maximum cut size: when it’s dark, it means that the algorithm took advantage of its metrics to aggressively save calculations; somewhat unintuitively, the most expensive parts to compute are the dark areas (in the actual picture, not in the false color one): having a relative error criterion means requiring a very accurate calculation precisely where the signal is weak, and that’s when the “max cut” limit is hit.

A sprouting tree

Focus on lowering algorithmic complexity and don’t perform other optimizations until their usefulness is demonstrated by thorough profiling: since I completely agree with this maxim, I feel obliged to explain why my latest lightcuts update seems to contradict it.

First of all, let’s recap: in order to select an optimal subset of the available lights per sample, a lightcuts implementation needs to maintain them organized into a binary tree. The leaves of this tree are the actual lights, while intermediate nodes represent clusters of lights. A cluster of lights is a sort of imaginary light whose position, intensity and orientation is somehow representative of all its children.

The original paper spends only a paragraph on tree building and related issues. The point is that building the light tree is trivial, but building it efficiently is far less trivial. Miroslav Mikšík, in his paper dealing with implementation issues regarding lightcuts, notes that a naive algorithm may have a O(n³) complexity; he devised a technique to reduce such complexity to O(nlogn).

Keep in mind that a robust implementation should be able to deal at least with several thousands of lights, and should allow venturing into the millions! This is one of those cases where complexity does matter.

Right now, though, I’ve implemented a simple O(n²) scheme, taking advantage of the nice heap mini-library available in Blender. I’ve spent some time, on the other hand, ensuring that a single memory allocation is required for the entire tree, instead of one for each node. This is possible because the number of nodes in the tree is predictable in advance. This reduces fragmentation, is cache friendly and, since it’s possible to use offsets instead of pointers, its memory footprint is the same on 64 bits machines instead of increasing because of the doubled pointer size.

Next, I want to move on to the other parts of the algorithm, in order to have a working prototype fairly soon. It probably won’t support a large number of lights, nor oriented lights (spot) which are probably going to be added later on, as they require special treatment. But at least it will be possible to validate the overall architecture of the project, and people will be able to start playing with it.

For this purpose, the current algorithm has both acceptable performance (I’m not going to debug with large number of lights at the beginning, anyway) and is easier to debug.

Stepping into the summer

My first week as a SoCer is coming to an end. I’ve been added to a couple of SoC-related mailing lists; those gave me the opportunity to really feel the international breadth of this program.

I’ve also had some exchanges with my mentor, Kent Mein. In particular, he reminded me that I should take care of external testers, should there be any. He’s right. In practice this means that maybe I should not delegate the light conversion/generation step to an external script, which would prove cumbersome to use for other people, and code that in C straight away instead. Originally I planned to do that later on as it is conceptually very simple but potentially longish to code; additionally, I would like to experiment a bit on different ways to do that, and Python would be way more flexible in this. We’ll see.

My own branch was created as well, and I finally have commit rights for Blender! Isn’t that cool? Far less cool was the horrendous breakage of Subclipse after a dry run of an svn merge command. There was no way to recover from it, and I had to disable Subclipse altogether. I don’t mind using svn from the command line, but this provided yet some more ground to question Eclipse CDT as a development environment. More on this in a future post.

Meanwhile, I started writing some code to test if my high-level design is viable. My hope is that the lightcuts project should eventually have only two entry points:

  1. an initialization routine, that generates point lights and builds the three required trees out of them (one for omni lights, one for directional lights, one for oriented lights)
  2. a “gimme the lights” routine that returns a different set of point lights per pixel/sample

Until now, I successfully created a fake step 1 that for each light in the scene creates another one, with random color and 1 unit displacement. This is a test image I kind of like:

For each light, create another one with a 1 unit translation and random color

Only the white lights were present in the scene.

Step 2 is a different story. Right now, the light list is iterated directly at various points in the code. My original plan was to add a lightcuts_get_light_list() API before each iteration, but on second thought, that’s not a good idea: I would have to allocate an actual list for each pixel/sample only to retain compatibility with existing code. The only other solution I can think of right now is to provide a sort of “iterator interface” to the lights list, along the lines of a get_next_light() method. In this case we trade an allocation overhead for a call overhead, so it could be worth to look for an other alternative.

Summer is starting now!

I’m both happy and proud to announce that my proposal for the Google Summer of Code 2008 has been accepted. I’ll be implementing the lightcuts algorithm in Blender.

I started using Blender in 2005 and have been a Blender fanatic ever since, so I am particularly excited by this opportunity. My hope is that this experience will be fruitful both for me and the Blender community.

I’ll be documenting my progress in this project both on this blog and on blender.org’s wiki.

Lightcuts in Blender: preliminary tests

This weekend I’ve been performing some preliminary experiments to get a feeling for what could be delivered by a lightcuts implementation in Blender.

In brief, the lightcuts algorithm is just a way to render insane amounts of point lights quickly, by adaptively selecting a different subset of the available lights at each pixel according to perceptual metrics. This means that it’s possible to have a grasp of how results would look like without actually implementing it, if you are willing to bear with huge rendering times.

The first bunch of tests concerned environment lighting. It required converting light probes into collections of point lights: to do this, I wrote a quick Python script that performs a Hammersley sampling of a light probe and places a new directional light at each sample position, with matching color and intensity (I was lucky that Blender.Image.getPixelHDR recently landed on svn), and 1-sample “ray shadow” mode set.

As a result, you should get something very similar to an AO pass with sky texture. Actually, it should be exactly the same calculation (bar any “distance” tweaks), but instead of sampling the environment using a different jitter table per pixel, you use the same sampling scheme over the whole scene. That of course defeats the very purpose of jittering, which is trading banding for noise, but please remember that lightcuts is designed to deal with very large collections of lights.

Environment lighting comparison

So far, I admit it’s no big deal. For sure, with actual lights you can also support specularity, as in the pictures; and AO shows a bit of the bias problem. But anyway, as far as environment lighting is concerned, even after a successful implementation is completed, the best you can get is still pretty similar to what you already have.

Things get more interesting if we add indirect lighting to the mix. Lightcuts is claimed to interact well with Instant Radiosity schemes: that is, you place a large number of small lights where the primary light hits the scene in order to simulate the first bounce of indirect lighting. To accomplish this, I preliminary rendered some color coded maps from the light’s point of view: positions, normals, and color. (By the way, this caused me some headaches because of the linear blending texture saturating at 0 and 1, which is a pity in the float buffer era).

Color maps used for indirect lighting

Afterwards, I wrote another script that, given those textures as input, places a number of 180° spot lights into the scene, with color and intensity matching the hitting surfaces’ color and orientation with respect to light.

Indirect lighting tests

In these test scenes the effect of indirect lighting is a bit exaggerated to see it better, but you get the idea. It is important to stress that Instant Radiosity is an approximate technique with its own shortcomings that would need to be properly addressed in a serious implementation. Still, it looks promising to me.

Significant savings on render times should be obtained when you employ all those lighting sources together: environment lighting, area lights and indirect lighting. This is because lightcuts ultimately just deals with a collection of point lights, without caring about their original purpose. My hope is that this would enable artists to set up complex lighting configurations with several area lights without worrying too much of rendering times.

As a closing note: top blenderheads, like @ndy, are known to use lots of lights in their renderings; nonetheless, I guess even them would be shocked to see something like this:

Thousands of lights

Of course, in an actual implementation, end users wouldn’t be able to see all these individual lights in 3d view… fortunately!