SunFlow

This document answers Frequently Asked Questions about the Sunflow Global Illumination Rendering System. It also provides numerous performance tips as well as more detailed explanations of how certain features of the renderer work. Most of this information comes directly from Christopher Kulla, the creator of Sunflow. The faq is comprised of his email and forum-post replies, with some contributions from others as well.

  1. Tuning Ambient Occlusion (AO)
  2. Tuning Instant Global Illumination (IGI)
  3. What Exactly Does Bias-Samples Do?
  4. Tuning Irradiance Caching
  5. Tuning Area Lights
  6. Tuning Soft Shadow Quality
  7. Tuning Antialiasing (AA)
  8. Tuning Antialiasing (AA) with Path Tracing
  9. Tuning Antialiasing (AA) with Ambient Occlusion (AO)
  10. Tuning The "rays per sample" Parameter
  11. How To Override Materials
  12. How To Use Constant Shaders
  13. How To Change Sunflow's Interface
  14. How to Render Caustics
  15. How Can I Get Smoother Soft Shadows In My IBL Renders?
  16. Is a Java Renderer Slow?
  17. What is the JRE or JDK?
  18. Which Java Virtual Machine (JVM) Should I Use?
  19. JVM Benchmarks: Server vs. Client
  20. Error When Using The '-server' Switch
  21. Removing The Need For The '-server' Switch
  22. What is GI?
  23. What is a Biased or Unbiased Renderer?
  24. Why Does My Rendering Stop Part Of The Way Through?
  25. Why is My DOF (Depth Of Field) Rendering Too Noisy?
  26. What Does 'dist' Do With The AO Shader?
  27. Why Does The Ward Shader Get Noisy?
  28. Would A Plane-Primitive Render Any Faster Than A Generic-Mesh One?
  29. The Sunflow Shader Guide
  30. Start SunFlow from a Desktop Icon (Windows XP)
  31. Start SunFlow from a Desktop Icon (OSX 10.4.5)
  32. Setup Sunflow for OSX 10.4.5
  33. OSX and XP Desktop Icons
  34. What exactly does Radiance do in the meshlight block? And what happend to the gamma correction? (v0.06.3)
  35. FAQ Credits

Tuning Ambient Occlusion (AO)

The options inside the shader block should be self-explanatory. Bright and dark are the fully visible/fully occluded colors. Samples is the number of rays to shoot, start with a low value to get quick but noisy renders, then slowly make it bigger to get better results. The 'dist' parameter is the maximum distance the rays will go to find occluding surfaces. This depends on the scale of your scene. You can set it to 0 to make the rays infinite.

Tuning Instant Global Illumination (IGI)

IGI is highly sensitive to the input values:

gi {
type igi
samples 128 % number of virtual photons per set
sets 1 % number of sets (increase this to translate shadow boundaries into noise)
b 0.01 % bias - decrease this values until bright spots disappear
bias-samples 0 % set this >0 to make the algorithm unbiased
}

Here's how to quickly tweak these values:

1. You should start by setting the bias value 'b parameter' as high as possible without introducing artifacts (try 1.0 to see what I mean). The bias value is related to the geometry and position of your light sources, so its pretty much fixed per scene. Start with a big value (like 1) and decrease it until artifacts go away. If you suddenly don't see those artifacts, try making it a bit bigger until you find the exact point where they go away.

The important thing is to set the bias value properly. Otherwise you will be clamping away all the indirect contributions. You can restore them by setting bias samples greater than zero but then you're back to a path tracing type of situation. The key things to look out for are:

  • bias too high: bright spots appear near corners
  • bias too low: indirect illuimination goes away

2. Once you have that, you can increase the number of samples to make things smoother (get rid of sharp shadow boundaries). Or you can increase the number of sets to trade off the sharp shadows with noise.

What Exactly Does Bias-Samples Do?

This controls the number of samples to take to do path tracing style bounces in areas where the indirect lighting is clamped away by the bias setting.

The igi algorithm approximates global illumination by placing small point lights randomly around the scene but the contribution of these needs to be clamped or you get bright spots in corners. Since the clamping makes things darker than they should be, you can restore that a little bit by doing path tracing in just those corners.

This is only effective if your bias is set properly (i.e., as large as possible without artifacts) of course, otherwise you are back to regular path tracing.

