Home Artists Posts Import Register

Content

This is a surprise feature I've been working on for a while.

The BSP architecture of the Quake engine is very efficient for tracing lines in 3D space, and entities in Quake also uses it for sampling environmental lights. When I implemented environmental light sampling in the particle renderer years ago, I was surprised that even when rendering hundreds of particles during multiple explosions (and therefore, tracing hundreds of lines to sample the environmental lighting), the impact on the performance was negligible.

With that in mind, some time ago I did some quick math, and figured out that if I did individual traces for each lightmap sample coordinate in the surfaces lit by dynamic lights, the performance should be acceptable.

So, in the last weeks I decided to finally tackle this. The first step was to find ways to optimize the dynamic lighting system even more, and I found two major ways to achieve that: skipping surfaces that were dynamically lit from the back, and skipping surfaces based on radius proximity.

Originally, the Quake engine only skips surfaces whose plane can't be reached by the dynamic light. However, planes have infinite dimensions, and this means that even if a polygon's edges are too far away from the light, but its plane is aligned near enough to the dynamic light, the renderer would still fully process the dynamic light on the surface, despite not outputting any light values onto the polygon surface's lightmap. The solution for this was to compute the centroid of the polygon, compute the maximum polygon radius from it, and then check the distance from the surface's polygon centroid to the dynamic light.

By combining both optimizations, most unreachable surfaces can be entirely skipped, which helps a lot to reduce the performance impact of the raytracing.

Funnily enough, all the work I did on this also helped me to fix the differences in the liquids' waves between mipmap levels:

There was a small misalignment between the miplevels of the lighting surface caches, which became too distracting after I implemented the radius proximity check on the lightmaps, because surfaces hit by dynamic lights always have their lighting surface caches generated at a lower mipmap level, and the surfaces hit by dynamic lights would become misaligned right next to the surfaces that were not hit.

Fixing that made me figure out a small inaccuracy that only happened in one axis of the surface coordinates, and then I wondered if the same inaccuracy could be what caused the weird distortion between different mipmap levels of the liquids. After implementing the same fix on the liquid surfaces' coordinates, the distortion between their mipmap levels is gone. Hooray! There's still a significant difference in the depth of the wavy shorelines between mipmap levels, but at least their curves are properly aligned now.

The next version should be released in a few days.

Files

Realtime raytraced light sampling in the Retroquad engine

Running in the Retroquad game engine, version 0.21.0: https://www.patreon.com/mankrip Hardware: CPU AMD Ryzen 5 PRO 3350G 3.6Ghz 4MB Cache AM4 Motherboard Biostar A320MH DDR4 RAM 16GB 2666MHz DDR4 SSD 256GB Sata 6GB/s Notes: This feature performs traces in world space, from dynamic point lights to each coordinate in the surface's lightmap, to check for collisions against the world geometry. It's a straightforward approach with no bouncing and no PBR features. Entirely done in a single-threaded 8-bit color software renderer.

Comments

SgtCrispy

Kick ass!