BERNARDLEBEL.COM > TUTORIALS > SOFTIMAGE|XSI

Interactive depth pass

By Bernard Lebel

 

Credits:
Inspiration: Guy Rabiller and Guillaume Lefebvre
Design: Bernard Lebel

 

To create post depth of field effects and other post effects based on depth, we oftenly rely on a depth pass.
A depth pass is a grayscale image of the 3D scene that is basically a gradient from black to white, taking place on the Z axis in camera space. In other words, the surfaces closest to the camera are white while the fartest are black.

However, techniques to create depth passes vary. This tutorial describes an approaches based on Guy Rabiller's "Bottom Pass". However, I added a some interactive features that allows you to edit the depth with the falloff of a spot light.

You can download the tutorial project folder here. This tutorial tutorial was made with XSI 3.01.


Initial setup - Pass and Render Tree - Breakdown - Interactive control - Workflow enhancements


1- Initial setup

Start by creating a simple scene with primitives. Place those primitive on the Z axis, each at a certain distance from each other.
It doesn't matter how precise the repartition is, the result will be the same.
Then encapsulate the scene in a cube, and make this cube pretty narrow.
Make the camera and its interest visible.
Move the camera in a way that will show you each primitives.

 

Delete the default scene light.
Then create a spot light (Get > Light > Spot).
Select the spot only, and do MCP > Constrain > Position. Pick the camera.
Now select the spot's interest, click with middle-mouse button on MCP > Constrain to call the last function, and pick the camera's interest.

We are constraining the light to the camera because since the light will drive the depth, and that the depth is dependent on the camera, the light needs to follow the camera wherever it goes.

You can turn off viewport visibility for the spot if you want.


2- Pass and Render Tree

Now we are ready to go. Create a new empty pass. Name this pass InteractiveDepth.

 

You can leave the partitions exactly as they are if you want, or you can create a new partition where you will put the objects you don't want too see. It's up to, for this tutorial we don't need to do that.

We are ready to build the Render Tree.
Select the Background_Object_Partition. Do Get > Material > Phong. This will apply a Phong material to the partition. Since the material is applied ont he partition, all its members will inherit the material, but their own material will not be destroyed. If you look at the image below, you'll see that there is a B overlapping the material icon. This means that the material is propagated on the members. You can rename the material if you want.

 

With the partition still selected, open the Render Tree.
Get rid of the Phong node, just keep the Material node. From now on, we are strictly working on the surface color, lighting won't have any impact on the rendering.

 

Now build the following Render Tree, I'll explain you in a moment what the parameters do.

Nodes > Texture Space Generator > Generator to get the Texture_space_generator node
Nodes > Conversion > Vector to Scalar to get the Vector2sclar node
Nodes > Math > Change Range to get the Change_range node
Connect the Change_range node into the Material's Surface input to get the Scalar2color node.


3- Breakdown

a) Texture_space_generator
Double-click ont he Texture_space_generator node to open its property page.
You can see that in Texture Space, there is nothing. We must assign a texture space.
To do so, click on New, and choose Advanced....

In Projection Type, choose Purely Implicit, and click Ok.

 

Now, in the Texture_space_generator ppg, set the Projection Method to Disabled.
Then, set the Space Transformation to Camera.

The important thing here is the Space Transformation. Let me explain.

The purpose of the Texture_space_generator is to assign a coordinate system (also called vector system) that will be used by the shader at render time. A coordinate system basically consists of three axes: X, Y, Z. Now, this coordinate system can be based on several things (we call this "space").
On World space (or Global space), the system is fixed, and the axes start at the scene's center.
On Object space (or Local space), each object has his own coordinate system.

Now, in Camera space, the system is based on the camera. X positive is right, X negative is left, Y positive is up, Y negative is down, Z positive is backward, Z negative is forward. No matter the camera does or where it moves, camera space is always like that. Since a deth pass is used to generate faked lens effects, the coordinate system needs to be the one of the camera.

 

b) Vector2scalar
First of all, a scalar value is a single value, where a color value consist of 4 values, and a vector value consist of 3 values.
Visally, scalar information is grayscale, white being the highest and black being the lowest.

What the Vector2scalar node does is that it takes the vector system that we created with the Texture_space_generator, and tries to convert it to a single value. However, since the vector system provides 3 values, we have to tell the Vector2scale wich value to use. So if you open the Vector2scalar node, you'll see that you can pick only one of the three axes.
Remember: in camera space, X is left-right, Y is up-down, and Z is back-front. What we need is the Z component, because we want the gradient effect to take effect on the back-front axis (depth axis).

Basically, the result is that the lowest value of the Z axis (black) will be the furthest from the camera, and the highest value will be the closest or "behind" the camera.

