| 1 | //////////////////////////////////////////////////////////////////////////////// | 
|---|
| 2 | // skeleton.cpp | 
|---|
| 3 | // Author     : Francesco Giordana | 
|---|
| 4 | // Start Date : January 13, 2005 | 
|---|
| 5 | // Copyright  : (C) 2006 by Francesco Giordana | 
|---|
| 6 | // Email      : fra.giordana@tiscali.it | 
|---|
| 7 | //////////////////////////////////////////////////////////////////////////////// | 
|---|
| 8 |  | 
|---|
| 9 | /********************************************************************************* | 
|---|
| 10 | *                                                                                * | 
|---|
| 11 | *   This program is free software; you can redistribute it and/or modify         * | 
|---|
| 12 | *   it under the terms of the GNU Lesser General Public License as published by  * | 
|---|
| 13 | *   the Free Software Foundation; either version 2 of the License, or            * | 
|---|
| 14 | *   (at your option) any later version.                                          * | 
|---|
| 15 | *                                                                                * | 
|---|
| 16 | **********************************************************************************/ | 
|---|
| 17 |  | 
|---|
| 18 | #include "skeleton.h" | 
|---|
| 19 | #include "submesh.h" | 
|---|
| 20 | #include <maya/MFnMatrixData.h> | 
|---|
| 21 |  | 
|---|
| 22 | namespace OgreMayaExporter | 
|---|
| 23 | { | 
|---|
| 24 |         // Constructor | 
|---|
| 25 |         Skeleton::Skeleton() | 
|---|
| 26 |         { | 
|---|
| 27 |                 m_joints.clear(); | 
|---|
| 28 |                 m_animations.clear(); | 
|---|
| 29 |                 m_restorePose = ""; | 
|---|
| 30 |         } | 
|---|
| 31 |  | 
|---|
| 32 |  | 
|---|
| 33 |         // Destructor | 
|---|
| 34 |         Skeleton::~Skeleton() | 
|---|
| 35 |         { | 
|---|
| 36 |                 clear(); | 
|---|
| 37 |         } | 
|---|
| 38 |  | 
|---|
| 39 |  | 
|---|
| 40 |         // Clear skeleton data | 
|---|
| 41 |         void Skeleton::clear() | 
|---|
| 42 |         { | 
|---|
| 43 |                 m_joints.clear(); | 
|---|
| 44 |                 m_animations.clear(); | 
|---|
| 45 |                 m_restorePose = ""; | 
|---|
| 46 |         } | 
|---|
| 47 |  | 
|---|
| 48 |  | 
|---|
| 49 |         // Load skeleton data from given skin cluster | 
|---|
| 50 |         MStatus Skeleton::load(MFnSkinCluster* pSkinCluster,ParamList& params) | 
|---|
| 51 |         { | 
|---|
| 52 |                 MStatus stat; | 
|---|
| 53 |                 //check for valid skin cluster pointer | 
|---|
| 54 |                 if (!pSkinCluster) | 
|---|
| 55 |                 { | 
|---|
| 56 |                         std::cout << "Could not load skeleton data, no skin cluster specified\n"; | 
|---|
| 57 |                         std::cout.flush(); | 
|---|
| 58 |                         return MS::kFailure; | 
|---|
| 59 |                 } | 
|---|
| 60 |                 //retrieve and load joints from the skin cluster | 
|---|
| 61 |                 MDagPath jointDag,rootDag; | 
|---|
| 62 |                 MDagPathArray influenceDags; | 
|---|
| 63 |                 int numInfluenceObjs = pSkinCluster->influenceObjects(influenceDags,&stat); | 
|---|
| 64 |                 std::cout << "num influence objects: " << numInfluenceObjs << "\n"; | 
|---|
| 65 |                 std::cout.flush(); | 
|---|
| 66 |                 for (int i=0; i<numInfluenceObjs; i++) | 
|---|
| 67 |                 { | 
|---|
| 68 |                         jointDag = influenceDags[i]; | 
|---|
| 69 |                         if (influenceDags[i].hasFn(MFn::kJoint)) | 
|---|
| 70 |                         { | 
|---|
| 71 |                                 //retrieve root joint | 
|---|
| 72 |                                 rootDag = jointDag; | 
|---|
| 73 |                                 while (jointDag.length()>0) | 
|---|
| 74 |                                 { | 
|---|
| 75 |                                         jointDag.pop(); | 
|---|
| 76 |                                         if (jointDag.hasFn(MFn::kJoint) && jointDag.length()>0) | 
|---|
| 77 |                                                 rootDag = jointDag; | 
|---|
| 78 |                                 } | 
|---|
| 79 |                                 //check if skeleton has already been loaded | 
|---|
| 80 |                                 bool skip = false; | 
|---|
| 81 |                                 for (int j=0; j<m_joints.size() && !skip; j++) | 
|---|
| 82 |                                 { | 
|---|
| 83 |                                         //skip skeleton if already loaded | 
|---|
| 84 |                                         if (rootDag.partialPathName() == m_joints[j].name) | 
|---|
| 85 |                                         { | 
|---|
| 86 |                                                 skip = true; | 
|---|
| 87 |                                         } | 
|---|
| 88 |                                 } | 
|---|
| 89 |                                 //load joints data from root | 
|---|
| 90 |                                 if (!skip) | 
|---|
| 91 |                                 { | 
|---|
| 92 |                                         // load the skeleton | 
|---|
| 93 |                                         std::cout <<  "Loading skeleton with root: " << rootDag.fullPathName().asChar() << "...\n"; | 
|---|
| 94 |                                         std::cout.flush(); | 
|---|
| 95 |                                         // save current selection list | 
|---|
| 96 |                                         MSelectionList selectionList; | 
|---|
| 97 |                                         MGlobal::getActiveSelectionList(selectionList); | 
|---|
| 98 |                                         // select the root joint dag | 
|---|
| 99 |                                         MGlobal::selectByName(rootDag.fullPathName(),MGlobal::kReplaceList); | 
|---|
| 100 |                                         //save current pose (if no pose has been saved yet) | 
|---|
| 101 |                                         if (m_restorePose == "") | 
|---|
| 102 |                                         { | 
|---|
| 103 |                                                 MString poseName; | 
|---|
| 104 |                                                 MGlobal::executeCommand("dagPose -s",poseName,true); | 
|---|
| 105 |                                                 m_restorePose = poseName; | 
|---|
| 106 |                                         } | 
|---|
| 107 |                                         //set the skeleton to the desired neutral pose | 
|---|
| 108 |                                         if (params.neutralPoseType == NPT_BINDPOSE) | 
|---|
| 109 |                                         { | 
|---|
| 110 |                                                 //disable constraints, IK, etc... | 
|---|
| 111 |                                                 MGlobal::executeCommand("doEnableNodeItems false all",true); | 
|---|
| 112 |                                                 // Note: we reset to the bind pose | 
|---|
| 113 |                                                 MGlobal::executeCommand("dagPose -r -g -bp",true); | 
|---|
| 114 |                                         } | 
|---|
| 115 |                                         //load joints data | 
|---|
| 116 |                                         stat = loadJoint(rootDag,NULL,params,pSkinCluster); | 
|---|
| 117 |                                         if (MS::kSuccess == stat) | 
|---|
| 118 |                                         { | 
|---|
| 119 |                                                 std::cout << "OK\n"; | 
|---|
| 120 |                                                 std::cout.flush(); | 
|---|
| 121 |                                         } | 
|---|
| 122 |                                         else | 
|---|
| 123 |                                         { | 
|---|
| 124 |                                                 std::cout << "Failed\n"; | 
|---|
| 125 |                                                 std::cout.flush(); | 
|---|
| 126 |                                         } | 
|---|
| 127 |                                         //restore selection list | 
|---|
| 128 |                                         MGlobal::setActiveSelectionList(selectionList,MGlobal::kReplaceList); | 
|---|
| 129 |                                 } | 
|---|
| 130 |                         } | 
|---|
| 131 |                 } | 
|---|
| 132 |  | 
|---|
| 133 |                 return MS::kSuccess; | 
|---|
| 134 |         } | 
|---|
| 135 |  | 
|---|
| 136 |  | 
|---|
| 137 |         // Load a joint | 
|---|
| 138 |         MStatus Skeleton::loadJoint(MDagPath& jointDag,joint* parent,ParamList& params,MFnSkinCluster* pSkinCluster) | 
|---|
| 139 |         { | 
|---|
| 140 |                 MStatus stat; | 
|---|
| 141 |                 int i; | 
|---|
| 142 |                 joint newJoint; | 
|---|
| 143 |                 joint* parentJoint = parent; | 
|---|
| 144 |                 // if it is a joint node translate it and then proceed to child nodes, otherwise skip it | 
|---|
| 145 |                 // and proceed directly to child nodes | 
|---|
| 146 |                 if (jointDag.hasFn(MFn::kJoint)) | 
|---|
| 147 |                 { | 
|---|
| 148 |                         MFnIkJoint jointFn(jointDag); | 
|---|
| 149 |                         // Display info | 
|---|
| 150 |                         std::cout << "Loading joint: " << jointFn.fullPathName().asChar(); | 
|---|
| 151 |                         std::cout.flush(); | 
|---|
| 152 |                         if (parent) | 
|---|
| 153 |                         { | 
|---|
| 154 |                                 std::cout << " (parent: " << parent->name.asChar() << ")\n"; | 
|---|
| 155 |                                 std::cout.flush(); | 
|---|
| 156 |                         } | 
|---|
| 157 |                         else | 
|---|
| 158 |                         { | 
|---|
| 159 |                                 std::cout << "\n"; | 
|---|
| 160 |                                 std::cout.flush(); | 
|---|
| 161 |                         } | 
|---|
| 162 |                         // Get parent index | 
|---|
| 163 |                         int idx=-1; | 
|---|
| 164 |                         if (parent) | 
|---|
| 165 |                         { | 
|---|
| 166 |                                 for (i=0; i<m_joints.size() && idx<0; i++) | 
|---|
| 167 |                                 { | 
|---|
| 168 |                                         if (m_joints[i].name == parent->name) | 
|---|
| 169 |                                                 idx=i; | 
|---|
| 170 |                                 } | 
|---|
| 171 |                         } | 
|---|
| 172 |                         // Get world bind matrix | 
|---|
| 173 |                         MMatrix bindMatrix = jointDag.inclusiveMatrix();; | 
|---|
| 174 |                         // Calculate local bind matrix | 
|---|
| 175 |                         MMatrix localMatrix; | 
|---|
| 176 |                         if (parent) | 
|---|
| 177 |                                 localMatrix = bindMatrix * parent->bindMatrix.inverse(); | 
|---|
| 178 |                         else | 
|---|
| 179 |                         {       // root node of skeleton | 
|---|
| 180 |                                 localMatrix = bindMatrix; | 
|---|
| 181 |                         } | 
|---|
| 182 |                         // Get translation | 
|---|
| 183 |                         MVector translation = ((MTransformationMatrix)localMatrix).translation(MSpace::kPostTransform); | 
|---|
| 184 |                         if (fabs(translation.x) < PRECISION) | 
|---|
| 185 |                                 translation.x = 0; | 
|---|
| 186 |                         if (fabs(translation.y) < PRECISION) | 
|---|
| 187 |                                 translation.y = 0; | 
|---|
| 188 |                         if (fabs(translation.z) < PRECISION) | 
|---|
| 189 |                                 translation.z = 0; | 
|---|
| 190 |                         // Calculate rotation data | 
|---|
| 191 |                         double qx,qy,qz,qw; | 
|---|
| 192 |                         ((MTransformationMatrix)localMatrix).getRotationQuaternion(qx,qy,qz,qw); | 
|---|
| 193 |                         MQuaternion rotation(qx,qy,qz,qw); | 
|---|
| 194 |                         MVector axis; | 
|---|
| 195 |                         double theta; | 
|---|
| 196 |                         rotation.getAxisAngle(axis,theta); | 
|---|
| 197 |                         if (fabs(axis.x) < PRECISION) | 
|---|
| 198 |                                 axis.x = 0; | 
|---|
| 199 |                         if (fabs(axis.y) < PRECISION) | 
|---|
| 200 |                                 axis.y = 0; | 
|---|
| 201 |                         if (fabs(axis.z) < PRECISION) | 
|---|
| 202 |                                 axis.z = 0; | 
|---|
| 203 |                         axis.normalize(); | 
|---|
| 204 |                         if (fabs(theta) < PRECISION) | 
|---|
| 205 |                                 theta = 0; | 
|---|
| 206 |                         if (axis.length() < 0.5) | 
|---|
| 207 |                         { | 
|---|
| 208 |                                 axis.x = 0; | 
|---|
| 209 |                                 axis.y = 1; | 
|---|
| 210 |                                 axis.z = 0; | 
|---|
| 211 |                                 theta = 0; | 
|---|
| 212 |                         } | 
|---|
| 213 |                         // Get joint scale | 
|---|
| 214 |                         double scale[3]; | 
|---|
| 215 |                         ((MTransformationMatrix)localMatrix).getScale(scale,MSpace::kPostTransform); | 
|---|
| 216 |                         if (fabs(scale[0]) < PRECISION) | 
|---|
| 217 |                                 scale[0] = 0; | 
|---|
| 218 |                         if (fabs(scale[1]) < PRECISION) | 
|---|
| 219 |                                 scale[1] = 0; | 
|---|
| 220 |                         if (fabs(scale[2]) < PRECISION) | 
|---|
| 221 |                                 scale[2] = 0; | 
|---|
| 222 |                         // Set joint info | 
|---|
| 223 |                         newJoint.name = jointFn.partialPathName(); | 
|---|
| 224 |                         newJoint.id = m_joints.size(); | 
|---|
| 225 |                         newJoint.parentIndex = idx; | 
|---|
| 226 |                         newJoint.bindMatrix = bindMatrix; | 
|---|
| 227 |                         newJoint.localMatrix = localMatrix; | 
|---|
| 228 |                         newJoint.posx = translation.x * params.lum; | 
|---|
| 229 |                         newJoint.posy = translation.y * params.lum; | 
|---|
| 230 |                         newJoint.posz = translation.z * params.lum; | 
|---|
| 231 |                         newJoint.angle = theta; | 
|---|
| 232 |                         newJoint.axisx = axis.x; | 
|---|
| 233 |                         newJoint.axisy = axis.y; | 
|---|
| 234 |                         newJoint.axisz = axis.z; | 
|---|
| 235 |                         newJoint.scalex = scale[0]; | 
|---|
| 236 |                         newJoint.scaley = scale[1]; | 
|---|
| 237 |                         newJoint.scalez = scale[2]; | 
|---|
| 238 |                         newJoint.jointDag = jointDag; | 
|---|
| 239 |                         m_joints.push_back(newJoint); | 
|---|
| 240 |                         // If root is a root joint, save it's index in the roots list | 
|---|
| 241 |                         if (idx < 0) | 
|---|
| 242 |                         { | 
|---|
| 243 |                                 m_roots.push_back(m_joints.size() - 1); | 
|---|
| 244 |                         } | 
|---|
| 245 |                         // Get pointer to newly created joint | 
|---|
| 246 |                         parentJoint = &newJoint; | 
|---|
| 247 |                 } | 
|---|
| 248 |                 // Load child joints | 
|---|
| 249 |                 for (i=0; i<jointDag.childCount();i++) | 
|---|
| 250 |                 { | 
|---|
| 251 |                         MObject child; | 
|---|
| 252 |                         child = jointDag.child(i); | 
|---|
| 253 |                         MDagPath childDag = jointDag; | 
|---|
| 254 |                         childDag.push(child); | 
|---|
| 255 |                         loadJoint(childDag,parentJoint,params,pSkinCluster); | 
|---|
| 256 |                 } | 
|---|
| 257 |                 return MS::kSuccess; | 
|---|
| 258 |         } | 
|---|
| 259 |  | 
|---|
| 260 |  | 
|---|
| 261 |         // Load animations | 
|---|
| 262 |         MStatus Skeleton::loadAnims(ParamList& params) | 
|---|
| 263 |         { | 
|---|
| 264 |                 //enable constraints, IK, etc... | 
|---|
| 265 |                 MGlobal::executeCommand("doEnableNodeItems true all",true); | 
|---|
| 266 |                 MStatus stat; | 
|---|
| 267 |                 int i; | 
|---|
| 268 |                 // save current time for later restore | 
|---|
| 269 |                 MTime curTime = MAnimControl::currentTime(); | 
|---|
| 270 |                 std::cout << "Loading joint animations...\n"; | 
|---|
| 271 |                 std::cout.flush(); | 
|---|
| 272 |                 // clear animations list | 
|---|
| 273 |                 m_animations.clear(); | 
|---|
| 274 |                 // load skeleton animation clips for the whole skeleton | 
|---|
| 275 |                 for (i=0; i<params.skelClipList.size(); i++) | 
|---|
| 276 |                 { | 
|---|
| 277 |                         stat = loadClip(params.skelClipList[i].name,params.skelClipList[i].start, | 
|---|
| 278 |                                 params.skelClipList[i].stop,params.skelClipList[i].rate,params); | 
|---|
| 279 |                         if (stat == MS::kSuccess) | 
|---|
| 280 |                         { | 
|---|
| 281 |                                 std::cout << "Clip successfully loaded\n"; | 
|---|
| 282 |                                 std::cout.flush(); | 
|---|
| 283 |                         } | 
|---|
| 284 |                         else | 
|---|
| 285 |                         { | 
|---|
| 286 |                                 std::cout << "Failed loading clip\n"; | 
|---|
| 287 |                                 std::cout.flush(); | 
|---|
| 288 |                         } | 
|---|
| 289 |                 } | 
|---|
| 290 |                 //restore current time | 
|---|
| 291 |                 MAnimControl::setCurrentTime(curTime); | 
|---|
| 292 |                 return MS::kSuccess; | 
|---|
| 293 |         } | 
|---|
| 294 |  | 
|---|
| 295 |         // Load an animation clip | 
|---|
| 296 |         MStatus Skeleton::loadClip(MString clipName,float start,float stop,float rate,ParamList& params) | 
|---|
| 297 |         { | 
|---|
| 298 |                 MStatus stat; | 
|---|
| 299 |                 int i,j,k; | 
|---|
| 300 |                 MString msg; | 
|---|
| 301 |                 std::vector<float> times; | 
|---|
| 302 |                 // if skeleton has no joints we can't load the clip | 
|---|
| 303 |                 if (m_joints.size() < 0) | 
|---|
| 304 |                         return MS::kFailure; | 
|---|
| 305 |                 // display clip name | 
|---|
| 306 |                 std::cout << "clip \"" << clipName.asChar() << "\"\n"; | 
|---|
| 307 |                 std::cout.flush(); | 
|---|
| 308 |                 // calculate times from clip sample rate | 
|---|
| 309 |                 times.clear(); | 
|---|
| 310 |                 if (rate <= 0) | 
|---|
| 311 |                 { | 
|---|
| 312 |                         std::cout << "invalid sample rate for the clip (must be >0), we skip it\n"; | 
|---|
| 313 |                         std::cout.flush(); | 
|---|
| 314 |                         return MS::kFailure; | 
|---|
| 315 |                 } | 
|---|
| 316 |                 for (float t=start; t<stop; t+=rate) | 
|---|
| 317 |                         times.push_back(t); | 
|---|
| 318 |                 times.push_back(stop); | 
|---|
| 319 |                 // get animation length | 
|---|
| 320 |                 float length=0; | 
|---|
| 321 |                 if (times.size() >= 0) | 
|---|
| 322 |                         length = times[times.size()-1] - times[0]; | 
|---|
| 323 |                 if (length < 0) | 
|---|
| 324 |                 { | 
|---|
| 325 |                         std::cout << "invalid time range for the clip, we skip it\n"; | 
|---|
| 326 |                         std::cout.flush(); | 
|---|
| 327 |                         return MS::kFailure; | 
|---|
| 328 |                 } | 
|---|
| 329 |                 // create the animation | 
|---|
| 330 |                 Animation a; | 
|---|
| 331 |                 a.m_name = clipName.asChar(); | 
|---|
| 332 |                 a.m_tracks.clear(); | 
|---|
| 333 |                 a.m_length = length; | 
|---|
| 334 |                 m_animations.push_back(a); | 
|---|
| 335 |                 int animIdx = m_animations.size() - 1; | 
|---|
| 336 |                 // create a track for current clip for all joints | 
|---|
| 337 |                 std::vector<Track> animTracks; | 
|---|
| 338 |                 for (i=0; i<m_joints.size(); i++) | 
|---|
| 339 |                 { | 
|---|
| 340 |                         Track t; | 
|---|
| 341 |                         t.m_type = TT_SKELETON; | 
|---|
| 342 |                         t.m_bone = m_joints[i].name; | 
|---|
| 343 |                         t.m_skeletonKeyframes.clear(); | 
|---|
| 344 |                         animTracks.push_back(t); | 
|---|
| 345 |                 } | 
|---|
| 346 |                 // evaluate animation curves at selected times | 
|---|
| 347 |                 for (i=0; i<times.size(); i++) | 
|---|
| 348 |                 { | 
|---|
| 349 |                         //set time to wanted sample time | 
|---|
| 350 |                         MAnimControl::setCurrentTime(MTime(times[i],MTime::kSeconds)); | 
|---|
| 351 |                         //load a keyframe for every joint at current time | 
|---|
| 352 |                         for (j=0; j<m_joints.size(); j++) | 
|---|
| 353 |                         { | 
|---|
| 354 |                                 skeletonKeyframe key = loadKeyframe(m_joints[j],times[i]-times[0],params); | 
|---|
| 355 |                                 //add keyframe to joint track | 
|---|
| 356 |                                 animTracks[j].addSkeletonKeyframe(key); | 
|---|
| 357 |                         } | 
|---|
| 358 |                         if (params.skelBB) | 
|---|
| 359 |                         { | 
|---|
| 360 |                                 // Update bounding boxes of loaded submeshes | 
|---|
| 361 |                                 for (j=0; j<params.loadedSubmeshes.size(); j++) | 
|---|
| 362 |                                 { | 
|---|
| 363 |                                         MFnMesh mesh(params.loadedSubmeshes[j]->m_dagPath); | 
|---|
| 364 |                                         MPoint min = mesh.boundingBox().min(); | 
|---|
| 365 |                                         MPoint max = mesh.boundingBox().max(); | 
|---|
| 366 |                                         MBoundingBox bbox(min,max); | 
|---|
| 367 |                                         if (params.exportWorldCoords) | 
|---|
| 368 |                                                 bbox.transformUsing(params.loadedSubmeshes[j]->m_dagPath.inclusiveMatrix()); | 
|---|
| 369 |                                         min = bbox.min() * params.lum; | 
|---|
| 370 |                                         max = bbox.max() * params.lum; | 
|---|
| 371 |                                         MBoundingBox newbbox(min,max); | 
|---|
| 372 |                                         params.loadedSubmeshes[j]->m_boundingBox.expand(newbbox); | 
|---|
| 373 |                                 } | 
|---|
| 374 |                         } | 
|---|
| 375 |                 } | 
|---|
| 376 |                 // add created tracks to current clip | 
|---|
| 377 |                 for (i=0; i<animTracks.size(); i++) | 
|---|
| 378 |                 { | 
|---|
| 379 |                         m_animations[animIdx].addTrack(animTracks[i]); | 
|---|
| 380 |                 } | 
|---|
| 381 |                 // display info | 
|---|
| 382 |                 std::cout << "length: " << m_animations[animIdx].m_length << "\n"; | 
|---|
| 383 |                 std::cout << "num keyframes: " << animTracks[0].m_skeletonKeyframes.size() << "\n"; | 
|---|
| 384 |                 std::cout.flush(); | 
|---|
| 385 |                 // clip successfully loaded | 
|---|
| 386 |                 return MS::kSuccess; | 
|---|
| 387 |         } | 
|---|
| 388 |  | 
|---|
| 389 |         // Load a keyframe for a given joint at current time | 
|---|
| 390 |         skeletonKeyframe Skeleton::loadKeyframe(joint& j,float time,ParamList& params) | 
|---|
| 391 |         { | 
|---|
| 392 |                 MVector position; | 
|---|
| 393 |                 int parentIdx = j.parentIndex; | 
|---|
| 394 |                 // Get joint matrix | 
|---|
| 395 |                 MMatrix worldMatrix = j.jointDag.inclusiveMatrix(); | 
|---|
| 396 |                 // Calculate Local Matrix | 
|---|
| 397 |                 MMatrix localMatrix; | 
|---|
| 398 |                 if (parentIdx >= 0) | 
|---|
| 399 |                 { | 
|---|
| 400 |                         // Get parent joint | 
|---|
| 401 |                         MDagPath parentDag = m_joints[parentIdx].jointDag; | 
|---|
| 402 |                         localMatrix = worldMatrix * parentDag.inclusiveMatrixInverse(); | 
|---|
| 403 |                 } | 
|---|
| 404 |                 else | 
|---|
| 405 |                 {       // Root node of skeleton | 
|---|
| 406 |                         if (params.exportWorldCoords) | 
|---|
| 407 |                                 localMatrix = worldMatrix; | 
|---|
| 408 |                         else | 
|---|
| 409 |                                 localMatrix = worldMatrix * j.jointDag.exclusiveMatrixInverse(); | 
|---|
| 410 |                 } | 
|---|
| 411 |                 // Get relative transformation matrix | 
|---|
| 412 |                 MMatrix relMatrix = localMatrix * j.localMatrix.inverse(); | 
|---|
| 413 |                 // Get relative translation | 
|---|
| 414 |                 MVector translation = ((MTransformationMatrix)localMatrix).translation(MSpace::kPostTransform) -  | 
|---|
| 415 |                         ((MTransformationMatrix)j.localMatrix).translation(MSpace::kPostTransform); | 
|---|
| 416 |                 if (fabs(translation.x) < PRECISION) | 
|---|
| 417 |                         translation.x = 0; | 
|---|
| 418 |                 if (fabs(translation.y) < PRECISION) | 
|---|
| 419 |                         translation.y = 0; | 
|---|
| 420 |                 if (fabs(translation.z) < PRECISION) | 
|---|
| 421 |                         translation.z = 0; | 
|---|
| 422 |                 // Get relative rotation | 
|---|
| 423 |                 double qx,qy,qz,qw; | 
|---|
| 424 |                 ((MTransformationMatrix)relMatrix).getRotationQuaternion(qx,qy,qz,qw); | 
|---|
| 425 |                 MQuaternion rotation(qx,qy,qz,qw); | 
|---|
| 426 |                 MVector axis; | 
|---|
| 427 |                 double theta; | 
|---|
| 428 |                 rotation.getAxisAngle(axis,theta); | 
|---|
| 429 |                 if (fabs(axis.x) < PRECISION) | 
|---|
| 430 |                         axis.x = 0; | 
|---|
| 431 |                 if (fabs(axis.y) < PRECISION) | 
|---|
| 432 |                         axis.y = 0; | 
|---|
| 433 |                 if (fabs(axis.z) < PRECISION) | 
|---|
| 434 |                         axis.z = 0; | 
|---|
| 435 |                 axis.normalize(); | 
|---|
| 436 |                 if (fabs(theta) < PRECISION) | 
|---|
| 437 |                         theta = 0; | 
|---|
| 438 |                 if (axis.length() < 0.5) | 
|---|
| 439 |                 { | 
|---|
| 440 |                         axis.x = 0; | 
|---|
| 441 |                         axis.y = 1; | 
|---|
| 442 |                         axis.z = 0; | 
|---|
| 443 |                         theta = 0; | 
|---|
| 444 |                 } | 
|---|
| 445 |                 // Get relative scale | 
|---|
| 446 |                 double scale[3]; | 
|---|
| 447 |                 ((MTransformationMatrix)relMatrix).getScale(scale,MSpace::kPostTransform); | 
|---|
| 448 |                 if (fabs(scale[0]) < PRECISION) | 
|---|
| 449 |                         scale[0] = 0; | 
|---|
| 450 |                 if (fabs(scale[1]) < PRECISION) | 
|---|
| 451 |                         scale[1] = 0; | 
|---|
| 452 |                 if (fabs(scale[2]) < PRECISION) | 
|---|
| 453 |                         scale[2] = 0; | 
|---|
| 454 |                 //create keyframe | 
|---|
| 455 |                 skeletonKeyframe key; | 
|---|
| 456 |                 key.time = time; | 
|---|
| 457 |                 key.tx = translation.x * params.lum; | 
|---|
| 458 |                 key.ty = translation.y * params.lum; | 
|---|
| 459 |                 key.tz = translation.z * params.lum; | 
|---|
| 460 |                 key.angle = theta; | 
|---|
| 461 |                 key.axis_x = axis.x; | 
|---|
| 462 |                 key.axis_y = axis.y; | 
|---|
| 463 |                 key.axis_z = axis.z; | 
|---|
| 464 |                 key.sx = scale[0]; | 
|---|
| 465 |                 key.sy = scale[1]; | 
|---|
| 466 |                 key.sz = scale[2]; | 
|---|
| 467 |                 return key; | 
|---|
| 468 |         } | 
|---|
| 469 |  | 
|---|
| 470 |  | 
|---|
| 471 |         // Restore skeleton pose | 
|---|
| 472 |         void Skeleton::restorePose() | 
|---|
| 473 |         { | 
|---|
| 474 |                 // save current selection list | 
|---|
| 475 |                 MSelectionList selectionList; | 
|---|
| 476 |                 MGlobal::getActiveSelectionList(selectionList); | 
|---|
| 477 |                 int i; | 
|---|
| 478 |                 for (i=0; i<m_roots.size(); i++) | 
|---|
| 479 |                 { | 
|---|
| 480 |                         MDagPath rootDag = m_joints[m_roots[i]].jointDag; | 
|---|
| 481 |                         // select the root joint dag | 
|---|
| 482 |                         MGlobal::selectByName(rootDag.fullPathName(),MGlobal::kReplaceList); | 
|---|
| 483 |                         // restore pose | 
|---|
| 484 |                         MString cmd = "dagPose -r -g -n \""+ m_restorePose; | 
|---|
| 485 |                         cmd += "\""; | 
|---|
| 486 |                         MGlobal::executeCommand(cmd,true); | 
|---|
| 487 |                 } | 
|---|
| 488 |                 //restore selection list | 
|---|
| 489 |                 MGlobal::setActiveSelectionList(selectionList,MGlobal::kReplaceList); | 
|---|
| 490 |                 //enable constraints, IK, etc... | 
|---|
| 491 |                 MGlobal::executeCommand("doEnableNodeItems true all",true); | 
|---|
| 492 |         } | 
|---|
| 493 |  | 
|---|
| 494 |  | 
|---|
| 495 |  | 
|---|
| 496 |         // Get joint list | 
|---|
| 497 |         std::vector<joint>& Skeleton::getJoints() | 
|---|
| 498 |         { | 
|---|
| 499 |                 return m_joints; | 
|---|
| 500 |         } | 
|---|
| 501 |  | 
|---|
| 502 |  | 
|---|
| 503 |  | 
|---|
| 504 |         // Get animations | 
|---|
| 505 |         std::vector<Animation>& Skeleton::getAnimations() | 
|---|
| 506 |         { | 
|---|
| 507 |                 return m_animations; | 
|---|
| 508 |         } | 
|---|
| 509 |  | 
|---|
| 510 |  | 
|---|
| 511 |  | 
|---|
| 512 |         // Write to an OGRE binary skeleton | 
|---|
| 513 |         MStatus Skeleton::writeOgreBinary(ParamList ¶ms) | 
|---|
| 514 |         { | 
|---|
| 515 |                 MStatus stat; | 
|---|
| 516 |                 // Construct skeleton | 
|---|
| 517 |                 MString name = "mayaExport"; | 
|---|
| 518 |                 Ogre::SkeletonPtr pSkeleton = Ogre::SkeletonManager::getSingleton().create(name.asChar(),  | 
|---|
| 519 |                         Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME); | 
|---|
| 520 |                 // Create skeleton bones | 
|---|
| 521 |                 stat = createOgreBones(pSkeleton,params); | 
|---|
| 522 |                 if (stat != MS::kSuccess) | 
|---|
| 523 |                 { | 
|---|
| 524 |                         std::cout << "Error writing skeleton binary file\n"; | 
|---|
| 525 |                         std::cout.flush(); | 
|---|
| 526 |                 } | 
|---|
| 527 |                 // Create skeleton animation | 
|---|
| 528 |                 if (params.exportSkelAnims) | 
|---|
| 529 |                 { | 
|---|
| 530 |                         stat = createOgreSkeletonAnimations(pSkeleton,params); | 
|---|
| 531 |                         if (stat != MS::kSuccess) | 
|---|
| 532 |                         { | 
|---|
| 533 |                                 std::cout << "Error writing ogre skeleton animations\n"; | 
|---|
| 534 |                                 std::cout.flush(); | 
|---|
| 535 |                         } | 
|---|
| 536 |                 } | 
|---|
| 537 |                 pSkeleton->setBindingPose(); | 
|---|
| 538 |                 // Optimise animations | 
|---|
| 539 |                 pSkeleton->optimiseAllAnimations(); | 
|---|
| 540 |                 // Export skeleton binary | 
|---|
| 541 |                 Ogre::SkeletonSerializer serializer; | 
|---|
| 542 |                 serializer.exportSkeleton(pSkeleton.getPointer(),params.skeletonFilename.asChar()); | 
|---|
| 543 |                 pSkeleton.setNull(); | 
|---|
| 544 |                 // Skeleton successfully exported | 
|---|
| 545 |                 return MS::kSuccess; | 
|---|
| 546 |         } | 
|---|
| 547 |  | 
|---|
| 548 |         // Write joints to an Ogre skeleton | 
|---|
| 549 |         MStatus Skeleton::createOgreBones(Ogre::SkeletonPtr pSkeleton,ParamList& params) | 
|---|
| 550 |         { | 
|---|
| 551 |                 int i; | 
|---|
| 552 |                 // Create the bones | 
|---|
| 553 |                 for (i=0; i<m_joints.size(); i++) | 
|---|
| 554 |                 { | 
|---|
| 555 |                         joint* j = &m_joints[i]; | 
|---|
| 556 |                         // Create a new bone | 
|---|
| 557 |                         Ogre::Bone* pBone = pSkeleton->createBone(m_joints[i].name.asChar(), m_joints[i].id); | 
|---|
| 558 |                         // Set bone position (relative to it's parent) | 
|---|
| 559 |                         pBone->setPosition(j->posx,j->posy,j->posz); | 
|---|
| 560 |                         // Set bone orientation (relative to it's parent) | 
|---|
| 561 |                         Ogre::Quaternion orient; | 
|---|
| 562 |                         orient.FromAngleAxis(Ogre::Radian(j->angle),Ogre::Vector3(j->axisx,j->axisy,j->axisz)); | 
|---|
| 563 |                         pBone->setOrientation(orient); | 
|---|
| 564 |                         // Set bone scale (relative to it's parent | 
|---|
| 565 |                         pBone->setScale(j->scalex,j->scaley,j->scalez); | 
|---|
| 566 |                 } | 
|---|
| 567 |                 // Create the hierarchy | 
|---|
| 568 |                 for (i=0; i<m_joints.size(); i++) | 
|---|
| 569 |                 { | 
|---|
| 570 |                         int parentIdx = m_joints[i].parentIndex; | 
|---|
| 571 |                         if (parentIdx >= 0) | 
|---|
| 572 |                         { | 
|---|
| 573 |                                 // Get the parent joint | 
|---|
| 574 |                                 Ogre::Bone* pParent = pSkeleton->getBone(m_joints[parentIdx].id); | 
|---|
| 575 |                                 // Get current joint from skeleton | 
|---|
| 576 |                                 Ogre::Bone* pBone = pSkeleton->getBone(m_joints[i].id); | 
|---|
| 577 |                                 // Place current bone in the parent's child list | 
|---|
| 578 |                                 pParent->addChild(pBone); | 
|---|
| 579 |                         } | 
|---|
| 580 |                 } | 
|---|
| 581 |                 return MS::kSuccess; | 
|---|
| 582 |         } | 
|---|
| 583 |  | 
|---|
| 584 |  | 
|---|
| 585 |         // Write skeleton animations to an Ogre skeleton | 
|---|
| 586 |         MStatus Skeleton::createOgreSkeletonAnimations(Ogre::SkeletonPtr pSkeleton,ParamList& params) | 
|---|
| 587 |         { | 
|---|
| 588 |                 int i,j,k; | 
|---|
| 589 |                 // Read loaded skeleton animations | 
|---|
| 590 |                 for (i=0; i<m_animations.size(); i++) | 
|---|
| 591 |                 { | 
|---|
| 592 |                         // Create a new animation | 
|---|
| 593 |                         Ogre::Animation* pAnimation = pSkeleton->createAnimation(m_animations[i].m_name.asChar(), | 
|---|
| 594 |                                 m_animations[i].m_length); | 
|---|
| 595 |                         // Create tracks for current animation | 
|---|
| 596 |                         for (j=0; j<m_animations[i].m_tracks.size(); j++) | 
|---|
| 597 |                         { | 
|---|
| 598 |                                 Track* t = &m_animations[i].m_tracks[j]; | 
|---|
| 599 |                                 // Create a new track | 
|---|
| 600 |                                 Ogre::NodeAnimationTrack* pTrack = pAnimation->createNodeTrack(j, | 
|---|
| 601 |                                         pSkeleton->getBone(t->m_bone.asChar())); | 
|---|
| 602 |                                 // Create keyframes for current track | 
|---|
| 603 |                                 for (k=0; k<t->m_skeletonKeyframes.size(); k++) | 
|---|
| 604 |                                 { | 
|---|
| 605 |                                         skeletonKeyframe* keyframe = &t->m_skeletonKeyframes[k]; | 
|---|
| 606 |                                         // Create a new keyframe | 
|---|
| 607 |                                         Ogre::TransformKeyFrame* pKeyframe = pTrack->createNodeKeyFrame(keyframe->time); | 
|---|
| 608 |                                         // Set translation | 
|---|
| 609 |                                         pKeyframe->setTranslate(Ogre::Vector3(keyframe->tx,keyframe->ty,keyframe->tz)); | 
|---|
| 610 |                                         // Set rotation | 
|---|
| 611 |                                         Ogre::Quaternion rot; | 
|---|
| 612 |                                         rot.FromAngleAxis(Ogre::Radian(keyframe->angle), | 
|---|
| 613 |                                                 Ogre::Vector3(keyframe->axis_x,keyframe->axis_y,keyframe->axis_z)); | 
|---|
| 614 |                                         pKeyframe->setRotation(rot); | 
|---|
| 615 |                                         // Set scale | 
|---|
| 616 |                                         pKeyframe->setScale(Ogre::Vector3(keyframe->sx,keyframe->sy,keyframe->sz)); | 
|---|
| 617 |                                 } | 
|---|
| 618 |                         } | 
|---|
| 619 |                 } | 
|---|
| 620 |                 return MS::kSuccess; | 
|---|
| 621 |         } | 
|---|
| 622 |  | 
|---|
| 623 |  | 
|---|
| 624 | };      //end namespace | 
|---|