There have been a lot of posts about the
maxSimultaneousLights on a material, and setting
light.includedOnlyMeshes helps get around most of the issues with this.
However the problem I’m running into is when I have meshes that need to move across more than
maxSimultaneousLights in a scene.
So far the way I’ve tried to workaround it is to add and remove meshes from the
includedOnlyMeshes list of the lights that they come into the influence of. This works, however there is a stutter when changing
includedOnlyMeshes on lights. My guess is that it’s shader recompilation?
Is there any way around that, or is there a better way to handle this type of scenario?
Things I haven’t tried yet, but may work:
- Assign 4 lights to the moving meshes, and update the lights position / color / intensity to match the world lights they come into influence of (I assume this will also create a shader recompilation though?).
- Somehow read the light level of the texture beneath the mesh and update the mesh to match (ala old 2.5d engines).
Any other ideas?
You can precompile the shaders. Say you know that your mesh will have up to 8 lights, you can precompile the shader for 1 to 8 lights with How Babylon.js Materials Work | Babylon.js Documentation
So basically setting the
maxSimultaneousLights to the number of lights in the entire scene, regardless of whether the mesh will ever come in contact with it?
You have to wire the lights in before calling the forceCompilation
Sorry, I don’t follow what you mean by “wire the lights”?
like making sure the lights are fully defined with the mesh in their includedOnlyMeshes list
Right, so then I’d be limited to the max size of the shader for number lights in a scene if I didn’t want to cause a hitch for recompilation while the scene is running?
This playground (https://www.babylonjs-playground.com/#IRVAX#3), starts throwing errors in my chrome after only 11 lights.
Error: VERTEX shader uniform block count exceeds GL_MAX_VERTEX_UNIFORM_BUFFERS (14)
The problem is that you have a limited number of uniform buffers that can be used in a shader.
Your GPU only supports 14. Each light take one buffer. You also have one for: scene, material, mesh. So, you should be able to use 11 lights and crash at 12.
One way to overcome the limitation is to switch to WebGL1 because it does not support uniform buffers: all data are passed as uniform variables. As the limit of uniforms that can be used in a shader is quite high, you can use more lights this way (but it’s slower on GPU side because all uniforms must be rebound each time, whereas we only bind the buffers when using uniform buffers).
Yeah, I get that there are GPU limits if you want to put that many lights on one material, which is why I’m trying to work around that by dynamically setting the number of lights per material, but it sounds like there’s no way to do that without the hitching related to shader compilation.
Which gets me back to my original question. How does anyone handle this scenario in babylon? How do you handle a mesh that needs to move across more than 11 lights?
Or is Babylon just not necessarily for that use case?
You generally avoid having so many dynamic lights affecting your meshes in the context of the web as each light add a performance penalty.
There are technics to work with many lights but they are not currently implemented by Babylon, like using a deferred renderer and ligth volumes. See “A large number of lights” in LearnOpenGL - Deferred Shading.
Note that with the new pre-pass renderer, something like that would be possible but you would need to write some custom shader code to generate the final color from the GBuffer data.
Completely agree, but I’m not really looking to have more than 11 dynamic lights affecting a mesh. 4 lights per mesh is plenty, but apparently that mesh can’t move anywhere otherwise there’s a runtime cost.
Having a mesh move farther than 11 lights worth of illumination seems like a fairy common scenario for games. Any player model or enemy model or physics model would seemingly fall under this scenario, so I assumed someone else would’ve had some ideas. But once again, maybe I’m misunderstanding Babylon’s use case, and it’s not really intended for this?
So I’ve tried having a single light move with a “dynamic” mesh that updates to the same intensity and color values of lights near the moving mesh, but that seems to be more expensive than adding and removing meshes from the
If I baked the lightmaps I’d still need some way to apply those lightmaps or at least a general light level from the lightmaps to the dynamic meshes. Having a runtime lightmapper might be a nice addition, it would at least save on download sizes.