= Z+
= Z-

So far we don't know these values. We just know the lowest Z value will be black and the highest one will be white, but we don't know what are the values. This is what the Change_range node will provide.

 

c) Scalar2color
We will see this node before the Change_range node because the Change_range node is where all the action is taking place. Be patient!

Since we want to affect the color of the objects, we have to connect the tree into the Surface input of the material. The thing is that the Surface input only accepts color information. So when we plug the Change_range node into it, the information has to be converted to color. This is why the Scalar2color node is created. Don't bother with this node.

 

d) Change_range
This is where the fun begins. First, lets explain what is a range.
The range is the relation between the mimimum and maximum values of a given parameter. The range is expressed by these two values. For instance, when you are dealing with color, a standard range is 0 1 (0 being black and 1 being white). A high range (like in HDRI) could be 0 3. mental ray also allows negative ranges (-1 1). With vectors and coordinates, this is the same thing! -1 1 could be the lowest and highest coordinates on a given axis of the vector system.

The Change_range node will allow you to edit that range. This is where we will control where the depth effect start and ends.
Open the Change_range property page.

Set the New Range Start to 0
Set the New Range End to 1.
This will have the following effect: whatever data comes into the node, it will be converted to 0 1 range, that is, a black-to-white image.

Now draw a Render Region.
You should get something quite uniform, like pure black or white color. This is because of the Old Range values, wich are probably set to 0 1.
Let's think about it: the range is expressed on the camera's Z axis. The Old Range Start values say that the lowest value is 0, wich is right on the camera (the camera being the origin of the coordinate system when in camera space), and the Old Range End value says that the highest value is 1, wich is 1 unit behind the camera (remember: in camera space, positive values for Z mean "behind the camera").

Now, if you change the Old Range Start to something like -25, now you are moving the lowest value 25 units away from the camera, on the negative Z axis.

 

You can put a negative value in the Old Range End too, the result will be that the white color will be visible in the camera.

 

Now we have our depth pass. All we need is to adjust the Old Range Start and Old Range End to tell mental ray where to put the black and white colors.


4- Interactive control

This is all nice and sweet, but between you and me, it is not very intuitive to tweak values this way. Plus, if you move the range sliders, dramatic changes occurs.
However, there is a way to adjust these values directly in the viewport, using the spot light falloff.

Lock the Change_range node property page.
Select the spot light, and hit enter to open its property page. Lock this property page too.

In the light ppg, go in soft_light tab, and enable the Light Falloff.
Put reasonable values, like Start 10, End 40.
Now switch a viewport to Top view, and enable Cones visibility.
If you hold down the B key, you'll see that you are able to edit the lights falloff directly in the viewport (just click on the green and purple lines and drag).

 

Now, we want these falloff values to drive the Change_range node.
Put the two ppg next to each other.

So wich falloff value should drive the Old Range Start?
Remember, the Old Range Start is the color the farest from the camera. So logically, the End Falloff of the light should drive the Old Range Start.

So click on the End Falloff animation divot, and drag it onto the Old Range Start animation divot.

 

An Expression Editor will open, only containing

Spot.light.soft_light.stop

This means that Old Range Start value is inherited by the End Falloff of the light. There is a problem. To have the black color to be further from the camera, we need to decrease the value, wich is a negative one. However, the End Falloff doesn't allow negative values. The only solution is to inverse the expression. Inversing the expression will result in that the End Falloff will value will be inverted in the Old Range Start. For instance, 50 will become -50.

To invert the expression, just a minus sign "-" before the expression.

Then click Apply.
From now on, the Old Range Start is controlled by the End Falloff. So, if you hold down B in viewport and move the end falloff manipulator, you will change how far from the camera the black color is.

 

To do the Old Range End, wich is the distance from the camera the white color is, you need to do the exact same thing, except that you will use the Start Falloff of the light.
Drag and drop the Start Falloff divot onto the Old Range End divot.

When the Expression Editor pops up, add a minus sign before the parameter and click Apply. That's it!


5- Workflow enhancements

To facilitate the viewport manipulation, I suggest that you make the Cone angle of you light pretty wide, and the Spread angle pretty narrow. This will prevent your from accidently picking them when you want to pick to the start or end falloff.

You should set the intensity of the light to 0, in case you forget to disable its visibility in other passes.

You should save the partition material to a preset file, so you just have to load it when needed. However, before saving it to a file, remove the expressions from the Change_range node. Otherwise, the expression will be looking for a light that may not be there.

You could also use scripting to faciliate this whole process. In one go you get generate the pass, add the material, build the render tree with the proper parameters, create the lights with its contraints, and set the expressions. Sorry if I'm no scripting guru, I can't provide you with a decent script.