Mercurial > cortex
changeset 466:da311eefbb09
finish body -- needs more work, but whatever.
author | Robert McIntyre <rlm@mit.edu> |
---|---|
date | Fri, 28 Mar 2014 13:16:37 -0400 |
parents | e4104ce9105c |
children | ade64947d2bf |
files | org/body.org thesis/cortex.org thesis/images/physical-hand.png |
diffstat | 3 files changed, 248 insertions(+), 12 deletions(-) [+] |
line wrap: on
line diff
1.1 --- a/org/body.org Fri Mar 28 11:08:32 2014 -0400 1.2 +++ b/org/body.org Fri Mar 28 13:16:37 2014 -0400 1.3 @@ -228,7 +228,7 @@ 1.4 functions must do three things to translate these into real joints: 1.5 1.6 - Find the children of the "joints" node. 1.7 - - Determine the two spatials the joint it meant to connect. 1.8 + - Determine the two spatials the joint is meant to connect. 1.9 - Create the joint based on the meta-data of the empty node. 1.10 1.11 ** Finding the Joints
2.1 --- a/thesis/cortex.org Fri Mar 28 11:08:32 2014 -0400 2.2 +++ b/thesis/cortex.org Fri Mar 28 13:16:37 2014 -0400 2.3 @@ -21,7 +21,7 @@ 2.4 #+caption: 2.5 #+name: name 2.6 #+ATTR_LaTeX: :width 10cm 2.7 - [[./images/Eve.jpg]] 2.8 + [[./images/aurellem-gray.png]] 2.9 2.10 2.11 2.12 @@ -530,16 +530,18 @@ 2.13 While trying to find a good compromise for body-design, one option 2.14 I ultimately rejected is to use blender's [[http://wiki.blender.org/index.php/Doc:2.6/Manual/Rigging/Armatures][armature]] system. The idea 2.15 would have been to define a mesh which describes the creature's 2.16 - entire body. To this you add an skeleton which deforms this 2.17 - mesh. This technique is used extensively to model humans and create 2.18 - realistic animations. It is hard to use for my purposes because it 2.19 - is difficult to update the creature's Physics Collision Mesh in 2.20 - tandem with its Geometric Mesh under the influence of the 2.21 - armature. Without this the creature will not be able to grab things 2.22 - in its environment, and it won't be able to tell where its physical 2.23 - body is by using its eyes. Also, armatures do not specify any 2.24 - rotational limits for a joint, making it hard to model elbows, 2.25 - shoulders, etc. 2.26 + entire body. To this you add a skeleton which deforms this mesh 2.27 + (called rigging). This technique is used extensively to model 2.28 + humans and create realistic animations. It is not a good technique 2.29 + for physical simulation, because deformable surfaces are hard to 2.30 + model. Humans work like a squishy bag with some hard bones to give 2.31 + it shape. The bones are easy to simulate physically, but they 2.32 + interact with thr world though the skin, which is contiguous, but 2.33 + does not have a constant shape. In order to simulate skin you need 2.34 + some way to continuously update the physical model of the skin 2.35 + along with the movement of the bones. Given that bullet is 2.36 + optimized for rigid, solid objects, this leads to unmanagable 2.37 + computation and incorrect simulation. 2.38 2.39 Instead of using the human-like ``deformable bag of bones'' 2.40 approach, I decided to base my body plans on multiple solid objects 2.41 @@ -586,14 +588,248 @@ 2.42 #+caption: node (highlighted in yellow) and its children which each 2.43 #+caption: represent a joint in the hand. Each joint node has metadata 2.44 #+caption: specifying what sort of joint it is. 2.45 + #+name: blender-hand 2.46 #+ATTR_LaTeX: :width 10cm 2.47 [[./images/hand-screenshot1.png]] 2.48 2.49 2.50 + =CORTEX= creates a creature in two steps: first, it traverses the 2.51 + nodes in the blender file and creates physical representations for 2.52 + any of them that have mass defined. 2.53 + 2.54 + #+caption: Program for iterating through the nodes in a blender file 2.55 + #+caption: and generating physical jMonkeyEngine3 objects with mass 2.56 + #+caption: and a matching physics shape. 2.57 + #+name: name 2.58 + #+begin_listing clojure 2.59 + #+begin_src clojure 2.60 +(defn physical! 2.61 + "Iterate through the nodes in creature and make them real physical 2.62 + objects in the simulation." 2.63 + [#^Node creature] 2.64 + (dorun 2.65 + (map 2.66 + (fn [geom] 2.67 + (let [physics-control 2.68 + (RigidBodyControl. 2.69 + (HullCollisionShape. 2.70 + (.getMesh geom)) 2.71 + (if-let [mass (meta-data geom "mass")] 2.72 + (float mass) (float 1)))] 2.73 + (.addControl geom physics-control))) 2.74 + (filter #(isa? (class %) Geometry ) 2.75 + (node-seq creature))))) 2.76 + #+end_src 2.77 + #+end_listing 2.78 2.79 + The next step to making a proper body is to connect those pieces 2.80 + together with joints. jMonkeyEngine has a large array of joints 2.81 + available via =bullet=, such as Point2Point, Cone, Hinge, and a 2.82 + generic Six Degree of Freedom joint, with or without spring 2.83 + restitution. =CORTEX='s procedure for binding the creature together 2.84 + with joints is as follows: 2.85 2.86 + - Find the children of the "joints" node. 2.87 + - Determine the two spatials the joint is meant to connect. 2.88 + - Create the joint based on the meta-data of the empty node. 2.89 + 2.90 + The higher order function =sense-nodes= from =cortex.sense= 2.91 + simplifies finding the joints based on their parent ``joints'' 2.92 + node. 2.93 + 2.94 + #+caption: Retrieving the children empty nodes from a single 2.95 + #+caption: named empty node is a common pattern in =CORTEX= 2.96 + #+caption: further instances of this technique for the senses 2.97 + #+caption: will be omitted 2.98 + #+name: get-empty-nodes 2.99 + #+begin_listing clojure 2.100 + #+begin_src clojure 2.101 +(defn sense-nodes 2.102 + "For some senses there is a special empty blender node whose 2.103 + children are considered markers for an instance of that sense. This 2.104 + function generates functions to find those children, given the name 2.105 + of the special parent node." 2.106 + [parent-name] 2.107 + (fn [#^Node creature] 2.108 + (if-let [sense-node (.getChild creature parent-name)] 2.109 + (seq (.getChildren sense-node)) []))) 2.110 + 2.111 +(def 2.112 + ^{:doc "Return the children of the creature's \"joints\" node." 2.113 + :arglists '([creature])} 2.114 + joints 2.115 + (sense-nodes "joints")) 2.116 + #+end_src 2.117 + #+end_listing 2.118 + 2.119 + To find a joint's targets targets, =CORTEX= creates a small cube, 2.120 + centered around the empty-node, and grows the cube exponentially 2.121 + until it intersects two /physical/ objects. The objects are ordered 2.122 + according to the joint's rotation, with the first one being the 2.123 + object that has more negative coordinates in the joint's reference 2.124 + frame. Since the objects must be physical, the empty-node itself 2.125 + escapes detection. Because the objects must be physical, 2.126 + =joint-targets= must be called /after/ =physical!= is called. 2.127 2.128 + #+caption: Program to find the targets of a joint node by 2.129 + #+caption: exponentiallly growth of a search cube. 2.130 + #+name: joint-targets 2.131 + #+begin_listing clojure 2.132 + #+begin_src clojure 2.133 +(defn joint-targets 2.134 + "Return the two closest two objects to the joint object, ordered 2.135 + from bottom to top according to the joint's rotation." 2.136 + [#^Node parts #^Node joint] 2.137 + (loop [radius (float 0.01)] 2.138 + (let [results (CollisionResults.)] 2.139 + (.collideWith 2.140 + parts 2.141 + (BoundingBox. (.getWorldTranslation joint) 2.142 + radius radius radius) results) 2.143 + (let [targets 2.144 + (distinct 2.145 + (map #(.getGeometry %) results))] 2.146 + (if (>= (count targets) 2) 2.147 + (sort-by 2.148 + #(let [joint-ref-frame-position 2.149 + (jme-to-blender 2.150 + (.mult 2.151 + (.inverse (.getWorldRotation joint)) 2.152 + (.subtract (.getWorldTranslation %) 2.153 + (.getWorldTranslation joint))))] 2.154 + (.dot (Vector3f. 1 1 1) joint-ref-frame-position)) 2.155 + (take 2 targets)) 2.156 + (recur (float (* radius 2)))))))) 2.157 + #+end_src 2.158 + #+end_listing 2.159 2.160 + Once =CORTEX= finds all joints and targets, it creates them using a 2.161 + simple dispatch on the metadata of the joint node. 2.162 + 2.163 + #+caption: Program to dispatch on blender metadata and create joints 2.164 + #+caption: sutiable for physical simulation. 2.165 + #+name: joint-dispatch 2.166 + #+begin_listing clojure 2.167 + #+begin_src clojure 2.168 +(defmulti joint-dispatch 2.169 + "Translate blender pseudo-joints into real JME joints." 2.170 + (fn [constraints & _] 2.171 + (:type constraints))) 2.172 + 2.173 +(defmethod joint-dispatch :point 2.174 + [constraints control-a control-b pivot-a pivot-b rotation] 2.175 + (doto (SixDofJoint. control-a control-b pivot-a pivot-b false) 2.176 + (.setLinearLowerLimit Vector3f/ZERO) 2.177 + (.setLinearUpperLimit Vector3f/ZERO))) 2.178 + 2.179 +(defmethod joint-dispatch :hinge 2.180 + [constraints control-a control-b pivot-a pivot-b rotation] 2.181 + (let [axis (if-let [axis (:axis constraints)] axis Vector3f/UNIT_X) 2.182 + [limit-1 limit-2] (:limit constraints) 2.183 + hinge-axis (.mult rotation (blender-to-jme axis))] 2.184 + (doto (HingeJoint. control-a control-b pivot-a pivot-b 2.185 + hinge-axis hinge-axis) 2.186 + (.setLimit limit-1 limit-2)))) 2.187 + 2.188 +(defmethod joint-dispatch :cone 2.189 + [constraints control-a control-b pivot-a pivot-b rotation] 2.190 + (let [limit-xz (:limit-xz constraints) 2.191 + limit-xy (:limit-xy constraints) 2.192 + twist (:twist constraints)] 2.193 + (doto (ConeJoint. control-a control-b pivot-a pivot-b 2.194 + rotation rotation) 2.195 + (.setLimit (float limit-xz) (float limit-xy) 2.196 + (float twist))))) 2.197 + #+end_src 2.198 + #+end_listing 2.199 + 2.200 + All that is left for joints it to combine the above pieces into a 2.201 + something that can operate on the collection of nodes that a 2.202 + blender file represents. 2.203 + 2.204 + #+caption: Program to completely create a joint given information 2.205 + #+caption: from a blender file. 2.206 + #+name: connect 2.207 + #+begin_listing clojure 2.208 + #+begin_src clojure 2.209 +(defn connect 2.210 + "Create a joint between 'obj-a and 'obj-b at the location of 2.211 + 'joint. The type of joint is determined by the metadata on 'joint. 2.212 + 2.213 + Here are some examples: 2.214 + {:type :point} 2.215 + {:type :hinge :limit [0 (/ Math/PI 2)] :axis (Vector3f. 0 1 0)} 2.216 + (:axis defaults to (Vector3f. 1 0 0) if not provided for hinge joints) 2.217 + 2.218 + {:type :cone :limit-xz 0] 2.219 + :limit-xy 0] 2.220 + :twist 0]} (use XZY rotation mode in blender!)" 2.221 + [#^Node obj-a #^Node obj-b #^Node joint] 2.222 + (let [control-a (.getControl obj-a RigidBodyControl) 2.223 + control-b (.getControl obj-b RigidBodyControl) 2.224 + joint-center (.getWorldTranslation joint) 2.225 + joint-rotation (.toRotationMatrix (.getWorldRotation joint)) 2.226 + pivot-a (world-to-local obj-a joint-center) 2.227 + pivot-b (world-to-local obj-b joint-center)] 2.228 + (if-let 2.229 + [constraints (map-vals eval (read-string (meta-data joint "joint")))] 2.230 + ;; A side-effect of creating a joint registers 2.231 + ;; it with both physics objects which in turn 2.232 + ;; will register the joint with the physics system 2.233 + ;; when the simulation is started. 2.234 + (joint-dispatch constraints 2.235 + control-a control-b 2.236 + pivot-a pivot-b 2.237 + joint-rotation)))) 2.238 + #+end_src 2.239 + #+end_listing 2.240 + 2.241 + In general, whenever =CORTEX= exposes a sense (or in this case 2.242 + physicality), it provides a function of the type =sense!=, which 2.243 + takes in a collection of nodes and augments it to support that 2.244 + sense. The function returns any controlls necessary to use that 2.245 + sense. In this case =body!= cerates a physical body and returns no 2.246 + control functions. 2.247 + 2.248 + #+caption: Program to give joints to a creature. 2.249 + #+name: name 2.250 + #+begin_listing clojure 2.251 + #+begin_src clojure 2.252 +(defn joints! 2.253 + "Connect the solid parts of the creature with physical joints. The 2.254 + joints are taken from the \"joints\" node in the creature." 2.255 + [#^Node creature] 2.256 + (dorun 2.257 + (map 2.258 + (fn [joint] 2.259 + (let [[obj-a obj-b] (joint-targets creature joint)] 2.260 + (connect obj-a obj-b joint))) 2.261 + (joints creature)))) 2.262 +(defn body! 2.263 + "Endow the creature with a physical body connected with joints. The 2.264 + particulars of the joints and the masses of each body part are 2.265 + determined in blender." 2.266 + [#^Node creature] 2.267 + (physical! creature) 2.268 + (joints! creature)) 2.269 + #+end_src 2.270 + #+end_listing 2.271 + 2.272 + All of the code you have just seen amounts to only 130 lines, yet 2.273 + because it builds on top of Blender and jMonkeyEngine3, those few 2.274 + lines pack quite a punch! 2.275 + 2.276 + The hand from figure \ref{blender-hand}, which was modeled after my 2.277 + own right hand, can now be given joints and simulated as a 2.278 + creature. 2.279 + 2.280 + #+caption: With the ability to create physical creatures from blender, 2.281 + #+caption: =CORTEX= gets one step closer to a full creature simulation 2.282 + #+caption: environment. 2.283 + #+name: name 2.284 + #+ATTR_LaTeX: :width 15cm 2.285 + [[./images/physical-hand.png]] 2.286 + 2.287 2.288 ** Eyes reuse standard video game components 2.289
3.1 Binary file thesis/images/physical-hand.png has changed