1.6.2 BUG? : maya2egg reverses geoms hierarchy order

I’m not sure if this is a bug, and I’m not sure either what this is good for.
Any parent geometry ends up as PandaNode (not GeomNode), and the geom is appended after the last children, resulting in reversed hierarchy order.

In maya :

Those geoms are spread towards X+Y- with noticable space in between.

The result :

PandaNode pPlane1
  PandaNode pSphere1
    PandaNode pCube1
      GeomNode pCone1
      GeomNode  (1 geoms) <-- pCube1
    GeomNode  (1 geoms) <-- pSphere1
  GeomNode  (1 geoms) <-- pPlane1

Just to make the issue obvious, I parented it to aspect2d.

The expected order :

PandaNode pPlane1
  GeomNode  (1 geoms) <-- pPlane1
  PandaNode pSphere1
    GeomNode  (1 geoms) <-- pSphere1
    PandaNode pCube1
      GeomNode  (1 geoms) <-- pCube1
      GeomNode pCone1

Thanks for any answer.

These two hierarchies are exactly the same, right?

PandaNode pPlane1
  PandaNode pSphere1
    PandaNode pCube1
      GeomNode pCone1
      GeomNode  (1 geoms) <-- pCube1
    GeomNode  (1 geoms) <-- pSphere1
  GeomNode  (1 geoms) <-- pPlane1
PandaNode pPlane1
  GeomNode  (1 geoms) <-- pPlane1
  PandaNode pSphere1
    GeomNode  (1 geoms) <-- pSphere1
    PandaNode pCube1
      GeomNode  (1 geoms) <-- pCube1
      GeomNode pCone1

Only the order in which children are printed differs - but that is arbitrary and meaningless.

Try to draw it in a tree form and you’ll see that the hierarchy is exactly the same.

Of course not, as you can see in the picture, the resulting render order is cone -> cube -> sphere -> plane.

It is arguably a bug, but it’s pretty obscure. I didn’t even know Maya supported attaching geometries together in a parent/child relationship like that.

I guess it’s only an issue when you are attempting to use the parent/child relationship to construct a GUI which has to be drawn in a particular order. But you can also use sibling/sibling relationships to do the same thing; and if you restrict your use of parent nodes to ordinary grouping nodes, the Panda scene graph should more nearly match your Maya scene graph.

David

Maya supports that, and so does Panda !

But it’s not maya2egg issue afterall, I just examined the egg, everything is in place as it should be, so it’s egg loader’s work.
I just tried it with blender too, and it ends up exactly the same graph.

Actually, the first time I realised that was from my 2D scene is in incorrect order.

To me, this issue yields another “bug”, say I [color=red]find(’**/sphere’).removeChildren(), then the sphere geom itself would be removed too !

Just a quick question, why not letting a GeomNode be the parent instead of replacing it with PandaNode ?

If you put:

egg-flatten 0

in your Config.prc file, you will see more accurately what is happening.

It’s not that the GeomNode is being converted to a PandaNode. It’s actually the other way around. The egg loader creates a PandaNode for the entry that appears in the egg file. Then it creates one or more GeomNodes that correspond to the polygons with that group. So you always end up with a PandaNode and a GeomNode below it.

When there are no other children of that , then the scene graph reducer can automatically flatten together the GeomNode and the PandaNode parent, so you just see a single GeomNode there instead. This is the normal case.

But when a has additional children, that flattening cannot happen, and you end up with what appears to be an extra PandaNode.

All this is necessary because unlike Maya, Blender, and Panda, the egg language doesn’t have a concept of an explicit GeomNode.

David

For what it’s worth, the maya hierarchy is slightly more complex than what’s displayed in the screenshot above. What you see there is a combination of shape nodes and transform nodes (equivalents of GeomNode and PandaNode, respectively). In Maya’s outliner you can select Display -> Shapes and it will show you a more detailed hierarchy:

pPlane1    (transform/PandaNode)
  pPlaneShape1    (shape/GeomNode)
  pSphere1    (transform/PandaNode)
    pSphereShape1    (shape/GeomNode)
    pCube1    (transform/PandaNode)
      pCubeShape1    (shape/GeomNode)
      pCone1    (transform/PandaNode)
        pConeShape1    (shape/GeomNode)

So what if maya is that nasty ?
Should panda follow that route 1:1 ?
Maybe that’s maya design limitation, which is not true for panda, since GeomNode can also store transform.

David, instead of simply parenting the GeomNode as the last child to the PandaNode parent, why doesn’t it take advantage of replaceNode() ?

I don’t know what you mean. It does use replaceNode(); the PandaNode that used to be called pCone1 becomes replaced with a GeomNode instead.

But it can’t use replaceNode() on the other nodes, because they have multiple children, and maybe you intended those children to be meaningful.

David

Then it need to stealChildren() first, IF a Group has polygons, regardless if it has children, so the graph would be :

GeomNode pPlane1
  GeomNode pSphere1
    GeomNode pCube1
      GeomNode pCone1

The cleaner, the better, isn’t it ?

Hmm, I’m not convinced.

Basically, you’re proposing a special-case exception in Panda’s flatten_medium() code (which is what is used to clean up the scene graph after loading the egg file), to compensate for the subtle difference in design between the egg scene graph and the Panda scene graph.

That’s not very clean. “Clean” is precisely following the input given, which in this case is what you got. But then flatten changed the order a bit when it operated, which it’s allowed to do.

If you really want the scene graph to match what you got from maya, you could turn off egg-flatten and just render the resulting scene graph exactly.

David

