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

Revision 10599, 9.5 kB (checked in by cedricpinson, 5 years ago)

From Michael Platings, In Target, the default constructor is explicitly called on _target. This is necessary for FloatTarget? and DoubleTarget? so that _target is initialised to 0, otherwise you get a junk value. In MorphGeometry?.cpp, UpdateMorph::link now links channels of the same index to the same target. Previously a new FloatTarget? was created for each channel, so multiple animations didn't work.

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    {
[10599]264        osgAnimation::FloatLinearChannel* fc = dynamic_cast<osgAnimation::FloatLinearChannel*>(channel);
265        if (fc)
266        {
267            osgAnimation::FloatTarget* ft = _weightTargets[weightIndex].get();
268            if (ft == 0)
269            {
270                ft = new osgAnimation::FloatTarget;
271                _weightTargets[weightIndex] = ft;
272            }
273            fc->setTarget(ft);
274            return true;
275        }
276    }
[9877]277    else
[10599]278    {
279        osg::notify(osg::WARN) << "Channel " << channel->getName() << " does not contain a valid symbolic name for this class" << std::endl;
280    }
281    return false;
[9877]282}
Note: See TracBrowser for help on using the browser.