root/OpenSceneGraph/trunk/src/osg/AutoTransform.cpp @ 7968

Revision 7968, 9.4 kB (checked in by robert, 7 years ago)

To osg::AutoTransform? added support for MinimumScale?, MaximumScale? and AutoScaleTransitionWidth? parameters
and a new scheme for computing the scaling when using autoscale that introduces smooth
transitions to the scaling of the subgraph so that it looks more natural.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
2 *
3 * This library is open source and may be redistributed and/or modified under 
4 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
5 * (at your option) any later version.  The full license is in LICENSE file
6 * included with this distribution, and on the openscenegraph.org website.
7 *
8 * This library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 * OpenSceneGraph Public License for more details.
12*/
13#include <osg/AutoTransform>
14#include <osg/CullStack>
15#include <osg/Notify>
16#include <osg/io_utils>
17
18using namespace osg;
19
20AutoTransform::AutoTransform():
21    _autoUpdateEyeMovementTolerance(0.0f),
22    _autoRotateMode(NO_ROTATION),
23    _autoScaleToScreen(false),
24    _scale(1.0f,1.0f,1.0f),
25    _firstTimeToInitEyePoint(true),
26    _minimumScale(0.0f),
27    _maximumScale(FLT_MAX),
28    _autoScaleTransitionWidthRatio(0.25f),
29    _matrixDirty(true)
30{
31//    setNumChildrenRequiringUpdateTraversal(1);
32}
33
34AutoTransform::AutoTransform(const AutoTransform& pat,const CopyOp& copyop):
35    Transform(pat,copyop),
36    _position(pat._position),
37    _pivotPoint(pat._pivotPoint),
38    _autoUpdateEyeMovementTolerance(pat._autoUpdateEyeMovementTolerance),
39    _autoRotateMode(pat._autoRotateMode),
40    _autoScaleToScreen(pat._autoScaleToScreen),
41    _rotation(pat._rotation),
42    _scale(pat._scale),
43    _firstTimeToInitEyePoint(true),
44    _minimumScale(pat._minimumScale),
45    _maximumScale(pat._maximumScale),
46    _autoScaleTransitionWidthRatio(pat._autoScaleTransitionWidthRatio),
47    _matrixDirty(true)
48{
49//    setNumChildrenRequiringUpdateTraversal(getNumChildrenRequiringUpdateTraversal()+1);           
50}
51
52void AutoTransform::setScale(const Vec3& scale)
53{
54    _scale = scale;
55    if (_scale.x()<_minimumScale) _scale.x() = _minimumScale;
56    if (_scale.y()<_minimumScale) _scale.y() = _minimumScale;
57    if (_scale.z()<_minimumScale) _scale.z() = _minimumScale;
58   
59    if (_scale.x()>_maximumScale) _scale.x() = _maximumScale;
60    if (_scale.y()>_maximumScale) _scale.y() = _maximumScale;
61    if (_scale.z()>_maximumScale) _scale.z() = _maximumScale;
62   
63    _matrixDirty=true;
64    dirtyBound();
65}
66
67
68bool AutoTransform::computeLocalToWorldMatrix(Matrix& matrix,NodeVisitor*) const
69{
70    if (_matrixDirty) computeMatrix();
71   
72    if (_referenceFrame==RELATIVE_RF)
73    {
74        matrix.preMult(_cachedMatrix);
75    }
76    else // absolute
77    {
78        matrix = _cachedMatrix;
79    }
80    return true;
81}
82
83
84bool AutoTransform::computeWorldToLocalMatrix(Matrix& matrix,NodeVisitor*) const
85{
86    if (_referenceFrame==RELATIVE_RF)
87    {
88        matrix.postMult(osg::Matrix::translate(-_position)*
89                        osg::Matrix::rotate(_rotation.inverse())*
90                        osg::Matrix::scale(1.0f/_scale.x(),1.0f/_scale.y(),1.0f/_scale.z())*
91                        osg::Matrix::translate(_pivotPoint));
92    }
93    else // absolute
94    {
95        matrix = osg::Matrix::translate(-_position)*
96                 osg::Matrix::rotate(_rotation.inverse())*
97                 osg::Matrix::scale(1.0f/_scale.x(),1.0f/_scale.y(),1.0f/_scale.z())*
98                 osg::Matrix::translate(_pivotPoint);
99    }
100    return true;
101}
102
103void AutoTransform::computeMatrix() const
104{
105    if (!_matrixDirty) return;
106   
107    _cachedMatrix.set(osg::Matrix::translate(-_pivotPoint)*
108                      osg::Matrix::scale(_scale)*
109                      osg::Matrix::rotate(_rotation)*
110                      osg::Matrix::translate(_position));
111   
112    _matrixDirty = false;
113}
114
115void AutoTransform::accept(NodeVisitor& nv)
116{
117    if (nv.validNodeMask(*this))
118    {
119        // if app traversal update the frame count.
120        if (nv.getVisitorType()==NodeVisitor::UPDATE_VISITOR)
121        {
122        }
123        else
124        if (nv.getVisitorType()==NodeVisitor::CULL_VISITOR)
125        {
126
127            CullStack* cs = dynamic_cast<CullStack*>(&nv);
128            if (cs)
129            {
130
131                Viewport::value_type width = _previousWidth;
132                Viewport::value_type height = _previousHeight;
133
134                osg::Viewport* viewport = cs->getViewport();
135                if (viewport)
136                {
137                    width = viewport->width();
138                    height = viewport->height();
139                }
140
141                osg::Vec3 eyePoint = cs->getEyeLocal();
142                osg::Vec3 localUp = cs->getUpLocal();
143                osg::Vec3 position = getPosition();
144
145                const osg::Matrix& projection = *(cs->getProjectionMatrix());
146
147                bool doUpdate = _firstTimeToInitEyePoint;
148                if (!_firstTimeToInitEyePoint)
149                {
150                    osg::Vec3 dv = _previousEyePoint-eyePoint;
151                    if (dv.length2()>getAutoUpdateEyeMovementTolerance()*(eyePoint-getPosition()).length2())
152                    {
153                        doUpdate = true;
154                    }
155                    osg::Vec3 dupv = _previousLocalUp-localUp;
156                    // rotating the camera only affects ROTATE_TO_*
157                    if (_autoRotateMode &&
158                        dupv.length2()>getAutoUpdateEyeMovementTolerance())
159                    {
160                        doUpdate = true;
161                    }
162                    else if (width!=_previousWidth || height!=_previousHeight)
163                    {
164                        doUpdate = true;
165                    }
166                    else if (projection != _previousProjection)
167                    {
168                        doUpdate = true;
169                    }               
170                    else if (position != _previousPosition)
171                    {
172                        doUpdate = true;
173                    }
174                }
175                _firstTimeToInitEyePoint = false;
176
177                if (doUpdate)
178                {           
179
180                    if (getAutoScaleToScreen())
181                    {
182                        float size = 1.0f/cs->pixelSize(getPosition(),0.48f);
183
184                        if (_autoScaleTransitionWidthRatio>0.0f)
185                        {
186                            if (_minimumScale>0.0f)
187                            {
188                                float j = _minimumScale;
189                                float i = (_maximumScale<FLT_MAX) ?
190                                            _minimumScale+(_maximumScale-_minimumScale)*_autoScaleTransitionWidthRatio :
191                                            _minimumScale*(1.0f+_autoScaleTransitionWidthRatio);
192                                float c = 1.0f/(4.0f*(i-j));
193                                float b = 1.0f - 2.0f*c*i;
194                                float a = j + b*b / (4.0f*c);
195                                float k = -b / (2.0f*c);
196
197                                if (size<k) size = _minimumScale;
198                                else if (size<i) size = a + b*size + c*(size*size);
199                            }
200
201                            if (_maximumScale<FLT_MAX)
202                            {
203                                float n = _maximumScale;
204                                float m = (_minimumScale>0.0) ?
205                                            _maximumScale+(_minimumScale-_maximumScale)*_autoScaleTransitionWidthRatio :
206                                            _maximumScale*(1.0f-_autoScaleTransitionWidthRatio);
207                                float c = 1.0f / (4.0f*(m-n));
208                                float b = 1.0f - 2.0f*c*m;
209                                float a = n + b*b/(4.0f*c);
210                                float p = -b / (2.0f*c);
211
212                                if (size>p) size = _maximumScale;
213                                else if (size>m) size = a + b*size + c*(size*size);
214                            }       
215                        }
216                       
217                        setScale(size);
218                    }
219
220                    if (_autoRotateMode==ROTATE_TO_SCREEN)
221                    {
222                        osg::Vec3d translation;
223                        osg::Quat rotation;
224                        osg::Vec3d scale;
225                        osg::Quat so;
226                       
227                        cs->getModelViewMatrix()->decompose( translation, rotation, scale, so );
228
229                        setRotation(rotation.inverse());
230                    }
231                    else if (_autoRotateMode==ROTATE_TO_CAMERA)
232                    {
233                        osg::Vec3 PosToEye = _position - eyePoint;
234                        osg::Matrix lookto = osg::Matrix::lookAt(
235                            osg::Vec3(0,0,0), PosToEye, localUp);
236                        Quat q;
237                        q.set(osg::Matrix::inverse(lookto));
238                        setRotation(q);
239                    }
240
241                    _previousEyePoint = eyePoint;
242                    _previousLocalUp = localUp;
243                    _previousWidth = width;
244                    _previousHeight = height;
245                    _previousProjection = projection;
246                    _previousPosition = position;
247
248                    _matrixDirty = true;
249                }
250
251            }
252        }
253
254        // now do the proper accept
255        Transform::accept(nv);
256    }
257}
258
259BoundingSphere AutoTransform::computeBound() const
260{
261    BoundingSphere bsphere;
262
263    if ( getAutoScaleToScreen() && _firstTimeToInitEyePoint )
264        return bsphere;
265
266    bsphere = Transform::computeBound();
267
268    return bsphere;
269}
Note: See TracBrowser for help on using the browser.