Houdini VOP raytracer part 3

Posted on August 16, 2013


Shadow Ray and Illumination Ray

Now this is where fun starts. Following a photon in our backward raytracing next step would be to test where it came from. We already know last hit position before photon hit our Image Plane, we can check if there is direct path from hit point to light source simply by shooting another ray. When a our new ray is able to reach a light source without any interruption, we call it illumination ray, otherwise, when there is any obstruct on our ray path we call it shadow ray.


Lets jump into Houdini and start implementing. Inside VOP SOP node we need to import light position. In our case it is last, third input of VOP SOP node.

TIP: When using Import Attribute VEX node to import single point, remember to create constant parameter with value of 0 and connect it to `ptnum` input. Otherwise, Import Attribute VEX node will use Global point number which may consist of more then one point.

Subtract light position from ‘last hit` position (`pos` output from intersect ray node) to calculate direction vector towards light. Create null node, connect it to subtract output and name it “dir_to_Light”. Create remaining null nodes as shown above. This will help us keep nodes organised.

We can build now our shadow ray. Create new intersect vex node and call it “intersect_SHADOW_RAY”. This will tell us if there are any intersecting obstacles on our way towards the light. As a `file` we will use same path to scene geometry as we have used in first intersect ray vex node. This is where our potential intersection might be. Input `ray origin` is our last hit point position (`pos` output of the first intersect RAY), `ray direction` input will be `dir_to_Light` null. At this point, we only care about potential intersection and first sentence from intersect vex documentation says:

This operator computes the intersection of the specified ray with the geometry, and returns the number of the hit primitive or -1.

It means that `prim` output will be [-1] if there was no intersection. Create compare vex node, leave the default test condition as `Equal (==)` and set `Compare to Integer` to -1. It will return False [0] if there was intersection on our way towards the light, otherwise True [1] (`prim` output == -1). Create if statement – switch vex node to switch between shadow and colour. For the first input (0) create spare colour parameter and call it `Shadow Colour` as a second input (1) we will use colour output from last switch. Connect switch output to vop sop Cd output and create remaining null nodes as shown below.


We can see some shadows but image seems to be noisy! what happened?


Our first ray hit position is placed exactly on our geometry, when we are looking for intersection towards the light, shadow ray is hitting surface at its origin. To fix this issue, we need to add small offset to the ray origin. But which direction we should offset it? In case of ground plane, offsetting ray upwards would help but it would create problems with other objects like sphere. Fortunately, we can use scene geometry normals.


Make a copy of Primitive Attribute vex node, “prim_Cd_attrib” that we have used to get Colour from scene geometry and rename it to “prim_N_attrib”. This time, instead scene geometry, we will ask for normal vectors. Enter “N” as an Attribute. Normal vectors of each object might have different magnitudes. We need to unify their lengths. Create normalize vex node and connect it to “prim_N_atttrib”. Now we have all the normals set to length of 1.0 but we need our offset to be very tiny. Create and connect constant multiply and set it to small value like 0.001. Add the output of multiplication to `last_HIT_pos` as shown below.

shadowOffset2 shadowOffset

Congratulations! our shadow should be visible now without any noise. Try changing light position and see how it changes.


<< [ 2 ] [ 3 ] [ 4 ] >>

What Others Are Saying

  1. damejudybenchJoe November 19, 2013 at 19:34

    Thanks dude, this is great stuff!

Leave a Reply

%d bloggers like this: