Mercurial > cortex
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