Many lights, nearly everything static: Shadows?

Hi there,

I’m working on a pinball simulator in JavaScript, and I’d like to get a few opinions about how I should go about lighting in my three.js scene. It’s my first three.js project, so be gentle :slight_smile:

Pinball tables are a bit special because they have many lights but very few moving objects (usually only the ball). And a big factor of a pinball sim is how well the lighting is handled.

So I’ve created a test table and set all materials and lights to receive and cast shadows, and I got this:

Which is great, but there are only four lights and I’m already getting below 60fps with a rather powerful GPU. A modern pinball game has 30+ lights. So my question is the following:

Is there a way to bake a shadow map for the static meshes but still get dynamic shadows for the ball? I imagine projecting one object only would be a lot less computing-intensive than if all objects were casting shadows?

I’ve also read about forward deferred rendering, but it seems like three’s deferred renderer was abandoned.

Lastly, usually even the camera is static, but I’m not sure which kind of advantages in terms of lighting and performance that can bring me.

Looking forward to your comments! Cheers,

-freezy.

2 Likes

It is definitely possible. However I think the biggest problem would still be the 30+ lights casting shadows. The scene needs to be rendered from the light’s point of view in order to produce the shadow maps.
Things get extremely awful especially with point lights, as those need SIX cameras in order to cast shadows in all directions, so you get 6 renders per each point light. With this path, things quickly escalate to unplayable.

My humble recommendation would be to simply bake all static lighting, and use some sort of a cheat for the ball shadow, for example a “shadow plane” underneath it. It won’t be as dynamic as you might want, but it’s pretty simple and the higher quality of baked soft shadows might look great as well :slightly_smiling_face:

I’m curious to know what others have to say about it, as I’ve ran into a similar problem before (please correct me if I wrote something incorrect).

Btw it looks pretty awesome already :star_struck:
May I ask what physics engine you’re using?

1 Like

Thanks! This gets my hope a little up :slight_smile: In one sentence, how would you go about mixing dynamic and static shadowing? Somehow you would need to blend both into one map, right?

I was wondering how the point lights work. Six cameras, oh boy. Maybe there is a way to cheat? Given there’s only one moving object, maybe the other angles could be skipped, since it’s pretty easy to know on which side the ball currently is?

I’ve ported Visual Pinball’s physics engine to JavaScript. The goal here is to be able to load all the awesome pinball recreations from the Visual Pinball community into the browser, so the physics must be the same. And they are really good.

Baked shadows will definitely give you the best performance. However I’ve had good results setting WebGLRenderer.shadowMap.autoUpdate = false and then needsUpdate = true once at the start to render the static shadow map.

1 Like

Well using baked shadowing only would be a pity for the ball movement, and maybe even weird if static objects cast shadows but not the ball?

I’ve read about WebGLRenderer.shadowMap.autoUpdate = false, but that would apply to the entire scene, right? So for any kind of ball movement (which is basically all the time), I’d need to set needsUpdate to true.

I suggest using 1-2 shadow casting light sources at most. You can have many lights in general - but you would need to go for deferred rendering pipeline. Baked shadows look great, if you tone them down a bit - the fact that the ball doesn’t have the same quality of shadows doesn’t stand out as much. Humans track motion, so when the ball is moving - it will not look “weird” in general.

Most of the games out there are smoke and mirrors, it’s not about “how long your light is - it’s how you use it”. When it comes to lights - they are generally expensive, with deferred lighting they become relatively cheap, but shadows still remain expensive. You only really get cheap shadows on ray-tracing API, but we don’t have that in WebGL yet.

Good luck :mermaid:

2 Likes

You can use a small transparent png for the ball’s shadow, and possibly for other moving parts like the levers.The car’s shadow in this example demonstrates that technique.

Exactly. You have to figure out what kind of tricks will work for your situation, and I think a mainly static model like a ping pong table is perfect for testing various methods out.

There’s some discussion around redesigning the shadow API to make it more flexible on Github at the moment

Thanks @looeee, I’ve read through the issues and it’s good to know that shadows seem to have more than a purely academical purpose. :wink:

I think shadowing on the lower playfield only would be fine. That would make four light sources. I just saw that #11035 got closed so I would be able to have many more non-shadow casting lights.