can't find docs about Panda's default lighting

I am trying to understand Panda’s default lighting.

If you don’t set explicit lights, some are created internally (otherwise your scene would be completely dark). What I am looking for is a detailed description of under what conditions these lights are created, their attributes, and how to turn them off. (And ideally a pointer to the code that does it.) This is not documented in the most relevant manual page:

panda3d.org/manual/index.php/Lighting

It does say “The default directional light is shining down the forward (+Y) axis”, but the context suggests it’s talking about the default attributes of a DirectionalLight you create, not about the lights that exist if you create nothing.

Experiments suggest that the nature of the default lights depends on how many other lights you create and/or their types. If I create no lights, cubes are lit on at least 5 faces, whereas if I create a very dim directional and ambient light, cubes are only lit on 3 faces (presumably by the remaining default light alone). Nothing I tried so far has completely turned off default lighting.

Besides the types and parameters of the default lights, it’s important to understand at what point and for what objects the decision is made to use them, e.g. per-node, per-DisplayArea, per-camera, etc.

(I am willing to document this in the manual once I find out definitive-enough info to document it correctly.)

If you don’t have lighting enabled on a node, everything will appear as if there was just an AmbientLight with colour (1, 1, 1, 1) applied.

As soon as you add any lights, this no longer applies, and the lights add up from black. This is the behaviour in many 3D applications and most 3D engines.

Or did you mean the default lighting you see when you press L in pview?

Thanks for the reply. (I did figure out since my post that render.setLightOff(), followed by adding a zero-intensity ambient light, would actually turn off all lighting in render (so all rendered geometry appears black).)

But unless I am mistaken, there is some other lighting going on in other cases, e.g. some default lights applied to render even when other lights are added. Just saying render.clearLight() followed by adding a red ambient light and a green directional light, I would expect to see purely blue objects appear black, but I don’t – they are just darker blue. I didn’t try the same code with render.setLightOff(), but if that makes it work, I think it means there was some sort of default lighting coming from above render in the scenegraph. (Or it could mean that render.clearLight() does nothing, but I copied that line from sample code distributed with Panda, so I doubt that.)

(If this result surprises you it may mean I’m doing something silly, like thinking my object is purely blue when it’s not, so in that case I’ll reduce it to a simple example and post it.)

(I don’t know what pview is, so I didn’t mean anything about that.)

What rdb said is accurate. More precisely, there are two modes: lighting off, and lighting on. When there are no lights at all applied, lighting is off–this is the default mode. In this mode, all objects are rendered in their direct colors, fully bright. This has (almost) the same appearance they would have with a (1, 1, 1, 1) ambient light. When there is any light at all, lighting is on; and in this case objects are passed through the lighting equation before being rendered.

Purely blue objects that are lit only by a green and red light should indeed appear black.

Note, for the record, that the total lighting equation is a little nonintuitive, and depends a bit on whether you have enabled the auto-shader or not. In the absence of the auto-shader, you have the standard OpenGL fixed-function lighting equation, which processes the lighting equation per vertex first, based on the vertex color of the model (and neglecting texture color). The result of this lighting equation produces a new color per vertex, which is then linearly blended between vertices to produce a smooth shaded model. Then the texture color is applied on top of the result.

So there are two different meanings to a “blue” object: you might mean that the object’s vertices are blue, or you might mean that its vertices are white but its texture is blue. There’s a difference in the overall result. Still, in either case, if it is illuminated by only a red and a green light, I agree it should appear black.

David

Well, sorry for a false alarm – I was all set to post this program that demonstrates the mysterious effect, when I noticed a tiny little bug in it which explains everything. For your amusement, here’s the program:

import direct.directbase.DirectStart
from direct.showbase.DirectObject import DirectObject
from panda3d.core import AmbientLight
from panda3d.core import DirectionalLight
from panda3d.core import Vec3
from panda3d.core import Vec4

red   = Vec4(1, 0, 0, 1)
green = Vec4(0, 1, 0, 1)
blue  = Vec4(0, 0, 1, 1)

class Game(DirectObject):
    
    def __init__(self):

        # lights
        
        alight = AmbientLight('ambientLight')
        alight.setColor(Vec4(0.2, 0.0, 0.0, 1)) # ambient light is dim red
        alightNP = render.attachNewNode(alight)

        dlight = DirectionalLight('directionalLight')
        dlight.setDirection(Vec3(1, 1, -1)) # (towards right-back-bottom; should only illuminate front/left/top )
        alight.setColor(Vec4(0.0, 0.2, 0.0, 1)) # directional light is dim green
        dlightNP = render.attachNewNode(dlight)

        render.setLightOff()
        render.setLight(alightNP)
        render.setLight(dlightNP)

        # ... so there should be no blue light in the scene,
        # and no green light except from the front/left/top.
        
        # camera

        base.cam.setPos(0, -20, 4)
        base.cam.lookAt(0, 0, 0)

        # action

        def makebox(where, color):
            visualNP = loader.loadModel("models/box.egg") # a wood-textured cube
            # skip ModelRoot, so the resulting node can be flattened with others of its kind
            assert visualNP.getNumChildren() == 1
            visualNP = visualNP.getChild(0) # e.g. box.egg/Box
            visualNP.setColor(color)
            visualNP.setPos(where)
            visualNP.reparentTo(render)
            return

        makebox((-2,0,0), red)
        makebox(( 0,0,0), green)
        makebox(( 2,0,0), blue)

    pass


game = Game()
run()

Until I noticed my bug, I was mystified by these results:

(notice that the right-hand cube is blue, not black, as confirmed by a pixel color analyzer)

And even stranger:

Notice that in the “dark faces”, which ought to be only lit by ambient light (dim red in the program), the left and right blocks are black, but the middle one is dim green, as if the ambient light was dim green.

Anyway, if I had run render.ls() and examined the output I would have noticed the bug in the program above. In case anyone likes puzzles like this, I won’t say yet what the bug is, but rest assured it is not in Panda – and after I fixed it (not shown above), everything rendered as expected. (But who knows how long it would have taken me to find it, if not for reexamining the program closely due to writing this post.)

And thanks, rdb and David, for your explanations of more details of normal lighting behavior. I still think the lighting manual page ought to say some of that; unless one of you wants to do it, I’ll add it soon.