root/OpenSceneGraph/trunk/src/osgAnimation/Bone.cpp @ 10558

Revision 10558, 7.7 kB (checked in by cedricpinson, 8 years ago)

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

Line 
1/*  -*-c++-*-
2 *  Copyright (C) 2008 Cedric Pinson <mornifle@plopbyte.net>
3 *
4 * This library is open source and may be redistributed and/or modified under 
5 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
6 * (at your option) any later version.  The full license is in LICENSE file
7 * included with this distribution, and on the openscenegraph.org website.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 * OpenSceneGraph Public License for more details.
13*/
14
15#include <osgAnimation/Skinning>
16#include <osgAnimation/Bone>
17#include <osgAnimation/Skeleton>
18
19
20struct FindNearestParentAnimationManager : public osg::NodeVisitor
21{
22    osg::ref_ptr<osgAnimation::AnimationManagerBase> _manager;
23    FindNearestParentAnimationManager() : osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_PARENTS) {}
24    void apply(osg::Node& node)
25    {
26        if (_manager.valid())
27            return;
28        osg::NodeCallback* callback = node.getUpdateCallback();
29        while (callback)
30        {
31            _manager = dynamic_cast<osgAnimation::AnimationManagerBase*>(callback);
32            if (_manager.valid())
33                return;
34            callback = callback->getNestedCallback();
35        }
36        traverse(node);
37    }
38};
39
40
41struct ComputeBindMatrixVisitor : public osg::NodeVisitor
42{
43    ComputeBindMatrixVisitor(): osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN) {}
44    void apply(osg::Node& node) { return; }
45    void apply(osg::Transform& node)
46    {
47        osgAnimation::Bone* bone = dynamic_cast<osgAnimation::Bone*>(&node);
48        if (!bone)
49            return;
50        if (bone->needToComputeBindMatrix())
51            bone->computeBindMatrix();
52
53        traverse(node);
54    }
55};
56
57
58
59osgAnimation::Bone::UpdateBone::UpdateBone(const osgAnimation::Bone::UpdateBone& apc,const osg::CopyOp& copyop) :
60    osg::Object(apc, copyop),
61    osgAnimation::AnimationUpdateCallback<osg::NodeCallback>(apc, copyop)
62{
63    _quaternion = new osgAnimation::QuatTarget(apc._quaternion->getValue());
64    _position = new osgAnimation::Vec3Target(apc._position->getValue());
65    _scale = new osgAnimation::Vec3Target(apc._scale->getValue());
66}
67
68bool osgAnimation::Bone::UpdateBone::link(osgAnimation::Channel* channel)
69{
70    if (channel->getName().find("quaternion") != std::string::npos)
71    {
72        return channel->setTarget(_quaternion.get());
73    }
74    else if (channel->getName().find("position") != std::string::npos)
75    {
76        return channel->setTarget(_position.get());
77    }
78    else if (channel->getName().find("scale") != std::string::npos)
79    {
80        return channel->setTarget(_scale.get());
81    }
82    else 
83    {
84        osg::notify(osg::WARN) << "Channel " << channel->getName() << " does not contain a valid symbolic name for this class" << className() << std::endl;
85    }
86    return false;
87}
88
89
90/** Callback method called by the NodeVisitor when visiting a node.*/
91void osgAnimation::Bone::UpdateBone::operator()(osg::Node* node, osg::NodeVisitor* nv)
92{
93    if (nv && nv->getVisitorType() == osg::NodeVisitor::UPDATE_VISITOR)
94    {
95        Bone* b = dynamic_cast<Bone*>(node);
96        if (!b)
97        {
98            osg::notify(osg::WARN) << "Warning: UpdateBone set on non-Bone object." << std::endl;
99            return;
100        }
101
102        if (b->needToComputeBindMatrix())
103        {
104            ComputeBindMatrixVisitor visitor;
105            b->accept(visitor);
106        }
107
108        if (!_manager.valid())
109        {
110            FindNearestParentAnimationManager finder;
111
112            if (b->getParents().size() > 1)
113            {
114                osg::notify(osg::WARN) << "A Bone should not have multi parent ( " << b->getName() << " ) has parents ";
115                osg::notify(osg::WARN) << "( " << b->getParents()[0]->getName();
116                for (int i = 1; i < (int)b->getParents().size(); i++)
117                    osg::notify(osg::WARN) << ", " << b->getParents()[i]->getName();
118                osg::notify(osg::WARN) << ")" << std::endl;
119                return;
120            }
121            b->getParents()[0]->accept(finder);
122
123            if (!finder._manager.valid())
124            {
125                osg::notify(osg::WARN) << "Warning can't update Bone, path to parent AnimationManagerBase not found" << std::endl;
126                return;
127            }
128
129            _manager = finder._manager.get();
130        }
131
132        updateLink();
133        update(*b);
134
135        Bone* parent = b->getBoneParent();
136        if (parent)
137            b->setMatrixInSkeletonSpace(b->getMatrixInBoneSpace() * parent->getMatrixInSkeletonSpace());
138        else
139            b->setMatrixInSkeletonSpace(b->getMatrixInBoneSpace());
140
141    }
142    traverse(node,nv);
143}
144
145
146osgAnimation::Bone::Bone(const Bone& b, const osg::CopyOp& copyop) :
147    osg::Transform(b,copyop),
148    _position(b._position),
149    _rotation(b._rotation),
150    _scale(b._scale),
151    _needToRecomputeBindMatrix(true),
152    _bindInBoneSpace(b._bindInBoneSpace),
153    _invBindInSkeletonSpace(b._invBindInSkeletonSpace),
154    _boneInSkeletonSpace(b._boneInSkeletonSpace)
155{
156    osg::ref_ptr<osg::NodeCallback> updatecallback = getUpdateCallback();
157    setUpdateCallback(0);
158    while (updatecallback.valid()) {
159        osg::NodeCallback* ucb = dynamic_cast<osg::NodeCallback*>(updatecallback->clone(copyop));
160        ucb->setNestedCallback(0);
161        addUpdateCallback(ucb);
162        updatecallback = updatecallback->getNestedCallback();
163    }
164}
165
166osgAnimation::Bone::Bone(const std::string& name)
167{
168    if (!name.empty())
169        setName(name);
170    _needToRecomputeBindMatrix = false;
171}
172
173
174void osgAnimation::Bone::setDefaultUpdateCallback(const std::string& name)
175{
176    std::string cbName = name;
177    if (cbName.empty())
178        cbName = getName();
179    setUpdateCallback(new UpdateBone(cbName));
180}
181
182void osgAnimation::Bone::computeBindMatrix()
183{
184    _invBindInSkeletonSpace = osg::Matrix::inverse(_bindInBoneSpace);
185    const Bone* parent = getBoneParent();
186    _needToRecomputeBindMatrix = false;
187    if (!parent)
188    {
189        osg::notify(osg::WARN) << "Warning " << className() <<"::computeBindMatrix you should not have this message, it means you miss to attach this bone(" << getName() <<") to a Skeleton node" << std::endl;
190        return;
191    }
192    _invBindInSkeletonSpace = parent->getInvBindMatrixInSkeletonSpace() * _invBindInSkeletonSpace;
193}
194
195osgAnimation::Bone* osgAnimation::Bone::getBoneParent()
196{
197    if (getParents().empty())
198        return 0;
199    osg::Node::ParentList parents = getParents();
200    for (osg::Node::ParentList::iterator it = parents.begin(); it != parents.end(); it++)
201    {
202        Bone* pb = dynamic_cast<Bone*>(*it);
203        if (pb)
204            return pb;
205    }
206    return 0;
207}
208const osgAnimation::Bone* osgAnimation::Bone::getBoneParent() const
209{
210    if (getParents().empty())
211        return 0;
212    const osg::Node::ParentList& parents = getParents();
213    for (osg::Node::ParentList::const_iterator it = parents.begin(); it != parents.end(); it++)
214    {
215        const Bone* pb = dynamic_cast<const Bone*>(*it);
216        if (pb)
217            return pb;
218    }
219    return 0;
220}
221
222
223/** Add Node to Group.
224 * If node is not NULL and is not contained in Group then increment its
225 * reference count, add it to the child list and dirty the bounding
226 * sphere to force it to recompute on next getBound() and return true for success.
227 * Otherwise return false. Scene nodes can't be added as child nodes.
228 */
229bool osgAnimation::Bone::addChild( Node *child )
230{
231    Bone* bone = dynamic_cast<Bone*>(child);
232    if (bone)
233        bone->setNeedToComputeBindMatrix(true);
234    return osg::Group::addChild(child);
235}
236
237osgAnimation::Bone::BoneMap osgAnimation::Bone::getBoneMap()
238{
239    BoneMapVisitor mapVisitor;
240    this->accept(mapVisitor);
241    return mapVisitor._map;
242}
Note: See TracBrowser for help on using the browser.