]> git.mxchange.org Git - simgear.git/blobdiff - simgear/scene/util/SGUpdateVisitor.hxx
Work around apparent OSG 3.2.0 normal binding bug.
[simgear.git] / simgear / scene / util / SGUpdateVisitor.hxx
index 68f8ecdb878defafd8b78ad74273990cc5d6c3da..8f16a270353d21478b08c77dab3d9ae61163120a 100644 (file)
@@ -1,6 +1,6 @@
 /* -*-c++-*-
  *
- * Copyright (C) 2006 Mathias Froehlich 
+ * Copyright (C) 2006-2009 Mathias Froehlich 
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
 #define SG_SCENE_UPDATEVISITOR_HXX
 
 #include <osg/NodeVisitor>
+#include <osg/PagedLOD>
 #include <osgUtil/UpdateVisitor>
 
-#include "simgear/math/SGMath.hxx"
+#include "OsgMath.hxx"
 
 class SGUpdateVisitor : public osgUtil::UpdateVisitor {
 public:
-  SGUpdateVisitor()
+  SGUpdateVisitor() :
+    mVisibility(-1)
   {
-    // Need to traverse all children, else some LOD nodes do not get updated
-    // Note that the broad number of updates is not done due to
-    // the update callback in the global position node.
-    setTraversalMode(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN);
+    setTraversalMode(osg::NodeVisitor::TRAVERSE_ACTIVE_CHILDREN);
+    setVisibility(10000);
   }
   void setViewData(const SGVec3d& globalEyePos,
                    const SGQuatd& globalViewOrientation)
   {
     mGlobalGeodEyePos = SGGeod::fromCart(globalEyePos);
+    _currentEyePos = toOsg(globalEyePos);
     mGlobalEyePos = globalEyePos;
     mGlobalViewOr = globalViewOrientation;
     mGlobalHorizLocalOr = SGQuatd::fromLonLat(mGlobalGeodEyePos);
@@ -48,15 +49,32 @@ public:
     mHorizLocalDown = mGlobalHorizLocalOr.backTransform(SGVec3d(0, 0, 1));
   }
 
-  void setSceneryCenter(const SGVec3d& sceneryCenter)
-  {
-    mSceneryCenter = sceneryCenter;
-  }
-
   void setVisibility(double visibility)
   {
+    if (mVisibility == visibility)
+      return;
     mVisibility = visibility;
     mSqrVisibility = visibility*visibility;
+
+    double m_log01 = -log( 0.01 );
+    double sqrt_m_log01 = sqrt( m_log01 );
+    double fog_exp_density = m_log01 / visibility;
+    double fog_exp2_density = sqrt_m_log01 / visibility;
+    double ground_exp2_punch_through = sqrt_m_log01 / (visibility * 1.5);
+    double rwy_exp2_punch_through, taxi_exp2_punch_through;
+    if ( visibility < 8000 ) {
+      rwy_exp2_punch_through = sqrt_m_log01 / (visibility * 2.5);
+      taxi_exp2_punch_through = sqrt_m_log01 / (visibility * 1.5);
+    } else {
+      rwy_exp2_punch_through = sqrt_m_log01 / ( 8000 * 2.5 );
+      taxi_exp2_punch_through = sqrt_m_log01 / ( 8000 * 1.5 );
+    }
+    
+    mFogExpDensity = fog_exp_density;
+    mFogExp2Density = fog_exp2_density;
+    mRunwayFogExp2Density = rwy_exp2_punch_through;
+    mTaxiFogExp2Density = taxi_exp2_punch_through;
+    mGroundLightsFogExp2Density = ground_exp2_punch_through;
   }
 
   double getVisibility() const
@@ -64,6 +82,17 @@ public:
   double getSqrVisibility() const
   { return mSqrVisibility; }
 
+  double getFogExpDensity() const
+  { return mFogExpDensity; }
+  double getFogExp2Density() const
+  { return mFogExp2Density; }
+  double getRunwayFogExp2Density() const
+  { return mRunwayFogExp2Density; }
+  double getTaxiFogExp2Density() const
+  { return mTaxiFogExp2Density; }
+  double getGroundLightsFogExp2Density() const
+  { return mGroundLightsFogExp2Density; }
+
   const SGVec3d& getGlobalEyePos() const
   { return mGlobalEyePos; }
   const SGGeod& getGeodEyePos() const
@@ -80,11 +109,15 @@ public:
   { return mHorizLocalDown; }
 
   void setLight(const SGVec3f& direction, const SGVec4f& ambient,
-                const SGVec4f& diffuse, const SGVec4f& specular)
+                const SGVec4f& diffuse, const SGVec4f& specular,
+                const SGVec4f& fogColor, double sunAngleDeg)
   {
     mLightDirection = direction;
     mAmbientLight = ambient;
     mDiffuseLight = diffuse;
+    mSpecularLight = specular;
+    mFogColor = fogColor;
+    mSunAngleDeg = sunAngleDeg;
   }
 
   const SGVec3f& getLightDirection() const
@@ -95,8 +128,78 @@ public:
   { return mDiffuseLight; }
   const SGVec4f& getSpecularLight() const
   { return mSpecularLight; }
+  const SGVec4f& getFogColor() const
+  { return mFogColor; }
+
+  double getSunAngleDeg() const
+  { return mSunAngleDeg; }
+
+  virtual void apply(osg::Node& node)
+  {
+    if (!needToEnterNode(node))
+      return;
+    osgUtil::UpdateVisitor::apply(node);
+  }
+  // To avoid expiry of LOD nodes that are in range and that are updated,
+  // mark them with the last traversal number, even if they are culled away
+  // by the cull frustum.
+  virtual void apply(osg::PagedLOD& pagedLOD)
+  {
+    if (!needToEnterNode(pagedLOD))
+      return;
+    if (getFrameStamp())
+      pagedLOD.setFrameNumberOfLastTraversal(getFrameStamp()->getFrameNumber());
+    osgUtil::UpdateVisitor::apply(pagedLOD);
+  }
+  // To be able to traverse correctly only the active children, we need to
+  // track the model view matrices during update.
+  virtual void apply(osg::Transform& transform)
+  {
+    if (!needToEnterNode(transform))
+      return;
+    osg::Matrix matrix = _matrix;
+    transform.computeLocalToWorldMatrix(_matrix, this);
+    osgUtil::UpdateVisitor::apply(transform);
+    _matrix = matrix;
+  }
+  virtual void apply(osg::Camera& camera)
+  {
+    if (!needToEnterNode(camera))
+      return;
+    if (camera.getReferenceFrame() == osg::Camera::ABSOLUTE_RF) {
+      osg::Vec3d currentEyePos = _currentEyePos;
+      _currentEyePos = osg::Vec3d(0, 0, 0);
+      apply(static_cast<osg::Transform&>(camera));
+      _currentEyePos = currentEyePos;
+    } else {
+      apply(static_cast<osg::Transform&>(camera));
+    }
+  }
+  // Function to make the LOD traversal only enter that children that
+  // are visible on the screen.
+  virtual float getDistanceToViewPoint(const osg::Vec3& pos, bool) const
+  { return (_currentEyePos - _matrix.preMult(osg::Vec3d(pos))).length(); }
 
+protected:
+  bool needToEnterNode(const osg::Node& node) const
+  {
+    if (!node.isCullingActive())
+      return true;
+    return isSphereInRange(node.getBound());
+  }
+  bool isSphereInRange(const osg::BoundingSphere& sphere) const
+  {
+    if (!sphere.valid())
+      return false;
+    float maxDist = mVisibility + sphere._radius;
+    osg::Vec3d center = _matrix.preMult(osg::Vec3d(sphere._center));
+    return (_currentEyePos - center).length2() <= maxDist*maxDist;
+  }
+    
 private:
+  osg::Matrix _matrix;
+  osg::Vec3d _currentEyePos;
+
   SGGeod mGlobalGeodEyePos;
   SGVec3d mGlobalEyePos;
   SGQuatd mGlobalViewOr;
@@ -105,15 +208,21 @@ private:
   SGVec3d mHorizLocalEast;
   SGVec3d mHorizLocalDown;
 
-  SGVec3d mSceneryCenter;
-
   double mVisibility;
   double mSqrVisibility;
+  double mFogExpDensity;
+  double mFogExp2Density;
+  double mRunwayFogExp2Density;
+  double mTaxiFogExp2Density;
+  double mGroundLightsFogExp2Density;
 
   SGVec3f mLightDirection;
   SGVec4f mAmbientLight;
   SGVec4f mDiffuseLight;
   SGVec4f mSpecularLight;
+  SGVec4f mFogColor;
+
+  double mSunAngleDeg;
 };
 
 #endif