Model loader corrupting the models?

Can someone help to explain very odd behavior of the model loader? Bear with the extremely long description. The behavior I see in the end strikes me as so weird that I don’t want to assume any piece of this is irrelevant.

First of all, I’m using Eclipse with PyDev under Windows and Panda3D 1.6.2. Broadly what I’m trying to do is work out a folder structure within a PyDev project that makes sense to me, and figure out what the configuration and code have to do to work with that structure. So I started with the Roaming Ralph sample.

Step 1:
I created a PyDev project called Roaming-Ralph. This gets me a project folder with nothing in it but an empty “src” subfolder and some hidden Eclipse information files.

Step 2:
I copied the following into the /src folder from the Roaming-Ralph folder of Panda: the Tut-Roaming-Ralph.py script, and all the .jpg and .egg.pz files in the models folder. Eclipse’s Import keeps them in their original structure, so I now have:
/src/Tut-Roaming-Ralph.py
/src/models/ground.jpg
/src/models/hedge.jpg
/src/models/ralph.egg.pz
etc.

At this point, if I run the .py file, it works perfectly. However, I don’t want my model, texture, and animation data in my /src folder, so…

Step 3:
I moved the models folder up one level. Now I have:
/src/Tut-Roaming-Ralph.py
/models/ground.jpg
/models/hedge.jpg
/models/ralph.egg.pz
etc.

When I run now I get “IOError: Could not load model file(s): [‘models/world’]”. This doesn’t surprise me; I figure I need a configuration change for the loader to find the models at their new home. But since a configuration file is again neither source nor a model…

Step 4:
I created a new folder in the project called “config”, and I create a “config.prc” file in it. The PRC contains only one line, which reads “model-path $THIS_PRC_DIR/…”. I noticed that the code gives all the model paths as “model/foo”, so I figure it expects to start in the parent folder of models. I don’t want to change the code just yet, except to have it load my custom config. So after the lines that “from pandac.PandaModules import” a bunch of stuff, I add another: “from pandac.PandaModules import loadPrcFile”. And then as soon as it’s done with all the imports I add “loadPrcFile(”…/config/config.prc")

At this point it again runs perfectly, so I’m making progress. But I’m still not satisfied. I’d rather consider “models” to be a subset of “resources”. There could be other data that falls under resources, such as localized messages, and those would get their own separate subfolder.

Step 5:
I created a “resources” folder in the project and moved the models folder under it. Now I have:
/src/Tut-Roaming-Ralph.py
/config/config.prc
/resources/models/ground.jpg
/resources/models/hedge.jpg
/resources/models/ralph.egg.pz
etc.

Then I changed the model-path in the PRC file from “$THIS_PRC_DIR/…” to “$THIS_PRC_DIR/…/resources”.

Still, the program runs just fine, so I’m going to go for one more refinement. As far as I’m concerned, textures are not “models” and don’t belong in the “models” folder. (I’ll worry about the animations later.)

Step 6:
I created a second subfolder of resources called “textures” and moved the .jpg files into it. Now I have:
/src/Tut-Roaming-Ralph.py
/config/config.prc
/resources/textures/ground.jpg
/resources/textures/hedge.jpg
/resources/models/ralph.egg.pz
etc.

Now, I’m not surprised that the program gives me problems at this point. The glaring one is that the display is stark black and white, no textures. When I look at the Python console, I see error messages, two for each texture:
:gobj(error): Texture::read() - couldn’t read: ralph.jpg
:gobj(error): Unable to find texture “ralph.jpg” on model-path /c/Documents and Settings/ […]

The model-path given includes a good path to my resources folder, as well as my src folder and a couple irrelevant ones inside the Panda installation. Okay, so apparently textures are not looked for in subfolders of the model-path. However, even before I start trying to resolve that I notice that things start to get fishy. If I run the program again with no changes, the display remains the same, but this time there are no errors on the console. Huh?

Okay, I just want to get it back to working now. So I undo the changes of Step 6, getting the project back to exactly what it looked like after Step 5. But it still doesn’t work. No errors on the console, but still no textures in the display. I can fix this, but only by doing something bizarre: I have to copy the original .egg.pz files from the Panda installation over the ones in my project.

What on earth is going on? Is the model loader actually corrupting my egg files when it can’t find the right textures? I’ll admit I haven’t yet read the full documentation on how egg files work or how to use the tools that generate them, but can someone at least tell me if this is documented, as-designed behavior? Cause it sure feels like a bug to this programmer.

From what I know missing textures produce just a warning not an error, a program can run without them.

Textures in the egg file have relative path to the path that the model was originally exported. So in Ralphs case panda is looking for the texture in the same dir as the model is in. When you’ll be making your own models just keep the textures in one dir and export the models to your models folder and it all be ok.

You could also edit the egg file and replace the textur patch in it with something you fancy(under a node the first line is the patch to the texture file)

I think there are two things that are confusing you here.

(1) The egg files store the relative paths of the texture files, so when you move the textures relative to the egg files without editing the egg files at the same time, you break the texture references. You can edit the egg files, they’re just text files; but you have to run the punzip program on them first (to decompress them and remove the .pz extension). You can load them in Panda either compressed or uncompressed.

(2) There is a model-cache folder which can sometimes find textures even if they’ve been moved from where they’re supposed to be found, and this might be causing confusing results by making things appear to work when they shouldn’t be working otherwise. You can blow away the model cache directory when you move things around to make sure you’re not getting burned by this. I forget which folder it is stored in by default, but you can look for “model-cache-dir” in the standard Config.prc file.

David

Yes, warnings not errors. Sorry if that was unclear: The missing texture warnings appear on the console but do not prevent the program from running.

I guessed that the eggs stored the relative paths. Although it seems like the paths are interpreted relative to the list of model-paths, not just to the location of their specific model, because once I “restored” the egg files I was also able to make this work after the following changes:

  • put all model eggs in /resources/models
  • put all animation eggs in /resources/animations
  • put all texture JPEGs in /resources/textures
  • add three model-path entries to config.prc, pointing at those three folders
  • change the model paths passed to loadModel() from “model/foo” to just “foo”

This is exactly what I want, and it apparently does not require the models and textures to stay in the same places relative to each other. Unless, drwr, your model-caching is coming into play there; I’ll have to look into that.

So that’s great, but my larger concern remains: Why does the act of running the program when the textures can’t be found cause it to still not work when the textures should be found? Is this also due to the caching somehow? Doesn’t seem plausible, as I wouldn’t expect restoring the egg files to fix it in that case.

The textures referenced by egg files are searched first relative to the egg file itself, and then relative to each directory on the model-path. So, both are true.

It is perfectly possible for the model-cache to cause the behavior you describe. When you run the program the first time, it loads the egg files, fails to find the textures so loads the model without reference to textures, and then caches the result. When you subsequently move the textures into place without changing the egg file, the cached version is still considered valid (because it is newer than the egg file), so it loads the cached version instead–which didn’t get any texture references properly stored within it because it had to be built without textures.

Normally, when a model is loaded and cached, the cache record contains a link to the original model file and each of the referenced textures, and the model loader will rebuild the cache if any of these files is newer than the cache file. But in this particular case, the cache record only has a link to the original model file, since it has no idea where or even if the textures were intended to be found.

David