Blender 3D: Noob to Pro/Dealing with Fireflies in Cycles
Applicable Blender version: 2.68. |
Cycles is a wonderful renderer, capable of some exquisite lighting effects. However, sooner or later, you will encounter the problem of fireflies, which are isolated bright pixels scattered over various parts of the image. Unlike simple noise (which can be reduced by increasing the number of render samples, or alternatively by simple filtering), fireflies are caused by numerical instabilities in the rendering computation, because after all computers can only calculate the formulas to a finite precision. They seem an inevitable consequence of trying to use realistic physics formulas to create our renders.
But are they so inevitable? In fact there are various tricks and tweaks we can use to keep them out of our renders. There are pros and cons to each technique (in terms of the amount of work involved and unwanted side-effects), so it is up to you to decide which to use and when.
Fireflies tend not to afflict the simplest renders. This means that it takes work to come up with a tutorial example sufficiently complex to exhibit them. If you already have one of your own renders which is being plagued with fireflies, and you came here hoping to find a fix, then great—you can skip ahead to the part with the fixes. Otherwise, please have some patience while we construct an example.
Making An Example
editThis example arose out of a real model I was trying to construct: a house with louvred windows made out of frosted glass. Some interaction involving light coming in through the panes of one window, bouncing around the diffuse walls of the room and out another window, together with the combination of shaders making up the glass material, led to the appearance of the fireflies. This example will cut the situation to the bare minimum I could come up with to exhibit the problem, namely a pair of adjoining rooms with two windows.
Start a new Blender document. Switch the renderer to Cycles. Select the default cube, and TAB into Edit mode. Scale the cube out horizontally a bit so the room is not so narrow and tall. Switch to face-select mode. Select the bottom face and DEL ete it. I found that the room needed a ceiling to show the fireflies, but not a floor, so why not get rid of it?
Give your cube a Solidify modifier, so the walls have a nonzero thickness. The exact thickness doesn’t matter.
Next, make a single loop cut CTRL + R around the sides of the shape to define the boundary between the front and rear rooms. Then press F , and the vertices of the new loop should be joined to form a new face which is the wall between the rooms.
Now we need to make holes for the windows, and for a doorway between the rooms. Still in face-select mode, select the front face (the one you see in NUM1 view), and I nset it a little way. If you inset it too far, you may find the height gets too small, so after the initial insetting, select just the middle face and scale it horizontally S + X to make a reasonable-looking window.
Do the same with the wall on the right side of the front room, and also on the wall between the rooms. A real doorway would extend to the floor, but our simple hole in the wall is sufficient for this exercise.
Add The Windows
editAdd a new horizontal plane. Shrink it along the Y-axis to 20% of its length along the X-axis. Add a couple of array modifiers: one along the Z-axis with a constant offset of something like 0.2 and a count of about a half a dozen, and another along the X-axis with a constant offset around 2.2 and a count of 4. Position your resulting array of louvres within the hole for the front window.
Before going any further, we mustn’t forget to make the windows out of frosted glass. Assign a new material to your window object. Bring up the Node Editor, and set up a material for the window glass as at right. Set the roughness on the Glossy BSDF to zero, but note the small, but nonzero Roughness setting on the Refraction BSDF: I deliberately tuned this to maximize the production of fireflies. A zero setting will make them go away, but that defeats the point of this exercise, doesn’t it?
(The room walls can be left at the default diffuse material assigned by Blender.)
After setting up your window material, duplicate your louvres object and rotate and position the copy within the hole for the side window. Leave the hole between the rooms empty (it is supposed to be a doorway, after all).
Completing The Recipe
editAs the final part of our recipe for fireflies, change the type of the Lamp object to Sun, and change its angle to close to horizontal so it will shine in through the side window. Give it a strength of 3. Position the camera to look directly into the front window. Also increase the number of render samples to 100; that should be sufficient to keep down the noise.
So, in summary, we have sunlight coming in low through louvres in a side window in the front room, bouncing around between front and back rooms, and exiting through louvres in the front window, the louvres all being made of lightly-frosted glass.
If all goes well, hitting F12 to render should produce an image like at right.
Fixing The Problem 1: Renderer Tweaks
editOK, now that we can create the problem, how do we solve it?
Probably the first things to try are one or two renderer settings. Look for the Sampling and Light Paths panels in the Render context, as at right. In the Sampling panel, look for the “Clamp” field. If nonzero, this imposes a maximum value on the light-intensity calculations at each pixel. Normally 1.0 corresponds to full white, but some points can be brighter than this. Try changing the default 0 value to, say, 3, and rerender.
In our simple example, this should be enough to fix the fireflies. However, I have come across a case or two where this reduced the intensity of some bright indirect lighting, leading to a more subdued appearance for the overall render.
So let’s try the next thing. Set the Clamp back to 0, and this time look in the Light Paths panel, for the “No Caustics” checkbox. Caustics can be an important part of realistic lighting effects, but if your scene doesn’t need them, disabling them can help get rid of fireflies, and perhaps speed up the render as well. However, the tooltip for this checkbox warns that the result can be a darker image.
In our simple case, checking this box does work.
The third renderer setting to try is the field just below the No Caustics checkbox, labelled “Filter Glossy”. This applies deliberate blurring to certain kinds of light bounces, sacrificing a bit of lighting accuracy for the sake of avoiding fireflies. And again, in our case, this option works: setting it to a value of, say, 1, does indeed fix the fireflies.
But, at some point, you may find that none of these three techniques will work for you: they may make no difference to the render, or may cause unacceptable loss of quality in places. After all, being settings that apply to the render as a whole, they can be something of a blunt instrument.
So for our next fix, we will need to resort to the compositor.
Fixing The Problem 2: The Despeckle Filter
editThe approach to fixing the fireflies problem is to apply some kind of processing to the rendered image. If you are familiar with image-editing programs like Gimp or Photoshop, you will have come across the despeckle filter, whose job is precisely to smooth out random dots that don’t fit in with the rest of the image. In principle you could use an image-editing program to touch up your renders (and some people producing professional-quality renders do), but what happens if you are rendering an animation? Imagine having to fix up hundreds or thousands of frames by hand!
Blender, too, has a bunch of image-processing operations available in its compositor, including a Despeckle filter. And the nice thing is, these operations can be applied automatically after rendering each frame.
Open up a Node Editor window in your Blender document (you can reuse the Timeline window at the bottom of the default window layout, just make it a bit taller). Look for the icons indicating what type of nodes to edit: click on the one showing little layers or sheets, representing the compositor (in the middle in Blender 2.68, on the left in earler Blender versions). Immediately you should see a “Use Nodes” checkbox appear to the right of these icons: check that to enable node-based compositing. You should get a default node setup like at right.
Move the two existing nodes a bit further apart, to make way for a new one in-between. Press SHIFT + A to bring up the Add menu, and look in the “Filter” submenu for the “Despeckle” entry. Move the new Despeckle node into the gap you previously cleared, and if you position it right, it should automatically connect itself into the chain like this.
To see the effect of your changes, switch the 3D view window to an Image Editor window. Make sure the image being shown is the “Render Result”. Next to the menu for selecting the image slot (which should be showing “Slot 1”), there is a menu for selecting which layer of the image to show: . “RenderLayer” is the raw output from the renderer, while “Composite” is the result after going through the compositor. By switching between these two, you should see that the default Despeckle filter settings have removed some of the fireflies, but not all. I found if I reduced the “Threshold” filter parameter from its default 0.5 to something like 0.1, then all the fireflies did indeed disappear.
What The Despeckle Filter Does
editThe despeckle filter is designed specifically to get rid of isolated anomalous pixels. This is unlike blur filters, which average a bunch of pixels together, and can spread the firefly across a larger area instead of removing it.
But what do those “Threshold” and “Neighbor” parameters actually mean? The following explanation was put together from studying the Blender source code, mainly source/blender/compositor/operations/COM_DespeckleOperation.cpp .
The target pixel being processed is compared with its eight neighbours. However, these neighbours are not treated equally: each one is given a weight that governs its relative importance to the computation. The horizontal and vertical neighbours each have a weight of 1, while the diagonal neighbours are each given a lower weight of (approximately 0.7). This reflects the fact that they are slightly further away along the diagonals, therefore they have correspondingly less influence on the outcome.
For each neighbour pixel, the “Threshold” input parameter is compared against the difference between each of the neighbour’s R, G and B components (normalized to 0 being black and 1 being maximum intensity) and those of the target pixel; if any of the corresponding pairs of components have a difference exceeding the threshold, then the neighbour pixel value is accumulated onto an average (weighted by neighbour weights) that the code calls color_mid_ok—the presumed “correct” value of the target pixel, if you like. All neighbour pixels, whether within or outside the threshold, are accumulated onto another (also weighted) average called color_mid. The value w is the total weight of all neighbours that contributed to color_mid_ok.
Then the value of w is divided by the total weights of all neighbouring pixels (4 × 1 + 4 × ), to produce a fraction in the range [0.0 .. 1.0], and the resulting fraction compared to the “Neighbor” input parameter. Also the difference between the components of color_mid (the average of all the neighbours) and those of the original target pixel are compared to the “Threshold”. If either comparison returns less than or equal, then the pixel is considered not to need correction. But if both comparisons are greater, then the target pixel is adjusted from its initial value towards the color_mid_ok average, according to the “Fac” input socket value. If “Fac” is 1.0 (the default), then the pixel is completely replaced with color_mid_ok; otherwise it becomes the corresponding blend of this and its original value.
“Fac” can be used to fine-tune the effect of the Despeckle. For example, if this was fed from an inverted edge-detection (“Kirsch”) filter, then it can be used to reduce the effect along sharp edges, which are otherwise likely to confuse the filter.