changeset 83:14b604e955ed

still testing joints... Dylan is helping
author Robert McIntyre <rlm@mit.edu>
date Sat, 07 Jan 2012 00:58:47 -0700
parents 6b4ca076285e
children 4f5e2c629e45
files assets/Models/creature1/one.blend org/cone-joints.txt org/test-creature.org
diffstat 3 files changed, 293 insertions(+), 105 deletions(-) [+]
line wrap: on
line diff
     1.1 Binary file assets/Models/creature1/one.blend has changed
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/org/cone-joints.txt	Sat Jan 07 00:58:47 2012 -0700
     2.3 @@ -0,0 +1,127 @@
     2.4 +
     2.5 +
     2.6 +
     2.7 +
     2.8 +(ConeJoint
     2.9 +	RigidBody A
    2.10 +	RigidBody B
    2.11 +	Vector3f PivotA
    2.12 +	Vector3f PivotB
    2.13 +	Matrix3f RotA
    2.14 +	Matrix3f RotB
    2.15 +)
    2.16 +
    2.17 +Parameters:
    2.18 +
    2.19 +The specification of a cone joint depends on local coordinates,
    2.20 +that is coordinates relative to the given rigid bodies.
    2.21 +
    2.22 +***
    2.23 +DIGRESSION ABOUT LOCAL COORDINATES
    2.24 +
    2.25 +Each rigid body has its own coordinate system.
    2.26 +If an object is placed, unrotated, at the origin of the world,
    2.27 +then its coordinate system is the same as the world's coordinate
    2.28 +system. In other words, the origin of the object coincides with the
    2.29 +origin of the world, and the XYZ axes of the object coincide with the
    2.30 +XYZ axes of the world.
    2.31 +
    2.32 +When you translate the object, its "origin" goes with it.
    2.33 +The origin of the object is always the center of the object.
    2.34 +
    2.35 +When you rotate the object, its axes go with it.
    2.36 +For example, if you rotate the object pi/2 radians righthandedly
    2.37 +about the Z axis, its own X axis will move to coincide with the
    2.38 +world's Y axis; its own Y axis will move to coincide with the
    2.39 +world's -X axis; its Z axis will remain aligned with the world's
    2.40 +Z-axis.
    2.41 +
    2.42 +
    2.43 +In such a way, you can see the way in which the translations and rotations of an
    2.44 +object alter its local coordinates.
    2.45 +
    2.46 +
    2.47 +## a haphazard elaboration of the above
    2.48 +
    2.49 +Converting from world coordinates to local coordinates amounts to
    2.50 +finding the transformation that undoes all the rotations and
    2.51 +translations that the Object has suffered, then applying that
    2.52 +undoing-transformation to the world coordinates.
    2.53 +
    2.54 +            +position of obj   +rot of obj
    2.55 +world axes  ---------------> x -----------> obj axes
    2.56 +
    2.57 +
    2.58 +1. Start with the world coordinates of the Object and a test-object.
    2.59 +2. Subtract the world coordinates of the Object from each. Now the
    2.60 +Object is at the origin (though still has its rotation, if any) and
    2.61 +the test-object is somewhere else (irrelevant).
    2.62 +3. Rotate the whole world about the origin so that the Object becomes
    2.63 +unrotated. Now the object is unrotated at the origin, and the
    2.64 +test-object is somewhere else.
    2.65 +4. That somewhere-else is the coordinates of the test-object as seen
    2.66 +from the Object's own coordinate system (the system in which the Object is always
    2.67 +unrotated and centered at the origin)
    2.68 +
    2.69 +cf: get-subjective-rotation
    2.70 +cf: get-subjective-position
    2.71 +
    2.72 +***
    2.73 +
    2.74 +
    2.75 +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
    2.76 +
    2.77 +Now, to understand the ConeJoint constructor: 
    2.78 +Suppose you have the position of the cone joint picked out, as well as its
    2.79 +orientation (orientation aka rotation matters because the limits of
    2.80 +rotation are taken with respect to the xy and xz plane of the _joint's_
    2.81 +coordinate system. This is what the documentation means by "by
    2.82 +default, the x-axis").
    2.83 +
    2.84 +Then: 
    2.85 +Pivot-a is the position of the joint, as expressed in the coordinate
    2.86 +system of object-a.
    2.87 +Pivot-a is the position of the joint again, this time as expressed in
    2.88 +the coordinate system of object-b.
    2.89 +
    2.90 +(Use get-subjective-position to calculate this conveniently)
    2.91 +
    2.92 +
    2.93 +Rot-a is the orientation of the joint, as expressed in the
    2.94 +coordinate system of object-a. By default, it is aligned with a's
    2.95 +coordinate system, making the cone's axis along a's x-axis, and its
    2.96 +limits of rotation in a's xy and xz planes.
    2.97 +
    2.98 +Analogously for b.
    2.99 +
   2.100 +If inconsistent pivot locations are given, it's possible to recover by
   2.101 +moving the objects. I think the engine prefers to keep object b still
   2.102 +and move everything else, but it may not always be so.
   2.103 +
   2.104 +If inconsistent rotations are given ... I don't know what
   2.105 +happens. Beez happens.
   2.106 +
   2.107 +
   2.108 +Modulo a bunch of forced object migration because your pivots give
   2.109 +inconsistent indicators of where the joint should be expected, etc., this is
   2.110 +how the method works.
   2.111 +
   2.112 +
   2.113 +
   2.114 +# Another implementation option would have been to specify the positions and
   2.115 +# rotations of THREE things --- object A, object B, and the joint --- all in terms of world
   2.116 +# coordinates. This wouldn't be any more or less fragile (i.e. subject to explosions
   2.117 +# of inconsistency) but it might be nice to avoid those
   2.118 +# transformations into local coordinates, even if we had to introduce
   2.119 +# more parameters into such a new method
   2.120 +# (specifically, the position and orientation of the joint would be new).
   2.121 +
   2.122 +# I wouldn't mind because after all, don't we already  need to keep in mind the position and orientation of the
   2.123 +# joint in the existing method? Lest it explode in inconsistency? I
   2.124 +# suggest we create a clojure method that creates cone joints in the
   2.125 +# transformation-free way.
   2.126 +# cf. joint-create, my first attempt
   2.127 +
   2.128 +
   2.129 +
   2.130 +
     3.1 --- a/org/test-creature.org	Fri Jan 06 02:03:43 2012 -0700
     3.2 +++ b/org/test-creature.org	Sat Jan 07 00:58:47 2012 -0700
     3.3 @@ -50,6 +50,11 @@
     3.4  
     3.5  (rlm.rlm-commands/help)
     3.6  
     3.7 +(declare joint-create get-subjective-position)
     3.8 +
     3.9 +(defn load-bullet []
    3.10 +  (.start (world (Node.) {} no-op no-op)))
    3.11 +
    3.12  (defn load-blender-model
    3.13    "Load a .blend file using an asset folder relative path."
    3.14    [^String model]
    3.15 @@ -179,14 +184,19 @@
    3.16                             (.fromAngleAxis
    3.17                              (float
    3.18                               (.angleBetween
    3.19 -                              pivot-a Vector3f/UNIT_X))
    3.20 -                            (.cross (.normalize pivot-a)
    3.21 -                                    Vector3f/UNIT_X))))
    3.22 -                        ]
    3.23 +                              (.normalize pivot-a) Vector3f/UNIT_X))
    3.24 +                            (.normalize
    3.25 +                             (.cross pivot-a
    3.26 +                                     Vector3f/UNIT_X)))))
    3.27 +                         ]
    3.28 +                    (println-repl "pivot-a" pivot-a)
    3.29                      (println-repl
    3.30 -                     "angle between pivot-a (" pivot-a ") and UNIT_X is"
    3.31 +                     "angle between pivot-a and UNIT_X is"
    3.32                       (.angleBetween Vector3f/UNIT_X (.normalize pivot-a)))
    3.33 -                    
    3.34 +                    (println-repl "frame-a:" frame-a)
    3.35 +                    (println-repl
    3.36 +                     "frame-a moves Vector3f/UNIT_X to"
    3.37 +                     (.mult frame-a Vector3f/UNIT_X ))
    3.38                      
    3.39                      
    3.40                      (doto
    3.41 @@ -197,22 +207,22 @@
    3.42                           pivot-b
    3.43  
    3.44                          
    3.45 -                         ;; ;; frame-in-A
    3.46 -                         frame-a
    3.47 -                         frame-a
    3.48 +                         ;; frame-in-A
    3.49 +                         ;;frame-a
    3.50 +                         ;;frame-a
    3.51                           
    3.52 -                         ;; (.toRotationMatrix
    3.53 -                         ;;  (doto (Quaternion.)
    3.54 -                         ;;    (.fromAngles
    3.55 -                         ;;     0 0 (* -1 (/ Math/PI 2)))))
    3.56 -
    3.57 +                         (.toRotationMatrix
    3.58 +                          (doto (Quaternion.)
    3.59 +                            (.fromAngles
    3.60 +                             0 0 (* -0.5 (/ Math/PI 2)))))
    3.61                           
    3.62 -                         ;; ;; frame-in-B
    3.63 -                         ;; (.toRotationMatrix
    3.64 -                         ;;  (doto (Quaternion.)
    3.65 -                         ;;    (.fromAngles
    3.66 -                         ;;     0 0 (* -1.2 (/ Math/PI 2)))))
    3.67 -
    3.68 +                         
    3.69 +                         ;; frame-in-B
    3.70 +                         (.toRotationMatrix
    3.71 +                          (doto (Quaternion.)
    3.72 +                            (.fromAngles
    3.73 +                             0 0 (* -0.5 (/ Math/PI 2)))))
    3.74 +                         
    3.75  
    3.76                           )
    3.77                        (.setLimit (float limit-xz)
    3.78 @@ -224,6 +234,7 @@
    3.79        
    3.80        (println-repl "could not find joint meta-data!"))))
    3.81  
    3.82 +
    3.83  (defn assemble-creature [#^Node pieces joints]
    3.84    (dorun
    3.85     (map
    3.86 @@ -296,105 +307,63 @@
    3.87     no-op)))
    3.88  
    3.89  (defn world-setup [joint]
    3.90 -  (let [top (doto
    3.91 +  (let [
    3.92 +
    3.93 +        joint-position (Vector3f. 0 4 0)
    3.94 +        joint-rotation
    3.95 +        (.toRotationMatrix
    3.96 +         (.mult
    3.97 +          (doto (Quaternion.)
    3.98 +            (.fromAngleAxis
    3.99 +             (* 1 (/ Math/PI 4))
   3.100 +             (Vector3f. -1 0 0)))
   3.101 +          (doto (Quaternion.)
   3.102 +            (.fromAngleAxis
   3.103 +             (/ Math/PI 2)
   3.104 +             (Vector3f. 0 0 1)))))
   3.105 +        
   3.106 +        origin (doto
   3.107 +                   (sphere 0.1 :physical? false :color ColorRGBA/Cyan
   3.108 +                           :position (Vector3f. 0 0 0)))
   3.109 +        top (doto
   3.110                  (sphere 0.1 :physical? false :color ColorRGBA/Yellow
   3.111 -                        :position (Vector3f. 0 7 0))
   3.112 +                        :position (.mult joint-rotation (Vector3f. 8 0 0)))
   3.113 +
   3.114                (.addControl
   3.115                 (RigidBodyControl.
   3.116 -                (CapsuleCollisionShape. 0.5 1.5 1) (float 15))))
   3.117 +                (CapsuleCollisionShape. 0.5 1.5 1) (float 20))))
   3.118          bottom (doto
   3.119                     (sphere 0.1 :physical? false :color ColorRGBA/DarkGray
   3.120 -                           :position (Vector3f. 0 -1 0))
   3.121 -              (.addControl
   3.122 +                           :position (Vector3f. 0 0 0))
   3.123 +                 (.addControl
   3.124                 (RigidBodyControl.
   3.125                  (CapsuleCollisionShape. 0.5 1.5 1) (float 0))))
   3.126 -        table (box 10 2 10 :position (Vector3f. 0 -6 0)
   3.127 +        table (box 10 2 10 :position (Vector3f. 0 -20 0)
   3.128                     :color ColorRGBA/Gray :mass 0)
   3.129          a (.getControl top RigidBodyControl)
   3.130          b (.getControl bottom RigidBodyControl)]
   3.131 +
   3.132      (cond
   3.133 -     (= joint :point)
   3.134 -     (doto
   3.135 -         (Point2PointJoint. a b
   3.136 -                            (Vector3f. 0 -2 0)
   3.137 -                            (Vector3f. 0  2 0))
   3.138 -       (.setCollisionBetweenLinkedBodys false))
   3.139 -     (= joint :hinge)
   3.140 -     (doto
   3.141 -         (HingeJoint.
   3.142 -          a b
   3.143 -          (Vector3f. 0 -2 0)
   3.144 -          (Vector3f. 0 2 0)
   3.145 -          (Vector3f. 0 0 1)
   3.146 -          (Vector3f. 0 0 1)
   3.147 +     (= joint :cone)
   3.148 +     
   3.149 +       (doto (ConeJoint.
   3.150 +              a b
   3.151 +              (get-subjective-position joint-position top)
   3.152 +              (get-subjective-position joint-position bottom)
   3.153 +              joint-rotation
   3.154 +              joint-rotation
   3.155 +              )
   3.156  
   3.157 -          )
   3.158 -       (.setCollisionBetweenLinkedBodys false)
   3.159 -       ;;(.setLimit (- Math/PI) Math/PI)
   3.160 -       )
   3.161 -     (= joint :cone)
   3.162 -     ;; note to self -- jbullet does NOT implement cone joints
   3.163 -     ;; correctly. You must use plain ol' bullet for this to work.
   3.164 -     ;; It's faster anyway, so whatever.
   3.165 -     
   3.166 -     (doto (ConeJoint.
   3.167 -            a b
   3.168 -            (Vector3f. 0 -5 0)
   3.169 -            (Vector3f. 0 2 0)
   3.170 -
   3.171 -            (doto (Matrix3f.)
   3.172 -              (.fromStartEndVectors Vector3f/UNIT_X
   3.173 -                                    Vector3f/UNIT_Y))
   3.174 -            (doto (Matrix3f.)
   3.175 -              (.fromStartEndVectors Vector3f/UNIT_X
   3.176 -                                    (.normalize
   3.177 -                                     (Vector3f. 0 0 -1))))
   3.178 -            )
   3.179 -       ;;(.setAngularOnly true)
   3.180 -       
   3.181 -       (.setCollisionBetweenLinkedBodys false)
   3.182 -       (.setLimit (* 1 (/ Math/PI 4))
   3.183 -                  (* 1 (/ Math/PI 2))
   3.184 -                  (* 0 (/ Math/PI 4)))
   3.185 -        
   3.186 -       )
   3.187 -     (= joint :six)
   3.188 -     (doto
   3.189 -         (SixDofJoint.
   3.190 -          a b
   3.191 -          (Vector3f. 0 -2 0)
   3.192 -          (Vector3f. 0 2 0)
   3.193 -          ;;(doto (Matrix3f.)
   3.194 -          ;;    (.fromStartEndVectors Vector3f/UNIT_X
   3.195 -          ;;                          Vector3f/UNIT_Y))
   3.196 -          ;;(doto (Matrix3f.)
   3.197 -          ;;  (.fromStartEndVectors Vector3f/UNIT_X
   3.198 -          ;;                        Vector3f/UNIT_Y))
   3.199 -          true)
   3.200 -       (.setCollisionBetweenLinkedBodys false)
   3.201 -       (.setAngularLowerLimit (Vector3f. 0
   3.202 -                                         (- (/ Math/PI 2))
   3.203 -                                         0))
   3.204 -                                         
   3.205 -       (.setAngularUpperLimit (Vector3f. 0
   3.206 -                                         (/ Math/PI 2)
   3.207 -                                         0))
   3.208 -       (.setLinearLowerLimit  (Vector3f. 0 0 0))
   3.209 -       (.setLinearUpperLimit  (Vector3f. 0 0 0))
   3.210 -
   3.211 -       )
   3.212 -          
   3.213 +              
   3.214 +         (.setLimit (* (/ 10) Math/PI)
   3.215 +                    (* (/ 4)  Math/PI)
   3.216 +                    0)))
   3.217 +  [origin top bottom table]))
   3.218              
   3.219 -            
   3.220 -          
   3.221 -     
   3.222 -    )
   3.223 -      
   3.224 -    [top bottom table]))
   3.225  
   3.226  
   3.227  (defn test-joint [joint]
   3.228 -  (let [[top bottom floor] (world-setup joint)
   3.229 +  (let [[origin top bottom floor] (world-setup joint)
   3.230          control (.getControl top RigidBodyControl)
   3.231          move-up? (atom false)
   3.232          move-down? (atom false)
   3.233 @@ -405,7 +374,7 @@
   3.234          timer (atom 0)]
   3.235  
   3.236      (world
   3.237 -     (nodify [top bottom floor])
   3.238 +     (nodify [top bottom floor origin])
   3.239       (merge standard-debug-controls
   3.240              {"key-r" (fn [_ pressed?] (reset! move-up? pressed?))
   3.241               "key-t" (fn [_ pressed?] (reset! move-down? pressed?))
   3.242 @@ -427,7 +396,12 @@
   3.243             (.attachChild (.getRootNode world)
   3.244                         (sphere 0.05 :color ColorRGBA/Yellow
   3.245                                 :position (.getWorldTranslation top)
   3.246 -                               :physical? false))))
   3.247 +                               :physical? false))
   3.248 +           (.attachChild (.getRootNode world)
   3.249 +                         (sphere 0.05 :color ColorRGBA/LightGray
   3.250 +                                 :position (.getWorldTranslation bottom)
   3.251 +                                 :physical? false))))
   3.252 +
   3.253         (if @move-up?
   3.254           (.applyTorque control
   3.255                         (.mult (.getPhysicsRotation control)
   3.256 @@ -452,6 +426,93 @@
   3.257           (.applyTorque control
   3.258                         (.mult (.getPhysicsRotation control)
   3.259                                (Vector3f. 1 0 0))))))))
   3.260 +
   3.261 +
   3.262 +
   3.263 +
   3.264 +
   3.265 +
   3.266 +
   3.267 +
   3.268 +
   3.269 +
   3.270 +
   3.271 +
   3.272 +
   3.273 +;; please validate these.
   3.274 +
   3.275 +(defn get-subjective-position
   3.276 +   "Convert the world coordinates into coordinates relative to
   3.277 +   object (i.e. local coordinates), taking into account the rotation
   3.278 +   of object."
   3.279 +   [#^Vector3f world-coordinates object]
   3.280 +   ;; I don't know if it's important to take into account the rotation
   3.281 +   ;; of the object. If it isn't, then remove the multiplication-by-inverse.
   3.282 +   (.mult (.inverse (.getWorldRotation object))
   3.283 +          (.subtract world-coordinates (.getWorldTranslation object))))
   3.284 +   
   3.285 +
   3.286 +(defn get-subjective-rotation
   3.287 +  "cf get-subjective-position. Converts a rotation specified relative
   3.288 +to the world's axes into a rotation specified in terms of the object's
   3.289 +  coordinate system."
   3.290 +  [#^Quaternion world-rotation object]
   3.291 +  (.mult (.inverse (.getWorldRotation object)) world-rotation))
   3.292 +
   3.293 +
   3.294 +
   3.295 +
   3.296 +(defn joint-create "Connect objects 1 and 2 using a joint constraint. If
   3.297 +  only position is specified, creates a point-to-point joint at the
   3.298 +  given location
   3.299 +  in world coordinates. etc. etc. for other joints.
   3.300 +To ensure consistency, I may alter this function
   3.301 +  so that it moves obj-1 to be at the apex of the cone.
   3.302 +
   3.303 +  NOTE:
   3.304 +  In the usual construction method, you create a joint and, if your
   3.305 +  contraints are consistent, all the objects snap into position and
   3.306 +  orientation around it, otherwise the systen explodes.
   3.307 +
   3.308 +  This construction method assumes that you have in mind a position and
   3.309 +  rotation for the joint, and that you have already put your objects
   3.310 +  at the required distances from that joint so that no snapping needs
   3.311 +  to occur. The radial distances ('pivot lengths') are therefore just set to be
   3.312 +  the pre-existing distances between the objects and the joint." 
   3.313 +  [#^Node obj-1
   3.314 +   #^Node obj-2
   3.315 +   #^Vector3f joint-position
   3.316 +   #^Quaternion joint-rotation
   3.317 +   span-1
   3.318 +   span-2
   3.319 +   twist
   3.320 +   ]
   3.321 +
   3.322 +  (let
   3.323 +      [body-1 (.getControl obj-1 RigidBodyControl)
   3.324 +       body-2 (.getControl obj-2 RigidBodyControl)
   3.325 +       ]
   3.326 +    (doto (ConeJoint.
   3.327 +           body-1
   3.328 +           body-2
   3.329 +           (get-subjective-position joint-position body-1)
   3.330 +           (get-subjective-position joint-position body-2)
   3.331 +           ;; ALIGN X-AXIS OF OBJECT-1 WITH THE CENTRAL AXIS OF THE CONE TO
   3.332 +           ;;LOWER THE RISK OF INCONSISTENCY
   3.333 +           ;;(Matrix3f/IDENTITY)
   3.334 +           (.toRotationMatrix (get-subjective-rotation joint-rotation body-1))
   3.335 +           (.toRotationMatrix (get-subjective-rotation joint-rotation body-2))
   3.336 +           )
   3.337 +      (.setLimit
   3.338 +       span-1
   3.339 +       span-2
   3.340 +       twist))))
   3.341 +
   3.342 +
   3.343 +
   3.344 +
   3.345 +
   3.346 +
   3.347  #+end_src
   3.348  
   3.349