Problems in spotlight

There are always problems in spotlight. I have set various configurations of spotlight, but still can’t form a spot! Why is that? This is my code, and renderings. In addition, there are model files.

import direct.directbase.DirectStart  
from panda3d.core import *
from direct.task import Task
try:
    window = WindowProperties()
    window.setTitle('House')
    window.setSize(1200, 800)
    base.win.requestProperties(window)
    base.setBackgroundColor(0.4, 0.6, 0.7, 0.5)
    envir = loader.loadModel('house')
    envir.reparentTo(render)
    base.cam.setPos(0, -29000, 7500)
    base.cam.setHpr(0, -15, 0)   
    sun = loader.loadModel('sphere')
    sun.setColor((0.7, 0.6, 0.4, 1))
    sun.setScale(300)
    sun.setPos(-6510, -6000, 0)
    sunLight = sun.attachNewNode(DirectionalLight("SUN"))
    sunLight.setH(-60)
    sunLight.node().setColor((1, 1, 1, 1))
    sunLight.node().setShadowCaster(True)
    sunLight.node().show_frustum()
    sunLight.node().setScene(render)
    sunLight.node().getLens().setFilmSize(60, 80)
    sunLight.node().getLens().setNearFar(10, 30)
    render.setShaderAuto(True)
    sunLightHelper = render.attachNewNode('change')
    sunLightHelper.setPos(0, 0, 0)
    sun.reparentTo(sunLightHelper)
    sunLightHelper.hprInterval(20, (0, 0, 360)).loop()
    #envir.setLight(sunLight)
    lamp = loader.loadModel('lamp')
    lamp.reparentTo(render)
    lamp.getChild(0).setHpr(90, 90, 0)
    lamp.setPos(-1000, -800, 0)
    lamp.setScale(350)
    lampLight = envir.attachNewNode(PointLight("lamp"))
    lampLight.node().setColor((1,1,1,1))
    lampLight.node().setAttenuation((0,0,0.0000004))
    lampLight.setPos(-1000, -800, 1800)
    envir.setLight(lampLight)
    state = {"ON": False}
    def Change_state(direction, sated):
        state[direction] = sated
        if state["ON"]:
            envir.setLight(lampLight)
        else:
            envir.setLightOff(lampLight)
    base.accept('q', Change_state, ['ON', True])
    base.accept('w', Change_state, ['ON', False])
    base.accept('FW', Change_state, ['ON', True])
    base.accept('KW', Change_state, ['ON', False])
    def autoLight(task):
        if not(sunLightHelper.getR() > 20 and sunLightHelper.getR() < 160):
            messenger.send('FW')
        else:
            messenger.send('KW')
        return task.cont
    taskMgr.add(autoLight, 'auto')
    spota = loader.loadModel('spot')
    spota.reparentTo(render)
    spota.setScale(10)
    spota.setPos(0,4000,10)
    spotLight = spota.attachNewNode(Spotlight("spot"))
    spotLight.node().setColor((0.8, 0.4, 0.7, 1))
    #spotLight.node().setAttenuation((0, 0.0003, 0))
    lens = PerspectiveLens()
    lens.setFov(2)
    spotLight.node().setLens(lens)
    spotLight.node().showFrustum()
    spotLight.setPos(0, -500, 1000)
    spotLight.setHpr(0,-90,0)
    spotLight.node().getLens().setNearFar(200, 350)
    spotLight.node().getLens().setFilmSize(10)
    spotLight.node().setScene(render)
    spotLight.node().setExponent(20)
    #spotLight.hprInterval(10, (-180, 0, 0), (-60, 0, 0)).loop()
    envir.setLight(spotLight)
    base.run() 
except Exception as e:
    print(e)
    base.destroy()


lamp.egg (22.1 KB)
sphere.egg.pz (48.5 KB)

One thing that I notice is that you place your spotlight at a z-position of 1000, but give its lens a far-distance of only 350. It may simply be that the spotlight is too far from the environment for the light to be visible.

A quick way to test this might be to lower your spotlight to about 100 (relative to the environment), and see whether the light becomes visible.

I do also note that you have a scale applied to the parent-node of the spotlight. I honestly don’t know what effect that might have; it might be worth testing whether removing that scaling-factor changes anything.

Finally, I don’t know the size of your environment; are you sure that having the spotlight’s parent-node be placed at a y-coordinate of 4000 and the spotlight itself be placed at a y-coordinate of -500 relative to that parent-node results in the the spotlight being located within the environment?

It seems that the key to the problem is to find out the scaling problem at the parent node. What’s more, I found that the spotlight only follows the scaling of the parent node, and what I reset later doesn’t work. In this case, how can I use the setting method to modify the scaling of spotlight?
This is the effect of this situation

    spotLight.node().getLens().setFilmSize(0.6,0.8)


This is the effect of another situation

    spotLight.node().getLens().setFilmSize(30,40)

It should, I think, be possible to set a counter-scale on the spotlight that negates the scaling of its parent-node. Note that because scales (like positions and rotations) are compounded through parent-child relationships, you can’t just set the final scale that you want the spotlight to have; you have to set a scale that also takes into account the scaling of the parent-node (and any nodes above it that might also be scaled).

So, for example, if you want the spotlight to have an effective scale of 1 (i.e. no scale), and the parent has a scale of 5, you would have to set the spotlight’s scale to 0.2 (i.e. 1/5).

That said, I think that the easier solution might be to just have the spotlight no longer be a child of a scaled node.

Now, I imagine that you want the spotlight to move with the lamp-model held in the parent-node. Thus I see two potential solutions, offhand:

First: You could give the lamp-model and the spotlight a common parent NodePath, and use that common parent to place them. Thus the lamp-model would no longer be the parent of the spotlight, and therefore it’s scaling would not affect the light.

Second: When you load a model, the model itself is usually not held in the NodePath that is returned from “loadModel”, but instead in one or more child-NodePaths. Thus, you could potentially set your scale on those child-NodePaths, rather than the NodePath returned by “loadModel”, allowing you to keep your current parentage without having a scaling factor apply to the spotlight.

Well, I see, thank you very much!

1 Like