diff --git a/include/ignition/gazebo/rendering/SceneManager.hh b/include/ignition/gazebo/rendering/SceneManager.hh index 60aefb24d3..d99a904a51 100644 --- a/include/ignition/gazebo/rendering/SceneManager.hh +++ b/include/ignition/gazebo/rendering/SceneManager.hh @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -200,6 +201,12 @@ inline namespace IGNITION_GAZEBO_VERSION_NAMESPACE { /// \return Pointer to requested visual public: rendering::VisualPtr VisualById(Entity _id); + /// \brief Load Actor animations + /// \param[in] _actor Actor + /// \return Animation name to ID map + public: std::unordered_map + LoadAnimations(const sdf::Actor &_actor); + /// \brief Sequences Trajectories /// \param[in] _trajectories Actor trajectories /// \param[in] _time Actor trajectory delay start time (miliseconds) diff --git a/src/rendering/SceneManager.cc b/src/rendering/SceneManager.cc index 7924bc61f2..3b53f5b9b0 100644 --- a/src/rendering/SceneManager.cc +++ b/src/rendering/SceneManager.cc @@ -18,7 +18,6 @@ #include #include -#include #include #include @@ -982,112 +981,11 @@ rendering::VisualPtr SceneManager::CreateActor(Entity _id, return rendering::VisualPtr(); } - unsigned int numAnims = 0; - std::unordered_map mapAnimNameId; - mapAnimNameId[descriptor.meshName] = numAnims++; - // Load all animations - for (unsigned i = 0; i < _actor.AnimationCount(); ++i) - { - std::string animName = _actor.AnimationByIndex(i)->Name(); - std::string animFilename = asFullPath( - _actor.AnimationByIndex(i)->Filename(), - _actor.AnimationByIndex(i)->FilePath()); - - double animScale = _actor.AnimationByIndex(i)->Scale(); - - std::string extension = animFilename.substr(animFilename.rfind('.') + 1, - animFilename.size()); - std::transform(extension.begin(), extension.end(), - extension.begin(), ::tolower); - - if (extension == "bvh") - { - // do not add duplicate animation - // start checking from index 1 since index 0 is reserved by skin mesh - bool addAnim = true; - for (unsigned int a = 1; a < meshSkel->AnimationCount(); ++a) - { - if (meshSkel->Animation(a)->Name() == animFilename) - { - addAnim = false; - break; - } - } - if (addAnim) - meshSkel->AddBvhAnimation(animFilename, animScale); - mapAnimNameId[animName] = numAnims++; - } - else if (extension == "dae") - { - // Load the mesh if it has not been loaded before - const common::Mesh *animMesh = nullptr; - if (!meshManager->HasMesh(animFilename)) - { - animMesh = meshManager->Load(animFilename); - if (animMesh->MeshSkeleton()->AnimationCount() > 1) - { - ignwarn << "File [" << animFilename - << "] has more than one animation, but only the 1st one is used." - << std::endl; - } - } - animMesh = meshManager->MeshByName(animFilename); - - // add the first animation - auto firstAnim = animMesh->MeshSkeleton()->Animation(0); - if (nullptr == firstAnim) - { - ignerr << "Failed to get animations from [" << animFilename - << "]" << std::endl; - return nullptr; - } - // do not add duplicate animation - // start checking from index 1 since index 0 is reserved by skin mesh - bool addAnim = true; - for (unsigned int a = 1; a < meshSkel->AnimationCount(); ++a) - { - if (meshSkel->Animation(a)->Name() == animName) - { - addAnim = false; - break; - } - } - if (addAnim) - { - // collada loader loads animations with name that defaults to - // "animation0", "animation"1", etc causing conflicts in names - // when multiple animations are added to meshSkel. - // We have to clone the skeleton animation before giving it a unique - // name otherwise if mulitple instances of the same animation were added - // to meshSkel, changing the name that would also change the name of - // other instances of the animation - // todo(anyone) cloning is inefficient and error-prone. We should - // add a copy constructor to animation classes in ign-common. - // The proper fix is probably to update ign-rendering to allow it to - // load multiple animations of the same name - common::SkeletonAnimation *skelAnim = - new common::SkeletonAnimation(animName); - for (unsigned int j = 0; j < meshSkel->NodeCount(); ++j) - { - common::SkeletonNode *node = meshSkel->NodeByHandle(j); - common::NodeAnimation *nodeAnim = firstAnim->NodeAnimationByName( - node->Name()); - if (!nodeAnim) - continue; - for (unsigned int k = 0; k < nodeAnim->FrameCount(); ++k) - { - std::pair keyFrame = nodeAnim->KeyFrame(k); - skelAnim->AddKeyFrame( - node->Name(), keyFrame.first, keyFrame.second); - } - } + auto mapAnimNameId = this->LoadAnimations(_actor); + if (mapAnimNameId.size() == 0) + return nullptr; - meshSkel->AddAnimation(skelAnim); - } - mapAnimNameId[animName] = numAnims++; - } - } this->dataPtr->actorSkeletons[_id] = meshSkel; std::vector trajectories; @@ -2336,3 +2234,123 @@ AnimationUpdateData SceneManagerPrivate::ActorTrajectoryAt( animData.valid = true; return animData; } + +std::unordered_map +SceneManager::LoadAnimations(const sdf::Actor &_actor) +{ + rendering::MeshDescriptor descriptor; + descriptor.meshName = asFullPath(_actor.SkinFilename(), _actor.FilePath()); + common::MeshManager *meshManager = common::MeshManager::Instance(); + descriptor.mesh = meshManager->Load(descriptor.meshName); + common::SkeletonPtr meshSkel = descriptor.mesh->MeshSkeleton(); + + unsigned int numAnims = 0; + std::unordered_map mapAnimNameId; + mapAnimNameId[descriptor.meshName] = numAnims++; + + // Load all animations + for (unsigned i = 0; i < _actor.AnimationCount(); ++i) + { + std::string animName = _actor.AnimationByIndex(i)->Name(); + std::string animFilename = asFullPath( + _actor.AnimationByIndex(i)->Filename(), + _actor.AnimationByIndex(i)->FilePath()); + + double animScale = _actor.AnimationByIndex(i)->Scale(); + + std::string extension = animFilename.substr(animFilename.rfind('.') + 1, + animFilename.size()); + std::transform(extension.begin(), extension.end(), + extension.begin(), ::tolower); + + if (extension == "bvh") + { + // do not add duplicate animation + // start checking from index 1 since index 0 is reserved by skin mesh + bool addAnim = true; + for (unsigned int a = 1; a < meshSkel->AnimationCount(); ++a) + { + if (meshSkel->Animation(a)->Name() == animFilename) + { + addAnim = false; + break; + } + } + if (addAnim) + meshSkel->AddBvhAnimation(animFilename, animScale); + mapAnimNameId[animName] = numAnims++; + } + else if (extension == "dae") + { + // Load the mesh if it has not been loaded before + const common::Mesh *animMesh = nullptr; + if (!meshManager->HasMesh(animFilename)) + { + animMesh = meshManager->Load(animFilename); + if (animMesh->MeshSkeleton()->AnimationCount() > 1) + { + ignwarn << "File [" << animFilename + << "] has more than one animation, " + << "but only the 1st one is used." + << std::endl; + } + } + animMesh = meshManager->MeshByName(animFilename); + + // add the first animation + auto firstAnim = animMesh->MeshSkeleton()->Animation(0); + if (nullptr == firstAnim) + { + ignerr << "Failed to get animations from [" << animFilename + << "]" << std::endl; + mapAnimNameId.clear(); + break; + } + // do not add duplicate animation + // start checking from index 1 since index 0 is reserved by skin mesh + bool addAnim = true; + for (unsigned int a = 1; a < meshSkel->AnimationCount(); ++a) + { + if (meshSkel->Animation(a)->Name() == animName) + { + addAnim = false; + break; + } + } + if (addAnim) + { + // collada loader loads animations with name that defaults to + // "animation0", "animation"1", etc causing conflicts in names + // when multiple animations are added to meshSkel. + // We have to clone the skeleton animation before giving it a unique + // name otherwise if mulitple instances of the same animation were added + // to meshSkel, changing the name that would also change the name of + // other instances of the animation + // todo(anyone) cloning is inefficient and error-prone. We should + // add a copy constructor to animation classes in ign-common. + // The proper fix is probably to update ign-rendering to allow it to + // load multiple animations of the same name + common::SkeletonAnimation *skelAnim = + new common::SkeletonAnimation(animName); + for (unsigned int j = 0; j < meshSkel->NodeCount(); ++j) + { + common::SkeletonNode *node = meshSkel->NodeByHandle(j); + common::NodeAnimation *nodeAnim = firstAnim->NodeAnimationByName( + node->Name()); + if (!nodeAnim) + continue; + for (unsigned int k = 0; k < nodeAnim->FrameCount(); ++k) + { + std::pair keyFrame = nodeAnim->KeyFrame(k); + skelAnim->AddKeyFrame( + node->Name(), keyFrame.first, keyFrame.second); + } + } + + meshSkel->AddAnimation(skelAnim); + } + mapAnimNameId[animName] = numAnims++; + } + } + return mapAnimNameId; +}