Refraction

This is an experiment I made recently. It displays the path that light would take when it refracts through variously-shaped objects, color-coded based on the initial angle of emission. In order to do this, it casts a series of rays and uses Snell's law to determine how they refract off of objects. It then iteratively casts more rays between rays that get too far apart or act differently (if one ray hits something and the other hits something else, for instance) to get higher accuracy. The raycasting is performed with JavaScript, and then the light intensity is interpolated between rays in WebGL. Basically, the algorithm casts a large number of rays (about 128) in all directions. These rays are connected in a linked list to the rays adjacent to them. Each time a ray hits an object, another ray is created and connected to the source ray using additional pointers. Ultimately, this creates a sort of 2D linked list.

First, all the initial rays are processed, generating additional rays where they intersect with objects. Then, the second-level rays are processed, generating third-level rays, which continues until all rays terminate on a side of the simulation. At each stage, if the ray being processed and the previously processed ray become too distant from each other, or if they hit different things, another initial ray is generated between the two rays and propagated forward up to the current level. After a certain limit is reached, or once no more rays are generated, execution stops, and the rays are drawn into WebGL using the GLOW framework.

Each polygon contains attribute information that allows any point within it to be accurately interpolated. This was difficult originally, as the interpolation across a triangle in WebGL is linear, but the interpolation needed for an accurate circular spread of light is radial. I solved this by passing the raw x and y positions of each vertex and also some identical values recording the locations of each ray, their intersections, and their intensities. While this is not an elegant solution and goes against the typical design patterns in GL, I was able to use it to accomplish my task. Feel free to view the shader source to understand how this part works.

I originally designed this experiment after learning about optics in my AP Physics class. More specifically, I learned about the spherical aberration, which is essentially the fact that circular or spherical lenses don't actually do what people teach about lenses. People teaching things that are just inaccurate is one of my biggest pet peeves, so I set out to show what light actually does when it hits a lens. As it turns out, it's actually quite pretty.

Update: This demo is now on the Chrome Experiments website!