How to extract vertex position and color from an Actor

All I want to know is the location and color of a loaded actor’s surfaces. Why is this so hard? The surfaces were colored in blender via materials and exported as .egg files using Yabee.

These two panda tutorials here and here seem like what I need but the vertex data doesn’t seem to have a color attribute. Looking at the .egg file, the polygon references the material which have the correct coloring, and so I’m wondering if there exists a polygon attribute or something that can be called to determine the material associated with each vertex.

If I call actor.getMaterials() I can clearly see the two materials but I have no idea which vertices are calling it. I know panda knows because the actor is clearly drawn correctly with the material colors. Please Help I’m desperate.

The materials are specified as a per-Geom setting on the GeomNode. All vertices in the Geom have the same material. You have to iterate over the geoms on the GeomNode, get the geom state (which is a RenderState) object, on which you can get the MaterialAttrib, which holds the Material.

As to why it’s so hard, I suspect that what you’re attempting to do is fairly uncommon, and is thus not something that has been given convenience functions.

So I did this:

state = geom.getGeomState(0)
material = state.getAttrib(MaterialAttrib).getMaterial()
print(material)

console output:

Material Material.006
  ambient = 1 1 1 1
  diffuse = 1 0 0 1
  specular = 0 0 0 1
  emission = 0 0 0 1
  shininess = 12.25
  local = 0
  twoside = 0

Thanks for the help rdb!

Personally I feel the documentation is a bit hard to follow. Like for this problem I would never have figured out that I needed to get the geomNode class instead of the geom object to get the renderstate since a geom has the same material…

The documentation isn’t always ideal, indeed. But I think that it is likely to be especially so for unusual cases like this. Panda3D has a lot of elements to it, so some elements–especially those that aren’t expected to see a lot of use–may not be as deeply or clearly documented as elements that are more-commonly used.

I can agree with that.

As a bonus, I wouldn’t suppose anyone knows how to get the vertex positions from the geoms in the world coordinate space? Currently I’m hard coding the transformation matrix specified in the .egg file and applying it manually.

An easy way is to call flattenLight() (or a stronger flatten operation) on your model, which will apply any transformations applied at a higher level directly onto the vertices.

Another way is to modify the Geom (or make a copy of it) and call transformVertices() on it with as parameter something like gnode.getTransform(render).getMat() (may need to swap around gnode and render there, I’m never 100% sure on the exact order). Or, you could take said matrix and manually call xformPoint(...) on it for each vertex that you process.

1 Like

Calling

loaded_actor.flattenLight()

solved it. Thanks!

I hope I’m not being a bother. So I just realized but calling flatten_light() on the actor will not apply any animation transformations, and therefore the 3d world coordinates of the vertices are not accurate after the first frame of the actor animation. How might I go about getting the 3d world coordinates of the vertices for an animated actor? I have tried so far doing

actor.getJoint(jointName)[-1].getTransform()

and then directly applying the transform but it doesn’t seem correct (visually speaking).

When you are accessing the Geom object, instead of calling geom.getVertexData(), you can call geom.getAnimatedVertexData(True, Thread.getCurrentThread()), which will return the vertex data as animated by the currently playing animation.