Fix osgAnimation for multiple creatures (#8045)

pull/3236/head
Sam Hellawell 6 months ago
parent 6b3c47a30d
commit 03413a895f

@ -86,12 +86,6 @@ namespace Resource
{ {
if (animation) if (animation)
{ {
//"Default" is osg dae plugin's default naming scheme for unnamed animations
if (animation->getName() == "Default")
{
animation->setName(std::string("idle"));
}
osg::ref_ptr<Resource::Animation> mergedAnimationTrack = new Resource::Animation; osg::ref_ptr<Resource::Animation> mergedAnimationTrack = new Resource::Animation;
const std::string animationName = animation->getName(); const std::string animationName = animation->getName();
mergedAnimationTrack->setName(animationName); mergedAnimationTrack->setName(animationName);
@ -99,9 +93,6 @@ namespace Resource
const osgAnimation::ChannelList& channels = animation->getChannels(); const osgAnimation::ChannelList& channels = animation->getChannels();
for (const auto& channel : channels) for (const auto& channel : channels)
{ {
// Replace channel target name to match the renamed bones/transforms
channel->setTargetName(Misc::StringUtils::underscoresToSpaces(channel->getTargetName()));
if (name == "Bip01 R Clavicle") if (name == "Bip01 R Clavicle")
{ {
if (!belongsToRightUpperExtremity(channel->getTargetName())) if (!belongsToRightUpperExtremity(channel->getTargetName()))

@ -9,9 +9,9 @@
#include <osg/Node> #include <osg/Node>
#include <osg/UserDataContainer> #include <osg/UserDataContainer>
#include <osgAnimation/BasicAnimationManager>
#include <osgAnimation/Bone> #include <osgAnimation/Bone>
#include <osgAnimation/RigGeometry> #include <osgAnimation/RigGeometry>
#include <osgAnimation/Skeleton>
#include <osgAnimation/UpdateBone> #include <osgAnimation/UpdateBone>
#include <osgParticle/ParticleSystem> #include <osgParticle/ParticleSystem>
@ -63,7 +63,6 @@
namespace namespace
{ {
class InitWorldSpaceParticlesCallback class InitWorldSpaceParticlesCallback
: public SceneUtil::NodeCallback<InitWorldSpaceParticlesCallback, osgParticle::ParticleSystem*> : public SceneUtil::NodeCallback<InitWorldSpaceParticlesCallback, osgParticle::ParticleSystem*>
{ {
@ -272,11 +271,6 @@ namespace Resource
void apply(osg::Node& node) override void apply(osg::Node& node) override
{ {
// If an osgAnimation bone/transform, ensure underscores in name are replaced with spaces
// this is for compatibility reasons
if (dynamic_cast<osgAnimation::Bone*>(&node))
node.setName(Misc::StringUtils::underscoresToSpaces(node.getName()));
if (osg::StateSet* stateset = node.getStateSet()) if (osg::StateSet* stateset = node.getStateSet())
{ {
if (stateset->getRenderingHint() == osg::StateSet::TRANSPARENT_BIN) if (stateset->getRenderingHint() == osg::StateSet::TRANSPARENT_BIN)
@ -362,50 +356,99 @@ namespace Resource
std::vector<osg::ref_ptr<SceneUtil::RigGeometryHolder>> mRigGeometryHolders; std::vector<osg::ref_ptr<SceneUtil::RigGeometryHolder>> mRigGeometryHolders;
}; };
class ReplaceAnimationUnderscoresVisitor : public osg::NodeVisitor
{
public:
ReplaceAnimationUnderscoresVisitor()
: osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN)
{
}
void apply(osg::Node& node) override
{
// NOTE: MUST update the animation manager names first!
if (auto* animationManager = dynamic_cast<osgAnimation::BasicAnimationManager*>(node.getUpdateCallback()))
renameAnimationChannelTargets(*animationManager);
// Then, any applicable node names
if (auto* rigGeometry = dynamic_cast<osgAnimation::RigGeometry*>(&node))
{
renameNode(*rigGeometry);
updateVertexInfluenceMap(*rigGeometry);
}
else if (auto* matrixTransform = dynamic_cast<osg::MatrixTransform*>(&node))
{
renameNode(*matrixTransform);
renameUpdateCallbacks(*matrixTransform);
}
traverse(node);
}
private:
inline void renameNode(osg::Node& node)
{
node.setName(Misc::StringUtils::underscoresToSpaces(node.getName()));
}
void renameUpdateCallbacks(osg::MatrixTransform& node)
{
osg::Callback* cb = node.getUpdateCallback();
while (cb)
{
auto* animCb = dynamic_cast<osgAnimation::AnimationUpdateCallback<osg::NodeCallback>*>(cb);
if (animCb)
{
std::string newAnimCbName = Misc::StringUtils::underscoresToSpaces(animCb->getName());
animCb->setName(newAnimCbName);
}
cb = cb->getNestedCallback();
}
}
void updateVertexInfluenceMap(osgAnimation::RigGeometry& rig) void updateVertexInfluenceMap(osgAnimation::RigGeometry& rig)
{ {
osgAnimation::VertexInfluenceMap* vertexInfluenceMap = rig.getInfluenceMap(); osgAnimation::VertexInfluenceMap* vertexInfluenceMap = rig.getInfluenceMap();
if (!vertexInfluenceMap) if (!vertexInfluenceMap)
return; return;
std::vector<std::string> renameList; std::vector<std::pair<std::string, std::string>> renameList;
for (const auto& [boneName, unused] : *vertexInfluenceMap) for (const auto& influence : *vertexInfluenceMap)
{ {
if (boneName.find('_') != std::string::npos) const std::string& oldBoneName = influence.first;
renameList.push_back(boneName); std::string newBoneName = Misc::StringUtils::underscoresToSpaces(oldBoneName);
if (newBoneName != oldBoneName)
renameList.emplace_back(oldBoneName, newBoneName);
} }
for (const std::string& oldName : renameList) for (const auto& rename : renameList)
{ {
const std::string newName = Misc::StringUtils::underscoresToSpaces(oldName); const std::string& oldName = rename.first;
const std::string& newName = rename.second;
if (vertexInfluenceMap->find(newName) == vertexInfluenceMap->end()) if (vertexInfluenceMap->find(newName) == vertexInfluenceMap->end())
(*vertexInfluenceMap)[newName] = std::move((*vertexInfluenceMap)[oldName]); (*vertexInfluenceMap)[newName] = std::move((*vertexInfluenceMap)[oldName]);
vertexInfluenceMap->erase(oldName); vertexInfluenceMap->erase(oldName);
} }
} }
class RenameAnimCallbacksVisitor : public osg::NodeVisitor void renameAnimationChannelTargets(osgAnimation::BasicAnimationManager& animManager)
{ {
public: for (const auto& animation : animManager.getAnimationList())
RenameAnimCallbacksVisitor()
: osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN)
{ {
} if (animation)
void apply(osg::MatrixTransform& node) override
{
// osgAnimation update callback name must match bone name/channel targets
osg::Callback* cb = node.getUpdateCallback();
while (cb)
{ {
auto animCb = dynamic_cast<osgAnimation::AnimationUpdateCallback<osg::NodeCallback>*>(cb); // "Default" is osg dae plugin's default naming scheme for unnamed animations
if (animCb) if (animation->getName() == "Default")
animCb->setName(Misc::StringUtils::underscoresToSpaces(animCb->getName())); animation->setName(std::string("idle"));
cb = cb->getNestedCallback(); auto& channels = animation->getChannels();
for (auto& channel : channels)
{
std::string newTargetName = Misc::StringUtils::underscoresToSpaces(channel->getTargetName());
channel->setTargetName(newTargetName);
}
}
} }
traverse(node);
} }
}; };
@ -655,15 +698,20 @@ namespace Resource
// Recognize and convert osgAnimation::RigGeometry to OpenMW-optimized type // Recognize and convert osgAnimation::RigGeometry to OpenMW-optimized type
SceneUtil::FindByClassVisitor rigFinder("RigGeometry"); SceneUtil::FindByClassVisitor rigFinder("RigGeometry");
node->accept(rigFinder); node->accept(rigFinder);
// If a collada file with rigs, we should replace underscores with spaces
if (isColladaFile && rigFinder.mFoundNodes.size() > 0)
{
ReplaceAnimationUnderscoresVisitor renamingVisitor;
node->accept(renamingVisitor);
}
for (osg::Node* foundRigNode : rigFinder.mFoundNodes) for (osg::Node* foundRigNode : rigFinder.mFoundNodes)
{ {
if (foundRigNode->libraryName() == std::string_view("osgAnimation")) if (foundRigNode->libraryName() == std::string_view("osgAnimation"))
{ {
osgAnimation::RigGeometry* foundRigGeometry = static_cast<osgAnimation::RigGeometry*>(foundRigNode); osgAnimation::RigGeometry* foundRigGeometry = static_cast<osgAnimation::RigGeometry*>(foundRigNode);
if (isColladaFile)
Resource::updateVertexInfluenceMap(*foundRigGeometry);
osg::ref_ptr<SceneUtil::RigGeometryHolder> newRig osg::ref_ptr<SceneUtil::RigGeometryHolder> newRig
= new SceneUtil::RigGeometryHolder(*foundRigGeometry, osg::CopyOp::DEEP_COPY_ALL); = new SceneUtil::RigGeometryHolder(*foundRigGeometry, osg::CopyOp::DEEP_COPY_ALL);
@ -685,11 +733,6 @@ namespace Resource
if (colladaDescriptionVisitor.mSkeleton) if (colladaDescriptionVisitor.mSkeleton)
{ {
// Collada bones may have underscores in place of spaces due to a collada limitation
// we should rename the bones and update callbacks here at load time
Resource::RenameAnimCallbacksVisitor renameBoneVisitor;
node->accept(renameBoneVisitor);
if (osg::Group* group = dynamic_cast<osg::Group*>(node)) if (osg::Group* group = dynamic_cast<osg::Group*>(node))
{ {
group->removeChildren(0, group->getNumChildren()); group->removeChildren(0, group->getNumChildren());

@ -26,10 +26,6 @@ namespace SceneUtil
void LinkVisitor::link(osgAnimation::UpdateMatrixTransform* umt) void LinkVisitor::link(osgAnimation::UpdateMatrixTransform* umt)
{ {
// If osgAnimation had underscores, we should update the umt name also
// otherwise the animation channel and updates wont be applied
umt->setName(Misc::StringUtils::underscoresToSpaces(umt->getName()));
const osgAnimation::ChannelList& channels = mAnimation->getChannels(); const osgAnimation::ChannelList& channels = mAnimation->getChannels();
for (const auto& channel : channels) for (const auto& channel : channels)
{ {

Loading…
Cancel
Save