Problems with asyncFlattenStrong

Hi, I would like to use asyncFlattenStrong, but I can’t. Here is an example of flattenStrong:

from panda3d.core import NodePath
import direct.directbase.DirectStart

root = NodePath('root')
for i in range(2):
    panda = loader.loadModel('panda')
    panda.reparent_to(root)

print '\nbefore'
root.ls()

root.clear_model_nodes()
root.flatten_strong()

print '\nafter'
root.ls()

base.run()

Here is its output:

before
PandaNode root
  ModelRoot panda.egg
    Character panda_soft
      GeomNode  (10 geoms: S:(ColorAttrib TextureAttrib TransparencyAttrib))
  ModelRoot panda.egg
    Character panda_soft
      GeomNode  (10 geoms: S:(ColorAttrib TextureAttrib TransparencyAttrib))

after
PandaNode root
  Character panda.egg
    GeomNode  (16 geoms: S:(ColorAttrib TextureAttrib TransparencyAttrib))

I would like to do the same with asyncFlattenStrong, here is the code:

from panda3d.core import NodePath
import direct.directbase.DirectStart

root = NodePath('root')
for i in range(2):
    panda = loader.loadModel('panda')
    panda.reparent_to(root)

print '\nbefore'
root.ls()

def after(model):
    print '\nafter'
    model.ls()

root.clear_model_nodes()
loader.asyncFlattenStrong(root, callback=after)

base.run()

The problem is that I obtain different results. Sometimes I get:

before
PandaNode root
  ModelRoot panda.egg
    Character panda_soft
      GeomNode  (10 geoms: S:(ColorAttrib TextureAttrib TransparencyAttrib))
  ModelRoot panda.egg
    Character panda_soft
      GeomNode  (10 geoms: S:(ColorAttrib TextureAttrib TransparencyAttrib))

after
Character root

Sometimes I get:

before
PandaNode root
  ModelRoot panda.egg
    Character panda_soft
      GeomNode  (10 geoms: S:(ColorAttrib TextureAttrib TransparencyAttrib))
  ModelRoot panda.egg
    Character panda_soft
      GeomNode  (10 geoms: S:(ColorAttrib TextureAttrib TransparencyAttrib))
Segmentation fault (core dumped)

(it’s an official 1.9.2 on Ubuntu Trusty). NB It also happen using the parameter inPlace=True.

What am I missing here? Thank you very much!

Hi, I have found another problem with asyncFlattenStrong. Here is the code:

from panda3d.core import NodePath
import direct.directbase.DirectStart
base.disableMouse()
base.cam.set_pos(-2, -2, 50)
base.cam.look_at(0, 0, 0)
root = NodePath('root')
root.reparent_to(render)
for i in range(10):
    for j in range(10):
        smiley = loader.loadModel('smiley')
        smiley.reparent_to(root)
        smiley.set_pos(i, j, 0)
root.clearModelNodes()

# root.flattenStrong()
# root.ls()
# these two lines work and print:
# PandaNode root
#   GeomNode smiley.egg (25 geoms: S:(TextureAttrib))

def end(model):
    root.ls()
loader.asyncFlattenStrong(root, callback=end)
# this doesn't work: at the end of the flattening
# it removes the models and prints
# PandaNode root

base.run()

This shows a different behavior among flattenStrong and asyncFlattenStrong. The current code unexpectedly produces an application which removes the flattened objects at the end of the process (so, the screen is empty). Uncommenting the flattenStrong block and commenting the asyncFlattenStrong one shows that the behavior for flattenStrong is the expected one. Is it a bug or am I misusing asyncFlattenStrong? Thank you!

The problem seems to be the inPlace parameter.

The default value is True as well, and that’s when it goes wrong. If you set it to False however, and use the callback to reparent the flattened geometry into the scene graph manually, it works, e.g.:

from panda3d.core import NodePath
import direct.directbase.DirectStart

root = NodePath('root')
for i in range(2):
    panda = loader.loadModel('panda')
    panda.reparent_to(root)

print '\nbefore'
root.ls()

def after(model):
    print '\nafter'
    model.ls()
    root.remove_node()
    model.reparent_to(render)

root.clear_model_nodes()
loader.asyncFlattenStrong(root, False, callback=after)

base.run()

Apart from that, running the code samples on Windows 8.1 using Panda3D development version 1.10.0 (Panda3D-SDK-1.10.0pre-20353f3-x64), I get the following AttributeError:

Traceback (most recent call last):
  File "async.py", line 18, in <module>
    loader.asyncFlattenStrong(root)#, callback=after)
  File "C:\Panda3D-1.10.0\direct\showbase\Loader.py", line 895, in asyncFlattenStrong
    request.setPythonObject((cb, i))
AttributeError: 'panda3d.core.ModelFlattenRequest' object has no attribute 'setPythonObject'

Thank you, the workaround works! :slight_smile:

All the aforementioned issues should be fixed now.

Bug link: bugs.launchpad.net/panda3d/+bug/1618959

Thank you very much! :slight_smile:

The AttributeError no longer occurs, thank you.

However, the following code is still problematic:

from panda3d.core import NodePath
import direct.directbase.DirectStart

root = NodePath('root')

# uncommenting the following fixes the flattening problem
#parent_node = NodePath('parent')
#root.reparent_to(parent_node)

for i in range(2):
    panda = loader.loadModel('panda')
    panda.reparent_to(root)

print '\nbefore'
root.ls()

def after(model):
    print '\nafter'
    model.ls()

root.clear_model_nodes()
loader.asyncFlattenStrong(root, callback=after)

base.run()

The result is still just a Character without GeomNode:

after
Character root

But when I reparent the “root” node to any other node, the result is correct:

after
Character root
  GeomNode  (6 geoms: S:(ColorAttrib TextureAttrib TransparencyAttrib))

This only seems to be an issue with Characters though, as flattening static models (e.g. ‘smiley’) works correctly either way.

This seems to be a separate issue that has something to do with Panda being unable to instance a node that has no parents, or something along those lines.

I’m checking in a workaround for 1.9.3. In the meantime, I suggest that you don’t call asyncFlattenStrong on a node without parents. You can parent it to a temporary dummy node if necessary.