Selective-Pass Raytracing in Rasterized Scenes by Tobias-Benedict Karras Written in Python + PyOpengl 1. Introduction In modern real-time rendering, hybrid techniques that combine rasterization and raytracing offer a compelling balance between performance and visual fidelity. One such technique is selective-pass raytracing, where raytracing is applied only to specific effects, such as reflections or shadows, on selected surfaces. This paper explores the integration of raytraced reflections into a rasterized scene using compute shaders in OpenGL, a graphics API not originally designed for raytracing workloads. 2. Background Rasterization is a feed-forward process that projects 3D geometry onto a 2D screen, shading pixels based on visibility and material properties. Raytracing, in contrast, simulates the physical behavior of light by tracing rays through the scene. While APIs like DirectX Raytracing (DXR) and Vulkan RT provide native support for raytracing, OpenGL lacks such capabilities. However, compute shaders in OpenGL 4.3+ can be leveraged to implement custom raytracing logic. 3. Selective-Pass Raytracing Selective-pass raytracing involves injecting a compute shader pass into the rasterization pipeline. This pass operates on a per-pixel basis, using G-buffer data (world-space position, normal, and mask) to trace reflection rays. Only pixels marked by a user-defined mask participate in raytracing, preserving performance. The reflection direction is computed using the standard reflection equation: R = reflect(-E, N) = -E + 2 * dot(N, E) * N Where E is the view direction vector and N is the surface normal. The compute shader samples the G-buffer and performs ray-object intersection tests against scene geometry such as boxes and planes. Figure 1 : Cornell Box Scene Demo 4. Normal Mapping for Deformable Reflections To simulate fine surface detail in reflections, tangent-space normal mapping is applied. The normal map perturbs the geometric normal using a TBN (Tangent, Bitangent, Normal) matrix derived from screen-space derivatives. T = normalize(duvdy.y * dpdx - duvdx.y * dpdy) B = normalize(-duvdy.x * dpdx + duvdx.x * dpdy) N = normalize(N_geom) TBN = mat3(T, B, N) N_world = normalize(TBN * (normal_map.rgb * 2.0 - 1.0)) Figure 2 : Normal Map Applied to Reflective Surface 5. Limitations of OpenGL for Raytracing OpenGL was not designed for raytracing workloads. It lacks acceleration structures like BVH, dedicated raytracing pipelines, and hardware traversal units. As a result, raytracing in OpenGL must be implemented manually using compute shaders, which is less efficient and more complex. Scene geometry must be encoded in arrays and traversed algorithmically, increasing CPU-GPU synchronization and memory overhead. Figure 3 : Manual Ray-Box Intersection in Compute Shader(Full Raytraced- reflection with Rasterization) 6. Example Implementation The following Python + PyOpenGL snippet shows how a compute shader is dispatched to generate raytraced reflections: glUseProgram(comp_prog) glUniform3fv(uCamPos, 1, cam_pos) glUniform1i(uCubeCount, len(cubes)) glDispatchCompute((width+7)//8, (height+7)//8, 1) glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT) The compute shader reads from G-buffer textures and writes the reflection color to an output image. This image is then blended with the rasterized scene in the final presentation pass. 7. Results The hybrid approach enables physically plausible reflections on selected surfaces. Normal mapping adds realism by distorting reflections based on surface detail. Performance remains acceptable since raytracing is limited to masked pixels. The technique is suitable for real-time applications such as games and interactive visualization. Figure 4 : Final Composited Scene with Reflections and Reflection-Mask 8. Conclusion Selective-pass raytracing in rasterized scenes provides a practical compromise between quality and performance. Although OpenGL lacks native raytracing support, compute shaders enable custom implementations. By combining G-buffer data, reflection equations, and normal mapping, we achieve realistic, deformable reflections in real-time. References Toy Box Normal: toy_box_normal.png (256×256) Toy Box Reflection Mask: toy_box_disp.png (256×256) (The Reflection-Mask was Inverted in the Render)