Aug 2023
Made with Shadertoy
After learning up on the basics of ray tracing, I wondered if I could use ray marching instead of ray casting for a refractive glass-type material.
You can click and move your mouse to adjust the camera. Will not work if hardware acceleration is turned off on your browser.
Part of the motivation for this was that ray marching can be performed on SDFs, meaning that all the geometric information can be stored in a function in the shader code, rather than needing vertex buffers and some kind of CPU involvement.


A nice side effect of using SDFs is the ability to do smooth constructive solid geometry operations (CSG) and surface perturbations with relatively straightforward math.


Lighting Model
The following describes some of the simulation techniques I was using.
The refraction was done using Snell’s Law, and I had a variable to affect the index of refraction, which you can see the effects of below.


Varying index of refraction on different shapes inside a multicolored room.
The refraction is actually achieved through some fakery. The environments are sampled from cubemaps, which are sampled using angles (i.e. a ray cast from the origin). Since I needed refraction to occur with location dependent views, I cast all the real rays onto a sphere, and then used the sphere to calculate the angle I should sample the cubemap.


2D view of the process. (Left) First, the real view is cast to a sphere, and an estimate angle is made. (Right) Then, the estimate angle is used to sample the cubemap.
For reflective illumination, I used diffuse and specular lighting based on the Lambertion reflection model, using a roughness parameter to control the spread of reflection. For the diffuse lighting, this involves using a cosine weighted hemisphere sampling (i.e. more samples parallel to the normal, less samples perpendicular to the normal), which I also sped up slightly by using stratified sampling to get a good spread of samples.
In ShaderToy, cubemaps are provided in pairs of non-blurred and blurred, so I could additionally cheat on the diffuse samples by just mixing in samples from the blurred cubemap.




Specular and diffuse lighting at different roughness values
I also added the Fresnel effect, which is subtle but important for realism. As the angle of incoming light becomes perpendicular to the surface normal, less light gets transmitted (i.e. enters the glass) and more light gets reflected, so the edges of the glassy material should be brighter near the edges.




Resources
A huge thanks to all the wonderful people who have documented these sorts of things. Some resources of particular note that helped me a lot were: