From 3f9216800da0976c239cc3f35cc0a4bc7d00f81a Mon Sep 17 00:00:00 2001 From: Cedric Pinson Date: Thu, 27 Aug 2009 16:21:01 +0000 Subject: [PATCH] From Michael Platings, I've moved the matrix updating from UpdateSkeleton to UpdateBone. UpdateSkeleton now merely checks that Bones appear before other children and issues a warning if this isn't the case --- include/osgAnimation/Bone | 84 +++--------------------- include/osgAnimation/Skeleton | 8 ++- src/osgAnimation/Bone.cpp | 117 ++++++++++++++++++++++++++++++++++ src/osgAnimation/Skeleton.cpp | 69 +++++++++----------- 4 files changed, 160 insertions(+), 118 deletions(-) diff --git a/include/osgAnimation/Bone b/include/osgAnimation/Bone index 425b6a065..2b4255ebb 100644 --- a/include/osgAnimation/Bone +++ b/include/osgAnimation/Bone @@ -42,7 +42,7 @@ namespace osgAnimation { // A bone can't have more than one parent Bone, so sharing a part of Bone's hierarchy - // has not sense. You can share the entire hierarchie but not only a part of + // makes no sense. You can share the entire hierarchy but not only a part of it. class OSGANIMATION_EXPORT Bone : public osg::Transform { public: @@ -75,27 +75,6 @@ namespace osgAnimation } }; - struct FindNearestParentAnimationManager : public osg::NodeVisitor - { - osg::ref_ptr _manager; - FindNearestParentAnimationManager() : osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_PARENTS) {} - void apply(osg::Node& node) - { - if (_manager.valid()) - return; - osg::NodeCallback* callback = node.getUpdateCallback(); - while (callback) - { - _manager = dynamic_cast(callback); - if (_manager.valid()) - return; - callback = callback->getNestedCallback(); - } - traverse(node); - } - }; - - class OSGANIMATION_EXPORT UpdateBone : public AnimationUpdateCallback { protected: @@ -123,68 +102,21 @@ namespace osgAnimation bone.dirtyBound(); } + osgAnimation::QuatTarget* getQuaternion() {return _quaternion.get();} + osgAnimation::Vec3Target* getPosition() {return _position.get();} + osgAnimation::Vec3Target* getScale() {return _scale.get();} + bool needLink() const { // the idea is to return true if nothing is linked return !((_position->getCount() + _quaternion->getCount() + _scale->getCount()) > 3); } - bool link(osgAnimation::Channel* channel) - { - if (channel->getName().find("quaternion") != std::string::npos) - { - return channel->setTarget(_quaternion.get()); - } - else if (channel->getName().find("position") != std::string::npos) - { - return channel->setTarget(_position.get()); - } - else if (channel->getName().find("scale") != std::string::npos) - { - return channel->setTarget(_scale.get()); - } - else - { - osg::notify(osg::WARN) << "Channel " << channel->getName() << " does not contain a valid symbolic name for this class" << className() << std::endl; - } - return false; - } + /** Link channel*/ + bool link(osgAnimation::Channel* channel); /** Callback method called by the NodeVisitor when visiting a node.*/ - virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) - { - if (nv && nv->getVisitorType() == osg::NodeVisitor::UPDATE_VISITOR) - { - Bone* b = dynamic_cast(node); - if (b && !_manager.valid()) - { - FindNearestParentAnimationManager finder; - - if (b->getParents().size() > 1) - { - osg::notify(osg::WARN) << "A Bone should not have multi parent ( " << b->getName() << " ) has parents "; - osg::notify(osg::WARN) << "( " << b->getParents()[0]->getName(); - for (int i = 1; i < (int)b->getParents().size(); i++) - osg::notify(osg::WARN) << ", " << b->getParents()[i]->getName(); - osg::notify(osg::WARN) << ")" << std::endl; - return; - } - b->getParents()[0]->accept(finder); - - if (!finder._manager.valid()) - { - osg::notify(osg::WARN) << "Warning can't update Bone, path to parent AnimationManagerBase not found" << std::endl; - return; - } - - _manager = finder._manager.get(); - } - - updateLink(); - update(*b); - } - traverse(node,nv); - } + virtual void operator()(osg::Node* node, osg::NodeVisitor* nv); }; virtual bool computeLocalToWorldMatrix(osg::Matrix& matrix,osg::NodeVisitor* nv) const; diff --git a/include/osgAnimation/Skeleton b/include/osgAnimation/Skeleton index 0bf732fe5..69689b8eb 100644 --- a/include/osgAnimation/Skeleton +++ b/include/osgAnimation/Skeleton @@ -27,12 +27,16 @@ namespace osgAnimation public: META_Node(osgAnimation, Skeleton); - struct OSGANIMATION_EXPORT UpdateSkeleton : public osg::NodeCallback + class OSGANIMATION_EXPORT UpdateSkeleton : public osg::NodeCallback { + public: META_Object(osgAnimation, UpdateSkeleton); - UpdateSkeleton() {} + UpdateSkeleton() : _needValidate(true) {} UpdateSkeleton(const UpdateSkeleton& us, const osg::CopyOp& copyop= osg::CopyOp::SHALLOW_COPY) : osg::Object(us, copyop), osg::NodeCallback(us, copyop) {} virtual void operator()(osg::Node* node, osg::NodeVisitor* nv); + + protected: + bool _needValidate; }; Skeleton(const Skeleton& b, const osg::CopyOp& copyop= osg::CopyOp::SHALLOW_COPY) : Bone(b,copyop) {} diff --git a/src/osgAnimation/Bone.cpp b/src/osgAnimation/Bone.cpp index 80e0a40c7..ea664092c 100644 --- a/src/osgAnimation/Bone.cpp +++ b/src/osgAnimation/Bone.cpp @@ -16,6 +16,46 @@ #include #include + +struct FindNearestParentAnimationManager : public osg::NodeVisitor +{ + osg::ref_ptr _manager; + FindNearestParentAnimationManager() : osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_PARENTS) {} + void apply(osg::Node& node) + { + if (_manager.valid()) + return; + osg::NodeCallback* callback = node.getUpdateCallback(); + while (callback) + { + _manager = dynamic_cast(callback); + if (_manager.valid()) + return; + callback = callback->getNestedCallback(); + } + traverse(node); + } +}; + + +struct ComputeBindMatrixVisitor : public osg::NodeVisitor +{ + ComputeBindMatrixVisitor(): osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN) {} + void apply(osg::Node& node) { return; } + void apply(osg::Transform& node) + { + osgAnimation::Bone* bone = dynamic_cast(&node); + if (!bone) + return; + if (bone->needToComputeBindMatrix()) + bone->computeBindMatrix(); + + traverse(node); + } +}; + + + osgAnimation::Bone::UpdateBone::UpdateBone(const osgAnimation::Bone::UpdateBone& apc,const osg::CopyOp& copyop) : osg::Object(apc, copyop), osgAnimation::AnimationUpdateCallback(apc, copyop) @@ -25,6 +65,83 @@ osgAnimation::Bone::UpdateBone::UpdateBone(const osgAnimation::Bone::UpdateBone& _scale = new osgAnimation::Vec3Target(apc._scale->getValue()); } +bool osgAnimation::Bone::UpdateBone::link(osgAnimation::Channel* channel) +{ + if (channel->getName().find("quaternion") != std::string::npos) + { + return channel->setTarget(_quaternion.get()); + } + else if (channel->getName().find("position") != std::string::npos) + { + return channel->setTarget(_position.get()); + } + else if (channel->getName().find("scale") != std::string::npos) + { + return channel->setTarget(_scale.get()); + } + else + { + osg::notify(osg::WARN) << "Channel " << channel->getName() << " does not contain a valid symbolic name for this class" << className() << std::endl; + } + return false; +} + + +/** Callback method called by the NodeVisitor when visiting a node.*/ +void osgAnimation::Bone::UpdateBone::operator()(osg::Node* node, osg::NodeVisitor* nv) +{ + if (nv && nv->getVisitorType() == osg::NodeVisitor::UPDATE_VISITOR) + { + Bone* b = dynamic_cast(node); + if (!b) + { + osg::notify(osg::WARN) << "Warning: UpdateBone set on non-Bone object." << std::endl; + return; + } + + if (b->needToComputeBindMatrix()) + { + ComputeBindMatrixVisitor visitor; + b->accept(visitor); + } + + if (!_manager.valid()) + { + FindNearestParentAnimationManager finder; + + if (b->getParents().size() > 1) + { + osg::notify(osg::WARN) << "A Bone should not have multi parent ( " << b->getName() << " ) has parents "; + osg::notify(osg::WARN) << "( " << b->getParents()[0]->getName(); + for (int i = 1; i < (int)b->getParents().size(); i++) + osg::notify(osg::WARN) << ", " << b->getParents()[i]->getName(); + osg::notify(osg::WARN) << ")" << std::endl; + return; + } + b->getParents()[0]->accept(finder); + + if (!finder._manager.valid()) + { + osg::notify(osg::WARN) << "Warning can't update Bone, path to parent AnimationManagerBase not found" << std::endl; + return; + } + + _manager = finder._manager.get(); + } + + updateLink(); + update(*b); + + Bone* parent = b->getBoneParent(); + if (parent) + b->setMatrixInSkeletonSpace(b->getMatrixInBoneSpace() * parent->getMatrixInSkeletonSpace()); + else + b->setMatrixInSkeletonSpace(b->getMatrixInBoneSpace()); + + } + traverse(node,nv); +} + osgAnimation::Bone::Bone(const Bone& b, const osg::CopyOp& copyop) : osg::Transform(b,copyop), diff --git a/src/osgAnimation/Skeleton.cpp b/src/osgAnimation/Skeleton.cpp index 496868e21..f80551ebd 100644 --- a/src/osgAnimation/Skeleton.cpp +++ b/src/osgAnimation/Skeleton.cpp @@ -1,5 +1,5 @@ /* -*-c++-*- - * Copyright (C) 2008 Cedric Pinson + * Copyright (C) 2008 Cedric Pinson * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or @@ -17,28 +17,11 @@ using namespace osgAnimation; -struct computeBindMatrixVisitor : public osg::NodeVisitor +class ValidateSkeletonVisitor : public osg::NodeVisitor { - osg::Matrix _skeleton; - computeBindMatrixVisitor(): osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN) {} - void apply(osg::Node& node) { return ;} - void apply(osg::Transform& node) - { - Bone* bone = dynamic_cast(&node); - if (!bone) - return; - if (bone->needToComputeBindMatrix()) - bone->computeBindMatrix(); - - traverse(node); - } -}; - -struct updateMatrixVisitor : public osg::NodeVisitor -{ - osg::Matrix _skeleton; - updateMatrixVisitor(): osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN) {} - void apply(osg::Node& node) { return ;} +public: + ValidateSkeletonVisitor(): osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN) {} + void apply(osg::Node& node) { return; } void apply(osg::Transform& node) { // the idea is to traverse the skeleton or bone but to stop if other node is found @@ -46,41 +29,47 @@ struct updateMatrixVisitor : public osg::NodeVisitor if (!bone) return; - Bone* parent = bone->getBoneParent(); - if (bone->needToComputeBindMatrix()) + bool foundNonBone = false; + + for (unsigned i = 0; i < bone->getNumChildren(); ++i) { - computeBindMatrixVisitor visitor; - bone->accept(visitor); + if (dynamic_cast(bone->getChild(i))) + { + if (foundNonBone) + { + osg::notify(osg::WARN) << + "Warning: a Bone was found after a non-Bone child " + "within a Skeleton. Children of a Bone must be ordered " + "with all child Bones first for correct update order." << std::endl; + setTraversalMode(TRAVERSE_NONE); + return; + } + } + else + { + foundNonBone = true; + } } - - if (parent) - bone->setMatrixInSkeletonSpace(bone->getMatrixInBoneSpace() * bone->getBoneParent()->getMatrixInSkeletonSpace()); - else - bone->setMatrixInSkeletonSpace(bone->getMatrixInBoneSpace()); - traverse(node); } }; void Skeleton::UpdateSkeleton::operator()(osg::Node* node, osg::NodeVisitor* nv) { - if (nv && nv->getVisitorType() == osg::NodeVisitor::UPDATE_VISITOR) + if (_needValidate && nv && nv->getVisitorType() == osg::NodeVisitor::UPDATE_VISITOR) { Skeleton* b = dynamic_cast(node); if (b) { - // apply the updater only on the root bone, The udpateMatrixVisitor will - // traverse only bone and will update only bone. Then we continu on the classic - // process. It's important to update Bone before other things because the update - // of RigGeometry need it - updateMatrixVisitor visitor; - b->accept(visitor); + ValidateSkeletonVisitor visitor; + node->accept(visitor); } + + _needValidate = false; } traverse(node,nv); } - Skeleton::Skeleton() { }