Why can't I make a narrow beam with a SpotLight?

I’m having a hard time getting the SpotLight beam to look even a little like a flashlight beam. I’ve tried many different settings of angle, penumbra, focus, and intensity and nothing results in a narrow beam. If try an angle value less than 1 radian I get no light at all. But all values above that give me a beam that much too wide for my purposes, and the penumbra effect is too strong. Instead of gently “eating away the edges” of the beam and leaving a high intensity inner cone, it weakens the whole beam markedly. The focus parameter doesn’t seem to do anything at all. I am using ThreeJS r127.

What really puzzles me is why the beam completely disappears when the light gets close to a wall, but not what I would think is too close. 20 world units for example and the light is gone

It’s almost as if the Spotlight has its own frustum and the near value is set to high. But the Spotlight object has no frustum property. It’s shadow.camera property does, but I’m not using shadows. I wouldn’t expect the beam to disappear when still around 25 world units from a wall.

Note, the slider in my screenshot for angle is a percentage between 0 and 100 of the maximum allowed angle, which is Pi / 2 radians. So 0.7 would be:

((pi radians) / 2) * 0.7 =1.09955743 rad

Here is a screenshot with the angle set at 73 percent (above 1 rad): The black sphere is the location of the animated light and is pointed to the wall (about 30 world units from the wall).

Here is a screenshot with the angle set at about 69 percent (below 1 rad)

Does anybody know how t make a tight beam with the SpotLight object. It’s the only object I found in the docs that seems to be at least close to what I want. Would projecting the light through a texture that is basically a circle cutout of a dark pattern work?

If there is a better tool or technique to do this please let me know, and link me to the code or docs that shows me how.

Most likely there is some misconfigured parameter. Spot light can have very narrow angles. Here is an example with angles varying from 0.005 to 0.595 radians, maximal prenumbra, Three.js r127:

https://codepen.io/boytchev/full/ZEMJEeR

image

2 Likes

This is something a bit weirder I think and truly maddening. Look at the following screenshots. If I position the black sphere which has the SpotLight attached to its front and move it close to the wall, then if the SpotLight angle property it is below the “magic angle”, I don’t see any light on the wall.

If I move the sphere/light behind the green reference sphere, but only by a narrow distance, I don’t see any light on the wall or on the green reference sphere either:

However, if I back the sphere/light up just a bit, then I do see the light but only on the green reference sphere, not on the wall. You can plainly see that in this screenshot. Note, I did try lots of different combinations of the light parameters using the mini-menu. The light never reaches the wall. Also, I did make the green reference sphere invisible in case it was blocking the light but that did not help. Also, if that was the problem the light should have shown on the wall in the first screenshot when the light/sphere was in front of the green reference sphere.

And if I raise the light angle up a bit past the “magic angle”, it goes from no light on the wall, to flooding the wall with light:

One more for the oddities collection. Look at this screenshot. The wall the light/sphere is pointed directly at is completely dark. The green sphere, and the walls above and below the light are lit up.

It’s like watching a light that is being eclipsed but what can a light be eclipsed by that causes the light beam to just stop after a certain dsitance?

@Mugen87 @prisoner849 Sorry to ping the two of you but any thoughts? I’m getting desperate now. I’ve lost a lot of time on this and I’m hoping you have some kind of tip you can give me. This has got to be something more than a silly error at this point? I’m using r12y… Is there something about the MeshLambertMaterial I’m using to make the walls that could cause it to have a weird “threshold” behavior whereby if the light is not above a certain intensity/power it dosn’t reflect at all?

What material are you using for the dog picture?

Use a spotlight helper to help make sure its casting where you think it is.

const helper = new THREE.SpotLightHelper( spotLight );
scene.add(helper);

Here is another example of using a spotlight shadow, Spot Light Shadow - Three.js Tutorials

1 Like

The images clearly show there is some problem.

Any chance to share a CodePen, so that it is possible to see the code and make experiments with it? It is not needed to post the whole project, you can just make a small model – a room with walls, green ball and a spot light.

Also, have you tried using a more recent Three.js release?

