vrshoot
diff libs/assimp/OgreSkeleton.cpp @ 0:b2f14e535253
initial commit
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Sat, 01 Feb 2014 19:58:19 +0200 |
parents | |
children |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/libs/assimp/OgreSkeleton.cpp Sat Feb 01 19:58:19 2014 +0200 1.3 @@ -0,0 +1,451 @@ 1.4 +/* 1.5 +Open Asset Import Library (assimp) 1.6 +---------------------------------------------------------------------- 1.7 + 1.8 +Copyright (c) 2006-2012, assimp team 1.9 +All rights reserved. 1.10 + 1.11 +Redistribution and use of this software in source and binary forms, 1.12 +with or without modification, are permitted provided that the 1.13 +following conditions are met: 1.14 + 1.15 +* Redistributions of source code must retain the above 1.16 + copyright notice, this list of conditions and the 1.17 + following disclaimer. 1.18 + 1.19 +* Redistributions in binary form must reproduce the above 1.20 + copyright notice, this list of conditions and the 1.21 + following disclaimer in the documentation and/or other 1.22 + materials provided with the distribution. 1.23 + 1.24 +* Neither the name of the assimp team, nor the names of its 1.25 + contributors may be used to endorse or promote products 1.26 + derived from this software without specific prior 1.27 + written permission of the assimp team. 1.28 + 1.29 +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 1.30 +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 1.31 +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 1.32 +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 1.33 +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 1.34 +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 1.35 +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 1.36 +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 1.37 +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 1.38 +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 1.39 +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 1.40 + 1.41 +---------------------------------------------------------------------- 1.42 +*/ 1.43 + 1.44 +#include "AssimpPCH.h" 1.45 + 1.46 +#ifndef ASSIMP_BUILD_NO_OGRE_IMPORTER 1.47 + 1.48 +#include "OgreImporter.hpp" 1.49 +#include "TinyFormatter.h" 1.50 + 1.51 +using namespace std; 1.52 + 1.53 +namespace Assimp 1.54 +{ 1.55 +namespace Ogre 1.56 +{ 1.57 + 1.58 + 1.59 + 1.60 +void OgreImporter::LoadSkeleton(std::string FileName, vector<Bone> &Bones, vector<Animation> &Animations) const 1.61 +{ 1.62 + const aiScene* const m_CurrentScene=this->m_CurrentScene;//make sure, that we can access but not change the scene 1.63 + (void)m_CurrentScene; 1.64 + 1.65 + 1.66 + //most likely the skeleton file will only end with .skeleton 1.67 + //But this is a xml reader, so we need: .skeleton.xml 1.68 + FileName+=".xml"; 1.69 + 1.70 + DefaultLogger::get()->debug(string("Loading Skeleton: ")+FileName); 1.71 + 1.72 + //Open the File: 1.73 + boost::scoped_ptr<IOStream> File(m_CurrentIOHandler->Open(FileName)); 1.74 + if(NULL==File.get()) 1.75 + throw DeadlyImportError("Failed to open skeleton file "+FileName+"."); 1.76 + 1.77 + //Read the Mesh File: 1.78 + boost::scoped_ptr<CIrrXML_IOStreamReader> mIOWrapper(new CIrrXML_IOStreamReader(File.get())); 1.79 + XmlReader* SkeletonFile = irr::io::createIrrXMLReader(mIOWrapper.get()); 1.80 + if(!SkeletonFile) 1.81 + throw DeadlyImportError(string("Failed to create XML Reader for ")+FileName); 1.82 + 1.83 + XmlRead(SkeletonFile); 1.84 + if(string("skeleton")!=SkeletonFile->getNodeName()) 1.85 + throw DeadlyImportError("No <skeleton> node in SkeletonFile: "+FileName); 1.86 + 1.87 + 1.88 + 1.89 + //------------------------------------load bones----------------------------------------- 1.90 + XmlRead(SkeletonFile); 1.91 + if(string("bones")!=SkeletonFile->getNodeName()) 1.92 + throw DeadlyImportError("No bones node in skeleton "+FileName); 1.93 + 1.94 + XmlRead(SkeletonFile); 1.95 + 1.96 + while(string("bone")==SkeletonFile->getNodeName()) 1.97 + { 1.98 + //TODO: Maybe we can have bone ids for the errrors, but normaly, they should never appear, so what.... 1.99 + 1.100 + //read a new bone: 1.101 + Bone NewBone; 1.102 + NewBone.Id=GetAttribute<int>(SkeletonFile, "id"); 1.103 + NewBone.Name=GetAttribute<string>(SkeletonFile, "name"); 1.104 + 1.105 + //load the position: 1.106 + XmlRead(SkeletonFile); 1.107 + if(string("position")!=SkeletonFile->getNodeName()) 1.108 + throw DeadlyImportError("Position is not first node in Bone!"); 1.109 + NewBone.Position.x=GetAttribute<float>(SkeletonFile, "x"); 1.110 + NewBone.Position.y=GetAttribute<float>(SkeletonFile, "y"); 1.111 + NewBone.Position.z=GetAttribute<float>(SkeletonFile, "z"); 1.112 + 1.113 + //Rotation: 1.114 + XmlRead(SkeletonFile); 1.115 + if(string("rotation")!=SkeletonFile->getNodeName()) 1.116 + throw DeadlyImportError("Rotation is not the second node in Bone!"); 1.117 + NewBone.RotationAngle=GetAttribute<float>(SkeletonFile, "angle"); 1.118 + XmlRead(SkeletonFile); 1.119 + if(string("axis")!=SkeletonFile->getNodeName()) 1.120 + throw DeadlyImportError("No axis specified for bone rotation!"); 1.121 + NewBone.RotationAxis.x=GetAttribute<float>(SkeletonFile, "x"); 1.122 + NewBone.RotationAxis.y=GetAttribute<float>(SkeletonFile, "y"); 1.123 + NewBone.RotationAxis.z=GetAttribute<float>(SkeletonFile, "z"); 1.124 + 1.125 + //append the newly loaded bone to the bone list 1.126 + Bones.push_back(NewBone); 1.127 + 1.128 + //Proceed to the next bone: 1.129 + XmlRead(SkeletonFile); 1.130 + } 1.131 + //The bones in the file a not neccesarly ordered by there id's so we do it now: 1.132 + std::sort(Bones.begin(), Bones.end()); 1.133 + 1.134 + //now the id of each bone should be equal to its position in the vector: 1.135 + //so we do a simple check: 1.136 + { 1.137 + bool IdsOk=true; 1.138 + for(int i=0; i<static_cast<signed int>(Bones.size()); ++i)//i is signed, because all Id's are also signed! 1.139 + { 1.140 + if(Bones[i].Id!=i) 1.141 + IdsOk=false; 1.142 + } 1.143 + if(!IdsOk) 1.144 + throw DeadlyImportError("Bone Ids are not valid!"+FileName); 1.145 + } 1.146 + DefaultLogger::get()->debug((Formatter::format(),"Number of bones: ",Bones.size())); 1.147 + //________________________________________________________________________________ 1.148 + 1.149 + 1.150 + 1.151 + 1.152 + 1.153 + 1.154 + //----------------------------load bonehierarchy-------------------------------- 1.155 + if(string("bonehierarchy")!=SkeletonFile->getNodeName()) 1.156 + throw DeadlyImportError("no bonehierarchy node in "+FileName); 1.157 + 1.158 + DefaultLogger::get()->debug("loading bonehierarchy..."); 1.159 + XmlRead(SkeletonFile); 1.160 + while(string("boneparent")==SkeletonFile->getNodeName()) 1.161 + { 1.162 + string Child, Parent; 1.163 + Child=GetAttribute<string>(SkeletonFile, "bone"); 1.164 + Parent=GetAttribute<string>(SkeletonFile, "parent"); 1.165 + 1.166 + unsigned int ChildId, ParentId; 1.167 + ChildId=find(Bones.begin(), Bones.end(), Child)->Id; 1.168 + ParentId=find(Bones.begin(), Bones.end(), Parent)->Id; 1.169 + 1.170 + Bones[ChildId].ParentId=ParentId; 1.171 + Bones[ParentId].Children.push_back(ChildId); 1.172 + 1.173 + XmlRead(SkeletonFile); 1.174 + } 1.175 + //_____________________________________________________________________________ 1.176 + 1.177 + 1.178 + //--------- Calculate the WorldToBoneSpace Matrix recursively for all bones: ------------------ 1.179 + BOOST_FOREACH(Bone &theBone, Bones) 1.180 + { 1.181 + if(-1==theBone.ParentId) //the bone is a root bone 1.182 + { 1.183 + theBone.CalculateBoneToWorldSpaceMatrix(Bones); 1.184 + } 1.185 + } 1.186 + //_______________________________________________________________________ 1.187 + 1.188 + 1.189 + //---------------------------load animations----------------------------- 1.190 + if(string("animations")==SkeletonFile->getNodeName())//animations are optional values 1.191 + { 1.192 + DefaultLogger::get()->debug("Loading Animations"); 1.193 + XmlRead(SkeletonFile); 1.194 + while(string("animation")==SkeletonFile->getNodeName()) 1.195 + { 1.196 + Animation NewAnimation; 1.197 + NewAnimation.Name=GetAttribute<string>(SkeletonFile, "name"); 1.198 + NewAnimation.Length=GetAttribute<float>(SkeletonFile, "length"); 1.199 + 1.200 + //Load all Tracks 1.201 + XmlRead(SkeletonFile); 1.202 + if(string("tracks")!=SkeletonFile->getNodeName()) 1.203 + throw DeadlyImportError("no tracks node in animation"); 1.204 + XmlRead(SkeletonFile); 1.205 + while(string("track")==SkeletonFile->getNodeName()) 1.206 + { 1.207 + Track NewTrack; 1.208 + NewTrack.BoneName=GetAttribute<string>(SkeletonFile, "bone"); 1.209 + 1.210 + //Load all keyframes; 1.211 + XmlRead(SkeletonFile); 1.212 + if(string("keyframes")!=SkeletonFile->getNodeName()) 1.213 + throw DeadlyImportError("no keyframes node!"); 1.214 + XmlRead(SkeletonFile); 1.215 + while(string("keyframe")==SkeletonFile->getNodeName()) 1.216 + { 1.217 + Keyframe NewKeyframe; 1.218 + NewKeyframe.Time=GetAttribute<float>(SkeletonFile, "time"); 1.219 + 1.220 + //loop over the attributes: 1.221 + 1.222 + while(true) //will quit, if a Node is not a animationkey 1.223 + { 1.224 + XmlRead(SkeletonFile); 1.225 + 1.226 + //If any property doesn't show up, it will keep its initialization value 1.227 + 1.228 + //Position: 1.229 + if(string("translate")==SkeletonFile->getNodeName()) 1.230 + { 1.231 + NewKeyframe.Position.x=GetAttribute<float>(SkeletonFile, "x"); 1.232 + NewKeyframe.Position.y=GetAttribute<float>(SkeletonFile, "y"); 1.233 + NewKeyframe.Position.z=GetAttribute<float>(SkeletonFile, "z"); 1.234 + } 1.235 + 1.236 + //Rotation: 1.237 + else if(string("rotate")==SkeletonFile->getNodeName()) 1.238 + { 1.239 + float RotationAngle=GetAttribute<float>(SkeletonFile, "angle"); 1.240 + aiVector3D RotationAxis; 1.241 + XmlRead(SkeletonFile); 1.242 + if(string("axis")!=SkeletonFile->getNodeName()) 1.243 + throw DeadlyImportError("No axis for keyframe rotation!"); 1.244 + RotationAxis.x=GetAttribute<float>(SkeletonFile, "x"); 1.245 + RotationAxis.y=GetAttribute<float>(SkeletonFile, "y"); 1.246 + RotationAxis.z=GetAttribute<float>(SkeletonFile, "z"); 1.247 + 1.248 + if(0==RotationAxis.x && 0==RotationAxis.y && 0==RotationAxis.z)//we have an invalid rotation axis 1.249 + { 1.250 + RotationAxis.x=1.0f; 1.251 + if(0!=RotationAngle)//if we don't rotate at all, the axis does not matter 1.252 + { 1.253 + DefaultLogger::get()->warn("Invalid Rotation Axis in Keyframe!"); 1.254 + } 1.255 + } 1.256 + NewKeyframe.Rotation=aiQuaternion(RotationAxis, RotationAngle); 1.257 + } 1.258 + 1.259 + //Scaling: 1.260 + else if(string("scale")==SkeletonFile->getNodeName()) 1.261 + { 1.262 + NewKeyframe.Scaling.x=GetAttribute<float>(SkeletonFile, "x"); 1.263 + NewKeyframe.Scaling.y=GetAttribute<float>(SkeletonFile, "y"); 1.264 + NewKeyframe.Scaling.z=GetAttribute<float>(SkeletonFile, "z"); 1.265 + } 1.266 + 1.267 + //we suppose, that we read all attributes and this is a new keyframe or the end of the animation 1.268 + else 1.269 + break; 1.270 + } 1.271 + 1.272 + NewTrack.Keyframes.push_back(NewKeyframe); 1.273 + } 1.274 + 1.275 + NewAnimation.Tracks.push_back(NewTrack); 1.276 + } 1.277 + 1.278 + Animations.push_back(NewAnimation); 1.279 + } 1.280 + } 1.281 + //_____________________________________________________________________________ 1.282 + 1.283 +} 1.284 + 1.285 + 1.286 +void OgreImporter::CreateAssimpSkeleton(const std::vector<Bone> &Bones, const std::vector<Animation> &/*Animations*/) 1.287 +{ 1.288 + if(!m_CurrentScene->mRootNode) 1.289 + throw DeadlyImportError("No root node exists!!"); 1.290 + if(0!=m_CurrentScene->mRootNode->mNumChildren) 1.291 + throw DeadlyImportError("Root Node already has childnodes!"); 1.292 + 1.293 + 1.294 + //Createt the assimp bone hierarchy 1.295 + vector<aiNode*> RootBoneNodes; 1.296 + BOOST_FOREACH(const Bone &theBone, Bones) 1.297 + { 1.298 + if(-1==theBone.ParentId) //the bone is a root bone 1.299 + { 1.300 + //which will recursily add all other nodes 1.301 + RootBoneNodes.push_back(CreateAiNodeFromBone(theBone.Id, Bones, m_CurrentScene->mRootNode)); 1.302 + } 1.303 + } 1.304 + 1.305 + if(RootBoneNodes.size() > 0) 1.306 + { 1.307 + m_CurrentScene->mRootNode->mNumChildren=RootBoneNodes.size(); 1.308 + m_CurrentScene->mRootNode->mChildren=new aiNode*[RootBoneNodes.size()]; 1.309 + memcpy(m_CurrentScene->mRootNode->mChildren, &RootBoneNodes[0], sizeof(aiNode*)*RootBoneNodes.size()); 1.310 + } 1.311 +} 1.312 + 1.313 + 1.314 +void OgreImporter::PutAnimationsInScene(const std::vector<Bone> &Bones, const std::vector<Animation> &Animations) 1.315 +{ 1.316 + //-----------------Create the Assimp Animations -------------------- 1.317 + if(Animations.size()>0)//Maybe the model had only a skeleton and no animations. (If it also has no skeleton, this function would'nt have been called 1.318 + { 1.319 + m_CurrentScene->mNumAnimations=Animations.size(); 1.320 + m_CurrentScene->mAnimations=new aiAnimation*[Animations.size()]; 1.321 + for(unsigned int i=0; i<Animations.size(); ++i)//create all animations 1.322 + { 1.323 + aiAnimation* NewAnimation=new aiAnimation(); 1.324 + NewAnimation->mName=Animations[i].Name; 1.325 + NewAnimation->mDuration=Animations[i].Length; 1.326 + NewAnimation->mTicksPerSecond=1.0f; 1.327 + 1.328 + //Create all tracks in this animation 1.329 + NewAnimation->mNumChannels=Animations[i].Tracks.size(); 1.330 + NewAnimation->mChannels=new aiNodeAnim*[Animations[i].Tracks.size()]; 1.331 + for(unsigned int j=0; j<Animations[i].Tracks.size(); ++j) 1.332 + { 1.333 + aiNodeAnim* NewNodeAnim=new aiNodeAnim(); 1.334 + NewNodeAnim->mNodeName=Animations[i].Tracks[j].BoneName; 1.335 + 1.336 + //we need this, to acces the bones default pose, which we need to make keys absolute to the default bone pose 1.337 + vector<Bone>::const_iterator CurBone=find(Bones.begin(), Bones.end(), NewNodeAnim->mNodeName); 1.338 + aiMatrix4x4 t0, t1; 1.339 + aiMatrix4x4 DefBonePose=aiMatrix4x4::Translation(CurBone->Position, t1) 1.340 + * aiMatrix4x4::Rotation(CurBone->RotationAngle, CurBone->RotationAxis, t0); 1.341 + 1.342 + 1.343 + //Create the keyframe arrays... 1.344 + unsigned int KeyframeCount=Animations[i].Tracks[j].Keyframes.size(); 1.345 + NewNodeAnim->mNumPositionKeys=KeyframeCount; 1.346 + NewNodeAnim->mNumRotationKeys=KeyframeCount; 1.347 + NewNodeAnim->mNumScalingKeys =KeyframeCount; 1.348 + NewNodeAnim->mPositionKeys=new aiVectorKey[KeyframeCount]; 1.349 + NewNodeAnim->mRotationKeys=new aiQuatKey[KeyframeCount]; 1.350 + NewNodeAnim->mScalingKeys =new aiVectorKey[KeyframeCount]; 1.351 + 1.352 + //...and fill them 1.353 + for(unsigned int k=0; k<KeyframeCount; ++k) 1.354 + { 1.355 + aiMatrix4x4 t2, t3; 1.356 + 1.357 + //Create a matrix to transfrom a vector from the bones default pose to the bone bones in this animation key 1.358 + aiMatrix4x4 PoseToKey= 1.359 + aiMatrix4x4::Translation(Animations[i].Tracks[j].Keyframes[k].Position, t3) //pos 1.360 + * aiMatrix4x4(Animations[i].Tracks[j].Keyframes[k].Rotation.GetMatrix()) //rot 1.361 + * aiMatrix4x4::Scaling(Animations[i].Tracks[j].Keyframes[k].Scaling, t2); //scale 1.362 + 1.363 + 1.364 + //calculate the complete transformation from world space to bone space 1.365 + aiMatrix4x4 CompleteTransform=DefBonePose * PoseToKey; 1.366 + 1.367 + aiVector3D Pos; 1.368 + aiQuaternion Rot; 1.369 + aiVector3D Scale; 1.370 + 1.371 + CompleteTransform.Decompose(Scale, Rot, Pos); 1.372 + 1.373 + double Time=Animations[i].Tracks[j].Keyframes[k].Time; 1.374 + 1.375 + NewNodeAnim->mPositionKeys[k].mTime=Time; 1.376 + NewNodeAnim->mPositionKeys[k].mValue=Pos; 1.377 + 1.378 + NewNodeAnim->mRotationKeys[k].mTime=Time; 1.379 + NewNodeAnim->mRotationKeys[k].mValue=Rot; 1.380 + 1.381 + NewNodeAnim->mScalingKeys[k].mTime=Time; 1.382 + NewNodeAnim->mScalingKeys[k].mValue=Scale; 1.383 + } 1.384 + 1.385 + NewAnimation->mChannels[j]=NewNodeAnim; 1.386 + } 1.387 + 1.388 + m_CurrentScene->mAnimations[i]=NewAnimation; 1.389 + } 1.390 + } 1.391 +//TODO: Auf nicht vorhandene Animationskeys achten! 1.392 +//#pragma warning (s.o.) 1.393 + //__________________________________________________________________ 1.394 +} 1.395 + 1.396 + 1.397 +aiNode* OgreImporter::CreateAiNodeFromBone(int BoneId, const std::vector<Bone> &Bones, aiNode* ParentNode) 1.398 +{ 1.399 + //----Create the node for this bone and set its values----- 1.400 + aiNode* NewNode=new aiNode(Bones[BoneId].Name); 1.401 + NewNode->mParent=ParentNode; 1.402 + 1.403 + aiMatrix4x4 t0,t1; 1.404 + NewNode->mTransformation= 1.405 + aiMatrix4x4::Translation(Bones[BoneId].Position, t0) 1.406 + *aiMatrix4x4::Rotation(Bones[BoneId].RotationAngle, Bones[BoneId].RotationAxis, t1) 1.407 + ; 1.408 + //__________________________________________________________ 1.409 + 1.410 + 1.411 + //---------- recursivly create all children Nodes: ---------- 1.412 + NewNode->mNumChildren=Bones[BoneId].Children.size(); 1.413 + NewNode->mChildren=new aiNode*[Bones[BoneId].Children.size()]; 1.414 + for(unsigned int i=0; i<Bones[BoneId].Children.size(); ++i) 1.415 + { 1.416 + NewNode->mChildren[i]=CreateAiNodeFromBone(Bones[BoneId].Children[i], Bones, NewNode); 1.417 + } 1.418 + //____________________________________________________ 1.419 + 1.420 + 1.421 + return NewNode; 1.422 +} 1.423 + 1.424 + 1.425 +void Bone::CalculateBoneToWorldSpaceMatrix(vector<Bone> &Bones) 1.426 +{ 1.427 + //Calculate the matrix for this bone: 1.428 + 1.429 + aiMatrix4x4 t0,t1; 1.430 + aiMatrix4x4 Transf= aiMatrix4x4::Rotation(-RotationAngle, RotationAxis, t1) 1.431 + * aiMatrix4x4::Translation(-Position, t0); 1.432 + 1.433 + if(-1==ParentId) 1.434 + { 1.435 + BoneToWorldSpace=Transf; 1.436 + } 1.437 + else 1.438 + { 1.439 + BoneToWorldSpace=Transf*Bones[ParentId].BoneToWorldSpace; 1.440 + } 1.441 + 1.442 + 1.443 + //and recursivly for all children: 1.444 + BOOST_FOREACH(int theChildren, Children) 1.445 + { 1.446 + Bones[theChildren].CalculateBoneToWorldSpaceMatrix(Bones); 1.447 + } 1.448 +} 1.449 + 1.450 + 1.451 +}//namespace Ogre 1.452 +}//namespace Assimp 1.453 + 1.454 +#endif // !! ASSIMP_BUILD_NO_OGRE_IMPORTER