Cycles scene optimizations: Ray visibility

If you want to make something invisible to a certain ray type in Blender/Cycles, most people do things like this:

Screen Shot 2015-02-21 at 7.24.15 PM

STOP DOING THAT.

You are making Cycles waste time doing worthless calculations. Instead, go over to the object tab, and use these instead:

Screen Shot 2015-02-21 at 7.27.14 PM

Unchecking “camera” there will produce the exact same result (the object is invisible when viewed directly, but otherwise appears normally), but it goes about it differently. The shader node setup tells Cycles when evaluating the material, figure out the current ray type, and if it’s camera, choose the second input on the mix shader. This is a transparent BSDF node at full white, so the ray passes unchanged.

Ray vis does it a much more efficient way: it just tells Cycles “if the current ray is a camera ray, don’t even bother checking if you hit this object, just assume you didn’t”. This is important, as it allows us to filter out the object while doing intersection tests (render nerd speak for “checking to see what the ray hit”). Even better, it allows us to avoid running the shader at all, much less realizing the result was a transparent BSDF and having to continue the path and do the whole thing over on the next object we hit.

It gets worse though. The light path shader includes a transparent BSDF, thus, it enables transparent shadows. Realtime engines and rasterizers have taught too many people to think alpha maps are their friends. But raytracers are different: to them alpha maps are evil, because they create a horrible effect called transparent shadows. Raytrace shadows are computed by tracing a path from the shading point (that’s where the initial ray landed) out to a lamp, and seeing if anything blocks the path. If something is there, the object is “in shadow” and the lamp contributes nothing. If it has a clear shot, it is not in shadow, and the lamp contributes at full strength. Simple.

Transparent shadows crap all over that simplicity. They cause the shadow ray test to return bullshit like “the ray might be blocked, or maybe it isn’t”. The only way to find out is to to run the shader (which we didn’t even have to do in the first place for opaque shadows!) and figure out what the actual opacity is at the point on the object we hit, then trace another ray from this point to see if we were actually blocked entirely by something else and we did all this for nothing (lolz). God help you if that “something else” is also transparent, then we have to do this shit all over again.

Needless to say, that wastes a lot of time. And now you know why that “transparent shadows” box is in the material options. Unchecking that tells Cycles “I know this mat has a transparent BSDF, but just ignore that and do opaque shadows anyway”. Because that can save a lot of time if no one is going to notice an object is casting solid shadows.

Now, sometimes we don’t have a choice, (alpha maps have their uses), but in the case of 100% transparency to a particular ray type, we do. We can just turn off ray visibility for that type, and have a simple shader with no transparency.

Just to compare, I set up this scene. The cube is invisible to camera rays:

Screen Shot 2015-02-21 at 7.42.18 PM

Regardless of if we use ray visibility or the light-path shader, the result is the same. But the render times aren’t:

  • Diffuse-only shader, camera ray visibility disabled: 1.73sec
  • Diffuse/transparent mix by “is camera ray”, camera ray visibility enabled: 2.28sec
  • Diffuse/transparent mix by “is camera ray”, camera ray visibility enabled, but “transparent shadows” disabled: 2.10sec

This is obviously a worst-case scenario, but you can see the impact of the extra calculations. 30% longer to render the exact same image! Using the same setup with transparent shadows disabled (still the same result, because light path “is camera ray” will never evaluate to 1 for a shadow ray) is only 2.1 sec. That’s means about 35% of that penalty wasn’t even due to our extra shader stuff, it was due to the useless enabling of transparent shadows.

So there we have it. Ray visibility is your friend.

_______

“But wait!” you might be saying, “I need to do some ray-switching for a bunch of objects with this one material! Light path is a lot easier in this case!”

Python to the rescue. This will disable camera visibility on all selected objects (select one object, then use “select > linked > material” to grab all objects with your mat):

import bpy

for obj in bpy.context.selected_objects:
    bpy.context.scene.objects.active = obj
    bpy.context.object.cycles_visibility.camera = False

If you need to flip a different ray visibility switch, you can just change that last line. This version will turn on transmission visibility:

import bpy

for obj in bpy.context.selected_objects:
    bpy.context.scene.objects.active = obj
    bpy.context.object.cycles_visibility.transmission = True

The python names for the 6 switches are:

camera
diffuse
glossy
transmission
scatter
shadow

Advertisements

2 thoughts on “Cycles scene optimizations: Ray visibility

  1. I’d be interested to know if the time efficiency is still true in the newer versions of Blender (>2.76). I thought I remembered seeing some obscure change-log note about this usage of nodes being more efficient…

  2. Seems a little faster than it used to be (although I don’t have the same test file to know for sure) but it’s still definitely slower. Which makes sense when you think about it; how do you optimize a calculation so much that doing it is faster than skipping it entirely? (of course, I’m not a render dev, they might think outside the box a bit more, they’re a clever species 😉 )

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s