Skip to content

Commit

Permalink
Refactor: Utilizes function to load animations (#1568)
Browse files Browse the repository at this point in the history
Signed-off-by: Onur Berk Tore <[email protected]>
  • Loading branch information
Onur Berk Töre authored Jul 4, 2022
1 parent e826c71 commit d6e69d0
Show file tree
Hide file tree
Showing 2 changed files with 130 additions and 105 deletions.
7 changes: 7 additions & 0 deletions include/ignition/gazebo/rendering/SceneManager.hh
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include <map>
#include <memory>
#include <string>
#include <unordered_map>
#include <utility>
#include <vector>

Expand Down Expand Up @@ -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<std::string, unsigned int>
LoadAnimations(const sdf::Actor &_actor);

/// \brief Sequences Trajectories
/// \param[in] _trajectories Actor trajectories
/// \param[in] _time Actor trajectory delay start time (miliseconds)
Expand Down
228 changes: 123 additions & 105 deletions src/rendering/SceneManager.cc
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@

#include <map>
#include <memory>
#include <unordered_map>

#include <sdf/Box.hh>
#include <sdf/Capsule.hh>
Expand Down Expand Up @@ -982,112 +981,11 @@ rendering::VisualPtr SceneManager::CreateActor(Entity _id,
return rendering::VisualPtr();
}

unsigned int numAnims = 0;
std::unordered_map<std::string, unsigned int> 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<double, math::Matrix4d> 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<common::TrajectoryInfo> trajectories;
Expand Down Expand Up @@ -2336,3 +2234,123 @@ AnimationUpdateData SceneManagerPrivate::ActorTrajectoryAt(
animData.valid = true;
return animData;
}

std::unordered_map<std::string, unsigned int>
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<std::string, unsigned int> 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<double, math::Matrix4d> keyFrame = nodeAnim->KeyFrame(k);
skelAnim->AddKeyFrame(
node->Name(), keyFrame.first, keyFrame.second);
}
}

meshSkel->AddAnimation(skelAnim);
}
mapAnimNameId[animName] = numAnims++;
}
}
return mapAnimNameId;
}

0 comments on commit d6e69d0

Please sign in to comment.