So I was thinking of caustics and how to do them for a while. Here is a naive approach I might try in my JS engine:
before rendering the scene: - prepare a surface the same size as the one you use for rendering the scene - cast N rays from each light in random directions (or uniform distribution, whatever) - follow each ray until it hits a surface that can accept a caustic - find where that hit point is from the camera's POV - record the distance from camera, and light colour, at the spot on the surface that corresponds to the point from camera's POV while rendering normally - when rendering a pixel, check the caustic map at the spot for the current pixel to see if there is any colour info there from a caustic - if the caustic is closer to the camera than the current hit, blend in the caustic colour
Notes:  if there is a semi transparent surface that splits the light and makes multiple caustics, it gets tricky...  do caustics appear on glossy surfaces? mirrors? semi transparencies? Need to play with it  record the closest caustic in case of multiple on the same spot.  make sure to account for multiple caustic rays ending up on the same spot and becoming super bright  this is like the shadow test. I expect the caustic distance to be epsilon closer than the hit surface
This will be pretty slow but will account (I think) for light coming off mirrors etc. Also you need a LOT of rays to get it looking good, I feel. To speed it up you can directly fire rays at any transparent object in view of a light so you are sure that every ray will contribute to a caustic but you lose light bounding off mirrors etc
Also the whole "record data at the spot that corresponds to the point from camera's POV" isnt possible in WebGL so I'll only be able to try it in slow JS
I'm kinda spitballing here- let me know if anyone has a better idea!
I read some articles and found that a Kd Tree is very useful to store the photons / caustic map so I will work on this first. This structure is useful to speed up rendering so I will practice and train on this subject before working on caustics or global illumnation.
I'm back after my first attempt to implement the above algorithm I posted. Here is an image from before that I posted when I was talking about better shadows for transparent objects
Here is the same rendering with caustics enabled.
Note there are 2 lights so there is 2 caustic effects, and they look pretty accurate. I have to try with more difficult objects. The strategy is: - render normal image - for each light - - for each object - - - cast a bunch of rays at the object (as above) - - - if a ray passes through a transparency and hits a surface, increase the brightness at that spot (update the rendered image)
The hardest part was actually going from a world position back to a pixel on the canvas. I'm going to keep testing objects and post more later. I can go into better detail if needed
An example with a cylinder. I've been trying to filter out the noisy parts and make those bright lines pop more but havn't found the right combination of settings yet. Also the caustic is at an angle from the shadow, not sure if that right or not. The bright lines do look correct if I can just get the noise down.
Ya it should act as a new light source. I'll set up a scene like that and try it out. I also was reading that caustics only come from specular light, so I added a specular check but I dont know if the result is more right or not
About the noise problem, you will have to cast a lot of rays from light to correct this I think. I've read (but not tested yet) a different way of solving this. The rendering has two steps: - first : cast a lot of rays and store their intersections (direct + reflection / refraction) This will be the "photon map".
- second: render the scene as usual but use the photon map to modify the pixel color you are drawing. With the photon map, you can have all the photons / lights close to your pixel and interpolate them so there is less noise. The best structure for the photon map is a KdTree because it allow to search for items "close" to a given point.
It's only theory to me as I have not tested anything yet.