SO3Engine
ALSkeleton.cpp
Go to the documentation of this file.
3
4#include <exception>
5#include <stack>
6
7namespace SO3
8{
9 aiNode* ALSkeleton::findMeshNode(aiNode* node, const aiMesh* mesh)
10 {
11 if (node == nullptr)
12 return nullptr;
13
14 for (unsigned int i = 0; i < node->mNumMeshes; ++i)
15 {
16 const aiMesh* nodeMesh = mScene->getAiScene()->mMeshes[node->mMeshes[i]];
17 if (nodeMesh == mesh)
18 return node;
19 }
20
21 for (unsigned int i = 0; i < node->mNumChildren; ++i)
22 {
23 aiNode* child = findMeshNode(node->mChildren[i], mesh);
24 if (child != nullptr)
25 return child;
26 }
27
28 return nullptr;
29 }
30
32 {
33 // Get the bone associated with this node, if any
34 const aiBone* bone = nullptr;
35 const aiScene* scene = mScene->getAiScene();
36
37 aiMatrix4x4 meshInverseTrans = aiMatrix4x4().Inverse();
38
39 for (unsigned int i = 0; i < scene->mNumMeshes; ++i)
40 {
41 const aiMesh* mesh = scene->mMeshes[i];
42 for (unsigned int j = 0; j < mesh->mNumBones; ++j)
43 {
44 const aiBone* b = mesh->mBones[j];
45 if (strcmp(b->mName.C_Str(), node->mName.C_Str()) == 0)
46 {
47 aiNode* meshNode = findMeshNode(scene->mRootNode, mesh);
48 if (meshNode != nullptr)
49 meshInverseTrans = mScene->getFullTransform(meshNode).Inverse();
50 bone = b;
51 break;
52 }
53 }
54 if (bone) break;
55 }
56
57 if (!bone)
58 {
59 // If the node has no associated bone, return its transformation matrix
60 return mScene->getFullTransform(node);
61 }
62
63 // Compute the transformation matrix from bone space to mesh space
64 aiMatrix4x4 boneToMesh = meshInverseTrans * mScene->getFullTransform(node) * bone->mOffsetMatrix;
65
66 return boneToMesh * meshInverseTrans.Inverse();
67 }
68
70 {
71 aiNode* node = mBones[bid].mNode;
72 aiBone* bone = mBones[bid].mBone;
73
74 aiNode* parent = (node->mParent && mScene->isBone(node->mParent)) ? node->mParent : mNode;
75
76 aiMatrix4x4 bonemat = mScene->getFullTransform(node);
77
78 if (parent == mScene->getAiScene()->mRootNode)
79 return bonemat;
80
81 aiMatrix4x4 parmat = mScene->getFullTransform(parent);
82
83 //then return relative matrix in coordinate space of parent
84 return parmat.Inverse() * bonemat;
85
86 /*
87 aiMatrix4x4 bonemat = getNodeLocalTransformWithBindPose(node);
88 if (parent == mScene->getAiScene()->mRootNode)
89 return bonemat;
90
91 aiMatrix4x4 parmat = getNodeLocalTransformWithBindPose(parent);
92
93 //then return relative matrix in coordinate space of parent
94 return parmat.Inverse() * bonemat;
95 */
96 }
97
99 {
100 mScene = 0;
101 mNode = 0;
102 }
103
104 ALSkeleton::ALSkeleton(ALScene* alscene, Ogre::SkeletonPtr skeleton, aiNode* attach)
105 {
106 mScene = alscene;
107 mSkeleton = skeleton;
108 mNode = attach;
109 }
110
114
116 {
117 aiNode* newBone = 0;
118 aiNode* curBone = mBones[0].mNode;
119 while(mScene->isBone(curBone))
120 {
121 newBone = curBone;
122 curBone = curBone->mParent;
123 }
124
125 return newBone;
126 }
127
128 aiBone* ALSkeleton::getBoneFromNode(aiNode* node)
129 {
130 //search the bone in all submeshes
131 aiBone* bone = 0;
132 for (unsigned int i = 0; i < mNode->mNumMeshes && !bone; ++i)
133 {
134 aiMesh* mesh = mScene->getAiScene()->mMeshes[mNode->mMeshes[i]];
135 for (unsigned int j = 0; j < mesh->mNumBones && !bone; ++j)
136 {
137 if (mesh->mBones[j]->mName == node->mName)
138 bone = mesh->mBones[j];
139 }
140 }
141
142 return bone;
143 }
144
145 ALBone ALSkeleton::getBoneNodeByName(const std::string name)
146 {
147 for(unsigned int i = 0; i < mBones.size(); ++i)
148 {
149 if (std::string(mBones[i].mNode->mName.C_Str()) == name)
150 {
151 return mBones[i];
152 }
153 }
154
155 return ALBone(0, 0);
156 }
157
158 int ALSkeleton::getBoneIndexByName(const std::string name)
159 {
160 for (unsigned int i = 0; i < mBones.size(); ++i)
161 {
162 if (std::string(mBones[i].mNode->mName.C_Str()) == name)
163 {
164 return i;
165 }
166 }
167
168 return -1;
169 }
170
171 void ALSkeleton::addBone(aiNode* node, aiBone* bone, Ogre::SubMesh* submesh)
172 {
173 std::string name = node->mName.C_Str();
174 if(node)
175 {
176 Ogre::Bone* ogreBone = 0;
177 if(mSkeleton->hasBone(name))
178 {
179 ogreBone = mSkeleton->getBone(name);
180 }
181 else
182 {
183 ogreBone = mSkeleton->createBone(name);
184 mBones.push_back(ALBone(node, bone));
185 }
186 }
187
188 if (bone)
189 {
190 int bid = getBoneIndexByName(name);
191 if (bid >= 0)
192 mBones[bid].mBone = bone;
193
194 //can fail with bad characters in names
195 if(mSkeleton->hasBone(name))
196 {
197 Ogre::Bone* ogreBone = mSkeleton->getBone(name);
198
199 for(unsigned int n=0; n<bone->mNumWeights; ++n)
200 {
201 Ogre::VertexBoneAssignment vba;
202 aiVertexWeight aiWeight = bone->mWeights[n];
203
204 vba.boneIndex = ogreBone->getHandle();
205 vba.vertexIndex = aiWeight.mVertexId;
206 vba.weight = aiWeight.mWeight;
207 submesh->addBoneAssignment(vba);
208 }
209 }
210 }
211 }
212
213 void ALSkeleton::makeHierarchy(aiMatrix4x4 meshInverseTrans)
214 {
215 for(unsigned int n=0; n<mBones.size(); ++n)
216 {
217 aiNode* node = mBones[n].mNode;
218 aiBone* bone = mBones[n].mBone;
219 std::string boneName = node->mName.C_Str();
220
221 // set bone matrix
222 Ogre::Bone* ogreBone = 0;
223 if (mSkeleton->hasBone(boneName))
224 ogreBone = mSkeleton->getBone(boneName);
225
226 if (ogreBone)
227 {
228 //todo getLocalUniformMatrix and apply bindoffset of bone and parent bone
229 aiMatrix4x4 bindTrans(getLocalUniformMatrix(n));
230 //if (bone != NULL)
231 //{
232 // aiMatrix4x4 localbone = bone->mOffsetMatrix;
233 // bindTrans = localbone;
234 //}
235
236 mBones[n].mBindMatrix = bindTrans;
237
238 //set bind pos
239 aiVector3D scale;
240 aiVector3D pos;
241 aiQuaternion rotation;
242
243 bindTrans.Decompose(scale, rotation, pos);
244 Ogre::Bone* ogreBone = mSkeleton->getBone(boneName);
245 ogreBone->setPosition(pos.x, pos.y, pos.z);
246 ogreBone->setScale(scale.x, scale.y, scale.z);
247 ogreBone->setOrientation(rotation.w, rotation.x, rotation.y, rotation.z);
248 ogreBone->setBindingPose();
249 ogreBone->setInitialState();
250
251 //mBones[n].mBindMatrix.Inverse();
252
253 for(unsigned int i=0; i<node->mNumChildren; ++i)
254 {
255 aiNode* child = node->mChildren[i];
256 std::string childName = child->mName.C_Str();
257 if(mScene->isBone(child))
258 {
259 if(mSkeleton->hasBone(childName))
260 {
261 try
262 {
263 ogreBone->addChild(mSkeleton->getBone(childName));
264 }
265 catch (Ogre::Exception &)
266 {
267 // Child already present for redundant bones.
268 // Ignore.
269 }
270 }
271 }
272 }
273 }
274 }
275 //force skeleton update
276 mSkeleton->getRootBones();
277 }
278
279 std::vector<aiAnimation*> ALSkeleton::findConcernedAnimation()
280 {
281 aiAnimation** allAnims = mScene->getAiScene()->mAnimations;
282 std::vector<aiAnimation*> concernedAnims;
283
284 for(unsigned int n=0; n<mScene->getAiScene()->mNumAnimations; ++n)
285 {
286 aiNodeAnim** allNodeAnims = allAnims[n]->mChannels;
287 for(unsigned int i=0; i<allAnims[n]->mNumChannels; ++i)
288 {
289 // only one needed
290 if (getBoneNodeByName(allNodeAnims[i]->mNodeName.C_Str()).mNode)
291 {
292 concernedAnims.push_back(allAnims[n]);
293 break;
294 }
295 }
296 }
297
298 return concernedAnims;
299 }
300
301 template<typename T> T ALSkeleton::getBiggerValue(T* data, unsigned int size)
302 {
303 T res = data[0];
304 for(unsigned int n=1; n<size; ++n)
305 {
306 if(data[n]>res)
307 res = data[n];
308 }
309 return res;
310 }
311
313 {
314 std::vector<aiAnimation*> anims = findConcernedAnimation();
315 for(unsigned int n=0; n<anims.size(); ++n)
316 {
317 generateAnimation(anims[n]);
318 }
319 }
320
321 void ALSkeleton::generateAnimation(aiAnimation* anim)
322 {
323 std::string animName(anim->mName.C_Str());
324 animName = ALStringCleaner::cleanString(animName);
325
326 Ogre::Animation* ogreAnim = mSkeleton->createAnimation(animName, static_cast<float>(anim->mDuration/anim->mTicksPerSecond));
327 ogreAnim->setLength((float)(anim->mDuration/anim->mTicksPerSecond));
328
329 aiMatrix4x4 meshTrans = mScene->getFullTransform(mNode);
330 aiMatrix4x4 meshInverseTrans = meshTrans;
331 meshInverseTrans.Inverse();
332
333 aiNodeAnim** boneAnim = anim->mChannels;
334 for(unsigned int i=0; i<anim->mNumChannels; ++i)
335 {
336 if(mSkeleton->hasBone(boneAnim[i]->mNodeName.C_Str()))
337 {
338 ALBone bone = getBoneNodeByName(boneAnim[i]->mNodeName.C_Str());
339 aiNode* currentBone = bone.mNode;
340 Ogre::Bone* ogbone = mSkeleton->getBone(boneAnim[i]->mNodeName.C_Str());
341
342 aiVectorKey* posKey = boneAnim[i]->mPositionKeys;
343 aiQuatKey* rotKey = boneAnim[i]->mRotationKeys;
344 aiVectorKey* scaleKey = boneAnim[i]->mScalingKeys;
345 unsigned int nbKey[3] = {boneAnim[i]->mNumPositionKeys, boneAnim[i]->mNumRotationKeys, boneAnim[i]->mNumScalingKeys};
346 unsigned int keySize = getBiggerValue(nbKey, 3);
347
348 std::set<float> times;
349 for(unsigned int n=0; n<keySize; ++n)
350 {
351 if(boneAnim[i]->mNumPositionKeys > n)
352 {
353 times.insert(static_cast<float>(posKey[n].mTime));
354 }
355
356 if(boneAnim[i]->mNumScalingKeys > n)
357 {
358 times.insert(static_cast<float>(scaleKey[n].mTime));
359 }
360
361 if(boneAnim[i]->mNumRotationKeys > n)
362 {
363 times.insert(static_cast<float>(rotKey[n].mTime));
364 }
365 }
366
367 std::vector<ALKeyFrame> keyframes;
368 for(std::set<float>::iterator it=times.begin(); it!=times.end(); ++it)
369 {
370 ALKeyFrame key(*it);
371
372 for(unsigned int n=0; n<keySize; ++n)
373 {
374 if(boneAnim[i]->mNumPositionKeys > n)
375 {
376 if(posKey[n].mTime == *it)
377 {
378 key.setPosition(posKey[n]);
379 }
380 }
381
382 if(boneAnim[i]->mNumScalingKeys > n)
383 {
384 if(scaleKey[n].mTime == *it)
385 {
386 key.setScale(scaleKey[n]);
387 }
388 }
389
390 if(boneAnim[i]->mNumRotationKeys > n)
391 {
392 if(rotKey[n].mTime == *it)
393 {
394 key.setRotation(rotKey[n]);
395 }
396 }
397 }
398
399 keyframes.push_back(key);
400 }
401
402 Ogre::NodeAnimationTrack* nAnimTrk = ogreAnim->createNodeTrack(ogbone->getHandle(), ogbone);
403 for(unsigned int n=0; n<keyframes.size(); ++n)
404 {
405 if (currentBone != 0)
406 {
407 keyframes[n].createInterpolation(keyframes, currentBone);
408
409 aiVector3D kpos = keyframes[n].getPosition().mValue;
410 aiQuaternion krotation = keyframes[n].getRotation().mValue;
411 aiVector3D kscale = keyframes[n].getScale().mValue;
412
413 aiVector3D bpos;
414 aiQuaternion brotation;
415 aiVector3D bscale;
416
417 aiMatrix4x4 boneMat(kscale, krotation, kpos);
418
419 bone.mBindMatrix.Decompose(bscale, brotation, bpos);
420 if (currentBone->mParent && !mScene->isBone(currentBone->mParent)) // root bone
421 {
422 boneMat = mScene->getFullTransform(currentBone->mParent) * boneMat;
423 boneMat = meshInverseTrans * boneMat;
424 boneMat.Decompose(kscale, krotation, kpos);
425 }
426
427 kpos -= bpos;
428 krotation = aiQuaternion(brotation.GetMatrix().Inverse() * krotation.GetMatrix());
429 Ogre::TransformKeyFrame* key = nAnimTrk->createNodeKeyFrame((float)(keyframes[n].getTime() / anim->mTicksPerSecond));
430 key->setTranslate(Ogre::Vector3(kpos.x, kpos.y, kpos.z));
431 key->setRotation(Ogre::Quaternion(krotation.w, krotation.x, krotation.y, krotation.z));
432 key->setScale(Ogre::Vector3(kscale.x, kscale.y, kscale.z));
433 }
434 }
435 }
436 }
437
438 mSkeleton->optimiseAllAnimations();
439 }
440}
static std::string cleanString(std::string str, bool toLower=true, bool clASCII=true, bool clSpaces=true, bool bUID=true)
Clean a string.
aiNode * mNode
Definition ALSkeleton.h:27
aiMatrix4x4 mBindMatrix
Definition ALSkeleton.h:26
void setRotation(aiQuatKey rotationKey)
void setPosition(aiVectorKey positionkey)
void setScale(aiVectorKey scaleKey)
aiMatrix4x4 getFullTransform(aiNode *toThis)
Definition ALScene.cpp:60
const aiScene * getAiScene()
Definition ALScene.cpp:492
bool isBone(aiNode *node)
Check if a node is a bone.
Definition ALScene.cpp:517
void addBone(aiNode *node, aiBone *bone, Ogre::SubMesh *submesh)
void makeHierarchy(aiMatrix4x4 meshInverseTrans)
aiNode * findMeshNode(aiNode *node, const aiMesh *mesh)
Definition ALSkeleton.cpp:9
int getBoneIndexByName(const std::string name)
aiNode * getRootNode()
void processAnimation()
aiMatrix4x4 getNodeLocalTransformWithBindPose(aiNode *node)
ALBone getBoneNodeByName(const std::string name)
void generateAnimation(aiAnimation *anim)
aiBone * getBoneFromNode(aiNode *node)
aiMatrix4x4 getLocalUniformMatrix(int bid)
std::vector< aiAnimation * > findConcernedAnimation()