Frequently Asked Questions

Table of Contents

What are the .pz files I am seeing in the samples?

Those are files that are zipped with pzip. Along with punzip, these command-line tools handle compression of files in a format that Panda3D can read; pzip for compressing and punzip for decompressing. Usage:

pzip file [file2 file3 ...]
pzip -o dest_file file

Usage:

punzip file.pz [file2.pz file3.pz ...]
punzip -o dest_file file.pz

What are the .pyc files that are created after I run the Python interpreter?

.pyc files are compiled versions of Python sources. Similarly, .pyo files are both compiled and “optimized”. As an important speed-up of the start-up time for short programs that use a lot of standard modules, if a file called “spam.pyc” exists in the directory where “spam.py” is found, this is assumed to contain an already-“byte-compiled” version of the module spam. The modification time of the version of “spam.py” used to create “spam.pyc” is recorded in “spam.pyc”, and the file is ignored if these don’t match.

Optimized bytecode (.pyo) is not generated by default, but you may tell the interpreter to generate them instead of the regular .pyc. When ‘-O’ is added to the command, all assert statements are removed before compiling. When ‘-OO’ is added instead of ‘-O’, all __doc__ strings are removed as well before compiling. Note that these optimizations currently do not significantly improve performance. The following illustrates how to do this (replace python with ppython on Windows):

python -O file.py
python -OO file.py

Note: if you wish to run the Python interpreter without generating compiled bytecode files at all, then add ‘-B’ to the command. The following illustrates how to do this (replace python with ppython on Windows):

python -B file.py

Why are my animations/intervals sometimes skipped when I run something heavy on the CPU before playing them?

If you’ll run this example code you might not see the position interval.

from panda3d.core import *
import direct.directbase.DirectStart
from direct.interval.IntervalGlobal import *

env = loader.loadModel('environment')
env.reparentTo(render)
env.setZ(-4)

def func():
    # something heavy on the CPU
    for i in range(9999999):
        pass
    # run the interval after
    posival.start()

posival = LerpPosInterval(base.cam, 0.4, (0,base.cam.getY()-12,0), base.cam.getPos())

func()

base.run()

But you will see the interval being played if you comment out the for-loop. What is going on? It looks like Panda3D had skipped the interval, even though it was after the loop, as if Panda3D had “lost focus” when running the loop and even after it had finished it needed some time to start running normally again.

The problem is that everything that happens within one frame is deemed to happen at the same time. This is the “frame time” of the clock object–it is the time as of the start of the frame, and everything you do within that frame is deemed to have happened at the “frame time”.

This is usually a good thing, because it makes the simulation internally consistent. Frames are atomic. If you start five animations in a row with five different calls to actor.start(), you want them all to have “started” at the exact same time, not within a few milliseconds of each other. If you start an interval, you also want it to have started at the same time as every other atomic operation in that frame.

The problem is when you have a single really long frame. In this case, anything you do at the end of this long frame is considered to have actually happened at the beginning of the frame, and when the next frame rolls around (after some considerable time has elapsed from the previous frame), Panda has to skip over all of the intervening time to catch up, and you miss seeing some part or all of your interval or animation.

There are several easy solutions. One is to munge the clock while you’re computing your slow frame so that it doesn’t actually allow time to advance during this period, by putting this line after your loop, etc.

globalClock.setFrameTime(globalClock.getRealTime())

This simply resets the “frame time” to whatever the current real time is towards the end of your long frame. This will break the atomic-frame rule for (only) that one frame, but in this case that’s what you want to happen.

Another approach, that doesn’t involve explicitly munging the clock, would be simply to wait to start the interval until the next frame, for instance with a doMethodLater().

taskMgr.doMethodLater(0, lambda task, posival=posival: posival.start(),
                      'startInterval')

I have a bunch of Maya Animations of one model in different mb files. I used maya2egg to port them into panda, but only one of the animations work.

The key is to use the -cn <character’s name> flag in maya2egg for every file. This ensures that the files work together. Let’s say you are making an animated dog. You have the following animations:

dog-walk.mb
dog-sit.mb
dog-run.mb

To convert these into panda, you would call

maya2egg6 dog-walk.mb -a model -cn dog -o dog-model.egg

Note, we can grab the model from any of the animations, as long as they are all using the exact same rig:

maya2egg6 dog-walk.mb -a chan -cn dog -o dog-walk.egg
maya2egg6 dog-sit.mb -a chan -cn dog -o dog-sit.egg
maya2egg6 dog-run.mb -a chan -cn dog -o dog-run.egg

I’m using the lookAt() method on a NodePath to point it at another object. It works fine until I point upwards, and then it starts to spin my object around randomly

lookAt() works as long as you aren’t telling it to look in the direction of its up vector. The up vector can be specified as the second argument of lookAt().

lookAt(object, Vec3(0, 0, 1))

