# HG changeset patch # User Robert McIntyre # Date 1325691402 25200 # Node ID 1f84f425e05d3a6481d0d6198a8626c7bed338dc # Parent 5e75b616ca60c867c32f49b2ab6edb4dee280bc5 first draft of automatic constraints from blender diff -r 5e75b616ca60 -r 1f84f425e05d assets/Models/creature1/one.blend Binary file assets/Models/creature1/one.blend has changed diff -r 5e75b616ca60 -r 1f84f425e05d assets/Models/creature1/try-again.blend Binary file assets/Models/creature1/try-again.blend has changed diff -r 5e75b616ca60 -r 1f84f425e05d org/test-creature.org --- a/org/test-creature.org Wed Dec 28 23:12:32 2011 -0700 +++ b/org/test-creature.org Wed Jan 04 08:36:42 2012 -0700 @@ -66,8 +66,6 @@ (.findValue data key) nil)) -(defn hand2 [] - (load-blender-model "Models/creature1/try-again.blend")) (defn hand [] (load-blender-model "Models/creature1/one.blend")) @@ -100,55 +98,450 @@ (map #(.getWorldTranslation %) (filter #(re-matches #"joint\.\d\d\d" (.getName %)) (node-seq (hand))))) +(defn worm [] + (load-blender-model "Models/creature1/try-again.blend")) + (defn worm-pieces [] (filter (comp #{"worm-2" "worm-1"} #(apply str (drop-last (.getName %)))) - (node-seq (hand2)))) + (node-seq (worm)))) (defn worm-joints [] - [Vector3f/ZERO]) + (filter #(re-matches #"joint\.\d\d\d" (.getName %)) + (node-seq (worm)))) +(defn bullet-trans [] + (let [obj-a (sphere 0.5 :color ColorRGBA/Red + :position (Vector3f. -10 5 0)) + obj-b (sphere 0.5 :color ColorRGBA/Blue + :position (Vector3f. -10 -5 0) + :mass 0) + control-a (.getControl obj-a RigidBodyControl) + control-b (.getControl obj-b RigidBodyControl) + swivel + (.toRotationMatrix + (doto (Quaternion.) + (.fromAngleAxis (/ Math/PI 2) + Vector3f/UNIT_X)))] + (doto + (ConeJoint. + control-a control-b + (Vector3f. 0 5 0) + (Vector3f. 0 -5 0) + swivel swivel) + (.setLimit (* 0.6 (/ Math/PI 4)) + (/ Math/PI 4) + (* Math/PI 0.8))) + (world (nodify + [obj-a obj-b]) + standard-debug-controls + enable-debug + no-op))) -(defn find-joint - [#^Node parts #^Vector3f joint-position] +(defn bullet-trans* [] + (let [obj-a (box 1.5 0.5 0.5 :color ColorRGBA/Red + :position (Vector3f. 5 0 0) + :mass 90) + obj-b (sphere 0.5 :color ColorRGBA/Blue + :position (Vector3f. -5 0 0) + :mass 0) + control-a (.getControl obj-a RigidBodyControl) + control-b (.getControl obj-b RigidBodyControl) + move-up? (atom nil) + move-down? (atom nil) + move-left? (atom nil) + move-right? (atom nil) + roll-left? (atom nil) + roll-right? (atom nil) + force 100 + swivel + (.toRotationMatrix + (doto (Quaternion.) + (.fromAngleAxis (/ Math/PI 2) + Vector3f/UNIT_X))) + x-move + (doto (Matrix3f.) + (.fromStartEndVectors Vector3f/UNIT_X + (.normalize (Vector3f. 1 1 0)))) + + timer (atom 0)] + (doto + (ConeJoint. + control-a control-b + (Vector3f. -8 0 0) + (Vector3f. 2 0 0) + ;;swivel swivel + ;;Matrix3f/IDENTITY Matrix3f/IDENTITY + x-move Matrix3f/IDENTITY + ) + (.setCollisionBetweenLinkedBodys false) + (.setLimit (* 1 (/ Math/PI 4)) ;; twist + (* 1 (/ Math/PI 4)) ;; swing span in X-Y plane + (* 0 (/ Math/PI 4)))) ;; swing span in Y-Z plane + (world (nodify + [obj-a obj-b]) + (merge standard-debug-controls + {"key-r" (fn [_ pressed?] (reset! move-up? pressed?)) + "key-t" (fn [_ pressed?] (reset! move-down? pressed?)) + "key-f" (fn [_ pressed?] (reset! move-left? pressed?)) + "key-g" (fn [_ pressed?] (reset! move-right? pressed?)) + "key-v" (fn [_ pressed?] (reset! roll-left? pressed?)) + "key-b" (fn [_ pressed?] (reset! roll-right? pressed?))}) + + (fn [world] + (enable-debug world) + (set-gravity world Vector3f/ZERO) + ) + + (fn [world _] + + (if @move-up? + (.applyForce control-a + (Vector3f. force 0 0) + (Vector3f. 0 0 0))) + (if @move-down? + (.applyForce control-a + (Vector3f. (- force) 0 0) + (Vector3f. 0 0 0))) + (if @move-left? + (.applyForce control-a + (Vector3f. 0 force 0) + (Vector3f. 0 0 0))) + (if @move-right? + (.applyForce control-a + (Vector3f. 0 (- force) 0) + (Vector3f. 0 0 0))) + + (if @roll-left? + (.applyForce control-a + (Vector3f. 0 0 force) + (Vector3f. 0 0 0))) + (if @roll-right? + (.applyForce control-a + (Vector3f. 0 0 (- force)) + (Vector3f. 0 0 0))) + + (if (zero? (rem (swap! timer inc) 100)) + (.attachChild + (.getRootNode world) + (sphere 0.05 :color ColorRGBA/Yellow + :physical? false :position + (.getWorldTranslation obj-a))))) + ) + )) + + + + + + + + + + + +(defn world-setup [joint] + (let [top (doto + (sphere 0.1 :physical? false :color ColorRGBA/Yellow + :position (Vector3f. 0 7 0)) + (.addControl + (RigidBodyControl. + (CapsuleCollisionShape. 0.5 1.5 1) (float 15)))) + bottom (doto + (sphere 0.1 :physical? false :color ColorRGBA/DarkGray + :position (Vector3f. 0 -1 0)) + (.addControl + (RigidBodyControl. + (CapsuleCollisionShape. 0.5 1.5 1) (float 0)))) + table (box 10 2 10 :position (Vector3f. 0 -6 0) + :color ColorRGBA/Gray :mass 0) + a (.getControl top RigidBodyControl) + b (.getControl bottom RigidBodyControl)] + (cond + (= joint :point) + (doto + (Point2PointJoint. a b + (Vector3f. 0 -2 0) + (Vector3f. 0 2 0)) + (.setCollisionBetweenLinkedBodys false)) + (= joint :hinge) + (doto + (HingeJoint. + a b + (Vector3f. 0 -2 0) + (Vector3f. 0 2 0) + (Vector3f. 0 0 1) + (Vector3f. 0 0 1) + + ) + (.setCollisionBetweenLinkedBodys false) + ;;(.setLimit (- Math/PI) Math/PI) + ) + (= joint :cone) + ;; note to self -- jbullet does NOT implement cone joints + ;; correctly. You must use plain ol' bullet for this to work. + ;; It's faster anyway, so whatever. + + (doto (ConeJoint. + a b + (Vector3f. 0 -5 0) + (Vector3f. 0 2 0) + + (doto (Matrix3f.) + (.fromStartEndVectors Vector3f/UNIT_X + Vector3f/UNIT_Y)) + (doto (Matrix3f.) + (.fromStartEndVectors Vector3f/UNIT_X + Vector3f/UNIT_Y)) + ) + ;;(.setAngularOnly true) + + (.setCollisionBetweenLinkedBodys false) + (.setLimit (* 1 (/ Math/PI 4)) + (* 1 (/ Math/PI 4)) + (* 0 (/ Math/PI 4))) + + ) + (= joint :six) + (doto + (SixDofJoint. + a b + (Vector3f. 0 -2 0) + (Vector3f. 0 2 0) + ;;(doto (Matrix3f.) + ;; (.fromStartEndVectors Vector3f/UNIT_X + ;; Vector3f/UNIT_Y)) + ;;(doto (Matrix3f.) + ;; (.fromStartEndVectors Vector3f/UNIT_X + ;; Vector3f/UNIT_Y)) + true) + (.setCollisionBetweenLinkedBodys false) + (.setAngularLowerLimit (Vector3f. 0 + (- (/ Math/PI 2)) + 0)) + + (.setAngularUpperLimit (Vector3f. 0 + (/ Math/PI 2) + 0)) + (.setLinearLowerLimit (Vector3f. 0 0 0)) + (.setLinearUpperLimit (Vector3f. 0 0 0)) + + ) + + + + + + ) + + [top bottom table])) + +(defn speed-up [world] + (.setMoveSpeed (.getFlyByCamera world) + (float 100)) + (.setRotationSpeed (.getFlyByCamera world) + (float 20)) + world) + + +(defn test-joint [joint] + (let [[top bottom floor] (world-setup joint) + control (.getControl top RigidBodyControl) + move-up? (atom false) + move-down? (atom false) + move-left? (atom false) + move-right? (atom false) + roll-left? (atom false) + roll-right? (atom false) + timer (atom 0)] + + (world + (nodify [top bottom floor]) + (merge standard-debug-controls + {"key-r" (fn [_ pressed?] (reset! move-up? pressed?)) + "key-t" (fn [_ pressed?] (reset! move-down? pressed?)) + "key-f" (fn [_ pressed?] (reset! move-left? pressed?)) + "key-g" (fn [_ pressed?] (reset! move-right? pressed?)) + "key-v" (fn [_ pressed?] (reset! roll-left? pressed?)) + "key-b" (fn [_ pressed?] (reset! roll-right? pressed?))}) + + (fn [world] + (light-up-everything world) + (enable-debug world) + (set-gravity world (Vector3f. 0 0 0)) + ) + + (fn [world _] + (if (zero? (rem (swap! timer inc) 100)) + (do + ;; (println-repl @timer) + (.attachChild (.getRootNode world) + (sphere 0.05 :color ColorRGBA/Yellow + :position (.getWorldTranslation top) + :physical? false)))) + (if @move-up? + (.applyTorque control + (.mult (.getPhysicsRotation control) + (Vector3f. 0 0 10)))) + (if @move-down? + (.applyTorque control + (.mult (.getPhysicsRotation control) + (Vector3f. 0 0 -10)))) + (if @move-left? + (.applyTorque control + (.mult (.getPhysicsRotation control) + (Vector3f. 0 10 0)))) + (if @move-right? + (.applyTorque control + (.mult (.getPhysicsRotation control) + (Vector3f. 0 -10 0)))) + (if @roll-left? + (.applyTorque control + (.mult (.getPhysicsRotation control) + (Vector3f. -1 0 0)))) + (if @roll-right? + (.applyTorque control + (.mult (.getPhysicsRotation control) + (Vector3f. 1 0 0)))))))) + + + +(defn run [joint] (.start (test-joint joint))) +(defn look [joint] (view (nodify (world-setup joint)))) + +(defn blender-to-jme + "Convert from Blender coordinates to JME coordinates" + [#^Vector3f in] + (Vector3f. (.getX in) + (.getZ in) + (- (.getY in)))) + + +(defn joint-targets + "Return the two closest two objects to the joint object, ordered + from bottom to top according to the joint's rotation." + [#^Node parts #^Node joint] + ;;(println (meta-data joint "joint")) + (.getWorldRotation joint) (loop [radius (float 0.01)] (let [results (CollisionResults.)] (.collideWith parts - (BoundingBox. joint-position radius radius radius) + (BoundingBox. (.getWorldTranslation joint) + radius radius radius) results) (let [targets (distinct (map #(.getGeometry %) results))] (if (>= (count targets) 2) - (take 2 targets) + (sort-by + #(.getY + (.mult + (.inverse (.getWorldRotation joint)) + (.subtract (.getWorldTranslation %) + (.getWorldTranslation joint)))) + (take 2 targets)) (recur (float (* radius 2)))))))) +(defn connect + "here are some examples: + {:type :point} + {:type :hinge :limit [0 (/ Math/PI 2)] :axis (Vector3f. 0 1 0)} + (:axis defaults to (Vector3f. 1 0 0) if not provided for hinge joints) + {:type :cone :limit-xz 0] + :limit-yz 0] + :twist 0]} +" + ([#^Node obj-a #^Node obj-b #^Node joint] + (let [center-a (.getWorldTranslation obj-a) + center-b (.getWorldTranslation obj-b) + joint-center (.getWorldTranslation joint) + pivot-a (.subtract joint-center center-a) + pivot-b (.subtract joint-center center-b) + control-a (.getControl obj-a RigidBodyControl) + control-b (.getControl obj-b RigidBodyControl)] + ;; A side-effect of creating a joint registers + ;; it with both physics objects which in turn + ;; will register the joint with the physics system + ;; when the simulation is started. + (if-let [constraints + (map-vals + eval + (read-string + (meta-data (first (worm-joints)) "joint")))] -(defn connect-at-point - [obj-a obj-b point] - (let [center-a (.getWorldTranslation obj-a) - center-b (.getWorldTranslation obj-b) - pivot-a (.subtract point center-a) - pivot-b (.subtract point center-b) - ;; A side-effect of creating a joint registers - ;; it with both physics objects which in turn - ;; will register the joint with the physics system - ;; when the simulation is started. - joint (Point2PointJoint. - (.getControl obj-a RigidBodyControl) - (.getControl obj-b RigidBodyControl) - pivot-a - pivot-b)] - obj-a)) + (let [joint-type (:type constraints)] + (cond (= :point joint-type) + (do + (println-repl "creating POINT joint") + (Point2PointJoint. + control-a + control-b + pivot-a + pivot-b)) + (= :hinge joint-type) + (do + (println-repl "creating HINGE joint") + (let [axis (if-let + [axis (:axis constraints)] + axis + Vector3f/UNIT_X) + [limit-1 limit-2] (:limit constraints) + hinge-axis + (.mult + (.getWorldRotation joint) + (blender-to-jme axis))] + (doto + (HingeJoint. + control-a + control-b + pivot-a + pivot-b + hinge-axis + hinge-axis) + (.setLimit limit-1 limit-2)))) + (= :cone joint-type) + (do + (let [limit-xy (:limit-xz constraints) + limit-yz (:limit-yz constraints) + twist (:twist constraints)] + + (println-repl "creating CONE joint") + (doto + (ConeJoint. + control-a + control-b + pivot-a + pivot-b + (doto (Matrix3f.) + (.fromStartEndVectors + Vector3f/UNIT_X + (.normalize + (.subtract (.getWorldTranslation joint) + (.getWorldTranslation obj-a))))) + (doto (Matrix3f.) + (.fromStartEndVectors + Vector3f/UNIT_X + (.normalize + (.subtract + (.getWorldTranslation obj-b) + (.getWorldTranslation joint)))))) + (.setLimit (float limit-xy) + (float limit-yz) + (float twist))))) + true + (println-repl + "joint-type " joint-type " not recognized"))) + + (println-repl "could not find joint meta-data!"))))) + -(defn physical-hand [#^Node pieces joints] - ;; Make each piece a physical entity in the simulation. +(defn physical-worm [#^Node pieces joints] (dorun (map (fn [geom] @@ -156,44 +549,48 @@ (RigidBodyControl. (HullCollisionShape. (.getMesh geom)) - ;; TODO: fix this. - (float 1.0))] + (if-let [mass (meta-data geom "mass")] + (do + (println-repl + "setting mass to " (float mass)) + (float mass)) + (float 1)))] + (.addControl geom physics-control))) (filter #(isa? (class %) Geometry ) (node-seq pieces)))) + (dorun (map - (fn [joint-position] - (let [[geom-a geom-b] (find-joint pieces joint-position)] - (connect-at-point geom-a geom-b joint-position))) - joints)) - pieces) + (fn [joint] + (let [[obj-a obj-b] + (joint-targets pieces joint)] + (connect obj-a obj-b joint))) + joints)) + pieces) +(defn the-worm [] + (physical-worm (worm) (worm-joints))) -(defn the-hand! [] (physical-hand (hand) (hand-joints))) - - -(defn test-hand [] +(defn test-worm [] (world - (nodify [(the-hand!) - (box 10 1 10 :position (Vector3f. 0 -10 0) - :color ColorRGBA/Gray - :mass 0)]) + (nodify [(the-worm) + (box 10 2 10 :position (Vector3f. 0 -5 0) + :color ColorRGBA/Gray :mass 0)]) standard-debug-controls - enable-debug - (fn [_ _] - (Thread/sleep 100)))) - - - - - - + (comp light-up-everything enable-debug + (fn [world] + (.setTimer world (NanoTimer.)) + (speed-up world) + ;;(set-gravity world (Vector3f. 0 0 0)) + world + )) + no-op)) #+end_src #+results: body-1 -: #'cortex.silly/test-hand +: #'cortex.silly/test-try-again