Lighting Optimizations, Compositing

Hey Folks! Making more progress on the alternate lighting engine today.

Yesterday's work got basic light rays drawn on the screen, which appeared to cast shadows on random blocks placed around the scene. Not a bad start, but one of the next things I wanted to check was whether this actually scaled up to many lights/shadow casters or not.

The short answer was "no."

Throwing 14 boxes into the scene ran at 60+fps at 2560x1600, which seemed good. But 140 objects dropped it quickly to 23fps. And 1400 objects dropped it to 1.6fps. Given a medium ship in this game can be composed of hundreds or thousands of objects, this wouldn't cut it.

However, there are some caveats and tricks we can use.

First of all, this framerate drop was due to recalculating shadow mesh every frame as I moved a light around. If lights and/or shadow casters don't move around, we don't need to waste any time recalculating. So for the large majority of lights on a ship, we calculate once and then ignore them until the player comes close enough to see them and/or block light rays from them.

Second, we could limit the range of lights to be on the scale of a room, so the number of boxes to check could be more like dozens instead of hundreds.

Third, the original code I was using assumed arbitrary shadow box sizes and positions. This being a grid-based game, we can enforce some placement and size rules on the shadow boxes. I.e. they are all grid-aligned and square. This meant I could immediately skip between 2-3 sides of every box when calculating the scene, since any given point can only see between 1-2 sides of a cube at once.

I could also make certain assumptions about distance sorting based on their simple shapes and sizes. No need for complex segment-segment distance checking and sorting per-frame.

Combining these, I was able to generate a screen with 200 shadow casters in it and see no framerate drop as I moved a light around. (I cranked it up to 400, with similar performance, but there was nary an open space left to see anything!)

So with performance a bit better, I now want to check the next thing: quality.

For that, I'm thinking we're going to have 3 textures generated each frame, and combine them to produce the illusion of light and shadow.

Texture 1 - The diffuse color of the scene. Brown floors, white walls, etc.
Texture 2 - The normal maps corresponding to those scene elements.
Texture 3 - Lighting info.

Using cameras with render textures for each of those views, I'll combine them via a shader to make it look like the light is affecting the meshes. Roughly speaking, the brightness of Texture 3 can be used to modulate the diffuse color of Texture 1. There might be a tricky bit to make the light honor Texture 2's normal direction (so the surface looks bumpy/3D), but there are a couple things I can think of that might work.

Anyway, today's image is a randomly generated scene with a light projecting through walls. We can see the dimmed wall textures, dimmed floor textures, and a white light fading with distance. This is the scene as the main camera currently sees it: everything drawn at once.

In the lower left corner is a separate view of just the light info. I have a similar render view setup for the walls and floors without light info. Tomorrow, we try to blend them!

Tags: Ostranauts