rope physics?

I only use Python, have no knowledge in physics engines.
This is the effect I need:
Can it be done with Panda’s physics engine or ODE?
I’m thinking of using textured geomlines for the rope.

Rope physics example starting at 3:55:

This is done using Panda’s native physics, but it can probably be done more easily using ODE or some more capable physics engine. The idea is just to connect a chain of rigid pieces together at joints, so that you’re actually computing a chain, and then use the Rope class to animate a smooth rope between the joints.


I have support for ropes (linear soft bodies) in libpandabullet r15. But so far there is no support for synchronzation with a RopeNode/NurbsCurveEvaluator. This means you have to read the knot locations from the soft body and copy them to the NurbsCurveEvaluator each frame yourself.

@drwr: what classes should I have a look at? … e.RopeNode
I found this but not sure how to make a curve procedurally, ive generated procedural geometry and textures before, but dont know anything about curves and how they are represented.

What are the classes for Panda’s physics engine?

@enn0x: I thought of switching to Bullet in the future for some of its features and I think your implementation is pretty good at this point, only I can’t find any documentation… Not sure how far I can go with the C++ documentation

Try searching the forums for “Rope” and/or “RopeNode”. It’s quite easy, and there are several examples.

but what about the physics?

There aren’t any special “rope” or “chain” classes in Panda’s physics engine. Just use standard objects like CollisionSphere and such. The Toontown example I linked placed a small CollisionSphere inside a larger CollisionInvSphere to make a joint, and then connected chains of three or four of these joints to make each rope. With this approach, you have to assign bitmasks carefully so that each small CollisionSphere collides only with its parent CollisionInvSphere and not with anything else.

Note that this is a bit of a stretch for Panda’s physics, but as demonstrated, it’s workable. If you’re not perfectly comfortable with the algorithm, it might be better to use a more off-the-shelf solution.


OK, do you think things will get slow with 20-30 ropes?

Not necessarily, but this is like asking “can I have a game with 40 characters running around.” It all depends on your implementation.


I guess it is.

What do you mean by a collision sphere inside an inverse collision sphere?

I mean create a CollisionSphere and put it in the same spot as a larger CollisionInvSphere. Set the bits so that the CollisionSphere collides with the CollisionInvSphere. The smaller CollisionSphere will roll around in the space inside the CollisionInvSphere.

If you then parent another node to the CollisionSphere, and parent another CollisionInvSphere to this node with an offset in one direction so that it is a bit farther away (and outside the first CollisionInvSphere), then this CollisionInvSphere will get dragged around when the CollisionSphere moves. Now put another CollisionSphere inside this CollisionInvSphere, and you’ve created a chain.

Like I said, this is all just hodgepodge, and YMMV. If you want real rope physics, you’re better off using an off-the-shelf solution like the bullet solution mentioned above, where people have already solved these problems for you.


By now I have implemented a link between the Panda3D NurbsCurveEvaluator/RopeNode and BulletSoftBodyNode. I also have a working sample. The next release (a few days) will contain this.

I’ll have a look when its done.
But if its possible to not use external physics engine for this particular projet,

is this what you mean?

lets say the red spheres are collisionSpheres and the icospheres are inverse collision spheres,\you want each collisionSphere to collide with its inverse collision sphere and the invCollisionSpheres with eachother? I dont really understand.

No, the first part is right, but not the second. Each red sphere collides only with its containing icososphere. There are no other collisions.

And your chain isn’t drawn correctly. Instead of connecting the red spheres to each other, you will connect each icososphere to the red sphere above it.

So each red sphere will roll (actually slide) around inside its containing icososphere, and as it moves, the icososphere below it will swing around freely, connected to the sliding sphere above it.



The normal and inverse spheres should form something like a bearing. Each bearing should consist of one normal and one inverse sphere around it. Every inverse sphere has only one normal sphere inside.

Now, the connections go like this. You connect each normal sphere from one bearing to the inverse sphere from the bearing that succeeds the current bearing.

No idea how to put it simpler…


from direct.directbase.DirectStart import *
from pandac.PandaModules import *
from direct.showutil.Rope import Rope

showChain = True
showRope = False

armLength = 15
isphereRadius = 8
ssphereRadius = 1
numLinks = 3

def makeLink(physicsFrame, parent, bitNumber):
    # Create an arm descending from the parent a bit.
    arm = parent.attachNewNode('arm_%s' % (bitNumber))
    arm.setPos(0, 0, -armLength)
    # Create a CollisionInvSphere to be rigidly attached to the parent.
    inode = CollisionNode('inode_%s' % (bitNumber))
    isphere = CollisionInvSphere((0, 0, 0), isphereRadius)
    inp = arm.attachNewNode(inode)

    if showChain:
        # A wireframe sphere to visualize it.
        smiley = loader.loadModel('smiley.egg')

    # Create a smaller CollisionSphere inside the CollisionInvSphere.
    # First, we'll need an ActorNode to contain it, so it can respond
    # to gravity and the like.
    anode = ActorNode('anode_%s' % (bitNumber))
    anp = physicsFrame.attachNewNode(anode)

    # Now the sphere itself.
    snode = CollisionNode('snode_%s' % (bitNumber))
    ssphere = CollisionSphere((0, 0, 0), ssphereRadius)
    snp = anp.attachNewNode(snode)

    if showChain:
        smiley = loader.loadModel('smiley.egg')

    # This smaller sphere is a "from" object.
    handler = PhysicsCollisionHandler()
    handler.addCollider(snp, anp)
    base.cTrav.addCollider(snp, handler)

    return anp

# We define physics to happen in the camera space, so that gravity is
# always towards the bottom of the screen, for convenience of this
# demo.
physicsFrame =

# Enable collisions.
base.cTrav = CollisionTraverser()

# Enable gravity.
gravityFN = ForceNode('world-forces')
gravityFNP = physicsFrame.attachNewNode(gravityFN)
gravityForce = LinearVectorForce(0, 0, -9.81)


# Create a node to be the root of the chain.
root = NodePath('root')

axis = loader.loadModel('zup-axis.egg')

# Create the chain.
links = []
link = root
for i in range(numLinks):
    link = makeLink(physicsFrame, link, i)
if showRope:
    # Connect the links of a chain with a rope.
    rope = Rope()
    ropeVerts = [(root, (0, 0, 0))]
    for link in links:
        ropeVerts.append((link, (0, 0, 0)))
    rope.setup(4, ropeVerts)

# Pull the camera back and observe the scene.
base.trackball.node().setPos(0, 200, 40)

now it makes perfect sense