root/OpenSceneGraph/trunk/src/osg/Billboard.cpp @ 13041

Revision 13041, 9.4 kB (checked in by robert, 2 years ago)

Ran script to remove trailing spaces and tabs

  • 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 <stdio.h>
14#include <math.h>
15
16#include <osg/Billboard>
17
18using namespace osg;
19
20#define square(x)   ((x)*(x))
21
22Billboard::Billboard()
23{
24    _mode = AXIAL_ROT;
25    _axis.set(0.0f,0.0f,1.0f);
26    //_normal.set(0.0f,-1.0f,0.0f);
27    setNormal(Vec3(0.0f,-1.0f,0.0f));
28    updateCache();
29}
30
31Billboard::Billboard(const Billboard& billboard,const CopyOp& copyop):
32        Geode(billboard,copyop),
33        _mode(billboard._mode),
34        _axis(billboard._axis),
35        _normal(billboard._normal),
36        _positionList(billboard._positionList),
37        _cachedMode(billboard._cachedMode),
38        _side(billboard._side)
39{
40    setNormal(_normal);
41}
42
43Billboard::~Billboard()
44{
45}
46
47void Billboard::setMode(Mode mode)
48{
49    _mode = mode;
50    _cachedMode = CACHE_DIRTY;
51    updateCache();
52}
53
54void Billboard::setAxis(const Vec3& axis)
55{
56    _axis = axis;
57    _axis.normalize();
58    updateCache();
59}
60
61void Billboard::setNormal(const Vec3& normal)
62{
63    _normal = normal;
64    _normal.normalize();
65    updateCache();
66
67    // Build rotation from normal to z-axis,
68    // for use with POINT_ROT_EYE
69    Vec3 z(0.0, 0.0, 1.0);
70    Vec3 cp(z^_normal);
71    float dot = z*_normal;
72    float cp_len = cp.length();
73    if (cp_len != 0.0f)
74    {
75        cp /= cp_len;
76        float rotation_cp = acosf(dot);
77        Matrix rotateNormalToZ;
78        _rotateNormalToZAxis.makeRotate(-rotation_cp, cp);
79    }
80    else
81        _rotateNormalToZAxis.makeIdentity();
82}
83
84void Billboard::updateCache()
85{
86    if (_mode==AXIAL_ROT)
87    {
88        if      (_axis==Vec3(1.0f,0.0,0.0f) && _normal==Vec3(0.0f,-1.0,0.0f)) _cachedMode = AXIAL_ROT_X_AXIS;
89        else if (_axis==Vec3(0.0f,1.0,0.0f) && _normal==Vec3(1.0f, 0.0,0.0f)) _cachedMode = AXIAL_ROT_Y_AXIS;
90        else if (_axis==Vec3(0.0f,0.0,1.0f) && _normal==Vec3(0.0f,-1.0,0.0f)) _cachedMode = AXIAL_ROT_Z_AXIS;
91        else                                                                  _cachedMode = AXIAL_ROT;
92    }
93    else if( _mode == POINT_ROT_WORLD )
94    {
95        if(_axis==Vec3(0.0f, 0.0, 1.0f) && _normal==Vec3(0.0f, -1.0f, 0.0f))  _cachedMode = POINT_ROT_WORLD_Z_AXIS;
96        else _cachedMode = _mode;
97
98    }
99    else _cachedMode = _mode;
100
101    _side = _axis^_normal;
102    _side.normalize();
103}
104
105bool Billboard::addDrawable(Drawable *gset)
106{
107    if (Geode::addDrawable(gset))
108    {
109        Vec3 pos(0.0f,0.0f,0.0f);
110        while (_positionList.size()<_drawables.size())
111        {
112            _positionList.push_back(pos);
113        }
114        return true;
115    }
116    return false;
117}
118
119
120bool Billboard::addDrawable(Drawable *gset,const Vec3& pos)
121{
122    if (Geode::addDrawable(gset))
123    {
124        while (_positionList.size()<_drawables.size())
125        {
126            _positionList.push_back(pos);
127        }
128        return true;
129    }
130    return false;
131}
132
133
134bool Billboard::removeDrawable( Drawable *gset )
135{
136    PositionList::iterator pitr = _positionList.begin();
137    for (DrawableList::iterator itr=_drawables.begin();
138        itr!=_drawables.end();
139        ++itr,++pitr)
140    {
141        if (itr->get()==gset)
142        {
143            // note ref_ptr<> automatically handles decrementing gset's reference count.
144            _drawables.erase(itr);
145            _positionList.erase(pitr);
146            dirtyBound();
147            return true;
148        }
149    }
150    return false;
151}
152
153bool Billboard::computeMatrix(Matrix& modelview, const Vec3& eye_local, const Vec3& pos_local) const
154{
155    //Vec3 up_local(matrix(0,1),matrix(1,1),matrix(2,1));
156
157    Matrix matrix;
158
159    Vec3 ev(eye_local-pos_local);
160    switch(_cachedMode)
161    {
162        case(AXIAL_ROT_Z_AXIS):
163        {
164
165            ev.z() = 0.0f;
166            float ev_length = ev.length();
167            if (ev_length>0.0f)
168            {
169                //float rotation_zrotation_z = atan2f(ev.x(),ev.y());
170                //mat.makeRotate(inRadians(rotation_z),0.0f,0.0f,1.0f);
171                float inv = 1.0f/ev_length;
172                float s = ev.x()*inv;
173                float c = -ev.y()*inv;
174                matrix(0,0) = c;
175                matrix(1,0) = -s;
176                matrix(0,1) = s;
177                matrix(1,1) = c;
178            }
179            break;
180        }
181        case(AXIAL_ROT_Y_AXIS):
182        {
183            ev.y() = 0.0f;
184            float ev_length = ev.length();
185            if (ev_length>0.0f)
186            {
187                //float rotation_zrotation_z = atan2f(ev.x(),ev.y());
188                //mat.makeRotate(inRadians(rotation_z),0.0f,0.0f,1.0f);
189                float inv = 1.0f/ev_length;
190                float s = -ev.z()*inv;
191                float c = ev.x()*inv;
192                matrix(0,0) = c;
193                matrix(2,0) = s;
194                matrix(0,2) = -s;
195                matrix(2,2) = c;
196            }
197            break;
198        }
199        case(AXIAL_ROT_X_AXIS):
200        {
201            ev.x() = 0.0f;
202            float ev_length = ev.length();
203            if (ev_length>0.0f)
204            {
205
206                //float rotation_zrotation_z = atan2f(ev.x(),ev.y());
207                //mat.makeRotate(inRadians(rotation_z),0.0f,0.0f,1.0f);
208                float inv = 1.0f/ev_length;
209                float s = -ev.z()*inv;
210                float c = -ev.y()*inv;
211                matrix(1,1) = c;
212                matrix(2,1) = -s;
213                matrix(1,2) = s;
214                matrix(2,2) = c;
215            }
216            break;
217        }
218        case(AXIAL_ROT): // need to implement
219        {
220            float ev_side = ev*_side;
221            float ev_normal = ev*_normal;
222            float rotation = atan2f(ev_side,ev_normal);
223            matrix.makeRotate(rotation,_axis);
224            break;
225        }
226        case(POINT_ROT_WORLD):
227        {
228            float ev_len = ev.length();
229            if (ev_len != 0.0f)
230            {
231                ev /= ev_len;
232
233                Vec3 cp(ev^_normal);
234                float dot = ev*_normal;
235
236                float cp_len = cp.length();
237                if (cp_len != 0.0f)
238                {
239                    cp /= cp_len;
240
241                    float rotation_cp = acosf(dot);
242                    matrix.makeRotate(-inRadians(rotation_cp),cp[0],cp[1],cp[2]);
243                }
244            }
245            break;
246        }
247        case(POINT_ROT_EYE):
248        {
249            float ev_len = ev.length();
250            if (ev_len != 0.0f)
251            {
252                ev /= ev_len;
253
254                Vec3 up(modelview(0,1), modelview(1,1), modelview(2,1));
255                Vec3 right(up^ev);
256                right.normalize();
257                up = ev^right;
258                up.normalize();
259
260                matrix(0,0) = right.x();
261                matrix(0,1) = right.y();
262                matrix(0,2) = right.z();
263                matrix(1,0) = up.x();
264                matrix(1,1) = up.y();
265                matrix(1,2) = up.z();
266                matrix(2,0) = ev.x();
267                matrix(2,1) = ev.y();
268                matrix(2,2) = ev.z();
269
270                matrix.preMult(_rotateNormalToZAxis);
271            }
272            break;
273        }
274        case(POINT_ROT_WORLD_Z_AXIS):
275        {
276           // float rotation_about_z = atan2( -ev.y(), ev.x() );
277           // float xy_distance = sqrt( ev.x()*ev.x() + ev.y()*ev.y() );
278           // float rotation_from_xy = atan2( xy_distance, -ev.z() );
279
280           Vec2   about_z( -ev.y(), ev.x() );
281           if( about_z.normalize() == 0.0f ) about_z.x() = 1.0f;
282           float  xy_distance = sqrt( ev.x()*ev.x() + ev.y()*ev.y() );
283           Vec2   from_xy( xy_distance, -ev.z() );
284           if( from_xy.normalize() == 0.0f ) from_xy.x() = 1.0f;
285
286           matrix(0,0) =  about_z.x();
287           matrix(0,1) =  about_z.y();
288           matrix(1,0) = -about_z.y()*from_xy.x();
289           matrix(1,1) =  about_z.x()*from_xy.x();
290           matrix(1,2) =  from_xy.y();
291           matrix(2,0) =  about_z.y()*from_xy.y();
292           matrix(2,1) = -about_z.x()*from_xy.y();
293           matrix(2,2) =  from_xy.x();
294
295           break;
296        }
297    }
298
299    matrix.setTrans(pos_local);
300
301    modelview.preMult(matrix);
302
303    return true;
304
305}
306
307BoundingSphere Billboard::computeBound() const
308{
309    int i;
310    int ngsets = _drawables.size();
311
312    if( ngsets == 0 ) return BoundingSphere();
313
314    BoundingSphere bsphere;
315    bsphere._center.set(0.0f,0.0f,0.0f);
316
317    for( i = 0; i < ngsets; i++ )
318    {
319        const Drawable *gset = _drawables[i].get();
320        const BoundingBox& bbox = gset->getBound();
321
322        bsphere._center += bbox.center();
323        bsphere._center += _positionList[i];
324    }
325
326    bsphere._center /= (float)(ngsets);
327
328    float maxd = 0.0;
329    for( i = 0; i < ngsets; ++i )
330    {
331        const Drawable *gset = _drawables[i].get();
332        const BoundingBox& bbox = gset->getBound();
333        Vec3 local_center = bsphere._center-_positionList[i];
334        for(unsigned int c=0;c<8;++c)
335        {
336            float d = (bbox.corner(c)-local_center).length2();
337            if( d > maxd ) maxd = d;
338        }
339    }
340    bsphere._radius = sqrtf(maxd);
341
342    return bsphere;
343}
Note: See TracBrowser for help on using the browser.