Of course, if you don't feel a need for compensating the bias, you can safely leave the bias-samples at 0 without any problems (and it will be faster).

Tuning Irradiance Caching

Irradiance caching requires a global photon map. Set a number of photons to emit and turn on the photon map. Note that this algorithm is kinda tricky to tweak for beginners.

Like I said, the current implementation uses photons which are pretty much broken in the current release. If you really really want to use it, first make sure all the lights in your scene have the same power. Best way is to stick to one square area light. If you use lights with different emit values or areas the intensity of the photons will be wrong.

Use the following code to emit a bunch of photon in your scene:

photons {
emit 200000
global grid 150 1.0
caustics none 100 1.0
}

Then view the result with this:

shader {
name debug_globals
type view-global
}
override debug_globals false

This will just render the photon map directly so you can see how it is stored. Pay attention to the stats printed to the console before/after photon tracing. The number of photon bounces is controlled by the global max-depth attribute.

When you think the photons looks well distributed and approximate the illumination well, switch on irr-cache (actually you have to have it in there during the first step otherwise it gets turned off because the photons wouldn't be used).

gi {
type irr-cache
samples 256
tolerance 0.01
spacing 0.05 5.0
}

Spacing is a minimum/maximum distance in world space. min is the number below which samples WILL be re-used, and max is the distance beyond which samples wont be re-used. In between, nearby samples are interpolated.

The tolerance controls the quality of the interpolation, think of it as an error threshold. 0.01 should roughly be ~1% error (in the interpolation - the actual samples can still be wrong and produce artifacts).

You can view the irr-cache by itself by using:

shader {
name debug_gi
type view-irradiance
}
override debug_gi false

If you get confused, try looking at the cornell_box_boxes examples from the v0.05.1 data files. It uses path trace by default but just comment out that block and it should use irr-cache.

Tuning Area Lights

1. Make sure the surface of the light isn't passing through any geometry. If part of the area light is occluded, its going to increase the noisiness of your shadows (because some samples will always be in shadow).

2. Pull the area light away from geometry. For example in your scene, the area lights were sitting inside the window enclosures. The pixels really close to the base of an area light are going to be very noisy at the moment (can be improved by better sampling). Moving the lights backwards a bit (outside the room) helps.

Tuning Soft Shadow Quality

You can adjust the quality of soft shadows with the number of direct-samples (16 by default). Be very careful with this one, it applies to each triangle. Keep your eye on the console output, it will tell you how many lights are in the scene and how many shadow rays are being used per sample. The best way to figure out the right number to use is to set AA to 0/0 (1 sample per pixel) and tweak the light-samples so that shadows are smooth. Then you can crank AA back up to 0/2 without worrying about noisy shadows forcing AA to oversample.

Tuning Antialiasing (AA)

Refer to this mental-ray tutorial about anti-aliasing. The minAA/maxAA have the same meaning in Sunflow. Try setting your AA to 0/2 instead of the default -2/0. See the README for more info.

Keep in mind the default image filter is a 1x1 box which is not very good either. Try using a 2x2 gaussian at least. This should give you a much better looking render.

Tuning Antialiasing (AA) with Path Tracing

Path tracing is going to be very slow to converge to the right solution, especially for indoor scenes. Start by setting the min/max AA to the same values (say 0 0 for preview). This will avoid the adaptive sampling engine from getting confused. Then, increase the number of path tracing samples slowly. When get something relatively smooth, you can switch to 1 1 or 2 2 for AA and lower the samples accordingly (divide by 4 or 16 respectively).

Tuning Antialiasing (AA) with Ambient Occlusion (AO)

For ambient occlusion you don't need to set min=max. This will slow you down. This suggestion is only valid for path tracing (because its really noisy and you don't want the adaptive AA getting confused). AO is typically rather smooth so you can use adaptive on it.

For most scenes, 0 1 should be fine. Even 0 2 for final quality.

The important number is the number of rays used for the AO shader. Unfortunately, when declaring the shader type as "amb-occ" you can't set the number of rays explicitly. Its 32 by default. The probe rays are also infinite when they could be clipped to a small range. Use "amb-occ2" to set the number of rays.

Tuning The "rays per sample" Parameter

The following:

image {
resolution 1024 768
aa 0 0
samples 8
}

