Basti's Scratchpad on the Internet

More Physics with Clojure, JBullet and Processing

Over the weekend, I was playing with the following snippet to get a feel for the JBullet library. JBullet is Java port of Bullet Physics Library. Their wiki contains a sample Hello World Application which covers everything about this snippet so I am not going to copy/paste it here, the only difference is that instead of dropping a sphere onto a surface, this example stacks some boxes on top of each other and shoots them with a sphere. You can grab JBullet from Clojars.

(ns ball.core
  (:use [incanter.core :only [view]])
  (:use [incanter.processing :exclude [box sphere]])
  (:import
   (javax.vecmath Vector3f Quat4f)
   (com.bulletphysics.dynamics DiscreteDynamicsWorld
			       RigidBodyConstructionInfo
			       RigidBody)
   (com.bulletphysics.collision.dispatch DefaultCollisionConfiguration
					 CollisionDispatcher)
   (com.bulletphysics.dynamics.constraintsolver
    SequentialImpulseConstraintSolver)
   (com.bulletphysics.collision.broadphase AxisSweep3)
   (com.bulletphysics.linearmath Transform DefaultMotionState)
   (com.bulletphysics.collision.shapes StaticPlaneShape
				       BoxShape
				       SphereShape)))

(defn world []
  (let [maxProxies 1024
	worldAabbMin (Vector3f. -10000 -10000 -10000)
	worldAabbMax (Vector3f.  10000  10000  10000)
	cc (DefaultCollisionConfiguration.)]
    (doto (DiscreteDynamicsWorld.
	   (CollisionDispatcher. cc)
	   (AxisSweep3. worldAabbMin worldAabbMax maxProxies)
	   (SequentialImpulseConstraintSolver.)
	   cc)
      (.setGravity (Vector3f. 0 60 0)))))

(defn surface [world]
  (let [shape (StaticPlaneShape. (Vector3f. 0 -1 0)  1)
	motion-state (DefaultMotionState.
		       (doto (Transform.)
			 (-> .origin (.set (Vector3f. 0 330 0)))
			 (.setRotation (Quat4f. 0 0 0 1))))
	construction-info (RigidBodyConstructionInfo.
			   0 motion-state shape (Vector3f. 0 0 0))
	rigid-body (RigidBody. construction-info)]
    (.addRigidBody world rigid-body)
    rigid-body))

(defn box [world [x y]]
  (let [fall-mass 1
	fall-inertia (Vector3f. 10 0 0)
	shape (doto (BoxShape. (Vector3f. 3 30 15))
		(.calculateLocalInertia fall-mass fall-inertia))
	motion-state (DefaultMotionState.
		       (doto (Transform.)
			 (-> .origin (.set (Vector3f. x y 0)))
			 (.setRotation (Quat4f. 0 0 0 1))))
	construction-info (RigidBodyConstructionInfo.
			   fall-mass motion-state shape fall-inertia)
	rigid-body (RigidBody. construction-info)]
    (.addRigidBody world rigid-body)
    rigid-body))

(defn sphere [world [x y]]
  (let [fall-mass 1
	fall-inertia (Vector3f. 10 0 0)
	shape (doto (SphereShape. 10.0)
		(.calculateLocalInertia fall-mass fall-inertia))
	motion-state (DefaultMotionState.
		       (doto (Transform.)
			 (-> .origin (.set (Vector3f. x y 0)))
			 (.setRotation (Quat4f. 0 0 0 1))))
	construction-info (RigidBodyConstructionInfo.
			   fall-mass motion-state shape fall-inertia)
	rigid-body (RigidBody. construction-info)]
    (.addRigidBody world rigid-body)
    rigid-body))

(defn coords [body]
  (let [transform (Transform.)]
    (-> (.getMotionState body) (.getWorldTransform transform))
    [(-> transform .origin .x)
     (-> transform .origin .y)
     (-> transform .origin .z)
     (-> transform .basis .m00)
     (-> transform .basis .m01)
     (-> transform .basis .m02)
     (-> transform .basis .m10)
     (-> transform .basis .m11)
     (-> transform .basis .m12)
     (-> transform .basis .m20)
     (-> transform .basis .m21)
     (-> transform .basis .m22)]))

(defn draw-body [applet body]
  (let [[x y z m00 m01 m02 m10 m11 m12 m20 m21 m22] (coords body)]
    (doto applet
      (.pushMatrix)
      (.translate x y z)
      (.applyMatrix m00 m01 m02 0
		    m10 m11 m12 0
		    m20 m21 m22 0
		    0 0 0 1))
    (if (instance? BoxShape (.getCollisionShape body))
      (.box applet 6 60 30)
      (.sphere applet 10))
    (.popMatrix applet)))

(defn frame []
  (let [fps 24
	world (world)
	surface (surface world)
	bodies (ref (map #(box world %) (for [x (range 200 500 60)
					      y (range 300 1 -60.1)]
					  [x y])))]
    (sketch
     (setup []
	    (doto this
	      (size 640 400 processing.core.PConstants/P3D)
	      (.noStroke)
	      (framerate fps)
	      smooth))
     (draw []
	   (.stepSimulation world (/ 1 fps) 8)
	   (doto this
	     (.background 50)
	     (.lights))
	   (doseq [body @bodies] 
	     (draw-body this body)))
     (mousePressed [e]
		   (let [cords [(.mouseX this) (.mouseY this)]
			 sphere (sphere world cords)]
		     (.setLinearVelocity sphere (Vector3f. -2000 0 0))
		     (dosync (alter bodies conj sphere)))))))

;;(view (frame) :size [640 400])
Other posts
comments powered by Disqus