Optimizing Point Lights

This optimization has such a strong effect that I couldn’t accurately measure the improvement with fps: the dynamic range is too big. I had to switch to using the time between renders (“frame time”).

I did three tests comparing “stock” Threejs with @DolphinIQ’s mod (“optimized”):

A. Stock with 250 lights: 1519ms (0.66 fps … oof)
B. Optimized with 250 lights: 22–26ms (38–45 fps)
C. Stock with 31 lights: 34ms (29 fps)

Comparing A and B shows us that for very large numbers of lights (the maximum my gpu would allow) the rendering performance in this scene is about 58 times faster with the optimization applied.

Also, comparing tests B and C we can see that, holding frame time constant (approximately), we can render about 8 times more lights, and that’s being conservative.

To be fairer, since test B is performing better than test C, another way of looking at this is “lights rendered per millisecond”. Stock is is 0.9 lr/ms and optimized is 9.6 lr/ms. This isn’t a super scientific measure, but I think it’s a useful way to adjust for this performance difference.

I also noticed that when you zoom in with the optimization enabled, the frame rate improves further. In stock three, the framerate is consistent no matter where the camera is pointing. This suggests the early return is working as intended, as though lights are being culled.

To check the effect on smaller, more “reasonable” numbers of lights, I did some tests with 10 lights. For these tests I rendered the scene 50 times per frame to multiply the small load enough to measure it.

D. Unoptimized with 10 lights (x50): 17–42ms (23–58 fps)
E. Optimized with 10 lights (x50): 16–37ms (27–60 fps)

I might be wrong, but I think taken together, these results mean two things:

  • This optimization has large effects for large numbers of dynamic lights
  • There seems to be no performance impact on smaller numbers of lights

I’d love to hear from the rest of you about what you think of these results. Further and/or more rigorous testing would be welcome from anyone.

Overall, given the potency and simplicity of this optimization, I think this warrants further discussion and consideration. I’d love to hear what core maintainers think of this: perhaps there are important aspects we’re overlooking.

PS. All these tests were on a 2021 Macbook Pro (M1 Max) running Safari 16.5.2 on MacOS 13.4.1. Canvas size 3174 * 2274 for all tests.