will sample each pixel 8 times. Note that the samples parameter is actually per sub-pixel so if you are already doing some adaptive anti-aliasing with the aa parameters you should be carefull what you set this to. The README should give more detail about how all this works.

How To Override Materials

To do this you will need to manually edit the exported .sc file. Add something like this at the end of the scene file:

shader {
name default-shader
type amb-occ2
bright 1 1 1
dark 0 0 0
samples 32
dist 50
}
override default-shader false

The shader block defines the actual ambient occlusion shader, the last line tells the renderer to apply this shader to every surface, regardless of what shader they already have. The false means that the shader override does not apply to the photon tracing phase (it is sometimes useful to bounce the photons with regular shaders then render the image with a single shader). In this particular case it doesn't matter, you shouldn't have photons turned on anyway.

How To Use Constant Shaders

An object with a constant shader acts as a light source when used with path tracing. Using meshlights is much faster (and less noisy) when the area of the light is small. However this can work well for outdoor scenes where a large sky dome has a constant shader and more than one bounce is needed. If one bounce is sufficient, AO would be better suited and much faster.

shader {
name Constant
type constant
10 10 10
}

A constant colored shader always returns the RGB triplet you give it. (10 10 10 in this case) This can be a good substitute when area light sampling is too noisy. Of course it only work when path tracing is turned on.

If a scene contains an object with a constant shader, and no direct lights, then bounces=1 in the path tracer now corresponds to direct lighting, and bounces=2 corresponds to single diffuse bounce. The 'bounces' parameter is now the 'diff' parameter in the 'trace-depths' block.

How To Change Sunflow's Interface

Recent versions of sunflow use a cross-platform look and feel called Metal. Although it is fully functional, some may not find the window borders/icons visually appealing. If you use Windows XP, and you want sunflow to look more like a windows application, try adding the following to the command line:

-Dswing.defaultlaf=com.sun.java.swing.plaf.windows.WindowsLookAndFeel

For a Motif look and feel try:

-Dswing.defaultlaf=com.sun.java.swing.plaf.motif.MotifLookAndFeel 

How to Render Caustics

The first step is to make sure you have some reflective / refractive materials.

Then, set the number of photons to emit: ~100,000 is a good start. Then pick kd as the caustic type (this will let the photons actually be stored). Leave the gather/radius values for caustics at their defaults to start with.

You should see some caustics now when you render.

How Can I Get Smoother Soft Shadows In My IBL Renders?

Simply increase the number of direct-samples. You can also set lock to false which will re-sample the environment light at each pixel instead of using the same everywhere. This isusually slower though.

Is a Java Renderer Slow?

Short answer: Yes, in general Java is slower than properly optimized native code.

Longer answer: It depends what your program needs to do. Modern JVMs do their best to translate the portable bytecode into native instructions. They do a surprisingly good job at handling this. When I first started writing Sunflow, it was a C++ application. Out of curiosity and because I preferred Java over C++ at the time, I rewrote the whole thing in Java and benchmarked the difference. Java came out 1.5 to 2x slower on average. I ended up moving forward with the Java version anyway because I felt it would be easier to experiment with. Raw performance was not the main concern.

