3 * Copyright (C) 2006-2009 Mathias Froehlich
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation; either version 2 of the
8 * License, or (at your option) any later version.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
22 #ifndef SG_SCENE_UPDATEVISITOR_HXX
23 #define SG_SCENE_UPDATEVISITOR_HXX
25 #include <osg/NodeVisitor>
26 #include <osg/PagedLOD>
27 #include <osgUtil/UpdateVisitor>
29 #include "simgear/math/SGMath.hxx"
31 class SGUpdateVisitor : public osgUtil::UpdateVisitor {
36 setTraversalMode(osg::NodeVisitor::TRAVERSE_ACTIVE_CHILDREN);
39 void setViewData(const SGVec3d& globalEyePos,
40 const SGQuatd& globalViewOrientation)
42 mGlobalGeodEyePos = SGGeod::fromCart(globalEyePos);
43 _currentEyePos = globalEyePos.osg();
44 mGlobalEyePos = globalEyePos;
45 mGlobalViewOr = globalViewOrientation;
46 mGlobalHorizLocalOr = SGQuatd::fromLonLat(mGlobalGeodEyePos);
47 mHorizLocalNorth = mGlobalHorizLocalOr.backTransform(SGVec3d(1, 0, 0));
48 mHorizLocalEast = mGlobalHorizLocalOr.backTransform(SGVec3d(0, 1, 0));
49 mHorizLocalDown = mGlobalHorizLocalOr.backTransform(SGVec3d(0, 0, 1));
52 void setVisibility(double visibility)
54 if (mVisibility == visibility)
56 mVisibility = visibility;
57 mSqrVisibility = visibility*visibility;
59 double m_log01 = -log( 0.01 );
60 double sqrt_m_log01 = sqrt( m_log01 );
61 double fog_exp_density = m_log01 / visibility;
62 double fog_exp2_density = sqrt_m_log01 / visibility;
63 double ground_exp2_punch_through = sqrt_m_log01 / (visibility * 1.5);
64 double rwy_exp2_punch_through, taxi_exp2_punch_through;
65 if ( visibility < 8000 ) {
66 rwy_exp2_punch_through = sqrt_m_log01 / (visibility * 2.5);
67 taxi_exp2_punch_through = sqrt_m_log01 / (visibility * 1.5);
69 rwy_exp2_punch_through = sqrt_m_log01 / ( 8000 * 2.5 );
70 taxi_exp2_punch_through = sqrt_m_log01 / ( 8000 * 1.5 );
73 mFogExpDensity = fog_exp_density;
74 mFogExp2Density = fog_exp2_density;
75 mRunwayFogExp2Density = rwy_exp2_punch_through;
76 mTaxiFogExp2Density = taxi_exp2_punch_through;
77 mGroundLightsFogExp2Density = ground_exp2_punch_through;
80 double getVisibility() const
81 { return mVisibility; }
82 double getSqrVisibility() const
83 { return mSqrVisibility; }
85 double getFogExpDensity() const
86 { return mFogExpDensity; }
87 double getFogExp2Density() const
88 { return mFogExp2Density; }
89 double getRunwayFogExp2Density() const
90 { return mRunwayFogExp2Density; }
91 double getTaxiFogExp2Density() const
92 { return mTaxiFogExp2Density; }
93 double getGroundLightsFogExp2Density() const
94 { return mGroundLightsFogExp2Density; }
96 const SGVec3d& getGlobalEyePos() const
97 { return mGlobalEyePos; }
98 const SGGeod& getGeodEyePos() const
99 { return mGlobalGeodEyePos; }
100 const SGQuatd& getGlobalViewOr() const
101 { return mGlobalViewOr; }
102 const SGQuatd& getGlobalHorizLocalOr() const
103 { return mGlobalViewOr; }
104 const SGVec3d& getHorizLocalNorth() const
105 { return mHorizLocalNorth; }
106 const SGVec3d& getHorizLocalEast() const
107 { return mHorizLocalEast; }
108 const SGVec3d& getHorizLocalDown() const
109 { return mHorizLocalDown; }
111 void setLight(const SGVec3f& direction, const SGVec4f& ambient,
112 const SGVec4f& diffuse, const SGVec4f& specular,
113 const SGVec4f& fogColor, double sunAngleDeg)
115 mLightDirection = direction;
116 mAmbientLight = ambient;
117 mDiffuseLight = diffuse;
118 mSpecularLight = specular;
119 mFogColor = fogColor;
120 mSunAngleDeg = sunAngleDeg;
123 const SGVec3f& getLightDirection() const
124 { return mLightDirection; }
125 const SGVec4f& getAmbientLight() const
126 { return mAmbientLight; }
127 const SGVec4f& getDiffuseLight() const
128 { return mDiffuseLight; }
129 const SGVec4f& getSpecularLight() const
130 { return mSpecularLight; }
131 const SGVec4f& getFogColor() const
132 { return mFogColor; }
134 double getSunAngleDeg() const
135 { return mSunAngleDeg; }
137 virtual void apply(osg::Node& node)
139 if (!needToEnterNode(node))
141 osgUtil::UpdateVisitor::apply(node);
143 // To avoid expiry of LOD nodes that are in range and that are updated,
144 // mark them with the last traversal number, even if they are culled away
145 // by the cull frustum.
146 virtual void apply(osg::PagedLOD& pagedLOD)
148 if (!needToEnterNode(pagedLOD))
151 pagedLOD.setFrameNumberOfLastTraversal(getFrameStamp()->getFrameNumber());
152 osgUtil::UpdateVisitor::apply(pagedLOD);
154 // To be able to traverse correctly only the active children, we need to
155 // track the model view matrices during update.
156 virtual void apply(osg::Transform& transform)
158 if (!needToEnterNode(transform))
160 osg::Matrix matrix = _matrix;
161 transform.computeLocalToWorldMatrix(_matrix, this);
162 osgUtil::UpdateVisitor::apply(transform);
165 virtual void apply(osg::Camera& camera)
167 if (!needToEnterNode(camera))
169 if (camera.getReferenceFrame() == osg::Camera::ABSOLUTE_RF) {
170 osg::Vec3d currentEyePos = _currentEyePos;
171 _currentEyePos = osg::Vec3d(0, 0, 0);
172 apply(static_cast<osg::Transform&>(camera));
173 _currentEyePos = currentEyePos;
175 apply(static_cast<osg::Transform&>(camera));
178 // Function to make the LOD traversal only enter that children that
179 // are visible on the screen.
180 virtual float getDistanceToViewPoint(const osg::Vec3& pos, bool) const
181 { return (_currentEyePos - _matrix.preMult(osg::Vec3d(pos))).length(); }
184 bool needToEnterNode(const osg::Node& node) const
186 if (!node.isCullingActive())
188 return isSphereInRange(node.getBound());
190 bool isSphereInRange(const osg::BoundingSphere& sphere) const
194 float maxDist = mVisibility + sphere._radius;
195 osg::Vec3d center = _matrix.preMult(osg::Vec3d(sphere._center));
196 return (_currentEyePos - center).length2() <= maxDist*maxDist;
201 osg::Vec3d _currentEyePos;
203 SGGeod mGlobalGeodEyePos;
204 SGVec3d mGlobalEyePos;
205 SGQuatd mGlobalViewOr;
206 SGQuatd mGlobalHorizLocalOr;
207 SGVec3d mHorizLocalNorth;
208 SGVec3d mHorizLocalEast;
209 SGVec3d mHorizLocalDown;
212 double mSqrVisibility;
213 double mFogExpDensity;
214 double mFogExp2Density;
215 double mRunwayFogExp2Density;
216 double mTaxiFogExp2Density;
217 double mGroundLightsFogExp2Density;
219 SGVec3f mLightDirection;
220 SGVec4f mAmbientLight;
221 SGVec4f mDiffuseLight;
222 SGVec4f mSpecularLight;