Jon Baker, Graphics Programming

    home

    writings

Weekend Project: Realtime Pathtraced Caustics

  This was an idea I got in my head and threw together in an evening for fun. It was inspired by the fact that my waveform and parade graphs look like smooth surfaces, under certain conditions. It's basically a one or two bounce forward pathtracer, depending on how you look at it. I'll start off by saying, there are certainly better ways to achieve this, that don't involve any kind of raytracing. Here are a couple different raster approaches, which are probably faster and scale much better than what I'm doing here.

  The idea is basically to do a raymarch from above, down to the surface of this water surface SDF. Because it's easy to get the normal vector from an SDF, it's easy to then refract at its surface. From there, you can do a ray-plane test using the refracted ray, and do an atomicAdd to an image which represents a square region on this plane. You can see the code and a visualization of this SDF, below. I masked it out to just the portion contained within a sphere, for this image.

	float deWater( vec3 p ) {
		float e, i=0., j, f, a, w;
		// p.yz *= mat2(cos(0.7f),sin(0.7f),-sin(0.7f),cos(0.7f));
		f = 0.3; // wave amplitude
		i < 45. ? p : p -= .001;
		e = p.y + 5.;
		for( a = j = .9; j++ < 30.; a *= .8 ){
			vec2 m = vec2( 1. ) * mat2(cos(j),sin(j),-sin(j),cos(j));
			// float x = dot( p.xz, m ) * f + t + t; // time varying behavior
			float x = dot( p.xz, m ) * f + 0.;
			w = exp( sin( x ) - 1. );
			p.xz -= m * w * cos( x ) * a;
			e -= w * a;
			f *= 1.2;
		}
		return e;
	}
			
water

  Running a couple dozen of these rays per pixel and displaying the sum, you can resolve some pretty convincing caustics in a couple of milliseconds. If you map that sum to a palette, you can do colors pretty easily. Something that might be cool to try would be to keep data for a couple of different wavelengths, and vary the IoR used during the refraction accordingly. This is probably a viable way to extend it to do some fake spectral effects.

  Another thing here, a couple bugs I found while I was implementing this, where ray-plane distances became negative - I think this has real potential as a method for doing IFS fractal rendering. By applying a series of transforms to 2d points, you can create some very neat images. A lot of times, you'll see this referred to as “fractal flames”, they were used in a lot of different media and advertising in the 90s and 00s.


Last updated 6/30/2024