DYT/Tool/OpenSceneGraph-3.6.5/include/osgEarth/CullingUtils

322 lines
11 KiB
Plaintext
Raw Normal View History

2024-12-24 23:49:36 +00:00
/* -*-c++-*- */
/* osgEarth - Geospatial SDK for OpenSceneGraph
* Copyright 2020 Pelican Mapping
* http://osgearth.org
*
* osgEarth is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
*/
#pragma once
#include <osgEarth/Common>
#include <osgEarth/optional>
#include <osgEarth/SpatialReference>
#include <osgEarth/Horizon>
#include <osgEarth/GeoTransform>
#include <osg/NodeCallback>
#include <osg/ClusterCullingCallback>
#include <osg/CoordinateSystemNode>
#include <osg/MatrixTransform>
#include <osg/Vec3d>
#include <osg/Vec3>
#include <osg/ClipPlane>
#include <osg/LOD>
#include <osgUtil/CullVisitor>
#include <osgUtil/RenderBin>
namespace osgEarth
{
//! Method to use when determining when to switch levels of detail.
enum class LODMethod
{
CAMERA_DISTANCE = osg::LOD::DISTANCE_FROM_EYE_POINT,
SCREEN_SPACE = osg::LOD::PIXEL_SIZE_ON_SCREEN
};
namespace Util
{
/**
* A customized CCC that works correctly under an RTT camera and also with
* an orthographic projection matrix.
*/
class SuperClusterCullingCallback : public osg::ClusterCullingCallback
{
public:
bool cull(osg::NodeVisitor* nv, osg::Drawable*, osg::State*) const;
};
/**
* Utility functions for creating cluster cullers
*/
class OSGEARTH_EXPORT ClusterCullingFactory
{
public:
/**
* Creates a cluster culling callback based on the data in a node graph.
* NOTE! Never put a CCC somewhere where it will be under a transform. They
* only work in absolute world space.
*/
static osg::NodeCallback* create(osg::Node* node, const osg::Vec3d& ecefControlPoint);
/**
* Same as above, but uses another method to compute the parameters. There should only
* be one, but we need to investigate to see which is the better algorithm. Keeping this
* for now since it works with the feature setup..
*/
static osg::NodeCallback* create2(osg::Node* node, const osg::Vec3d& ecefControlPoint);
/**
* Creates a cluster culling callback and installs it on the node. If the node is
* a transform, it will create a group above the transform and install the callback
* on that group instead.
*/
static osg::Node* createAndInstall(osg::Node* node, const osg::Vec3d& ecefControlPoint);
/**
* Creates a cluster culling callback with the standard parameters.
*/
static osg::NodeCallback* create(const osg::Vec3& controlPoint, const osg::Vec3& normal, float deviation, float radius);
/**
* Creates a cluster culling callback based on an extent (for geocentric tiles).
*/
static osg::NodeCallback* create(const class GeoExtent& extent);
};
/**
* Simple occlusion culling callback that does a ray interseciton between the eyepoint
* and a A GeoTransform node.
*/
struct OSGEARTH_EXPORT OcclusionCullingCallback : public osg::NodeCallback
{
OcclusionCullingCallback(GeoTransform* xform);
/** Maximum eye altitude at which to perform the occlusion culling test */
double getMaxAltitude() const;
void setMaxAltitude(double value);
/**
* Gets the maximum number of ms that the OcclusionCullingCallback can run on each frame.
*/
static double getMaxFrameTime();
/**
* Sets the maximum number of ms that the OcclusionCullingCallback can run on each frame.
* @param ms
* The maximum number of milliseconds to run the OcclusionCullingCallback on each frame.
*/
static void setMaxFrameTime(double ms);
public: //NodeCallback
void operator()(osg::Node* node, osg::NodeVisitor* nv);
private:
osg::observer_ptr<GeoTransform> _xform;
osg::Vec3d _prevEye;
bool _visible;
double _maxAltitude;
static double _maxFrameTime;
};
/**
* Culling utilities.
*/
struct OSGEARTH_EXPORT Culling
{
static osgUtil::CullVisitor* asCullVisitor(osg::NodeVisitor* nv);
static osgUtil::CullVisitor* asCullVisitor(osg::NodeVisitor& nv) { return asCullVisitor(&nv); }
};
/**
* Node Visitor that proxies the CullVisitor but uses a separate
* frustum for bounds-culling.
*/
class ProxyCullVisitor : public osg::NodeVisitor, public osg::CullStack
{
private:
osgUtil::CullVisitor* _cv;
osg::Polytope _proxyFrustum;
osg::Polytope _proxyProjFrustum;
osg::Matrix _proxyModelViewMatrix;
osg::Matrix _proxyProjMatrix;
public:
ProxyCullVisitor(osgUtil::CullVisitor* cv, const osg::Matrix& proj, const osg::Matrix& view);
// access to the underlying cull visitor.
osgUtil::CullVisitor* getCullVisitor() { return _cv; }
bool isCulledByProxyFrustum(osg::Node& node);
bool isCulledByProxyFrustum(const osg::BoundingBox& bbox);
public: // proxy functions:
osg::Vec3 getEyePoint() const;
osg::Vec3 getViewPoint() const;
float getDistanceToEyePoint(const osg::Vec3& pos, bool useLODScale) const;
float getDistanceFromEyePoint(const osg::Vec3& pos, bool useLODScale) const;
float getDistanceToViewPoint(const osg::Vec3& pos, bool useLODScale) const;
protected:
osgUtil::CullVisitor::value_type distance(const osg::Vec3& coord, const osg::Matrix& matrix);
void handle_cull_callbacks_and_traverse(osg::Node& node);
void apply(osg::Node& node);
void apply(osg::Transform& xform);
void apply(osg::Drawable& drawable);
void apply(osg::LOD& lod);
};
/**
* Horizon culling in a shader program.
*/
class OSGEARTH_EXPORT HorizonCullingProgram
{
public:
static void install(osg::StateSet* stateset);
static void remove(osg::StateSet* stateset);
};
/**
* Group that lets you adjust the LOD scale on its children.
*/
class OSGEARTH_EXPORT LODScaleGroup : public osg::Group
{
public:
LODScaleGroup();
/**
* Factor by which to multiply the camera's LOD scale.
*/
void setLODScaleFactor(float value) { _scaleFactor = value; }
float getLODScaleFactor() const { return _scaleFactor; }
public: // osg::Group
virtual void traverse(osg::NodeVisitor& nv);
protected:
virtual ~LODScaleGroup() { }
private:
float _scaleFactor;
};
struct OSGEARTH_EXPORT CullDebugger
{
Config dumpRenderBin(osgUtil::RenderBin* bin) const;
};
/**
* Cull callback for cameras that sets the oe_Camera uniform.
*/
class OSGEARTH_EXPORT InstallCameraUniform : public osg::NodeCallback
{
public:
META_Object(osgEarth, InstallCameraUniform);
void operator()(osg::Node* node, osg::NodeVisitor* nv);
InstallCameraUniform() { }
protected:
InstallCameraUniform(const InstallCameraUniform& rhs, const osg::CopyOp& copy) :
osg::NodeCallback(rhs, copy) { }
};
/**
* Cull callback that limits visibility to an altitude range (HAE)
*/
class OSGEARTH_EXPORT AltitudeCullCallback : public osg::NodeCallback
{
public:
optional<float>& maxAltitude() { return _maxAltitude; }
osg::ref_ptr<const SpatialReference>& srs() { return _srs; }
void operator()(osg::Node* node, osg::NodeVisitor* nv);
private:
optional<float> _maxAltitude;
osg::ref_ptr<const SpatialReference> _srs;
};
/**
* Cull callback that will permit culling but will supress rendering.
* We use this to toggle node visibility to that paged scene graphs
* will continue to page in/out even when the layer is not visible.
*/
class OSGEARTH_EXPORT ToggleVisibleCullCallback : public osg::NodeCallback
{
public:
void setVisible(bool value)
{
_visible = value;
}
bool getVisible() const
{
return _visible;
}
private:
struct EmptyRenderBin : public osgUtil::RenderBin
{
EmptyRenderBin(osgUtil::RenderStage* stage) :
osgUtil::RenderBin()
{
setName("OE_EMPTY_RENDER_BIN");
_stage = stage;
}
};
bool _visible = true;
public:
void operator()(osg::Node* node, osg::NodeVisitor* nv) override
{
if (_visible)
{
traverse(node, nv);
}
else
{
osgUtil::CullVisitor* cv = dynamic_cast<osgUtil::CullVisitor*>(nv);
osg::ref_ptr<osgUtil::RenderBin> savedBin;
osg::ref_ptr<EmptyRenderBin> emptyStage;
if (cv)
{
savedBin = cv->getCurrentRenderBin();
emptyStage = new EmptyRenderBin(savedBin->getStage());
cv->setCurrentRenderBin(emptyStage.get());
}
traverse(node, nv);
if (cv)
{
cv->setCurrentRenderBin(savedBin.get());
}
}
}
};
}
}