Trouble with spotlight illuminating gltf model

Please help me figure out what configuration I missed. Hemisphere lights are illuminating my gltf mesh, but spotlights aren’t. I figure it’s something to do with the material’s texture. I started noticing this in lite, but then I recreated in regular Babylon.js, and it happens there too.

Regular Playground Link

Lite Playground Link

The issue is similar to this old question, but if I view vertex normals (e.g. see three.js screenshot below), they appear fine.

This is driving me insane because we did a game jam in the spring with these exact models, and it worked fine then (spoiler: game is not very fun). Anyway, that codebase is really large and convoluted, and I can’t figure out what’s different between that jam codebase and these playgrounds.

Thanks!

Your spotlight is working, but it is extremely weak for a PBR material at that distance. The glTF is loaded as a PBRMaterial, which uses physical inverse-square attenuation by default. The hemispheric light has no distance attenuation, and the ground’s StandardMaterial uses different lighting behavior, so comparing their responses is misleading.

With the spotlight roughly 7-10 scene units away and an intensity of 1, only around 1/50 to 1/100 of its intensity reaches the model before the remaining PBR lighting calculations.

Either move the spotlight closer or substantially increase its intensity:

spotlight.intensity = 100; // Adjust for the desired exposure

In the Babylon Lite example, the fourth argument is the intensity:

const spotlight = createSpotLight(
    [0, 10, 0],
    [0, -1, 0],
    Math.PI / 4,
    100,
);

If you intentionally want nonphysical/legacy attenuation instead:

spotlight.falloffType = BABYLON.Light.FALLOFF_STANDARD;
spotlight.range = 20;

An environment texture is recommended for PBR fill lighting, but it is not required for the spotlight itself to work.

I also checked the old game’s shipped code. Its spotlight has an intensity of 3, but more importantly, it is parented to the drone and positioned only about one unit above it. In the Playgrounds, the spotlight is around ten units away, which explains the apparent behavioral difference.

There is also an unrelated loader warning because the Firebase URL has no .glb suffix. The regular Playground can make the format explicit:

await BABYLON.AppendSceneAsync(model, scene, {
    pluginExtension: ".glb",
});

Thank you so much! :folded_hands: Your explanation clarified so much for me about lighting, and it also helped me find this snippet hidden in a corner of my code. I apparently wrote it over 3 years ago, probably while sleep deprived during a game jam. :sweat_smile:

if (!enablePhysicalLighting) {
  for (const m of scene.materials) {
    if (m instanceof PBRMaterial) {
      m.usePhysicalLightFalloff = false;
    }
  }
}

Past me can be a real pain sometimes.