11
$\begingroup$

I would like to modify the intensity of a light ray based on the ray total distance traveled from camera to emitter.

In the light path node, ray length gives how far ray has traveled since the last bounce.

How could I get to the total length for all bounces?

$\endgroup$

1 Answer 1

8
$\begingroup$

Cycles only provides the Ray Length for the current section of the path (ie, between bounces or interactions with a surface) and does not prove a means of summing that over the entire path of the ray - the only link between one 'bounce' and the next is the intensity of light and we cannot even directly access that. However, we can use a maths trick to encode the 'length' into the intensity of light and later use the compositor to decode it.

example using sine to show distance bars

Consider an imagined ray that follows an assumed path :

  1. It leaves the lamp
  2. It bounces off a reflective (glossy) surface
  3. It bounces off the ground
  4. It bounces off an object
  5. It gets to the camera

showing path of imagined ray

Each 'surface' (and the lamp) has a Color - lets call those C1 (lamp), C2 (glossy), C3 (refractive), C4 (diffuse). In addition, the light may fade between the interactions - eg, light travelling from the point source lamp will 'falloff' as it travels and so will be less intense the further it is from the source - lets call those F1, F2, F3, F4.

The light from the lamp (with initial intensite 'I') travels the path from the lamp, through all the interactions and to the camera and at each stage the intensity of the light is multiplied by each of the interaction's Color and Falloff.

So,

FinalIllumination = I x C1 x F1 x C2 x F2 x C3 x F3 x C4 x F4

At each stage along the path we can control the Color of that interaction - so we could vary the resultant light based on the ray length for each 'bounce' and combine these to represent the total ray length, extracting the result in the compositor.

However, this mechanism only allows us to multiply values together - we need to be able to add each individual ray length into the total at each stage, and we can do this using exponents and logarithms.

We can use the Maths 'Power' node to raise a number to an exponent - eg, 2^5 (or 'pow(2, 5)' or 2x2x2x2x2) = 32. Mathematically, multiplying two or more such powers together (with the same 'base' number - eg, 2^5 and 2^4) is equivalent to adding the exponents together.

ie, b^n x b^m = b^(n+m)

The Logarithm function is the reverse of the Power function and this can be used to extract the result (n+m) at the end. We can use this trick to manipulate the 'color' at each bounce to add in the ray length at each stage and extract the result (the total ray length) in the compositor.

Using a large 'base' would result in distant rays flooding the more relevant 'closer' bounces - using a 'base' slightly less than '1' results in progressively smaller values for longer distant rays while keeping reasonable precision. 0.95 seems to work OK for my range of distances - use a smaller number to increase the precision at small scales (eg, 0.9) and a higher value to allow for much longer distances (eg, 0.98 or 0.99 or higher).

We can use the different color channels (Red, Green, Blue) to represent different quantities. By making one of the channels always multiplied by '1' we can use that to accumulate the falloff of the entire journey (ie, F1 x F2 x F3 x F4) and this can be used to adjust the exponential accumulation of the ray length prior to the logarithm to effectively 'cancel out' the falloff prior to extracting the result. I used Green to represent the exponential accumulation, and Blue as a constant to measure the natural illumination falloff so the logarithm of Green / Blue should provide the total distance travelled by the ray. This leaves the Red channel which could potentially be used to 'count' the number of bounces using a similar technique (ie, use 'base ^ 1' to add '1' for each bounce).

To achieve this we need to replace each material in the scene with one that performs the calculations to generate a Color based on ray length. Here are materials for Diffuse, Glossy, Emission and Lamps. Similar materials can be used for Refraction/Glass.

NOTE : The World illumination should be set to zero to avoid it conflicting with the ray length (since they'll be coming from 'infinity' and would swamp our measurements).

Diffuse diffuse

Glossy glossy

Emission emission

Lamp lamp Once the scene is rendered you can extract the path length in the compositor using the following nodes :

compositor

Note that the 'base' (0.95) used in the compositor must match those in all of the materials.

To demonstrate, here's a test scene consisting of a diffuse cube and plane, an emissive sphere, and a glossy mirror :

demonstration setup

The result of the captured ray length (using a color ramp to map colours based on distance) :

result - color ramp

Showing a progressive 'pulse' based on total ray length (bear in mind that the total ray length is measured from emitter to camera, not just the distance from emitter to the surface - also where multiple paths exist the shorted path will tend to override any longer paths) :

progressive pulse

Blend file attached.

$\endgroup$
1
  • 1
    $\begingroup$ Thank you. This is really a great solution. Very creative and well documented. $\endgroup$
    – Ed Tate
    Apr 7, 2021 at 21:07

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .