Losing Materials when using Bam2Egg

Hello everyone, thanks in advance for any help offered.

I’m running into an issue with my pipeline from Blender to Panda3d. I’m converting my Blend file to a bam file using the latest version of Blend2Bam, which I installed with pip. I’m then converting that bam file to an egg file using bam2egg for a couple of reasons. It lets me change texture paths to relative paths and remove unwanted nodes from the blender scene (the lights I use to preview the model in Blender, for example).

The model has four materials on it in Blender, Body, Face, Eyes, and TeethNails. When I load the bam into a simple panda3D app and use .findAllMaterials(), all four of them are present. After I use bam2egg, two of the materials (Face and TeethNails) are missing from the egg file. When I load the egg and use .findAllMaterials() they’re of course missing from the loaded model, too.

Looking at the egg file, the polygons that should be assigned the Face and TeethNails materials are assigned with the Body material instead. I can tell because each material has a texture associated with it, and the polygons still have the correct textures assigned.

Can anyone tell me why those materials might be lost during the conversion, and what I can do to prevent that?

I can provide the bam and egg files if that will help, but they’re a bit large because the model is high res (4 and 24 MB respectively).

Hi, welcome to the community!

First off, I don’t recommend using bam2egg. It is inherently a lossy process. As alternative, perhaps you can modify the bam file programmatically, by loading it in with loadModel, doing manipulations on the scene, and then writing it out with .writeBamFile?

Alternatively, you can export the model to .gltf, make any modifications there, and then convert that to bam using panda3d-gltf (in fact, blend2bam uses this process under the hood).

With regards to the blend2bam issue, that does sound like a bug, but we’ll need to have the model file to reproduce and fix it.

I’ll try making the changes programmatically as you suggest, instead of converting to egg. Thanks for the information! I’d like to provide the Blend file for your debugging, but not publicly. Is there a way to hand it over via private messages or something?

There are some other exporters, which can convert .blend files directly to .egg.
But .gltf is also nice alternative because it’s a plain text file just like an .egg (with json inside). So it’s readable too.

Feel free to send me the model via private messaging. If it’s too big, I will PM you my email address.

I started on the no bam2egg approach you suggsted, rdb, and I immediately ran into an issue I’d forgotten about. It started me using bam2egg to begin with, so I’m surprised I forgot it. My model appears to be a flat black void in Panda3D when I load the bam created with blend2bam.

When I use findAllTextures, there are textures that I presume were created by blend2bam (or its components) with no images in them (as far as I can tell). They’re called pbr-fallback, emission-fallback, and normal-fallback. I don’t want to use pbr (at least not until I understand it better and the current limits of the implementation in Panda3D), and I don’t want to use an emission or normal map (I’m going for a simple look that doesn’t require normals, and I want to control emission with the material).

There’s also a lot more texture stages listed by findAllTextureStages() than seems necessary, 3 of them repeated 4 times (one repetition for each material or set of polygons with a diffuse texture applied?).

I’ve tried replacing the textures and changing their format to F_rgb (which I saw in another topic on this forum), both the fallbacks and the textures I applied in Blender (which do show up in findAllTextures()), but nothing changes. I’m at a complete loss as to what to do about this.

Here’s my code, not that there’s much of it at the moment.

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

class BamCleaner(ShowBase):
  def __init__(self):

    # Load the bam.
    self.model = loader.loadModel("b2bTest/modelReduced.bam")

    # Add the bam to the scene.
    self.model.setPos(0, 10, -5)

    # Light the scene
    self.lightModel = PointLight('Light Model')
    self.lightModelNP = render.attachNewNode(self.lightModel)
    self.lightModelNP.setPos(0, -10, 10)

bc = BamCleaner()

Also, rdb, I can’t figure out how to send private messages. I feel silly, but that’s the truth of it. I tried clicking your name/profile pic and couldn’t find a button for it. I also tried going to the messages in my own profile, but I couldn’t find any “new” or “compose” buttons. So I made a stripped down version of my Blender file that I’m comfortable sharing publicly, that still exhibits my problems. It won’t let me upload it because I’m a new user, though. Maybe the ability to send private messages isn’t appearing for the same reason.

I just got upgraded a trust level and I can upload the blend file now!
modelReduced.blend (2.2 MB)

I continued working on this problem and I managed to solve the black void issue by installing and using simplepbr. I kept running into additional issues when trying to programmatically change textures and material properties. It might just be my lack of familiarity with pbr, I don’t know.

My project revolves around letting a user alter textures and materials during runtime. Without that, it falls apart. So I switched from using blend2bam to the blender 2.8 version of Yabee on github.

Using that, I put together the basics of the functionality I need with this code:


# Load the environment model.
self.model = Actor("Eggs/model62-4.egg")

self.model.setPos(0, 10, -5)
self.lightModel = PointLight('Light Model')
self.lightModelNP = self.model.attachNewNode(self.lightModel)
self.lightModelNP.setPos(0, -10, 10)

matBody = self.model.findMaterial("Body")
matBody.setEmission((0.2, 0.16, 0.16, 1))
matBody.setDiffuse((0.8, 0.8, 0.8, 1))
matFace = self.model.findMaterial("Face")
matFace.setEmission((0.2, 0.16, 0.16, 1))
matFace.setDiffuse((0.8, 0.8, 0.8, 1))

bodyImg = PNMImage(2048,2048,4)
bodyImg.fill(0.95, 0.77, 0.68)
bodyColor = Texture("Body Color")

faceImg = PNMImage(2048,2048,4)
faceImg.fill(0.95, 0.77, 0.68)
faceColor = Texture("Face Color")

self.model.replaceTexture(self.model.findTexture("BodyBase"), bodyColor)
self.model.replaceTexture(self.model.findTexture("FaceBase"), faceColor)

If someone can show me how to do these operations with a model imported through a blend2bam pipeline, using PBR, I’d be interested to see that. Until then, this is what I’m going with.

Material.diffuse is a legacy material setting, and base_color should be used for PBR materials.

For texture issues, I will need more information on what behavior you’re seeing versus what you expect.

One thing to keep in mind with panda3d-gltf and, by extension, blend2bam, every material has default/fallback textures to make custom shaders easier. This means NodePath.set_texture() needs to have the override parameter set to 1 (e.g., model.set_texture(newtex, 1)). However, I do not believe you’re running into this issue since you’re replacing your own textures and not trying to assign new textures to a material you thought had no textures.

Here’s a comparison of the two. On the left is the bam from blend2bam with simplepbr, on the right is the egg from Yabee using render.setShaderAuto. I’ve done the same texture and material property changes on both (using setBaseColor on the left, and setDiffuse on the right). Ignore the difference in the eyes/teeth right now, they aren’t set the same.

By comparison, the bam is substantially faded and dark. I tried setting the texture format to F_srgb_alpha and that brings it closer to the intended color, but still quite dark.

I tried moving the light closer, in case the fall off worked differently with the pbr shader, but that didn’t change anything.