root/OpenSceneGraph/trunk/src/osgAnimation/MorphGeometry.cpp @ 11009

Revision 11009, 9.3 kB (checked in by robert, 4 years ago)

From Cedric Pinson, "Here a list of changes:
Bone now inherit from MatrixTransform?. It simplify a lot the update of
Bone matrix. It helps to have the bone system more generic. eg it's now
possible to have animation data with precomputed bind matrix. The other
benefit, is now the collada plugin will be able to use osgAnimation to
display skinned mesh. Michael Plating did a great work to improve this
aspect, he is working on the collada plugin and should be able to submit
a new version soon.
The RigGeometry? has been refactored so now it works when you save and
reload RigGeometry? because the source is not touched anymore. The
benefit with this update is that it should be now possible to use a
MorphGeometry? as source for a RigGeometry?.

The bad news is that the format has changed, so i have rebuild osg-data
related to osgAnimation data, updated the blender exporter to export to
the new format.
The fbx plugin could be touched about this commit, i dont compile it so
i can't give more information about it.
The bvh plugin has been updated by Wang rui so this one is fixed with
the new code of osgAnimation.
The examples has been updated to work with the new code too...

The example osg-data/example.osg should be remove, it's an old example
that does not work.

For people using blender the blender exporter up to date is here:
http://hg.plopbyte.net/osgexport2/
it will be merge to http://hg.plopbyte.net/osgexport/ as soon as the
modification will be push in the trunk.
"

