source: OGRE/trunk/ogrenew/Tools/MayaExport/src/skeleton.cpp @ 692

Revision 692, 14.1 KB checked in by mattausch, 18 years ago (diff)

adding ogre 1.2 and dependencies

Line 
1#include "skeleton.h"
2
3namespace OgreMayaExporter
4{
5        // Constructor
6        Skeleton::Skeleton()
7        {
8                m_joints.clear();
9                m_animations.clear();
10        }
11
12
13        // Destructor
14        Skeleton::~Skeleton()
15        {
16                clear();
17        }
18
19
20        // Clear skeleton data
21        void Skeleton::clear()
22        {
23                m_joints.clear();
24                m_animations.clear();
25        }
26
27
28        // Load skeleton data from given skin cluster
29        MStatus Skeleton::load(MFnSkinCluster* pSkinCluster,ParamList& params)
30        {
31                MStatus stat;
32                //update skin cluster pointer
33                if (!pSkinCluster)
34                {
35                        std::cout << "Could not load skeleton data, no skin cluster specified\n";
36                        return MS::kFailure;
37                }
38                //retrieve and load joints from the skin cluster
39                MDagPath jointDag,rootDag;
40                MDagPathArray influenceDags;
41                int numInfluenceObjs = pSkinCluster->influenceObjects(influenceDags,&stat);
42                std::cout << "num influence objects: " << numInfluenceObjs << "\n";
43                for (int i=0; i<numInfluenceObjs; i++)
44                {
45                        jointDag = influenceDags[i];
46                        std::cout << "influence object " << i << ": " << jointDag.fullPathName().asChar() << "\n";
47                        if (influenceDags[i].hasFn(MFn::kJoint))
48                        {
49                                //retrieve root joint
50                                rootDag = jointDag;
51                                while (jointDag.length()>0)
52                                {
53                                        jointDag.pop();
54                                        if (jointDag.hasFn(MFn::kJoint) && jointDag.length()>0)
55                                                rootDag = jointDag;
56                                }
57                                //check if skeleton has already been loaded
58                                bool skip = false;
59                                for (int j=0; j<m_joints.size() && !skip; j++)
60                                {
61                                        //skip skeleton if already loaded
62                                        if (rootDag.partialPathName() == m_joints[j].name)
63                                        {
64                                                skip = true;
65                                                std::cout << "joint already loaded: skipped\n";
66                                        }
67                                }
68                                //load joints data from root
69                                if (!skip)
70                                {
71                                        std::cout <<  "Loading skeleton with root: " << rootDag.partialPathName().asChar() << "...\n";
72                                        MSelectionList selectionList;
73                                        MGlobal::getActiveSelectionList(selectionList);
74                                        // Set Neutral Pose
75                                        //check if we want the skin bind pose
76                                        if (params.neutralPoseFrame == NPT_BINDPOSE)
77                                        {
78                                                // Note: we reset to the bind pose, then get current matrix
79                                                // if bind pose could not be restored we use the current pose as a bind pose
80                                                MGlobal::selectByName(jointDag.partialPathName(),MGlobal::kReplaceList);
81                                                MGlobal::executeCommand("dagPose -r -g -bp");
82                                        }
83                                        //check if we want specified frame as neutral pose
84                                        else if (params.neutralPoseType == NPT_FRAME)
85                                        {
86                                                //set time to desired time
87                                                MTime npTime = (double)params.neutralPoseFrame;
88                                                MAnimControl::setCurrentTime(npTime.as(MTime::kSeconds));
89                                        }
90                                       
91                                        //load joints data
92                                        stat = loadJoint(rootDag,NULL,params);
93                                        if (MS::kSuccess == stat)
94                                                std::cout << "OK\n";
95                                        else
96                                                std::cout << "Failed\n";
97
98                                        /*
99                                        //restore skeleton to neutral pose
100                                        if (params.neutralPoseFrame == 1)
101                                        {
102                                                MGlobal::executeCommand("dagPose -r -g -bp");
103                                                MGlobal::setActiveSelectionList(selectionList,MGlobal::kReplaceList);
104                                        }
105                                        else if (params.neutralPoseType == 2)
106                                        {
107                                                //set time to desired time
108                                                MTime npTime = (double)params.neutralPoseFrame;
109                                                MAnimControl::setCurrentTime(npTime.as(MTime::kSeconds));
110                                        }
111                                        */
112                                }
113                        }
114                }
115
116                return MS::kSuccess;
117        }
118
119
120        // Load a joint
121        MStatus Skeleton::loadJoint(MDagPath& jointDag,joint* parent,ParamList& params)
122        {
123                int i;
124                joint newJoint;
125                joint* parentJoint = parent;
126                // if it is a joint node translate it and then proceed to child nodes, otherwise skip it
127                // and proceed directly to child nodes
128                if (jointDag.hasFn(MFn::kJoint))
129                {
130                        MFnIkJoint jointFn(jointDag);
131                        // Display info
132                        std::cout << "Loading joint: " << jointFn.partialPathName().asChar();
133                        if (parent)
134                                std::cout << " (parent: " << parent->name.asChar() << ")\n";
135                        else
136                                std::cout << "\n";
137                        // Get parent index
138                        int idx=-1;
139                        if (parent)
140                        {
141                                for (i=0; i<m_joints.size() && idx<0; i++)
142                                {
143                                        if (m_joints[i].name == parent->name)
144                                                idx=i;
145                                }
146                        }
147                        // Get joint matrix
148                        MMatrix bindMatrix = jointDag.inclusiveMatrix();
149                        // Calculate scaling factor inherited by parent
150                        double scale[3];
151                        if (parent)
152                        {
153                                MTransformationMatrix M(parent->worldMatrix);
154                                M.getScale(scale,MSpace::kWorld);
155                        }
156                        else
157                        {
158                                scale[0] = 1;
159                                scale[1] = 1;
160                                scale[2] = 1;
161                        }
162                        // Calculate Local Matrix
163                        MMatrix localMatrix;
164                        if (parent)
165                                localMatrix = bindMatrix * parent->worldMatrix.inverse();
166                        else
167                        {       // root node of skeleton
168                                if (params.exportWorldCoords)
169                                        localMatrix = bindMatrix;
170                                else
171                                        localMatrix = bindMatrix * jointDag.exclusiveMatrix().inverse();
172                        }
173                        // Calculate rotation data
174                        double qx,qy,qz,qw;
175                        ((MTransformationMatrix)localMatrix).getRotationQuaternion(qx,qy,qz,qw);
176                        MQuaternion rotation(qx,qy,qz,qw);
177                        MVector axis;
178                        double theta;
179                        rotation.getAxisAngle(axis,theta);
180                        axis.normalize();
181                        if (axis.length() < 0.5)
182                        {
183                                axis.x = 0;
184                                axis.y = 1;
185                                axis.z = 0;
186                                theta = 0;
187                        }
188                        // Set joint info
189                        newJoint.name = jointFn.partialPathName();
190                        newJoint.id = m_joints.size();
191                        newJoint.parentIndex = idx;
192                        newJoint.worldMatrix = bindMatrix;
193                        newJoint.localMatrix = localMatrix;
194                        newJoint.posx = localMatrix(3,0) * scale[0];
195                        newJoint.posy = localMatrix(3,1) * scale[1];
196                        newJoint.posz = localMatrix(3,2) * scale[2];
197                        newJoint.angle = theta;
198                        newJoint.axisx = axis.x;
199                        newJoint.axisy = axis.y;
200                        newJoint.axisz = axis.z;
201                        newJoint.jointDag = jointDag;
202                        m_joints.push_back(newJoint);
203                        // Get pointer to newly created joint
204                        parentJoint = &newJoint;
205                }
206                // Load children joints
207                for (i=0; i<jointDag.childCount();i++)
208                {
209                        MObject child;
210                        child = jointDag.child(i);
211                        MDagPath childDag = jointDag;
212                        childDag.push(child);
213                        loadJoint(childDag,parentJoint,params);
214                }
215                return MS::kSuccess;
216        }
217
218
219        // Load animations
220        MStatus Skeleton::loadAnims(ParamList& params)
221        {
222                MStatus stat;
223                int i;
224                std::cout << "Loading joint animations...\n";
225                // save current time for later restore
226                double curtime = MAnimControl::currentTime().as(MTime::kSeconds);
227                // clear animations list
228                m_animations.clear();
229                // load animation clips for the whole skeleton
230                for (i=0; i<params.clipList.size(); i++)
231                {
232                        stat = loadClip(params.clipList[i].name,params.clipList[i].start,
233                                params.clipList[i].stop,params.clipList[i].rate,params);
234                        if (stat == MS::kSuccess)
235                                std::cout << "Clip successfully loaded\n";
236                        else
237                                std::cout << "Failed loading clip\n";
238                }
239                //restore current time
240                MAnimControl::setCurrentTime(MTime(curtime,MTime::kSeconds));
241                return MS::kSuccess;
242        }
243
244       
245        // Load an animation clip
246        MStatus Skeleton::loadClip(MString clipName,double start,double stop,double rate,ParamList& params)
247        {
248                MStatus stat;
249                int i,j;
250                MString msg;
251                std::vector<double> times;
252                // if skeleton has no joint we can't load the clip
253                if (m_joints.size() < 0)
254                        return MS::kFailure;
255                // display clip name
256                std::cout << "clip \"" << clipName.asChar() << "\"\n";
257                // calculate times from clip sample rate
258                times.clear();
259                for (double t=start; t<stop; t+=rate)
260                        times.push_back(t);
261                times.push_back(stop);
262                // get animation length
263                double length=0;
264                if (times.size() > 0)
265                        length = times[times.size()-1] - times[0];
266                // check if clip length is >0
267                if (length <= 0)
268                {
269                        std::cout << "the clip has 0 length, we skip it\n";
270                        return MS::kFailure;
271                }
272                // create the animation
273                animation a;
274                a.name = clipName.asChar();
275                a.tracks.clear();
276                a.length = length;
277                m_animations.push_back(a);
278                int animIdx = m_animations.size() - 1;
279                // create a track for current clip for all joints
280                std::vector<track> animTracks;
281                for (i=0; i<m_joints.size(); i++)
282                {
283                        track t;
284                        t.bone = m_joints[i].name;
285                        t.keyframes.clear();
286                        animTracks.push_back(t);
287                }
288                // evaluate animation curves at selected times
289                for (i=0; i<times.size(); i++)
290                {
291                        //set time to wanted sample time
292                        MAnimControl::setCurrentTime(MTime(times[i],MTime::kSeconds));
293                        //load a keyframe for every joint at current time
294                        for (j=0; j<m_joints.size(); j++)
295                        {
296                                keyframe key = loadKeyframe(m_joints[j],times[i]-times[0],params);
297                                //add keyframe to joint track
298                                animTracks[j].keyframes.push_back(key);
299                        }
300                }
301                // add created tracks to current clip
302                for (i=0; i<animTracks.size(); i++)
303                {
304                        m_animations[animIdx].tracks.push_back(animTracks[i]);
305                }
306                // display info
307                std::cout << "length: " << m_animations[animIdx].length << "\n";
308                std::cout << "num keyframes: " << animTracks[0].keyframes.size() << "\n";
309                // clip successfully loaded
310                return MS::kSuccess;
311        }
312
313       
314        // Load a keyframe for a given joint at current time
315        keyframe Skeleton::loadKeyframe(joint& j,double time,ParamList& params)
316        {
317                MFnIkJoint jointFn(j.jointDag);
318                MTransformationMatrix matrix;
319                MVector position;
320                double scale[3];
321                scale[0] = 1; scale[1] = 1; scale[2] = 1;
322                int parentIdx = j.parentIndex;
323                //get joint matrix at current time
324                matrix = j.jointDag.inclusiveMatrix();
325                if (parentIdx >= 0)
326                {
327                        //calculate inherited scale factor
328                        ((MTransformationMatrix)j.jointDag.exclusiveMatrix()).getScale(scale,MSpace::kWorld);
329                        //calculate relative matrix
330                        matrix = j.jointDag.inclusiveMatrix() * j.jointDag.exclusiveMatrixInverse();
331                }
332                else
333                {       // root joint
334                        if (params.exportWorldCoords)
335                                matrix = j.jointDag.inclusiveMatrix();
336                        else
337                                matrix = j.jointDag.inclusiveMatrix() * j.jointDag.exclusiveMatrixInverse();
338                }
339                //calculate position of joint at given time
340                position.x = matrix.asMatrix()(3,0) * scale[0];
341                position.y = matrix.asMatrix()(3,1) * scale[1];
342                position.z = matrix.asMatrix()(3,2) * scale[2];
343                //get relative transformation matrix
344                matrix = matrix.asMatrix() * j.localMatrix.inverse();
345                //calculate rotation
346                double qx,qy,qz,qw;
347                ((MTransformationMatrix)matrix).getRotationQuaternion(qx,qy,qz,qw);
348                MQuaternion rotation(qx,qy,qz,qw);
349                double theta;
350                MVector axis;
351                rotation.getAxisAngle(axis,theta);
352                axis.normalize();
353                if (axis.length() < 0.5)
354                {
355                        axis.x = 0;
356                        axis.y = 1;
357                        axis.z = 0;
358                        theta = 0;
359                }
360                //create keyframe
361                keyframe key;
362                key.time = time;
363                key.tx = position.x - j.posx;
364                key.ty = position.y - j.posy;
365                key.tz = position.z - j.posz;
366                key.angle = theta;
367                key.axis_x = axis.x;
368                key.axis_y = axis.y;
369                key.axis_z = axis.z;
370                key.sx = 1;
371                key.sy = 1;
372                key.sz = 1;
373                return key;
374        }
375
376
377        // Get joint list
378        std::vector<joint>& Skeleton::getJoints()
379        {
380                return m_joints;
381        }
382
383
384        // Get animations
385        std::vector<animation>& Skeleton::getAnimations()
386        {
387                return m_animations;
388        }
389
390
391        // Write skeleton data to Ogre XML file
392        MStatus Skeleton::writeXML(ParamList &params)
393        {
394                // Start skeleton description
395                params.outSkeleton << "<skeleton>\n";
396
397                // Write bones list
398                params.outSkeleton << "\t<bones>\n";
399                // For each joint write it's description
400                for (int i=0; i<m_joints.size(); i++)
401                {
402                        params.outSkeleton << "\t\t<bone id=\"" << m_joints[i].id << "\" name=\"" << m_joints[i].name.asChar() << "\">\n";
403                        params.outSkeleton << "\t\t\t<position x=\"" << m_joints[i].posx << "\" y=\"" << m_joints[i].posy
404                                << "\" z=\"" << m_joints[i].posz << "\"/>\n";
405                        params.outSkeleton << "\t\t\t<rotation angle=\"" << m_joints[i].angle << "\">\n";
406                        params.outSkeleton << "\t\t\t\t<axis x=\"" << m_joints[i].axisx << "\" y=\"" << m_joints[i].axisy
407                                << "\" z=\"" << m_joints[i].axisz << "\"/>\n";
408                        params.outSkeleton << "\t\t\t</rotation>\n";
409                        params.outSkeleton << "\t\t</bone>\n";
410                }
411                params.outSkeleton << "\t</bones>\n";
412
413                // Write bone hierarchy
414                params.outSkeleton << "\t<bonehierarchy>\n";
415                for (i=0; i<m_joints.size(); i++)
416                {
417                        if (m_joints[i].parentIndex>=0)
418                        {
419                                params.outSkeleton << "\t\t<boneparent bone=\"" << m_joints[i].name.asChar() << "\" parent=\""
420                                        << m_joints[m_joints[i].parentIndex].name.asChar() << "\"/>\n";
421                        }
422                }
423                params.outSkeleton << "\t</bonehierarchy>\n";
424
425                // Write animations description
426                if (params.exportAnims)
427                {
428                        params.outSkeleton << "\t<animations>\n";
429                        // For every animation
430                        for (i=0; i<m_animations.size(); i++)
431                        {
432                                // Write animation info
433                                params.outSkeleton << "\t\t<animation name=\"" << m_animations[i].name.asChar() << "\" length=\"" <<
434                                        m_animations[i].length << "\">\n";
435                                // Write tracks
436                                params.outSkeleton << "\t\t\t<tracks>\n";
437                                // Cycle through tracks
438                                for (int j=0; j<m_animations[i].tracks.size(); j++)
439                                {
440                                        track t = m_animations[i].tracks[j];
441                                        params.outSkeleton << "\t\t\t\t<track bone=\"" << t.bone.asChar() << "\">\n";
442                                        // Write track keyframes
443                                        params.outSkeleton << "\t\t\t\t\t<keyframes>\n";
444                                        for (int k=0; k<t.keyframes.size(); k++)
445                                        {
446                                                // time
447                                                params.outSkeleton << "\t\t\t\t\t\t<keyframe time=\"" << t.keyframes[k].time << "\">\n";
448                                                // translation
449                                                params.outSkeleton << "\t\t\t\t\t\t\t<translate x=\"" << t.keyframes[k].tx << "\" y=\"" <<
450                                                        t.keyframes[k].ty << "\" z=\"" << t.keyframes[k].tz << "\"/>\n";
451                                                // rotation
452                                                params.outSkeleton << "\t\t\t\t\t\t\t<rotate angle=\"" << t.keyframes[k].angle << "\">\n";
453                                                params.outSkeleton << "\t\t\t\t\t\t\t\t<axis x=\"" << t.keyframes[k].axis_x << "\" y=\"" <<
454                                                        t.keyframes[k].axis_y << "\" z=\"" << t.keyframes[k].axis_z << "\"/>\n";
455                                                params.outSkeleton << "\t\t\t\t\t\t\t</rotate>\n";
456                                                //scale
457                                                params.outSkeleton << "\t\t\t\t\t\t\t<scale x=\"" << t.keyframes[k].sx << "\" y=\"" <<
458                                                        t.keyframes[k].sy << "\" z=\"" << t.keyframes[k].sz << "\"/>\n";
459                                                params.outSkeleton << "\t\t\t\t\t\t</keyframe>\n";
460                                        }
461                                        params.outSkeleton << "\t\t\t\t\t</keyframes>\n";
462                                        params.outSkeleton << "\t\t\t\t</track>\n";
463                                }
464                                // End tracks description
465                                params.outSkeleton << "\t\t\t</tracks>\n";
466                                // End animation description
467                                params.outSkeleton << "\t\t</animation>\n";
468                        }
469                        params.outSkeleton << "\t</animations>\n";
470                }
471
472                // End skeleton description
473                params.outSkeleton << "</skeleton>\n";
474
475                return MS::kSuccess;
476        }
477
478
479};      //end namespace
Note: See TracBrowser for help on using the repository browser.