Mercurial > cortex
diff thesis/cortex.org @ 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 |
line wrap: on
line diff
1.1 --- a/thesis/cortex.org Fri Mar 28 11:08:32 2014 -0400 1.2 +++ b/thesis/cortex.org Fri Mar 28 13:16:37 2014 -0400 1.3 @@ -21,7 +21,7 @@ 1.4 #+caption: 1.5 #+name: name 1.6 #+ATTR_LaTeX: :width 10cm 1.7 - [[./images/Eve.jpg]] 1.8 + [[./images/aurellem-gray.png]] 1.9 1.10 1.11 1.12 @@ -530,16 +530,18 @@ 1.13 While trying to find a good compromise for body-design, one option 1.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 1.15 would have been to define a mesh which describes the creature's 1.16 - entire body. To this you add an skeleton which deforms this 1.17 - mesh. This technique is used extensively to model humans and create 1.18 - realistic animations. It is hard to use for my purposes because it 1.19 - is difficult to update the creature's Physics Collision Mesh in 1.20 - tandem with its Geometric Mesh under the influence of the 1.21 - armature. Without this the creature will not be able to grab things 1.22 - in its environment, and it won't be able to tell where its physical 1.23 - body is by using its eyes. Also, armatures do not specify any 1.24 - rotational limits for a joint, making it hard to model elbows, 1.25 - shoulders, etc. 1.26 + entire body. To this you add a skeleton which deforms this mesh 1.27 + (called rigging). This technique is used extensively to model 1.28 + humans and create realistic animations. It is not a good technique 1.29 + for physical simulation, because deformable surfaces are hard to 1.30 + model. Humans work like a squishy bag with some hard bones to give 1.31 + it shape. The bones are easy to simulate physically, but they 1.32 + interact with thr world though the skin, which is contiguous, but 1.33 + does not have a constant shape. In order to simulate skin you need 1.34 + some way to continuously update the physical model of the skin 1.35 + along with the movement of the bones. Given that bullet is 1.36 + optimized for rigid, solid objects, this leads to unmanagable 1.37 + computation and incorrect simulation. 1.38 1.39 Instead of using the human-like ``deformable bag of bones'' 1.40 approach, I decided to base my body plans on multiple solid objects 1.41 @@ -586,14 +588,248 @@ 1.42 #+caption: node (highlighted in yellow) and its children which each 1.43 #+caption: represent a joint in the hand. Each joint node has metadata 1.44 #+caption: specifying what sort of joint it is. 1.45 + #+name: blender-hand 1.46 #+ATTR_LaTeX: :width 10cm 1.47 [[./images/hand-screenshot1.png]] 1.48 1.49 1.50 + =CORTEX= creates a creature in two steps: first, it traverses the 1.51 + nodes in the blender file and creates physical representations for 1.52 + any of them that have mass defined. 1.53 + 1.54 + #+caption: Program for iterating through the nodes in a blender file 1.55 + #+caption: and generating physical jMonkeyEngine3 objects with mass 1.56 + #+caption: and a matching physics shape. 1.57 + #+name: name 1.58 + #+begin_listing clojure 1.59 + #+begin_src clojure 1.60 +(defn physical! 1.61 + "Iterate through the nodes in creature and make them real physical 1.62 + objects in the simulation." 1.63 + [#^Node creature] 1.64 + (dorun 1.65 + (map 1.66 + (fn [geom] 1.67 + (let [physics-control 1.68 + (RigidBodyControl. 1.69 + (HullCollisionShape. 1.70 + (.getMesh geom)) 1.71 + (if-let [mass (meta-data geom "mass")] 1.72 + (float mass) (float 1)))] 1.73 + (.addControl geom physics-control))) 1.74 + (filter #(isa? (class %) Geometry ) 1.75 + (node-seq creature))))) 1.76 + #+end_src 1.77 + #+end_listing 1.78 1.79 + The next step to making a proper body is to connect those pieces 1.80 + together with joints. jMonkeyEngine has a large array of joints 1.81 + available via =bullet=, such as Point2Point, Cone, Hinge, and a 1.82 + generic Six Degree of Freedom joint, with or without spring 1.83 + restitution. =CORTEX='s procedure for binding the creature together 1.84 + with joints is as follows: 1.85 1.86 + - Find the children of the "joints" node. 1.87 + - Determine the two spatials the joint is meant to connect. 1.88 + - Create the joint based on the meta-data of the empty node. 1.89 + 1.90 + The higher order function =sense-nodes= from =cortex.sense= 1.91 + simplifies finding the joints based on their parent ``joints'' 1.92 + node. 1.93 + 1.94 + #+caption: Retrieving the children empty nodes from a single 1.95 + #+caption: named empty node is a common pattern in =CORTEX= 1.96 + #+caption: further instances of this technique for the senses 1.97 + #+caption: will be omitted 1.98 + #+name: get-empty-nodes 1.99 + #+begin_listing clojure 1.100 + #+begin_src clojure 1.101 +(defn sense-nodes 1.102 + "For some senses there is a special empty blender node whose 1.103 + children are considered markers for an instance of that sense. This 1.104 + function generates functions to find those children, given the name 1.105 + of the special parent node." 1.106 + [parent-name] 1.107 + (fn [#^Node creature] 1.108 + (if-let [sense-node (.getChild creature parent-name)] 1.109 + (seq (.getChildren sense-node)) []))) 1.110 + 1.111 +(def 1.112 + ^{:doc "Return the children of the creature's \"joints\" node." 1.113 + :arglists '([creature])} 1.114 + joints 1.115 + (sense-nodes "joints")) 1.116 + #+end_src 1.117 + #+end_listing 1.118 + 1.119 + To find a joint's targets targets, =CORTEX= creates a small cube, 1.120 + centered around the empty-node, and grows the cube exponentially 1.121 + until it intersects two /physical/ objects. The objects are ordered 1.122 + according to the joint's rotation, with the first one being the 1.123 + object that has more negative coordinates in the joint's reference 1.124 + frame. Since the objects must be physical, the empty-node itself 1.125 + escapes detection. Because the objects must be physical, 1.126 + =joint-targets= must be called /after/ =physical!= is called. 1.127 1.128 + #+caption: Program to find the targets of a joint node by 1.129 + #+caption: exponentiallly growth of a search cube. 1.130 + #+name: joint-targets 1.131 + #+begin_listing clojure 1.132 + #+begin_src clojure 1.133 +(defn joint-targets 1.134 + "Return the two closest two objects to the joint object, ordered 1.135 + from bottom to top according to the joint's rotation." 1.136 + [#^Node parts #^Node joint] 1.137 + (loop [radius (float 0.01)] 1.138 + (let [results (CollisionResults.)] 1.139 + (.collideWith 1.140 + parts 1.141 + (BoundingBox. (.getWorldTranslation joint) 1.142 + radius radius radius) results) 1.143 + (let [targets 1.144 + (distinct 1.145 + (map #(.getGeometry %) results))] 1.146 + (if (>= (count targets) 2) 1.147 + (sort-by 1.148 + #(let [joint-ref-frame-position 1.149 + (jme-to-blender 1.150 + (.mult 1.151 + (.inverse (.getWorldRotation joint)) 1.152 + (.subtract (.getWorldTranslation %) 1.153 + (.getWorldTranslation joint))))] 1.154 + (.dot (Vector3f. 1 1 1) joint-ref-frame-position)) 1.155 + (take 2 targets)) 1.156 + (recur (float (* radius 2)))))))) 1.157 + #+end_src 1.158 + #+end_listing 1.159 1.160 + Once =CORTEX= finds all joints and targets, it creates them using a 1.161 + simple dispatch on the metadata of the joint node. 1.162 + 1.163 + #+caption: Program to dispatch on blender metadata and create joints 1.164 + #+caption: sutiable for physical simulation. 1.165 + #+name: joint-dispatch 1.166 + #+begin_listing clojure 1.167 + #+begin_src clojure 1.168 +(defmulti joint-dispatch 1.169 + "Translate blender pseudo-joints into real JME joints." 1.170 + (fn [constraints & _] 1.171 + (:type constraints))) 1.172 + 1.173 +(defmethod joint-dispatch :point 1.174 + [constraints control-a control-b pivot-a pivot-b rotation] 1.175 + (doto (SixDofJoint. control-a control-b pivot-a pivot-b false) 1.176 + (.setLinearLowerLimit Vector3f/ZERO) 1.177 + (.setLinearUpperLimit Vector3f/ZERO))) 1.178 + 1.179 +(defmethod joint-dispatch :hinge 1.180 + [constraints control-a control-b pivot-a pivot-b rotation] 1.181 + (let [axis (if-let [axis (:axis constraints)] axis Vector3f/UNIT_X) 1.182 + [limit-1 limit-2] (:limit constraints) 1.183 + hinge-axis (.mult rotation (blender-to-jme axis))] 1.184 + (doto (HingeJoint. control-a control-b pivot-a pivot-b 1.185 + hinge-axis hinge-axis) 1.186 + (.setLimit limit-1 limit-2)))) 1.187 + 1.188 +(defmethod joint-dispatch :cone 1.189 + [constraints control-a control-b pivot-a pivot-b rotation] 1.190 + (let [limit-xz (:limit-xz constraints) 1.191 + limit-xy (:limit-xy constraints) 1.192 + twist (:twist constraints)] 1.193 + (doto (ConeJoint. control-a control-b pivot-a pivot-b 1.194 + rotation rotation) 1.195 + (.setLimit (float limit-xz) (float limit-xy) 1.196 + (float twist))))) 1.197 + #+end_src 1.198 + #+end_listing 1.199 + 1.200 + All that is left for joints it to combine the above pieces into a 1.201 + something that can operate on the collection of nodes that a 1.202 + blender file represents. 1.203 + 1.204 + #+caption: Program to completely create a joint given information 1.205 + #+caption: from a blender file. 1.206 + #+name: connect 1.207 + #+begin_listing clojure 1.208 + #+begin_src clojure 1.209 +(defn connect 1.210 + "Create a joint between 'obj-a and 'obj-b at the location of 1.211 + 'joint. The type of joint is determined by the metadata on 'joint. 1.212 + 1.213 + Here are some examples: 1.214 + {:type :point} 1.215 + {:type :hinge :limit [0 (/ Math/PI 2)] :axis (Vector3f. 0 1 0)} 1.216 + (:axis defaults to (Vector3f. 1 0 0) if not provided for hinge joints) 1.217 + 1.218 + {:type :cone :limit-xz 0] 1.219 + :limit-xy 0] 1.220 + :twist 0]} (use XZY rotation mode in blender!)" 1.221 + [#^Node obj-a #^Node obj-b #^Node joint] 1.222 + (let [control-a (.getControl obj-a RigidBodyControl) 1.223 + control-b (.getControl obj-b RigidBodyControl) 1.224 + joint-center (.getWorldTranslation joint) 1.225 + joint-rotation (.toRotationMatrix (.getWorldRotation joint)) 1.226 + pivot-a (world-to-local obj-a joint-center) 1.227 + pivot-b (world-to-local obj-b joint-center)] 1.228 + (if-let 1.229 + [constraints (map-vals eval (read-string (meta-data joint "joint")))] 1.230 + ;; A side-effect of creating a joint registers 1.231 + ;; it with both physics objects which in turn 1.232 + ;; will register the joint with the physics system 1.233 + ;; when the simulation is started. 1.234 + (joint-dispatch constraints 1.235 + control-a control-b 1.236 + pivot-a pivot-b 1.237 + joint-rotation)))) 1.238 + #+end_src 1.239 + #+end_listing 1.240 + 1.241 + In general, whenever =CORTEX= exposes a sense (or in this case 1.242 + physicality), it provides a function of the type =sense!=, which 1.243 + takes in a collection of nodes and augments it to support that 1.244 + sense. The function returns any controlls necessary to use that 1.245 + sense. In this case =body!= cerates a physical body and returns no 1.246 + control functions. 1.247 + 1.248 + #+caption: Program to give joints to a creature. 1.249 + #+name: name 1.250 + #+begin_listing clojure 1.251 + #+begin_src clojure 1.252 +(defn joints! 1.253 + "Connect the solid parts of the creature with physical joints. The 1.254 + joints are taken from the \"joints\" node in the creature." 1.255 + [#^Node creature] 1.256 + (dorun 1.257 + (map 1.258 + (fn [joint] 1.259 + (let [[obj-a obj-b] (joint-targets creature joint)] 1.260 + (connect obj-a obj-b joint))) 1.261 + (joints creature)))) 1.262 +(defn body! 1.263 + "Endow the creature with a physical body connected with joints. The 1.264 + particulars of the joints and the masses of each body part are 1.265 + determined in blender." 1.266 + [#^Node creature] 1.267 + (physical! creature) 1.268 + (joints! creature)) 1.269 + #+end_src 1.270 + #+end_listing 1.271 + 1.272 + All of the code you have just seen amounts to only 130 lines, yet 1.273 + because it builds on top of Blender and jMonkeyEngine3, those few 1.274 + lines pack quite a punch! 1.275 + 1.276 + The hand from figure \ref{blender-hand}, which was modeled after my 1.277 + own right hand, can now be given joints and simulated as a 1.278 + creature. 1.279 + 1.280 + #+caption: With the ability to create physical creatures from blender, 1.281 + #+caption: =CORTEX= gets one step closer to a full creature simulation 1.282 + #+caption: environment. 1.283 + #+name: name 1.284 + #+ATTR_LaTeX: :width 15cm 1.285 + [[./images/physical-hand.png]] 1.286 + 1.287 1.288 ** Eyes reuse standard video game components 1.289