PyODE performance test, stacking100 bars in 10fps ???

blackgun

19-07-2007 13:06:13

This is a Python ODE performance test. It crashed when obj count=98 and performance is low. maybe 10-20 fps in my Coreduo 1.8G


I think it is too slow , novodex demo is 50-80fps with more than 1000 boxes, maybe more. Is this the ODE's problem, or PyODE's?

May anyone do this test with ODE(C++) and show the performance?

Thanks

This is the code:

# pyODE example 3: Collision detection

# Originally by Matthias Baas.
# Updated by Pierre Gay to work without pygame or cgkit.

import sys, os, random, time
from math import *
from OpenGL.GL import *
from OpenGL.GLU import *
from OpenGL.GLUT import *

import ode



# geometric utility functions
def scalp (vec, scal):
vec[0] *= scal
vec[1] *= scal
vec[2] *= scal

def length (vec):
return sqrt (vec[0]**2 + vec[1]**2 + vec[2]**2)

# prepare_GL
def prepare_GL():
"""Prepare drawing.
"""

# Viewport
glViewport(0,0,640,480)

# Initialize
glClearColor(0.8,0.8,0.9,0)
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_DEPTH_TEST)
glDisable(GL_LIGHTING)
glEnable(GL_LIGHTING)
glEnable(GL_NORMALIZE)
glShadeModel(GL_FLAT)

# Projection
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
gluPerspective (45,1.3333,0.2,20)

# Initialize ModelView matrix
glMatrixMode(GL_MODELVIEW)
glLoadIdentity()

# Light source
glLightfv(GL_LIGHT0,GL_POSITION,[0,0,1,0])
glLightfv(GL_LIGHT0,GL_DIFFUSE,[1,1,1,1])
glLightfv(GL_LIGHT0,GL_SPECULAR,[1,1,1,1])
glEnable(GL_LIGHT0)

# View transformation
gluLookAt (2.4, 3.6, 4.8, 0.5, 0.5, 0, 0, 1, 0)

# draw_body
def draw_body(body):
"""Draw an ODE body.
"""

x,y,z = body.getPosition()
R = body.getRotation()
rot = [R[0], R[3], R[6], 0.,
R[1], R[4], R[7], 0.,
R[2], R[5], R[8], 0.,
x, y, z, 1.0]
glPushMatrix()
glMultMatrixd(rot)
if body.shape=="box":
sx,sy,sz = body.boxsize
glScale(sx, sy, sz)
glutSolidCube(1)
glPopMatrix()


# create_box
def create_box(world, space, density, lx, ly, lz):
"""Create a box body and its corresponding geom."""

# Create body
body = ode.Body(world)
M = ode.Mass()
M.setBox(density, lx, ly, lz)
body.setMass(M)

# Set parameters for drawing the body
body.shape = "box"
body.boxsize = (lx, ly, lz)

# Create a box geom for collision detection
geom = ode.GeomBox(space, lengths=body.boxsize)
geom.setBody(body)

return body

# drop_object
def drop_object():
"""Drop an object into the scene."""

global bodies, counter, objcount

body = create_box(world, space, 1000, 0.6,0.2,0.2)
body.setPosition( (random.gauss(0,0.1),3.0,random.gauss(0,0.1)) )
theta = random.uniform(0,2*pi)
ct = cos (theta)
st = sin (theta)
body.setRotation([ct, 0., -st, 0., 1., 0., st, 0., ct])
bodies.append(body)
counter=0
objcount+=1
print "obj count =%d " % (objcount)

# explosion
def explosion():
"""Simulate an explosion.

Every object is pushed away from the origin.
The force is dependent on the objects distance from the origin.
"""
global bodies

for b in bodies:
l=b.getPosition ()
d = length (l)
a = max(0, 40000*(1.0-0.2*d*d))
l = [l[0] / 4, l[1], l[2] /4]
scalp (l, a / length (l))
b.addForce(l)

# pull
def pull():
"""Pull the objects back to the origin.

Every object will be pulled back to the origin.
Every couple of frames there'll be a thrust upwards so that
the objects won't stick to the ground all the time.
"""
global bodies, counter

for b in bodies:
l=list (b.getPosition ())
scalp (l, -1000 / length (l))
b.addForce(l)
if counter%60==0:
b.addForce((0,10000,0))

# Collision callback
def near_callback(args, geom1, geom2):
"""Callback function for the collide() method.

This function checks if the given geoms do collide and
creates contact joints if they do.
"""

# Check if the objects do collide
contacts = ode.collide(geom1, geom2)

# Create contact joints
world,contactgroup = args
for c in contacts:
c.setBounce(0.2)
c.setMu(5000)
j = ode.ContactJoint(world, contactgroup, c)
j.attach(geom1.getBody(), geom2.getBody())



######################################################################
if __name__ == '__main__':
# Import Psyco if available
try:
import psyco
psyco.full()
except ImportError:
pass

# Initialize Glut
glutInit ([])

# Open a window
glutInitDisplayMode (GLUT_RGB | GLUT_DOUBLE)