I’m building a 3D game, and I have a huge world. When my world starts up, the program hangs for a few seconds the first time I look around. Is there any way to avoid this?

It can take a while to prepare objects to be rendered.

Ideally, you don’t want this to happen the first time you see an object. You can offload the wait time to the beginning by calling:

# self.myWorld is a NodePath that contains a ton of objects
self.myWorld.prepareScene(base.win.getGsg())

This will walk through the scene graph, starting at self.myWorld, and prepare each object for rendering.

Is there a way to hide the mouse pointer so that it doesn’t show up on my screen?

You can change to properties of the Panda3D window so that it doesn’t show the cursor.

props = WindowProperties()
props.setCursorHidden(True)
base.win.requestProperties(props)

If a model has an animation, then is that animation necessarily represented by an additional .egg file?

No. A .egg file can either be just geometry, just an animation or a combination of the two. It’s often easiest, however, to create a separate egg for every animation and an egg that contains just the model/skeleton information.

I have a model with an animation. When I try to play the animation I get a KeyError. Why?

The exact error is this:

KeyError: lodRoot
:display: Closing wglGraphicsWindow

This often happens when you are trying to load animations onto a model that wasn’t exported to have animations. There are two pieces to objects that have animations; their geometry and their skeleton. The geometry is what you see when you load a model, the skeleton is what controls the geometry in an animation. If only the geometry was used to make the egg file, you will have problems when you try to play animations. Look at the manual for more details about exporting models as eggs.

I called setTexture('tex.png') and it didn’t change or send an error. Why?

To override an existing texture, you need to specify a priority. The setTexture() call includes an optional priority parameter, and if the priority is less than 1 the texture will not change.

setTexture('tex.png', 1)

Why do I get sometimes get an AssertionError when instantiating Sequence?

Specifically, I get the following error:

assert(self.validateComponents(self.ivals))
AssertionError

It happens at this line of code:

move = Sequence(obj.setX(5))

Sequences and Parallels are a way to combine intervals. You can’t put anything inside them that isn’t an interval. The following would have the same effect and work:

move = Sequence(Func(obj.setX, 5))

This will start the execution of the function, but not wait for it to finish.

Does Panda3D use degrees or radians?

Degrees, but see also the deg2Rad() and rad2Deg() functions. But note that functions like math.sin(), math.cos(), math.tan() are calculated in radians. Don’t forget to convert the values!

Why do all my flat objects look weird when lit?

Flats don’t often have a lot of vertices. Lighting is only calculated at the vertices, and then linearly interpolated between the vertices. If your vertices are very far apart, lighting can look very strange–for instance, a point light in the center of a large polygon might not show up at all. (The light is far from all four vertices, even though it’s very near the polygon’s center.)

One solution is to create a model with a lot of polygons to pick up the lighting. It also helps to make a flat surface slightly curved to improve its appearance.

Another approach might be to create an ambient light that only affects this object. See the manual for more detail about attaching lights to objects in your scene.

To smooth my animations, I used the “interpolate-frames 1” option, but it doesn’t work somehow. Why?

Interpolate-frames flag gets set in the PartBundle at the time it is first created, and then baked into the model cache. Thenceforth, later changes to the interpolate-frames variable mean nothing. If you changed interpolate-frames flag, you will also need to empty your modelcache folder.

Actually, it is not recommended to use interpolate-frames; it is a global setting. It’s better to achieve the same effect via actor.setBlend(frameBlend=True), which is a per-actor setting (and doesn’t get baked into the model cache).

I’m trying to redirect the output of some commands like myNode.ls() to a file, but the usual method python >> file, myNode.ls() doesn’t work. What’s the alternative?

There are several alternative approaches. One approach using StringStream is this:

strm = StringStream()
render.ls(strm)
open('out.txt', 'w').write(strm.getData())

The following is another approach using StringStream:

strm = StringStream()
cvMgr.write(strm)
open('out.txt', 'w').write(strm.getData())

If you don’t want to use a StringStream you can do this:

strm = MultiplexStream()
strm.addFile(Filename('out.txt'))
render.ls(strm)

There is also a way to specify the output file in the config file.

notify-output out.txt

How do I create a node from a string containing a .egg source?

Use the EggData class.

egg = EggData()
egg.read(StringStream(eggText))
model = NodePath(loadEggData(egg))

How can I know which letter is below the pointer when I click on a TextNode?

Use the TextAssembler class.

tn = TextNode('tn')
tn.setText('abcdef\nghi')
ta = TextAssembler(tn)
ta.setWtext(tn.getWtext())
for ri in range(ta.getNumRows()):
    for ci in range(ta.getNumCols(ri)):
        print("ri = %s, ci = %s, char = %s, pos = %s, %s" %
              (ri, ci, chr(ta.getCharacter(ri, ci)),
                           ta.getXpos(ri, ci),
                           ta.getYpos(ri, ci)))