Back to the question at hand however, JVMs are mainly designed and tested against server/database type of applications. These do very little number crunching and lots of passing data around (I'm oversimplifying but bear with me). Sun knows this and optimizes their bytecode -> native code translation accordingly. Applications like Sunflow don't really fit that model, so they can't reap all the benefits of the native code translation (although it still helps a lot).

If speed/memory requirements really come a big issue, I'm totally open to writing the relevant portions in C/C++.

My personal feeling however is that the current version has still a lot of room to grow (speedwise) just from algorithmic changes (smarter ray-intersection, faster sampling, etc).

Conclusion: Java does have a slight performance disadvantage over native applications, but I rather compensate it by smarter algorithms.

I realize many people are turned off when they see that Sunflow is written in Java. I hope that eventually the features/cross platformness/extensibility will make them change their mind.

What is the JRE or JDK?

JDK stands for Java Development Kit, and JRE stands for Java Runtime Kit.

The JDK happens to be the only way to get the optimized server VM.

After the JDK is installed, you may still get complaints that it can't find the server VM. If thats the case, check that your system path is pointing to the right version. Installing the JDK installs one copy with all the tools and both client and sever vms, and one copy that is just a plain install of the JRE. Type path at the command line to see which folder is getting used by default. If its the jre, go to the command panel like scorpius described and change the path.

Which Java Virtual Machine (JVM) Should I Use?

This reminds me to mention to everyone that you should be using the server version of the JVM. Enter this command:

java -server -version

at the command line and see what you get. If you see something a hotspot client vm you aren't using the right one. If it says something about a server vm, then just make sure you start your command line with java -server when launching Sunflow. From memory, I think the server version only ships with the JSDK (the developer package) so be sure you download that one. It gives a substantial performance increase.

JVM Benchmarks: Server vs. Client

Here are the results of timing tests on my toon-house scene, the revised archive can be downlaoded here:

  • Overall, sunflow is just slightly faster under Linux (on average about 1.25x faster).
  • For either OS, the Server VM is about 1.5x faster than the Client VM. It's definately worth it to download the JDK to get the server VM.
  • Loading the textures takes about 30 seconds for both OS's; reloading them is instantaneous because they are cached. You'd think loading a jpg would be quicker, though.

Operating System WinXP Linux
Virtual Machine Server Client Server Client
AO: toon-house 1:24 1:55 1:04 1:31
GI: toon-house 1:59 3:09 1:56 2:53
AO: chrono-sphere 6:06 9:42 4:39 7:13
GI: chrono-sphere 8:21 13:24 6:48 10:32

AO denotes the ambient-occlusion scene and GI demotes the global-illumination scene, which features one-bounce path-tracing used in combination with a large constant-shaded sphere primitive acting as a sky-dome.

For outdoor scenes, both methods produce identical results (I subtracted the two images in the Gimp and got a black screen, then auto levels shows the very few pixels that are actually different.) AO does some kind of path-tracing, but it is more optimized.

Error When Using The '-server' Switch

If you get this error even if you have the JDK installed:

Error: no `server' JVM at `C:\Program Files\Java\jrexxx\bin\server\jvm.dll'

Check your system paths. When you install the JDK you get TWO copies of the VM, one that has only the client and one that has both server and client. Repoint your PATH environment variable to point to the one with both.

Look around your program files directory, you should be able to spot the right one because it will have a client and server directories inside its bin.

You can also copy the "server" directory from my JDK folder to the JRE folder.

Removing The Need For The '-server' Switch

For those that want to know, you can permanently switch to the server JVM as the default by editing the jvm.cfg file in the jre/lib/i386 of your java subdirectory. For instance, on my Linux box it is located in /usr/java/jdk1.5.0_06/jre/lib/i386. You should find something like this:

-client IF_SERVER_CLASS -server
-server KNOWN
-hotspot ALIASED_TO -client
-classic WARN
-native ERROR
-green ERROR

Switch the order of the -client and the -server lines in the file like this:

-server KNOWN
-client IF_SERVER_CLASS -server
-hotspot ALIASED_TO -client
-classic WARN
-native ERROR
-green ERROR

NOTE: ORDER IS IMPORTANT. Only switch the two lines!

If I understand correctly it will take the JVM a little longer to initialize and use more memory, but it should yield run-time speeds similar to C or C++. Then if you need to use the client JVM, launch java with the -client flag.

What is GI?

GI stands for global illumination. It refers to a class of rendering algorithms that try to simulate how light behaves in real life. There are many such algorithms, and some are more accurate than others. Here are a couple that you might have heard of:

  • Radiosity. Traditionally it refers to a method of computing bounces by cutting up your geometry into small patches and calculating energy transfer between these little squares. Its a pretty old method that no one really uses anymore. Povray's GI algorithm is called "radiosity" but its most probably not. It looks more like irradiance caching (below).
  • Photon mapping. This is a method where you shoot little photons from the light sources and bounce them around and store them at each hit. At every point you want to render, you just look up nearby photons and average them. This gives an approximate value of what the shading should be there. Its a very fast method but gives pretty splotchy results. So you typically never want to view it directly. Photon mapping is usually combined with ....
  • Irradiance caching (or final gathering). This method was first developed for the radiance rendering system. Basically, you calculate a single bounce with very high accuracy by shooting rays on a hemisphere. Secondary bounces can be approximated with your favorite technique. This could be photon mapping (what Sunflow does) or just direct lighting (giving only single bounce GI) or path tracing (see below). Each calculation is very expensive so the results are cached and get re-used for nearby pixels. This caching introduces some error in the solution, but the end result is usually so smooth it doesn't matter.
  • Path tracing. This is one of the first GI algorithms ever published. It is the most accurate one and the easiest to code. The only problem is that it is really really slow and gives noisy results. Basically its the same as Irradiance caching but without any of the approximations introduced by caching or using photon maps for secondary bounces. Sunflow has this method available too.

There's plenty more but these are the main ones. All of these are "true GI" in that they all try to calculate the same thing. They just make different trade offs.

What is a Biased or Unbiased Renderer?

Biased Vs. Unbiased (the new hype in render engines at the moment):

Biased algorithms: (e.g., photon mapping, irradiance caching) take some shortcuts to speedup the calculation (interpolation usually). This means that while the result looks mostly correct, it in fact is very slightly "off". In practice you usually don't notice, but if you wanted to make some measurements, say for lighting design, you'd have some error, no matter how high your sampling rates were.

Unbiased algorithms: (e.g., path tracing, bidrectional path tracing, MLT) these take no shortcuts. They statistically will go everywhere in the scene to simulate everything that goes on. This means that the result will eventually be correct but it will take a really long time. If you're smart about how you code your unbiased algorithm, you can guarantee that the remaining error goes down relatively fast as you add more samples. But in theory it still takes an infinite amount of samples to get the correct value. But unlike biased algorithms, an images computed with infinite samples will be totally correct.

Since no one is going to wait for an infinite number of samples to calculate, most renderers give sampling limits (in sunflow for example you set the number of samples for path tracing). The problem with that is that you might wait a really long time and then realize its still not enough and have to start all over. So the better way to present those algorithms is in conjunction with progressive rendering (IPR in sunflow) which keeps adding more samples until you tell it to stop. Sunflow's progressive sampling currently stops when it reaches 1 sample/pixel since its meant for previews, but that will probably change. The important thing to understand is that unbiased and progressive rendering are not the same thing, just that they go very well together.

Why Does My Rendering Stop Part Of The Way Through?

My guess is the error is due to running out of memory. Try running sunflow from the command line with the -Xmx option. For example, to allow java to use up to 512MB of memory use -Xmx512M.

Why is My DOF (Depth Of Field) Rendering Too Noisy?

You can increase the dof quality by changing the amount of image samples. Here is an example, tweak this to suit your scene

image {
resolution 640 480
aa 0 1
samples 4
}

The 'aa' parameter affects the min/max number of sub-pixels. These controls work like they do in mental ray or other such renderers.

The 'samples' parameter affects the number of samples per sub-pixel. This will directly improve DOF quality.

What Does 'dist' Do With The AO Shader?

The 'dist' parameter specifies how far the ambient occlusion rays look to find a surface. Say you have a sphere floating 1 unit above a plane: to get any occlusion you will need to specify dist > 1. A special case is dist=0 in which case the rays are infinite.

In general shorter rays are faster (less to look at) and will make the result less noisy (less potential occluders). So use the smallest dist that gives the desired effect.

Why Does The Ward Shader Get Noisy?

It's a blurry reflection, so it needs to shoot several rays to calculate the reflection. If there aren't enough you need to either turn up the AA depths or use "glossy-samples n" (n is 4 by default - try increasing it slowly). Add that line right below "direct-samples n" in the lightserver block.

Would A Plane-Primitive Render Any Faster Than A Generic-Mesh One?

It should yes. Since the plane primitive is infinitely big it doesn't get stored in the acceleration structure which lets it enclose the objects better instead of growing to fit the corners of a big ground polygon.

The Sunflow Shader Guide

Some detailed tips and info about shaders is available here.

Start SunFlow from a Desktop Icon (Windows XP)

Here's how to setup sunflow so it's just one click away on your Windows XP desktop. Assuming that you unzipped the archive to a directory called c:\sunflow:

1. Right-click on the desktop and create a new shortcut. Paste the following line in the target field:

javaw.exe -server -Xmx512M -jar c:\sunflow\sunflow.jar

2. Optionally set the start in field to c:\sunflow\data and you're done.

Note that you should use 'javaw.exe' not 'java.exe' so that an annoying dos box doesn't open up. You may need to enter the full path to the java executable if your path isn't set up properly. It's usually found here:
c:\Program Files\Java\jdk1.5.0_XX\bin\javaw.exe

Start SunFlow from a Desktop Icon (OSX 10.4.5)

After you successfully complete the "Setup Sunflow for OSX 10.4.5" section, you can easily use AppleScript to put sunflow on your desktop. Start up the AppleScript Editor and paste the following line:

do shell script "java -server -Xmx512M -jar ~/sunflow/sunflow.jar"

Select File->Save from the Script Editor, and save it to the Desktop as "SunFlow" and make sure to select the "Application Bundle" file format. Now double clicking will start up sunflow without opening the run script dialog box or startup screen.

You may need to enter the full path to the java executable if the link isn't set up properly. It's usually found here:
/System/Library/Frameworks/JavaVM.framework/Versions/1.5/Commands/java

Setup Sunflow for OSX 10.4.5

Here's how to setup sunflow for OSX 10.4.5. Type 'java -version' and see if it reports v1.5.0_xx. If not, you may need to change the link in the Java VM Framework. Type the following commands (login as root, or prefix commands with sudo) to make the changes:

cd /System/Library/Frameworks/JavaVM.framework/Versions
sudo rm CurrentJDK
sudo ln -s 1.5.0 CurrentJDK

Assuming that you unzipped the archive to a folder called sunflow in your home directory type:

java -server -Xmx512M -jar ~/sunflow/sunflow.jar

Just make sure that the path after "-jar" points to the sunflow.jar file. You can also make an alias called sf with this command:

alias sf='java -server -Xmx512M -jar ~/sunflow/sunflow.jar'

Then you can simply type "sf" from any directory and you're ready to load *.sc files and render. You can make this permanent by adding the above line to /etc/bashrc so it is globally available. It can also be added to your own private ~/.bash_profile.

OSX and XP Desktop Icons

Sunflow now supports relative scene paths (for both image textures and include files) making it possible to start from an icon with less problems.

I made some desktop icons with proper transparency and drop shadows for OSX. I also made an applescript application and packaged it as a DMG file for easy installation. All you have to do to is put the sunflow jar files in a folder called sunflow in your home folder, and open the dmg file.

Here's the 128x128 OSX icon pack plus the script, and a single 32x32 Windows XP icon.

What exactly does Radiance do in the meshlight block? And what happend to the gamma correction? (v0.06.3)

These two points are inter-related.

Most renderers, including Sunflow, assume a linear colorspace. However, most monitors do not have a linear response to their input signal. That means that 0.5 grey is not half as bright as 1.0 white. There are plenty of websites that go into this. Sunflow had a gamma correction option that helps compensate for this. Unfortunately, not all programs are as carefull to provide those kinds of options. Most just simply let RGB values go to the screen uncorrected. So in previous versions of Sunflow, when you setup your gamma correction to match your monitor's (usually around 2.2), the colors and textures in your scene started to look more washed out than how they appear in other programs (say the Blender color picker, or your texture editor). This is because you were looking at them without any correction. In order for them to look right a reverse gamma correction has to be applied. Sunflow now does this automatically for 8-bit textures. The same is true for colors, you can now use a new syntax to tell the parser to apply an inverse correction before using the colors, like this:

{ "sRGB nonlinear" r g b }

instead of the old way:

r g b

In the future, I may add other color spaces to match different sources of color. I probably should also add the same options to textures (right now they are assumed to be nonlinear).

The gamma option is gone, because I now assume that your monitor matches the sRGB standard. Most modern monitors are setup this way out of the box, or can be calibrated to this standard fairly easily. Its not a problem to support other standards, but sRGB is a good start. If people feel really strongly about other options I can include them as well.

Onto the other point, light colors were previously specified as linear color values that could go way beyond 1 (as most lights in the real world do). Since I know handle color spaces more accurately, it becomes required to specify the light intensities in two parts. A color which lies between 0 and 1 in your color space of choice, and a radiance/intensity/power (depending on the light type) which is a simple multiplier to the linear corrected value to put it into the right units. The old behaviour is still supported, but has been deprecated.

FAQ Credits

This FAQ was created on May 26, 2006 by Anthony D'Agostino.