Hi. It’s a MeshLambertMaterial with reflectivity set to 1. I have tried the SpotLight helper and it is definitely pointing at the wall. I can turn it on and off with a keystroke. (see screenshot). Is it possible it is something with the renderer’s gammaFactor or outputEncoding properties? I’m not passing those in to the renderer construction, just this:

new THREE.WebGLRenderer( { antialias: true }

But I figured I’d ask.

This screenshot shows the SpotLight helper:

Your helper shows your near is beyond the picture.

See my example. The near is the orange square starting from the red lines.
image

Also check you don’t have a high intensity ambient light cancelling your shadows?

1 Like

Making a CodePen that would recreate the conditions is actually quite hard and I’m pretty sure that the CodePen would work fine. I’ve seen several of them and none of them have any indication of the problem I’m having.

Regarding using a new release, my code uses BoxGeometry a lot and I’m trying to make a deadline. Trying to do an upgrade now would mean I’d have two problems instead of just this one. After the deadline I can try that.

For what it’s worth, here the code for constructing the light. Nothing special I think?

// Create a mini-menu for this type of light.
retLightObj = new THREE.SpotLight(color, intensity, distance, angle, penumbra, decay);

I think it’s pretty safe to say this is due to really strange interacton between various parts of my code. I’m hoping someone has some kind of a hunch that would lead me to a solution. If not, I will to disable some really cool featured I wanted to show before the deadline and they are features I really wanted to demonstrate.

Interesting. I double-checked and the light itself doesn’t have near and far properties, only the light’s shadow property does and I am not using shadows. How could I change the light’s near and far properties?

Regarding ambient light. Here is the code I am using to set up the singular ambient light for the scene. Do you see anything potentially problematic?


    const light = new THREE.AmbientLight(0xffffff, 0.7);
    light.position.set(100, 250, 100);
    g_ThreeJsScene.add(light);

One thing that confuses me about the near issue. How is it the green sphere is receiving light? I’m sure you are right about the near plane, I can see that from the wireframe hints, but why is the green sphere receiving at least some light but not the wall?

NOTE: I did try creating a shadow map anyways as shown below, so I could adjust the near plane`, but that did not help:

            retLightObj = new THREE.SpotLight(color, intensity, distance, angle, penumbra, decay);
            
            // Disable shadows but add a shadow map so we can adjust the
            //  SpotLight's near and far plane.
            retLightObj.castShadow = false; // disable shadows
            retLightObj.shadow.map = new THREE.WebGLRenderTarget(1024, 1024);
            // retLightObj.shadow.mapSize.width = 1024;
            // retLightObj.shadow.mapSize.height = 1024;
            retLightObj.shadow.camera.near = 1; // set near plane
            retLightObj.shadow.camera.far = 1000;   

How can I change the SpotLight’s near value? I looked at the docs and only the SpotLIght’s shadow property has near and far properties, not the SpotLight itself, and I am not using shadows at the moment.

Just a blind guess – try MeshPhongMaterial instead of MeshLambertMaterial.

Is there any difference?

I was using MeshPhongMaterial before MeshLambertMaterial and had the problem back then too.

Sorry, you are correct. There is no near property on spotlight itself.

Here is another minimal example that shows you can get a narrow beam using just the spotlight
image

Check you don’t also have a high intensity ambient light in your scene.

I have noticed something really strange. When I change the angle of my SpotLight the angle of the SpotLightHelper does not change. When I look at the SpotLight example in ThreeJs, the projection lines of the SpotLightHelper do narrow and widen as the SpotLight angle changes. Can you think of a reason why this might happen? I’m wondering if this is related to the problem that is the root cause of my issue, the fact that the frustum of the SpotLight is too large.

UPDATE: For some weird reason, the update() method of my SpotLightHelper is not being called. The constructor is, but not the update(), despite my adding the SpotLightHelper to the scene.

Call it manually after changing the spot light. See the CodePen from my first reply.

this seems like the only way to allow users to help with your issue, although the screenshots are insightful there’s most likely something in your code setup causing this issue, it’s difficult to blindly try and evaluate what might be happening in your code…

1 Like