There was one other issue with the “render point-sprite quad and ray/box-intersect the resulting fragments”: Numerical stability when cubes are far away. The intersection code from the paper uses a ray/plane intersection test and determines whether the point of intersection lies within any of the possible three sides of the cube visible to the ray.
When rendering many cubes beneath each other, it is sometimes possible that the intersection test will determine that the top side of the cube was hit (giving a normal color of green in the below images) whereas the adjacent pixel is determined to have hit the front or left/right side of the cube (giving a red or blue color). This is effectively aliasing due to the low framebuffer/pixel resolution at far distances. But worse, sometimes the ray even went straight through the cube without a hit being detected for either side!
Although the effect is exaggerated when using those high contrast colors and diminishes when actually shading the cubes, this error became severely apparent when rendering depth values for occlusion culling. It is unacceptable for a ray to go through a cube and hit another cube hundred meters behind it because that higher maximum Z value will propagate through the HiZ mip chain and destroy any occlusion benefits (because no occlusion will be detected for big occluded objects, which use a high mip level to sample depth values from).
To counteract this, on voxel creation I gave each voxel a bitflag (as the w component in the voxel’s GLSL u16vec4 vertex attribute) saying which of its neighbors actually exist. This information is then used in the ray/box intersection test to determine whether the ray could actually have hit that side of the box (it couldn’t when there is an adjacent box at this side), in addition with an epsilon value depending on the distance between camera and voxel center effectively giving a margin around each possible side of the cube hit by the ray, so that no ray will go through a voxel anymore and proper depth values will be preserved.
Image without and with epsilon and side-flag correction:
https://gist.github.com/httpdigest/15399efe2b60a2b31d1c2cbe414ce5cf
cullAndMultiDrawGenerate.glsl
#version 430 core
#ifdef GL_NV_gpu_shader5
#extension GL_NV_gpu_shader5 : enable
#elif GL_AMD_gpu_shader_int16
#extension GL_AMD_gpu_shader_int16 : enable
#endif
#ifdef GL_ARB_shader_atomic_counter_ops
#extension GL_ARB_shader_atomic_counter_ops : enable
#endif
This file has been truncated. show original