Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor: Utilizes function to load animations #1568

Merged
merged 9 commits into from
Jul 4, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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;
}