I’m trying to create the infrastructure for volume shaders in my raytracer, but I’m a bit confused about things at the moment. I want shaders to have access to all the information that Renderman volume shaders have access to. The trouble I’m having is figuring out how to implement an equivalent of Renderman SL’s illuminance() for volumes. The problem is when a light casts shadows, how will the light coming into the point be computed? Because the light ray must travel through the volume being rendered, it seems the light will be attenuated by that volume. Which means that the volume shader will need to be run, finding the color in the direction of the light. But this would seem to cause an infinite recursion, because that volume shader will again want to know the color of the light ray entering that point. etc. etc. So how does Renderman do it? Or how would you all suggest it be done? This kind of thing is required for self-shadowed clouds and the like.
I also had a question about dealing with intersecting volumes, but that’s of lesser importance at the moment.
Volume shaders aren’t very good in RenderMan. There are two ways of doing volumetric shadows.
The very slow way is for each shading point raymarch towards the light along the shadow ray. Then step one sample and repeat. This is very wasteful as you’ll often be going through the same point again - or very close to it.
A better way is to do this in several shadow passes raymarching from the lightsource, save this information in a 3d point cloud, and use it to shadow the light in the beauty pass.
Also RenderMan doesn’t handle overlapping volumes very well - such as if you have lots of volumetric particles. A better way is to have a larger bouding volume and, again, have the density saved in some sort of point cloud.
You’re on the right track, but it seems you’re slightly confused as to exactly what it is you want to calculate.
First thing to mention is that trying to ape renderman shaders in a raytracer isn’t necessarily a good idea, but then again it kinda depends on what you want to achieve.
When you’re calculating light interaction with volumes, you’re dealing with two seperate effects: in-scattering and attenuation (itself a combination of out-scattering and absorption).
in-scattering is light that is scattered towards the camera by the volume, so to calculate this you need to calculate the lights, and hence their shadows.
For attenuation, you’re just calculating how much light is either absorbed by the volume (a constant term per step) or scattered away from the view direction (again a constant term per step). For calculating your shadow rays, you only need to worry about absorption, so you don’t need to get into any recursive shadow generation.
For a homogeneous volume (i.e. a volume that doesn’t change its characteristics over space), the attenuation term integrates to an exponential function over the length of your ray, i.e.
Latten = L * exp( -attenuation * distance )
where L is the radiance from your light source and Latten is the attenuated radiance you use in your volume shaders illuminance() call.