Lighting fails when using render.setShaderAuto() but good when shader generator is off

I’ve got a scene like below.

from direct.showbase.ShowBase import ShowBase
from panda3d.core import PointLight


class ProblemScene(ShowBase):
    def __init__(self):
        super().__init__()

        self.floor = self.loader.load_model("assets/models/WoodFloor.glb")
        self.floor.reparentTo(self.render)

        plight = PointLight('plight')
        plight.setColor((1, 1, 1, 1))
        plnp = self.render.attachNewNode(plight)
        plnp.setPos(0, 0, 4)
        plnp.lookAt(self.floor)
        self.render.setLight(plnp)
        # self.render.setShaderAuto()


scene = ProblemScene()
scene.run()

When I run this, the result looks good.

However, when I add a render.setShaderAuto() (i.e., uncomment the last line in the scene), everything becomes black and no light is showing.

Ambient light works though.

from direct.showbase.ShowBase import ShowBase
from panda3d.core import AmbientLight


class ProblemScene(ShowBase):
    def __init__(self):
        super().__init__()

        self.floor = self.loader.load_model("assets/models/WoodFloor.glb")
        self.floor.reparentTo(self.render)

        alight = AmbientLight('alight')
        alight.setColor((0.2, 0.2, 0.2, 1))
        alnp = self.render.attachNewNode(alight)
        self.render.setLight(alnp)
        self.render.setShaderAuto()


scene = ProblemScene()
scene.run()

I’m guessing it’s because there’s missing normal data somewhere in the shader. The problem is, why did per-vertex lighting work? How should I know what data is missing?

The model was in glb (glTf binary) format, made in Blender with an image texture.

Thanks in advance.

Oh. It just occurred to me that, do I need something like a per-pixel normal map for shader generator to work?

That didn’t work.

In fact, there is a difference in the vector storage format for tangent and binormals. .gltf assumes a four-component tangent vector, on the basis of which the binormal will be calculated.

That’s the problem to use.gltf you need panda3d-simplepbr, because the standard shader generator expects a three-component vector and the presence of a binormal column

To fix this, you can disable the normal map stage, but this will only lead to the render of a diffuse map, which is not in your interests.

Could you share the model file and the necessary textures so we can take a look?

@rdb Hi. I’m a new user so I can’t upload attachments. Could you try if this link works?

https://drive.google.com/drive/folders/1dmeWfAb4cDJ7uTqX9xQG4D-O065nVMor

In there, there should be three files. “WoodFloor.glb” was the model. The others are diffuse and normal maps. The diffuse map was added this way in Blender.

The normal map was not used when exporting this model.

@serega-kkz I’ve heard there is a difference with glTf format. Is there a way I can verify the difference in vector format myself, for example, by exporting the model to .gltf and looking at its text content?

Oh, just checking - do you have panda3d-gltf installed? If not, then the file will be loaded with the Assimp loader, which is a lower-quality loader.

When you have installed panda3d-gltf, you will need to make a modification to the model or clear your model-cache to ensure that it isn’t still loading a cached version of the model.

This way you can print the data about the vertices and the format.

from direct.showbase.ShowBase import ShowBase

class Parse(ShowBase):
    def __init__(self):
        ShowBase.__init__(self)

        model = loader.load_model("box")
        model.reparent_to(render)

        for node_path in model.find_all_matches('**/+GeomNode'):
            geom_node = node_path.node()
            for i in range(geom_node.get_num_geoms()):
                geom = geom_node.get_geom(i)
                format_vd = geom.get_vertex_data()
                #print(format_vd)
                print(format_vd.get_format())

app = Parse()
app.run()

It looks like there is no tangent column in your model. I was use assimp loader, maybe there is a problem with that, but I’m not sure.

Array 0:
  Array format (stride = 32):
    vertex(3f) float32 point start at 0
    normal(3f) float32 normal start at 12
    texcoord(2f) float32 texcoord start at 24
Array 1:
  Array format (stride = 24):
    tangent(3f) float32 vector start at 0
    binormal(3f) float32 vector start at 12

Array 0:
  Array format (stride = 32):
    vertex(3f) float32 point start at 0
    normal(3f) float32 normal start at 12
    texcoord(2f) float32 texcoord start at 24
Array 1:
  Array format (stride = 24):
    tangent(3f) float32 vector start at 0
    binormal(3f) float32 vector start at 12

Array 0:
  Array format (stride = 32):
    vertex(3f) float32 point start at 0
    normal(3f) float32 normal start at 12
    texcoord(2f) float32 texcoord start at 24
Array 1:
  Array format (stride = 24):
    tangent(3f) float32 vector start at 0
    binormal(3f) float32 vector start at 12

For the test, I used the abstractroom.egg model from the bump-mapping example.

Before you look into that, I’d check that the problem is the normal mapping at all by disabling normal mapping and seeing if the problem still occurs.

That said, I’d check panda3d-simplepbr, which is optimized for use with panda3d-gltf, which may work better than the shader generator.

I can already conclude, yes, this will solve the problem. This situation has already been the subject of proceedings in this forum.

@serega-kkz My model does have a tangent column. However, it is of type vector 4f, rather than a vector 3f plus a binomial of type vector 3f.

Array 0:
  Array format (stride = 32):
    vertex(3f) float32 point start at 0
    normal(3f) float32 normal start at 12
    texcoord.0(2f) float32 texcoord start at 24
Array 1:
  Array format (stride = 16):
    tangent(4f) float32 other start at 0

I guess this is the difference you mentioned in your first reply.

I tried simplepbr and now the scene looks correct.

Thanks everyone.