This is a simple technique which uses some dynamic geometry (created in Houdini) and a renderman shader to simulate the collective focusing and diffusion of light rays. The geometry starts off as a flat NURBS grid. The control points are then perturbed in height and over time to simulate waves. Finally, the control points are projected onto a flat plane along the normals to the surface. This creates a laterally distorted, but flat, NURBS grid, which can have multiple overlaps and where parts of the surface have been either streched or contracted depending on the initial geometry of the surface.
The shader is sensitive to the relative distortion of the NURBS surface through the global variables dPdu and dPdv, and uses this as a control for the brightness; small values for both, reveal that the surface has been compressed at that point, and as a representation for focused light, this increases the brightness. The strongest compression occurs at the cusps - those areas where the surface folds back onto itself.surfaceAdditionally, the shader uses "Oi = 0" to accumulate multiple surface layers which might overlap. The max and min values are highly dependant on the size of the rendered geometry. A rough guide can be obtained uncommenting the printf line and inspecting the numbers for appropriate max/min values.
caustic(float brightness = 1.0;
float maxval = 80.0;
float minval = 10.0)
{
float lu,lv;
/*printf("du: %g dv: %g\n",length(dPdu), length(dPdv));
*/
lu = 1-smoothstep(minval,maxval,length(dPdu));
lv = 1-smoothstep(minval,maxval,length(dPdv));
Ci = 0.4*(lu*lu*lv*lv)*brightness;
Oi = 0;
}
Here is the final result.
![]()
Here is a 200 frame animation of the caustic in motion.
caustic.mov ( 2.4M Quicktime)
caustic.mpv ( 1M MPEG)The Shader caustic.sl
The RIB file used to generate the above image caustic.rib
Thanks to Ivan DeWolf for suggestions.