Real-time Ray-traced Caustics
Project Details
-
Role: Graphics Programmer
-
Engine: Venus Engine
-
Language: C++, HLSL 6.0
-
Development Time: 7 months
Screen Space Photon Mapping
The fundamental concept behind caustics rendering is calculating the contribution of photon. Caustics are visible when photons concentrating on an opaque surface.
To simulate the caustics effect, I use the screen space photon mapping (SSPM), introduced by Hyuk Kim [1], instead of traditional algorithm. The algorithm use screen space buffer to store photons from light camera view, and sample the photon buffer by view vector, which is same as shadow mapping. The main purpose of this is to:
-
Guarantee the real-time performance.
-
Use DXR api function to generate photon rays.
Below flowchart illustrate the process of screen space photon mapping.
When updating the photon info that hit on translucent material, radiances as energy would be attenuated, and the new direction is calculated by these rules:
-
Reflected vector: RayDirection - 2 * DotProduct(RayDirection, SurfaceNormal) * SurfaceNormal
-
Refracted vector: Snell's law
Reflective and refraction factor determines the contribution of new photon rays.
Reflected and refracted ray direction
Radiance of photons could be color, or the coefficient of color enhancement. Below image is the visualization using red channel.
Gaussian Blur
As the image above shows the SSPM, photon buffer is filled with noise. Since most of the noise are low-pass, so I implement the gaussian filtering in compute shader to denoise the buffer. Here's the code:
Gaussian Blur CS
After denoising, the quality of photon buffer is improved.
Static Object Caustics
SSPM is a 2-Pass algorithm. After photon mapping pass, the ray-traced pass performs to shade the scene with specific lighting model. The basic concept of caustics shading is the additive blending, or the enhancement of shaded color. Below source codes are the raytracing shaders used in static glassware rendering.
Raytraced shading
Translucent effect and shadow are calculated in this pass. User can set a higher bouncing limitation to get a better effect, but it would reduce the performance extremely.
In the first scene, I put several glassware (5 cups with 1 upside down, and 1 ring), at the center of an opaque plane with ground texture. Light source is 1 spot light or 1 directional light. The performance of 2-Pass raytracing (limited in 3 bounces) of this scene is stable 60 fps.
The quality of photon mapping is determined by resolution. Higher the resolution, more accurate the caustics. Here's the comparison among 512 x 512, 1024 x 1024 and 2048 x 2048.
512 x 512
1024 x 1024
2048 x 2048
Gerstner Wave Function
In fluid dynamics, Gerstner wave is an exact solution of the Euler equations for periodic surface gravity waves [2]. I implement this method to generate the water wave for caustics. In application, there're 8 random wave coefficients to synthesize the final wave and it allow user to reset by debug key. Below vertex shader is the implementation of this method.
Gerstner Wave Function VS
There's one issue in here. The normal calculated in vertex shader is incorrect. To solve this issue, I recalculate the normal in the pixel shader by using hlsl intrinsic function ddx() and ddy().
Since the vertex data of water would be changed in every frame, the bottom level acceleration structure of water should also rebuild correspondingly.
Water Caustics
Water caustics rendering is more complex than static objects because the acceleration structure is updated in every frame. In order to shorten the calculation time, we limit the number of bouncing to 1, and start the photon mapping from water vertex position instead of light camera view. This is based on the algorithm invented by Holger Gruen [3].
To get the water position and normal, we render the water in the light camera view, and use Multiple Render Targets (MRT) in pixel shader to output the information.
MRT pixel shader
Below images shows the water position (RGB), normal and depth (RGB for normal, A for depth).
Water position buffer
Water normal and depth buffer
The output is not only the radiance of photon, but the hit position and the radiance (RGB for position, A for radiance). After that, we accumulate the photon to player screen by using compute shader.
Photon accumulation CS
In the end, we get the caustics output of dynamic water.
References
-
Kim, Hyuk. (2019). Caustics Using Screen-Space Photon Mapping: High-Quality and Real-Time Rendering with DXR and Other APIs. 10.1007/978-1-4842-4427-2_30.
-
Wikipedia contributors. (2021, July 1). Trochoidal wave. In Wikipedia, The Free Encyclopedia. Retrieved 21:08, March 19, 2022, from https://en.wikipedia.org/w/index.php?title=Trochoidal_wave&oldid=1031477851
-
Gruen, Holger. "Ray-guided volumetric water caustics in single scattering media with dxr." Ray Tracing Gems. Apress, Berkeley, CA, 2019. 183-201.