The idea was to use the native WebGL mesh rasterizer instead of the custom distance-field-accelerated raymarching algorithm for the initial rays cast into the scene, while keeping the raymarching for the secondary bounces. At first, this was done with plain mesh rasterization into 1x1 quads, but even with overlap and normals culling, mesh rasterization performs approximately 2x worse than SDF raymarching. So I had to simplify the mesh. By using a greedy voxel meshing algorithm popularized by Mikola Lysenko, I was able to significantly reduce the number of polygons, and the performance shifted in the mesh rasterizer’s favor. Without reflections, the mesh rasterizer with a simplified mesh performs approximately 1.5x to 2x better than SDF raymarching.

However, the now comparatively slow raymarching was still used to calculate whether the first point is in the shadow, where a ray is reflected to, and whether the reflected point is in shadow. I was able to eliminate the need to raymarch the shadow of the reflected point by utilizing screen-space reflections. This meant creating a framebuffer in addition to the default canvas, where I rendered the base color (+ raymarched shadow), and coordinates (UV) of the reflected point (via raymarching). Then, in the default canvas (now given the role of compositing), the base color of every surface is mixed with the base color at the UV of the ray reflected from the surface.

With reflections, this branch performed approximately 2x better than the purely-raymarched branch. Additional changes included the accounting of the reference (aka CSS) pixel to device pixel ratio for a more accurate resolution, increasing the Z range to 32 blocks (32 yards or 96 feet) to fit tall structures such as the Performing Arts Center and the pool, and speeding up the SDF texture generation with thread-based parallelization (thanks Shin) and restricting the search gradient to ±1 (distance to the nearest surface cannot change by more than the change in an observer’s position). One regression which I plan on soon fixing is the removal of glass transparency, which is not supported by depth-tested mesh rasterization.

Performance metrics at default position:

  • Reflections on:
    • Halfscreen:
      • Motorola G: 15.9 fps → 36.0 fps
      • HP laptop: 24.6 fps → 39.9 fps
    • Fullscreen:
      • Motorola G: 5.6 fps → 15.6 fps
      • HP laptop: 15.0 fps → 25.1 fps
  • Reflections off:
    • Halfscreen:
      • Motorola G: 41.6 fps → 54.6 fps
      • HP laptop: 20.0 fps → 39.9 fps