RevLine 
[9877]1/*  -*-c++-*-
[10518]2 *  Copyright (C) 2008 Cedric Pinson <cedric.pinson@plopbyte.net>
[9877]3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program 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 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17 *
18 * Authors:
19 *
20 * Roland Smeenk
[10518]21 * Cedric Pinson <cedric.pinson@plopbyte.net>
[9877]22 *
23 */
24#include <osg/Geode>
25#include <osgAnimation/MorphGeometry>
26
27#include <stdlib.h>
28
29using namespace osgAnimation;
30
31MorphGeometry::MorphGeometry() :
32    _dirty(false),
33    _method(NORMALIZED),
34    _morphNormals(true)
35{
36    setUseDisplayList(false);
37    setUpdateCallback(new UpdateVertex);
38    setDataVariance(osg::Object::DYNAMIC);
39    setUseVertexBufferObjects(true);
40}
41
42MorphGeometry::MorphGeometry(const osg::Geometry& b) :
43    osg::Geometry(b, osg::CopyOp::DEEP_COPY_ARRAYS),
44    _dirty(false),
45    _method(NORMALIZED),
46    _morphNormals(true)
47{
48    setUseDisplayList(false);
49    setUpdateCallback(new UpdateVertex);
50    setDataVariance(osg::Object::DYNAMIC);
51    setUseVertexBufferObjects(true);
52    if (b.getInternalOptimizedGeometry())
53        computeInternalOptimizedGeometry();
54}
55
56MorphGeometry::MorphGeometry(const MorphGeometry& b, const osg::CopyOp& copyop) :
57    osg::Geometry(b,copyop),
58    _dirty(b._dirty),
59    _method(b._method),
60    _morphTargets(b._morphTargets),
61    _positionSource(b._positionSource),
62    _normalSource(b._normalSource),
63    _morphNormals(b._morphNormals)
64{
65    setUseDisplayList(false);
66    setUseVertexBufferObjects(true);
67    if (b.getInternalOptimizedGeometry())
68        computeInternalOptimizedGeometry();
69}
70
71void MorphGeometry::transformSoftwareMethod()
72{
73    if (_dirty)
74    {
75        // See if we have an internal optimized geometry
76        osg::Geometry* morphGeometry = this;
77        if (_internalOptimizedGeometry.valid())
[10186]78            morphGeometry = _internalOptimizedGeometry.get();
[9877]79
80        osg::Vec3Array* pos = dynamic_cast<osg::Vec3Array*>(morphGeometry->getVertexArray());
81        if (pos && _positionSource.size() != pos->size())
82        {
83            _positionSource = std::vector<osg::Vec3>(pos->begin(),pos->end());
84            pos->setDataVariance(osg::Object::DYNAMIC);
85        }
86
87        osg::Vec3Array* normal = dynamic_cast<osg::Vec3Array*>(morphGeometry->getNormalArray());
88        if (normal && _normalSource.size() != normal->size())
89        {
90            _normalSource = std::vector<osg::Vec3>(normal->begin(),normal->end());
91            normal->setDataVariance(osg::Object::DYNAMIC);
92        }
93       
94
95        if (!_positionSource.empty())
96        {
97            bool initialized = false;
98            if (_method == NORMALIZED)
99            {
100                // base * 1 - (sum of weights) + sum of (weight * target)
101                float baseWeight = 0;
102                for (unsigned int i=0; i < _morphTargets.size(); i++)
103                {
104                    baseWeight += _morphTargets[i].getWeight();
105                }
106                baseWeight = 1 - baseWeight;
107
108                if (baseWeight != 0)
109                {
110                    initialized = true;
111                    for (unsigned int i=0; i < pos->size(); i++)
112                    {
113                        (*pos)[i] = _positionSource[i] * baseWeight;
114                    }
115                    if (_morphNormals)
116                    {
117                        for (unsigned int i=0; i < normal->size(); i++)
118                        {
119                            (*normal)[i] = _normalSource[i] * baseWeight;
120                        }
121                    }
122                }
123            }
124            else //if (_method == RELATIVE)
125            {
126                // base + sum of (weight * target)
127                initialized = true;
128                for (unsigned int i=0; i < pos->size(); i++)
129                {
130                    (*pos)[i] = _positionSource[i];
131                }
132                if (_morphNormals)
133                {
134                    for (unsigned int i=0; i < normal->size(); i++)
135                    {
136                        (*normal)[i] = _normalSource[i];
137                    }
138                }
139            }
140
141            for (unsigned int i=0; i < _morphTargets.size(); i++)
142            {
143                if (_morphTargets[i].getWeight() > 0)
144                {
145                    // See if any the targets use the internal optimized geometry
146                    osg::Geometry* targetGeometry = _morphTargets[i].getGeometry()->getInternalOptimizedGeometry();
147                    if (!targetGeometry)
148                        targetGeometry = _morphTargets[i].getGeometry();
149
150                    osg::Vec3Array* targetPos = dynamic_cast<osg::Vec3Array*>(targetGeometry->getVertexArray());
151                    osg::Vec3Array* targetNormals = dynamic_cast<osg::Vec3Array*>(targetGeometry->getNormalArray());
152
153                    if (initialized)
154                    {
155                        // If vertices are initialized, add the morphtargets
156                        for (unsigned int j=0; j < pos->size(); j++)
157                        {
158                            (*pos)[j] += (*targetPos)[j] * _morphTargets[i].getWeight();
159                        }
160
161                        if (_morphNormals)
162                        {
163                            for (unsigned int j=0; j < normal->size(); j++)
164                            {
165                                (*normal)[j] += (*targetNormals)[j] * _morphTargets[i].getWeight();
166                            }
167                        }
168                    }
169                    else
170                    {
171                        // If not initialized, initialize with this morph target
172                        initialized = true;
173                        for (unsigned int j=0; j < pos->size(); j++)
174                        {
175                            (*pos)[j] = (*targetPos)[j] * _morphTargets[i].getWeight();
176                        }
177
178                        if (_morphNormals)
179                        {
180                            for (unsigned int j=0; j < normal->size(); j++)
181                            {
182                                (*normal)[j] = (*targetNormals)[j] * _morphTargets[i].getWeight();
183                            }
184                        }
185                    }
186                }
187            }
188
189            pos->dirty();
190            if (_morphNormals)
191            {
192                for (unsigned int j=0; j < normal->size(); j++)
193                {
194                    (*normal)[j].normalize();
195                }
196                normal->dirty();
197            }
198        }
199
200        dirtyBound();
201        _dirty = false;
202    }
203}
204
[10556]205UpdateMorph::UpdateMorph(const UpdateMorph& apc,const osg::CopyOp& copyop) :
206    osg::Object(apc, copyop),
207    AnimationUpdateCallback<osg::NodeCallback>(apc, copyop)
[9877]208{
209}
210
[10518]211UpdateMorph::UpdateMorph(const std::string& name) : AnimationUpdateCallback<osg::NodeCallback>(name)
[9877]212{
213}
214
215/** Callback method called by the NodeVisitor when visiting a node.*/
216void UpdateMorph::operator()(osg::Node* node, osg::NodeVisitor* nv)
217{
218    if (nv && nv->getVisitorType() == osg::NodeVisitor::UPDATE_VISITOR)
219    {
220        osg::Geode* geode = dynamic_cast<osg::Geode*>(node);
221        if (geode)
222        {
223            unsigned int numDrawables = geode->getNumDrawables();
224            for (unsigned int i = 0; i != numDrawables; ++i)
225            {
226                osgAnimation::MorphGeometry* morph = dynamic_cast<osgAnimation::MorphGeometry*>(geode->getDrawable(i));
227                if (morph)
228                {
229                    // Update morph weights
230                    std::map<int, osg::ref_ptr<osgAnimation::FloatTarget> >::iterator iter = _weightTargets.begin();
231                    while (iter != _weightTargets.end())
232                    {
233                        if (iter->second->getValue() >= 0)
234                        {
235                            morph->setWeight(iter->first, iter->second->getValue());
236                        }
237                        ++iter;
238                    }
239                }
240            }
241        }
242    }
243    traverse(node,nv);
244}
245
246
247
248bool UpdateMorph::needLink() const
249{
250    // the idea is to return true if nothing is linked
251    return (_weightTargets.size() == 0);
252}
253
254bool UpdateMorph::link(osgAnimation::Channel* channel)
255{
256    // Typically morph geometries only have the weights for morph targets animated
257
258    // Expect a weight value
259    // TODO Should we make this more generic to handle other things than single values?
260    int weightIndex = atoi(channel->getName().c_str());
261
262    if (weightIndex >= 0)
263    {
[11009]264        osgAnimation::FloatTarget* ft = _weightTargets[weightIndex].get();
265        if (!ft)
[10599]266        {
[11009]267            ft = new osgAnimation::FloatTarget;
268            _weightTargets[weightIndex] = ft;
[10599]269        }
[11009]270        return channel->setTarget(ft);
[10599]271    }
[9877]272    else
[10599]273    {
274        osg::notify(osg::WARN) << "Channel " << channel->getName() << " does not contain a valid symbolic name for this class" << std::endl;
275    }
276    return false;
[9877]277}
Note: See TracBrowser for help on using the browser.