“Clean” for me means clean panda graph, not clean conversion, since modeling tools graph is not clean, not only maya, but also blender, and maybe all others too.
In the modeling tools, the separated transform and shape yields minimum problem, since there is usually no operation done in between. But in case of further operations involving programming, it starts getting annoying. Eg. removeChildren and stealChildren, which give unexpected result.

For me, consistent unification of transform and geom is ideal.

Let me be clear: I certainly agree there is real a bug here. The model looks one way in Maya, and a different way in Panda. Clearly something went wrong in conversion, which means we have a bug.

I’d be perfectly happy to fix this particular bug. Unfortunately, it happens to be a particularly difficult bug to fix, because it goes all the way down into the fundamental design of the egg syntax, and the low-level optimization tools like flatten_medium().

On the other hand, this particular example has an easy workaround. So, though it does trouble me that the maya2egg conversion pipeline has issues, I’m willing to accept them in this case. There are other bugs that demand my attention first.

If you’re offering to fix this bug, though, I’d be happy to accept your patches. :wink: Unfortunately, I think a proper fix would have to go deep; it wouldn’t be a simple matter of changing the way flatten_medium() works.

In all seriousness, I do apologize for the troubles. I really do wish I had more time to fix things like this. :frowning:

David

Now I don’t think it’s a conversion bug, since the egg is perfect to me.
Each Group has Transform, VtxPool, and Polygon in exactly the same order.
I haven’t analyzed the result without flattening. So, I think it’s the flatten operation puts the GeomNode as the last child. I think it’s intentional, to avoid giving the GeomNode of itself when asking for getChild(0), isn’t it ?

The flatten operation is designed to be very general; it isn’t only used for loading egg files.

The rules that flatten_medium follows is: only remove nodes that do not contribute meaningfully to the hierarchy. This means that a node with only one child may be combined with its child, but a node with multiple children must remain.

David

I’ve tried it without flatten, the graph remains the same. I’ve also removed the model cache before loading.

So, I ran some analysis and this is what I found in the EggGroup vector :

## from Maya ##
GROUP: pPlane1
  pPlaneShape1.verts  <-- vtx pool
  pSphere1
GROUP: pSphere1
  pSphereShape1.verts  <-- vtx pool
  pCube1
GROUP: pCube1
  pCubeShape1.verts  <-- vtx pool
  pCone1
GROUP: pCone1
  pConeShape1.verts  <-- vtx pool

## from Blender ##
GROUP: Plane
  Plane  <-- vtx pool
  Sphere
GROUP: Sphere
  Sphere  <-- vtx pool
  Cube
GROUP: Cube
  Cube  <-- vtx pool
  Cone
GROUP: Cone
  Cone  <-- vtx pool

Based on that, I simply changed the node type from PandaNode to GeomNode, only if its first child is a vertex pool.
The full graph is :

ModelRoot nested nodes export.egg T:(scale 0.4)
  PandaNode
    PandaNode groundPlane_transform T:m(hpr 0 90 0 scale 12 12 1)
    GeomNode pPlane1 (1 geoms: S:(ColorAttrib)) T:m(scale 1.36824)
      GeomNode pSphere1 (1 geoms: S:(ColorAttrib)) T:m(pos 0.364181 -0.770978 0 scale 0.451685)
        GeomNode pCube1 (1 geoms: S:(ColorAttrib)) T:m(pos 0.631612 -2.14094 0 scale 1.34221)
          GeomNode pCone1 (1 geoms: S:(ColorAttrib)) T:m(pos 0.692365 -1.58746 0.719874 hpr -180 89.8 -180 scale 0.838791)

originally :

ModelRoot nested nodes export.egg T:(scale 0.4)
  PandaNode 
    PandaNode groundPlane_transform T:m(hpr 0 90 0 scale 12 12 1)
    PandaNode pPlane1 T:m(scale 1.36824)
      PandaNode pSphere1 T:m(pos 0.364181 -0.770978 0 scale 0.451685)
        PandaNode pCube1 T:m(pos 0.631612 -2.14094 0 scale 1.34221)
          GeomNode pCone1 (1 geoms: S:(ColorAttrib)) T:m(pos 0.692365 -1.58746 0.719874 hpr -180 89.8 -180 scale 0.838791)
          GeomNode  (1 geoms: S:(ColorAttrib))
        GeomNode  (1 geoms: S:(ColorAttrib))
      GeomNode  (1 geoms: S:(ColorAttrib))

eggLoader.cxx, make_node (EggGroup)
changed this :

    if (all_polysets && !any_hidden) {
      node = new GeomNode(egg_group->get_name());
    } else {
      node = new PandaNode(egg_group->get_name());
    }

to :

    if (all_polysets && !any_hidden) {
      node = new GeomNode(egg_group->get_name());
    } else if (egg_group->size()>0 && (*egg_group->begin())->is_exact_type(EggVertexPool::get_class_type())) {
      node = new GeomNode(egg_group->get_name());
    } else {
      node = new PandaNode(egg_group->get_name());
    }

Hmm, something bears further investigation in here. I will look into it more deeply.

Something’s not right then; that graph is certainly the result of a flatten operation having been applied. If the graph remains the same, then you haven’t successfully disabled flatten yet. I will have to try to replicate.

It’s a bit of a hack, isn’t it? Even though the Blender and Maya converters both do this, there’s no requirement in the egg syntax that the vertex pool has to be the first child of a group that contains polygons. In fact, the vertex pool may be anywhere in the egg file prior to that; it doesn’t have to be within that group at all. And what if it is in a group by itself–should the egg loader create a GeomNode that contains no polygons then?

Still, you have illustrated that whatever is wrong may have an easy solution after all. I will look more closely.

David

That’s because I couldn’t find any other mean to ask “is this node has primitive by itself (not including the children) ?”.
has_primitive() works recursively.