Ray's Cave

Ray's Cave

2023    

Introduction

Raytracing is more commonly associated with 3D rendering techniques. However in this project I explored how to apply this in a 2D space. Casting rays and detecting obstacles to render a scene with shadows and reflections in real time on the CPU using many optimizations.

How I did this

Shadows and reflections

Shadows are the absence of light, and are created by occluding a pixel from light. Seeing if a pixel is shadowed the ray traced to it has to intersect with an obstacle.

Reflections add more complexity to this. Needing to check if a light reflected in a reflected surface can reach the pixel unobstructed.

alt text

Grid

Tracing a ray to every light source from every pixel was very much hurting performance. A solution I found to this problem was to implement a light grid in view space. This grid holds handles to the lights that are influencing each cell by tracing rays. Eliminating redundant ray tracing and reducing computation per pixel.

BVH

To achieve shadows I needed to test a ray for intersections with obstacles. Performing intersection for every ray on every object in the scene was not an efficient way to go about this. I followed a series of blog posts by my lecturer Jacco Bikker on implementing a BVH to spatially partition and check only relevant objects. Link to the posts

Performance

By implementing optimizations like the spatial partitioning from grids and BVHs. I was able to achieve a playable frame-rate and keep the rendering in real-time.

A large boost to performance came from moving the computations to multiple cores by adapting my code to utilize OpenMP.

Challenges

  • Precision issues in intersections -> solved using floating-point epsilon corrections
  • Performance -> Spatial partitioning
  • Possible performance increases -> Adapting code to run in multiple threads

Results