flicker when setting material in script

When I use an .egg file without the material (rook.egg) and set the material in the code then the color flickers when I rotate the view (hold middle mouse and drag). The .egg file that has the material set in the .egg file (rook_white.egg) there is no flickering when I rotate the camera by dragging middle mouse button. Any ideas on why? I’m trying to avoid explicitly defining the material in the .egg model file.

In both cases the material gets set but I guess whatever is in the .egg file trumpts that. Anyway any thoughts on the cause of the flickering?

from direct.showbase.ShowBase import ShowBase
from panda3d.core import AmbientLight, DirectionalLight, LightAttrib
from panda3d.core import Vec4
from panda3d.core import Vec3
from panda3d.core import ShadeModelAttrib
from panda3d.core import Material

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

        #listModels = ["bishop_white.egg", "king_white.egg", "queen_white.egg", "knight_white.egg", "pawn_white.egg", "rook.egg", "rook_white.egg"]
        listModels = ["rook.egg", "rook_white.egg"]
        offsetX = -15.0
        matRed = Material()
        matRed.setDiffuse((1.0, 0.0, 0.0, 1.0))
        for modname in listModels:
            self.loadPiece(modname, Vec3(offsetX, 0, 0), matRed)
            offsetX = offsetX + 20.0
        
        # Directional light 01
        self.directionalLight = DirectionalLight('directionalLight')
        self.directionalLight.setColor(Vec4(1, 1, 1, 1))
        self.directionalLightNP = render.attachNewNode(self.directionalLight)
        # This light is facing backwards, towards the camera.
        self.directionalLightNP.setHpr(180, -20, 0)
        render.setLight(self.directionalLightNP)
        self.cam.setPos(0, -200, 0)
        self.cam.lookAt(0.0, 20.0, 0.0)
        
    def loadPiece(self, modelname, position, mat):
        print 'load', modelname
        self.modelpiece = loader.loadModel(modelname)
        self.modelpiece.setMaterial(mat)
        self.modelpiece.reparentTo(render)
        self.modelpiece.setScale(1.0)
        self.modelpiece.setPos(position)

app = MyApp()
app.run()

Both .egg files are attached. You should be able run by doing…

ppython cviewer.py

in the CLI

rook_white.egg (1.05 MB)rook.egg (1.01 MB)

When a model is loaded from an .egg file, you actually end up with a hierarchy of PandaNodes instead of just the GeomNode containing the model geometry. If you call self.modelpiece.ls(), you will see the following output in the console for rook_white.egg:

ModelRoot rook_white.egg
  GeomNode polyline32215 (1 geoms: S:(MaterialAttrib)) T:m(hpr 0 90 0)

Panda creates a ModelRoot node to which the model GeomNode gets parented, so it is this ModelRoot that you end up assigning the material to, but it gets overridden by the material that is set lower in the hierarchy: not even on the GeomNode, but directly on the Geom contained within the GeomNode. If you need to get rid of that material in order to see the one you apply manually, you can do this:

self.modelpiece.getChild(0).node().setGeomState(0, RenderState.makeEmpty())

There does seem to be something strange going on here. Although I don’t see any flickering, I get different results each time I run the code sample; sometimes the material shows up correctly on the model, while at other times the model simply remains white. Could it be that the flickering you observe is the model switching between the red material and its white color? Then it’s likely the same issue, but manifesting itself in a different way, perhaps because of different graphics hardware/drivers or Panda version.
(Myself I’m using Panda3D-SDK-1.10.0pre-82b7728-x64.exe on Windows 8.1)

Anyway, it also happens with procedurally created geometry, so it’s probably not related to specific .egg files.
But it does seem to be related to the fixed-function pipeline, as enabling the shader generator makes the material show up every time:

        render.setShaderInput("light", self.directionalLightNP)
        render.setShaderAuto()

EDIT:
Using an older Panda3D 1.9.0 version, I do see the flickering now; each time the view changes, the manually applied material seems to appear or disappear from the model.

EDIT 2:

Further testing has revealed that the problem is caused by not specifying an ambient color for the material.
Also, the material doesn’t disappear from the model as I previously thought, but the diffuse color just turns white, depending on the view.

Checking the render state on the loaded model, it turns out that the diffuse color gets copied to the ambient color if the latter is not specified in the .egg file, which explains why a material set in the .egg file looks correct.

Thank you very much for all the information! Sorry for my late response. Got the materials settings to work. :slight_smile:

For anyone else who comes along, to sum up, most relevant part, where modelpiece node is a loaded .egg model…

        self.pieceMaterials = {}
        self.pieceMaterials["redmat"] = Material()
        self.pieceMaterials["redmat"].setDiffuse((1.0, 0.0, 0.0, 1.0))
        self.pieceMaterials["redmat"].setAmbient((1.0, 1.0, 1.0, 1.0))
        self.pieceMaterials["redmat"].setSpecular((0.5, 0.5, 0.5, 1.0))
        self.pieceMaterials["redmat"].setShininess(70.0)
        modelpiece.getChild(0).node().setGeomState(0, RenderState.makeEmpty())
        modelpiece.setMaterial(self.pieceMaterials["redmat"])

Edit, what the red material looks like…