tutorial3.py 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284
  1. #!/usr/bin/env python
  2. # http://pyode.sourceforge.net/tutorials/tutorial3.html
  3. # pyODE example 3: Collision detection
  4. # Originally by Matthias Baas.
  5. # Updated by Pierre Gay to work without pygame or cgkit.
  6. import sys, os, random, time
  7. from math import *
  8. from OpenGL.GL import *
  9. from OpenGL.GLU import *
  10. from OpenGL.GLUT import *
  11. import ode
  12. # geometric utility functions
  13. def scalp (vec, scal):
  14. vec[0] *= scal
  15. vec[1] *= scal
  16. vec[2] *= scal
  17. def length (vec):
  18. return sqrt (vec[0]**2 + vec[1]**2 + vec[2]**2)
  19. # prepare_GL
  20. def prepare_GL():
  21. """Prepare drawing.
  22. """
  23. # Viewport
  24. glViewport(0,0,640,480)
  25. # Initialize
  26. glClearColor(0.8,0.8,0.9,0)
  27. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  28. glEnable(GL_DEPTH_TEST)
  29. glDisable(GL_LIGHTING)
  30. glEnable(GL_LIGHTING)
  31. glEnable(GL_NORMALIZE)
  32. glShadeModel(GL_FLAT)
  33. # Projection
  34. glMatrixMode(GL_PROJECTION)
  35. glLoadIdentity()
  36. gluPerspective (45,1.3333,0.2,20)
  37. # Initialize ModelView matrix
  38. glMatrixMode(GL_MODELVIEW)
  39. glLoadIdentity()
  40. # Light source
  41. glLightfv(GL_LIGHT0,GL_POSITION,[0,0,1,0])
  42. glLightfv(GL_LIGHT0,GL_DIFFUSE,[1,1,1,1])
  43. glLightfv(GL_LIGHT0,GL_SPECULAR,[1,1,1,1])
  44. glEnable(GL_LIGHT0)
  45. # View transformation
  46. gluLookAt (2.4, 3.6, 4.8, 0.5, 0.5, 0, 0, 1, 0)
  47. # draw_body
  48. def draw_body(body):
  49. """Draw an ODE body.
  50. """
  51. x,y,z = body.getPosition()
  52. R = body.getRotation()
  53. rot = [R[0], R[3], R[6], 0.,
  54. R[1], R[4], R[7], 0.,
  55. R[2], R[5], R[8], 0.,
  56. x, y, z, 1.0]
  57. glPushMatrix()
  58. glMultMatrixd(rot)
  59. if body.shape=="box":
  60. sx,sy,sz = body.boxsize
  61. glScalef(sx, sy, sz)
  62. glutSolidCube(1)
  63. glPopMatrix()
  64. # create_box
  65. def create_box(world, space, density, lx, ly, lz):
  66. """Create a box body and its corresponding geom."""
  67. # Create body
  68. body = ode.Body(world)
  69. M = ode.Mass()
  70. M.setBox(density, lx, ly, lz)
  71. body.setMass(M)
  72. # Set parameters for drawing the body
  73. body.shape = "box"
  74. body.boxsize = (lx, ly, lz)
  75. # Create a box geom for collision detection
  76. geom = ode.GeomBox(space, lengths=body.boxsize)
  77. geom.setBody(body)
  78. return body, geom
  79. # drop_object
  80. def drop_object():
  81. """Drop an object into the scene."""
  82. global bodies, geom, counter, objcount
  83. body, geom = create_box(world, space, 1000, 1.0,0.2,0.2)
  84. body.setPosition( (random.gauss(0,0.1),3.0,random.gauss(0,0.1)) )
  85. theta = random.uniform(0,2*pi)
  86. ct = cos (theta)
  87. st = sin (theta)
  88. body.setRotation([ct, 0., -st, 0., 1., 0., st, 0., ct])
  89. bodies.append(body)
  90. geoms.append(geom)
  91. counter=0
  92. objcount+=1
  93. # explosion
  94. def explosion():
  95. """Simulate an explosion.
  96. Every object is pushed away from the origin.
  97. The force is dependent on the objects distance from the origin.
  98. """
  99. global bodies
  100. for b in bodies:
  101. l=b.getPosition ()
  102. d = length (l)
  103. a = max(0, 40000*(1.0-0.2*d*d))
  104. l = [l[0] / 4, l[1], l[2] /4]
  105. scalp (l, a / length (l))
  106. b.addForce(l)
  107. # pull
  108. def pull():
  109. """Pull the objects back to the origin.
  110. Every object will be pulled back to the origin.
  111. Every couple of frames there'll be a thrust upwards so that
  112. the objects won't stick to the ground all the time.
  113. """
  114. global bodies, counter
  115. for b in bodies:
  116. l=list (b.getPosition ())
  117. scalp (l, -1000 / length (l))
  118. b.addForce(l)
  119. if counter%60==0:
  120. b.addForce((0,10000,0))
  121. # Collision callback
  122. def near_callback(args, geom1, geom2):
  123. """Callback function for the collide() method.
  124. This function checks if the given geoms do collide and
  125. creates contact joints if they do.
  126. """
  127. # Check if the objects do collide
  128. contacts = ode.collide(geom1, geom2)
  129. # Create contact joints
  130. world,contactgroup = args
  131. for c in contacts:
  132. c.setBounce(0.2)
  133. c.setMu(5000)
  134. j = ode.ContactJoint(world, contactgroup, c)
  135. j.attach(geom1.getBody(), geom2.getBody())
  136. ######################################################################
  137. # Initialize Glut
  138. glutInit ([])
  139. # Open a window
  140. glutInitDisplayMode (GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE)
  141. x = 0
  142. y = 0
  143. width = 640
  144. height = 480
  145. glutInitWindowPosition (x, y);
  146. glutInitWindowSize (width, height);
  147. glutCreateWindow ("testode")
  148. # Create a world object
  149. world = ode.World()
  150. world.setGravity( (0,-9.81,0) )
  151. world.setERP(0.8)
  152. world.setCFM(1E-5)
  153. # Create a space object
  154. space = ode.Space()
  155. # Create a plane geom which prevent the objects from falling forever
  156. floor = ode.GeomPlane(space, (0,1,0), 0)
  157. # A list with ODE bodies
  158. bodies = []
  159. # The geoms for each of the bodies
  160. geoms = []
  161. # A joint group for the contact joints that are generated whenever
  162. # two bodies collide
  163. contactgroup = ode.JointGroup()
  164. # Some variables used inside the simulation loop
  165. fps = 50
  166. dt = 1.0/fps
  167. running = True
  168. state = 0
  169. counter = 0
  170. objcount = 0
  171. lasttime = time.time()
  172. # keyboard callback
  173. def _keyfunc (c, x, y):
  174. sys.exit (0)
  175. glutKeyboardFunc (_keyfunc)
  176. # draw callback
  177. def _drawfunc ():
  178. # Draw the scene
  179. prepare_GL()
  180. for b in bodies:
  181. draw_body(b)
  182. glutSwapBuffers ()
  183. glutDisplayFunc (_drawfunc)
  184. # idle callback
  185. def _idlefunc ():
  186. global counter, state, lasttime
  187. t = dt - (time.time() - lasttime)
  188. if (t > 0):
  189. time.sleep(t)
  190. counter += 1
  191. if state==0:
  192. if counter==20:
  193. drop_object()
  194. if objcount==30:
  195. state=1
  196. counter=0
  197. # State 1: Explosion and pulling back the objects
  198. elif state==1:
  199. if counter==100:
  200. explosion()
  201. if counter>300:
  202. pull()
  203. if counter==500:
  204. counter=20
  205. glutPostRedisplay ()
  206. # Simulate
  207. n = 4
  208. for i in range(n):
  209. # Detect collisions and create contact joints
  210. space.collide((world,contactgroup), near_callback)
  211. # Simulation step
  212. world.step(dt/n)
  213. # Remove all contact joints
  214. contactgroup.empty()
  215. lasttime = time.time()
  216. glutIdleFunc (_idlefunc)
  217. glutMainLoop ()