x = 0
y = 0
width = 640
height = 480
glutInitWindowPosition (x, y);
glutInitWindowSize (width, height);
glutCreateWindow ("testode")

# Create a world object
world = ode.World()
world.setGravity( (0,-9.81,0) )
world.setERP(0.8)
world.setCFM(1E-5)

# Create a space object
space = ode.Space()

# Create a plane geom which prevent the objects from falling forever
floor = ode.GeomPlane(space, (0,1,0), 0)

# A list with ODE bodies
bodies = []

# A joint group for the contact joints that are generated whenever
# two bodies collide
contactgroup = ode.JointGroup()

# Some variables used inside the simulation loop
fps = 50
dt = 1.0/fps
running = True
state = 0
counter = 0
objcount = 0
lasttime = time.time()


# keyboard callback
def _keyfunc (c, x, y):
sys.exit (0)

glutKeyboardFunc (_keyfunc)

# draw callback
def _drawfunc ():
# Draw the scene
prepare_GL()
for b in bodies:
draw_body(b)

glutSwapBuffers ()

glutDisplayFunc (_drawfunc)

# idle callback
def _idlefunc ():
global counter, state, lasttime

t = dt - (time.time() - lasttime)
if (t > 0):
time.sleep(t)

counter += 1

if state==0:
if counter==20:
drop_object()
if objcount==200:
state=1
counter=0
# State 1: Explosion and pulling back the objects
elif state==1:
if counter==100:
explosion()
if counter>300:
pull()
if counter==500:
counter=20

glutPostRedisplay ()

# Simulate
n = 2

for i in range(n):
# Detect collisions and create contact joints
space.collide((world,contactgroup), near_callback)

# Simulation step
world.step(dt/n)

# Remove all contact joints
contactgroup.empty()

lasttime = time.time()

glutIdleFunc (_idlefunc)

glutMainLoop ()

andy

20-07-2007 05:31:54

I'm not sure this is the right forum to post this question (as you aren't using Ogre or Python-Ogre) -- however it's probably relevant anyway :)

The first thing to do is to remove the GL drawing and see what your performance is like -- ie simply return from the _drawfunc call without doing anything. This way you'll see if it's an ODE limitation or a GL one.

I do have a collision test program I used to demo the OgreCollideListener which I will modify to use ODE and see how well it works.

Of course if you change over to Python-Ogre not only will you get MUCH better graphics (thanks to the Ogre engine) you'll get a choice of Physics engines (currently ODE and Newton, with PhysX on the way).

Cheers
Andy

saluk

20-07-2007 20:33:43

I think he's probably looking to use ode with ogre but is worried about performance from this test. (Forgive me if my assumptions are incorrect.)

Also, this test appears to be an example that came with pyode. It runs really slow for me as well, can't even get >100 objects before it basically dies. I'm not sure what the problem is, but you should take it up with the pyode developers :) I use pyode, and don't experience much slowdown with anything I do, but I'm not sure I have even close to 100 objects in any of my projects. It would stink if I later find out that I can't scale too much.

Looking at the code, the first thing I notice is that it is using world.step rather than world.quickStep. quickStep is much, much faster, and for games it seems accurate enough for me. Also, it is running the simulation twice on each frame, no matter how long a frame takes. As the objects pile up, the speed of the physics is going to appear slower, as the framerate slows down. The framerate may not be as bad as it appears, but without a fps indicator it's hard to tell.

Anyway, bring it up with the pyODE guys. My bet is that this demo is just really old and not a very good example. ODE is a good library, but much tweaking is required to get a good feel, as well as to get good speed.

blackgun

21-07-2007 02:24:01

@andy, just as saluk said, i want to make a game with Python OGRE, but i am not sure choose which physics system.

Thanks saluk and andy.

actually , i am a little dispointed after the above test. but saluk give me a light. thank you. i need to learn more about ODE. but most ODE guys talk about ODE but not PyODE, so i don't know this is pyode's performance or ODE's? i change to "world.quickstep", it runs much faster, 200 ones pile is ok. maybe 3-4 times faster than "world.step".

If novodex is free, should i use novodex instead of ode for my game?

bharling

21-07-2007 10:02:32

I started off by using OgreNewt, I dont know why really, but I can say that I have no performance issues that I have noticed, framerates are consistently good if you keep the physics scene within reason. Am I right in thinking ODE has a larger feature set though?

blackgun

22-07-2007 00:02:26

I think all physics systems have the basic rigid body features. because i am doing ragdoll, besides those, I need these,

1) joint motor
2) joint limits
3) linear damp and angel damp

I am not sure bullet and newton has them

bharling

22-07-2007 11:55:14

I think newton has all those, (not sure about damping - linear friction can be done with newton materials). I'm using joint limits in the procedural demo. You're right about there being no motors as such, but you could use a custom force callback to make your own. There do seem to be motors in the newton SDK though. Only trouble is that you have to credit newton physics a lot (on packaging etc) if you decide to use it commercially