Instancing particle effects

I have been making a game with a lot of particles. Since animating particles takes quite some CPU time I have tried to instance them. However the result was that only one (randomly chosen?) of the instanced particle effects is visible and i get the following warning:

:pgraph(warning): PandaNode E has 3 parents; choosing arbitrary path to root.
:pgraph(warning): Chose: render/e2/E/particle-effect-1/particles-1

Here is a small example that reproduces my problem:

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

def main(*args):
    app = ShowBase()

    base.enableParticles()
    part = ParticleEffect()
    part.loadConfig("default.ptf")
    part.start(parent = render, renderParent = render)
    ph=render.attachNewNode("E")
    ph.setPos(0,10,0)
    part.reparentTo(ph)
    h1=render.attachNewNode("e1")
    h1.setPos(5,10,0)
    h2=render.attachNewNode("e2")
    h2.setPos(-5,10,0)
    ph.instanceTo(h1)
    ph.instanceTo(h2)

    app.run()

if __name__=="__main__":
    main()

where default.ptf is any particle effect.

Am I doing something wrong? Is instancing of particle effects even allowed?

Btw I’m using Panda 1.8.1 on windows 8.1.

Hmm, yes, there does seem to be an issue with the particle system not liking instancing there. I would suggest you file a bug report and include a test case.

I built from the latest panda3d git source and this problem seems to be still there.

In the above code when I put:

part.start(parent = None, renderParent = render)

all the three particle instances appear correctly, but the same warnings are reported

:pgraph(warning): PandaNode E has 3 parents; choosing arbitrary path to root.
:pgraph(warning): Chose: render/E/particle-effect-1/particles-1

I’m wondering how you’re doing this.

Assuming animation frames, you can put them all in a texture and have the animation run in the pixel shader using texture coordinates and can pass along a texture filled with step data for the frames, which you could update in a seperate shader pass?

Why instancing?

Here particles effects are what is explained in https://www.panda3d.org/manual/index.php/Particle_Effects.
ParticleEffect is derived from NodePath and so it should be possible to instance it as any other NodePath, but this doesn’t work correctly.
You could try to create your own ParticleEffect with Particle Panel in panda3d samples.

After some investigations, I found that particle effects instancing works if you instance the “render parent” of the ParticleEffect, i.e. the second parameter to start. So the above sample could become:

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

def main(*args):
    app = ShowBase()

    base.enableParticles()
    #render parent NodePath
    renderPNP = app.render.attachNewNode("renderPNP")
    #
    part = ParticleEffect()
    part.loadConfig("default.ptf")
    part.start(parent = render, renderParent = renderPNP)
    ph=render.attachNewNode("E")
    ph.setPos(0,10,0)
    part.reparentTo(ph)
    h1=render.attachNewNode("e1")
    h1.setPos(5,10,0)
    h2=render.attachNewNode("e2")
    h2.setPos(-5,10,0)
    renderPNP.instanceTo(h1)
    renderPNP.instanceTo(h2)

    app.run()

if __name__=="__main__":
    main()
        

One caveat: position and orientation of instances seem relative to the base particle effect (“part”).

Hmm, it seems this is a bit of a design problem in Panda’s physics manager: it adds PhysicalNode objects to the physics manager, and the physics integrator uses the NodePath constructor to get a NodePath to this PhysicalNode. However, in the case of instancing, there is more than one such path (in other words, the same node has more than one position), so you get this error.

The solution that comes to mind would be to rework the physics manager’s add_physical_node method to take a NodePath instead of a PhysicalNode. However, I suppose this breaks backward compatibility, and this probably won’t help you directly since the particle system does all this stuff under the hood and would only allow you to add forces to a single instance of the particle.

Maybe it makes sense to say that instancing at any level below the render parent isn’t allowed.