AstroNaughty Games shows how to implement ray tracing with space game Grimmstar
Issues with lighting spaceGrimmstar features entire solar systems through which the player can freely traverse. We have to incorporate rather large levels that have enormous planets, moons, stars, and other celestial objects in realistic proportion to the size of the player’s ship. This presented a number of issues.
First, building lighting information (even with Lightmass Importance Volumes) for each level was far too strenuous. A single sub-level gave us 7GB of lightmap information. That just won’t cut it, so we had no other option but to check the box to force no pre-computed lighting. Second, the vast majority of objects are in space, so they are dynamically moving. Space station rings, asteroids, ships, planets, and moons all move because there is no resistance. Lastly, the very large distances between objects and the enormous variation in the size of assets inside levels led to some less-than-desired outputs when using Cascaded Shadow Maps. They aren’t bad, but they’re not quite the quality we set out to achieve.
How real-time ray tracing solves these issuesSince we’re not using any precomputed lighting (no light build information), RTX allows us to achieve incredible shadow results in real-time, no matter where the player is located, regardless of whether the mesh is set to static or dynamic. This adds to the believability of being in space.
Right: Shadows transition from being sharp to soft as the shadows grow more distant. The mining frigate’s windows are reflective, and ray-traced reflections help bring metallic surfaces to life.
With our shadow information solved, we took things a step further and added ray-traced reflections. This took certain assets to a whole new level of fidelity for us. Small details like the pilot’s visor reflecting the Multifunctional Displays inside the ship’s cockpit enhanced the fidelity and brought out further cinematic capabilities.
Performance improvementsReal-time ray tracing is a very resource expensive method of lighting. Thankfully, Unreal Engine does a great job hybridizing a number of the lighting techniques used so that you can mix RTX technologies with more classical methods of lighting to get the best of both worlds. For example, we’re using a material node called RayTracingQualitySwitch to disable any normal information from most of our ray-traced reflections. Heavy usage of normals will cause lighting information to bounce in many different directions, requiring more information to be collected to receive proper results. By disabling the normal information with reflection bounces, we disable some of those extra calculations. On top of that, we’re ensuring some settings are optimized for the player from the very start by setting some console variables during the start of the persistent level we’re using for our current demo. A lot of these variables can be found by typing “r.RayTracing” into Unreal Engine’s console. You can take a look at everything available at your disposal from there. Some examples of variables that we use are setting r.RayTracing.Reflections.HeightFog to 0 and r.RayTracing.Reflections.ScreenPercentage to 50. By lowering the reflection screen percentage, we’re able to drastically reduce the calculations needed for ray-traced reflections. The results are still very good and hardly noticeable in most scenarios. If we do need improved reflections, we can always set a separate volume to override that.
Real-time ray-traced lighting is a perfect use case for a game of Grimmstar’s scope and scale. It has not only solved some technical issues for us, but the output is better than classical lighting techniques. While the tech is still maturing, we’re seeing consistent improvements to the performance and methods that enable us to deliver incredibly realistic lighting results with lots of flexibility.