DYT/Tool/OpenSceneGraph-3.6.5/include/osgEarth/Chonk
2024-12-25 07:49:36 +08:00

454 lines
15 KiB
C++

/* -*-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.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
* 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/GLUtils>
#include <osgEarth/TextureArena>
#include <osgEarth/Utils>
#include <osg/Geometry>
#include <osgUtil/RenderLeaf>
#include <osgUtil/RenderBin>
#include <vector>
#include <unordered_set>
#include <unordered_map>
// Usage hint to signal which textures are external materials. Currently only two slots are supported [0, 1]
#define CHONK_HINT_EXTENDED_MATERIAL_SLOT "osgEarth.Chonk.ExtendedMaterial.Slot"
namespace osgEarth
{
class OSGEARTH_EXPORT ChonkMaterial
{
public:
using Ptr = std::shared_ptr<ChonkMaterial>;
static Ptr create() {
return Ptr(new ChonkMaterial);
}
// texturearena indexes of material textures
int albedo_index = -1;
int normal_index = -1;
int pbr_index = -1;
int material1_index = -1;
int material2_index = -1;
// store refs to the original textures when the
// factory objects's texture arena is using auto-release.
// otherwise they are null.
Texture::Ptr albedo_tex;
Texture::Ptr normal_tex;
Texture::Ptr pbr_tex;
Texture::Ptr material1_tex;
Texture::Ptr material2_tex;
private:
//! hidden to force use of create()
ChonkMaterial() = default;
};
class ChonkFactory;
class ChonkDrawable;
/**
* A bindless rendering unit comprised of one VBO and one EBO.
* A single Chonk usually represents one drawable "Object" in
* the scene. It can include up to 2 LODs.
*/
class OSGEARTH_EXPORT Chonk
{
public:
using element_t = GLuint;
using Ptr = std::shared_ptr<Chonk>;
using WeakPtr = std::weak_ptr<Chonk>;
//! Adds a node.
bool add(
osg::Node* node,
ChonkFactory& factory);
//! Adds a node with screen-space-error limits.
bool add(
osg::Node* node,
float far_pixel_scale,
float near_pixel_scale,
ChonkFactory& factory);
//! Local bounding box of this Chonk.
const osg::BoundingBoxf& getBound();
//! Name, which will appear in GL debug labels
std::string& name() { return _name; }
const std::string& name() const { return _name; }
public:
//! Single vertex data.
struct VertexGPU
{
osg::Vec3f position;
osg::Vec3f normal;
char normal_technique = (char)0;
osg::Vec4ub color;
osg::Vec2f uv;
osg::Vec3f flex;
// texturearena indexes of materials
// TODO: use a material index instead?
GLshort albedo_index = -1;
GLshort normalmap_index = -1;
GLshort pbr_index = -1;
osg::Vec2s extended_material_index = osg::Vec2s(-1, -1);
};
static GLubyte NORMAL_TECHNIQUE_DEFAULT;
static GLubyte NORMAL_TECHNIQUE_ZAXIS;
static GLubyte NORMAL_TECHNIQUE_HEMISPHERE;
static unsigned MATERIAL_VERTEX_SLOT;
//! Geometry variant for a given pixel size range
struct LOD
{
unsigned offset;
std::size_t length;
float far_pixel_scale;
float near_pixel_scale;
};
public:
//! Creates a new empty chonk.
static Ptr create();
std::string _name;
std::vector<ChonkMaterial::Ptr> _materials;
std::vector<VertexGPU> _vbo_store;
std::vector<element_t> _ebo_store;
std::vector<LOD> _lods;
osg::BoundingBoxf _box;
// Customed draw command
using DrawCommand = DrawElementsIndirectBindlessCommandNV;
using DrawCommands = std::vector<DrawCommand>;
//! GL objects that can be used across shared GCs
//! (because they are static and they are bindless)
struct GLObjects : public BindlessShareableGLObjects
{
GLBuffer::Ptr vbo;
GLBuffer::Ptr ebo;
DrawCommands commands;
};
mutable osg::buffered_object<GLObjects> _globjects;
//! Gets (or creates) a draw command, possibly
//! resolving texture handles and uploading buffers.
const DrawCommands& getOrCreateCommands(osg::State&) const;
private:
Chonk();
friend class ChonkFactory;
friend class ChonkDrawable;
};
/**
* Converts OSG geometry into Chonk data.
*/
class OSGEARTH_EXPORT ChonkFactory
{
public:
using GetOrCreateFunction =
std::function<Texture::Ptr(osg::Texture* osgTex, bool& isNew)>;
//! Texture arena into which this factory will place textures it finds
osg::ref_ptr<TextureArena> textures;
//! Texture caching function
GetOrCreateFunction getOrCreateTexture;
public:
//! Default, user should supply a TextureArena.
ChonkFactory();
//! Construct with a texture arena.
ChonkFactory(TextureArena* textures);
//! Function that can try to find textures instead of
//! creating new ones. Good for sharing data across invocations, and
//! for preventint duplicate textures in the arena.
void setGetOrCreateFunction(GetOrCreateFunction);
//! For the given node, this method populates the provided Chonk wit
//! its geometry. If the factory finds any InstancedGeometry's along
//! the way it will create a Chonk for each one in out_instances.
//! Returns false if the node contained no geometry.
bool load(
osg::Node* node,
Chonk* chonk,
float far_pixel_scale,
float near_pixel_scale);
bool load(
osg::Node* node,
ChonkDrawable* drawable,
float far_pixel_scale,
float near_pixel_scale);
//! Stock "getOrCreateTexture" function for the ChonkFactory that works on
//! a vector of Weak pointers. Use this or provide your own or don't use
//! one at all.
static GetOrCreateFunction getWeakTextureCacheFunction(
std::vector<Texture::WeakPtr>& cache,
std::mutex& cache_mutex);
private:
mutable std::vector<Texture::WeakPtr> _texcache;
mutable std::mutex _texcache_mutex;
};
/**
* Renders batches of chonks with gpu culling.
*/
class OSGEARTH_EXPORT ChonkDrawable : public osg::Geometry //public osg::Drawable
{
public:
META_Node(osgEarth, ChonkDrawable);
using Vector = std::vector<osg::ref_ptr<ChonkDrawable>>;
public:
//! Construct a default drawable
//! @param renderBinNumber OSG render bin number for the drawable
ChonkDrawable(int render_bin_number = 3);
//! Adds a node to the drawable. This method will rip all the geometry
//! from the node, find any instances, and assemble everything into
//! this drawable.
bool add(
osg::Node* node,
ChonkFactory& factory,
float far_pixel_scale = 1.0f,
float near_pixel_scale = FLT_MAX);
//! Adds one instance of a chonk to the drawable.
void add(Chonk::Ptr value);
//! Adds an instance of a chonk to the drawable.
void add(
Chonk::Ptr value,
const osg::Matrixf& xform);
//! Adds a chonk instance to the drawable, along with
//! a tile-local UV coordinate. You only need this if you
//! intend to set a custom culling shader.
void add(
Chonk::Ptr value,
const osg::Matrixf& xform,
const osg::Vec2f& local_uv);
//! The timestamp at which this drawable was first created.
//! Used for new data fade-in.
void setBirthday(double value);
double getBirthday() const;
//! Set the camera distances for distance-based fading.
void setFadeNearFar(float nearDist, float farDist);
//! Sets the cutoff value for transparency
void setAlphaCutoff(float value);
//! Whether to GPU cull on the per-chonk basis.
//! Default is true.
void setUseGPUCulling(bool value);
//! Render bin number to use for this drawable
void setRenderBinNumber(int value);
int getRenderBinNumber() const;
//! Installs a basic chonk-rendering shader on a drawable.
static void installRenderBin(ChonkDrawable*);
//! Whether this drawable contains any geometry
bool empty() const {
return _batches.empty();
}
public:
osg::BoundingBox computeBoundingBox() const override;
osg::BoundingSphere computeBound() const override;
void drawImplementation(osg::RenderInfo& ri) const override;
void compileGLObjects(osg::RenderInfo& ri) const override;
void resizeGLObjectBuffers(unsigned) override;
void releaseGLObjects(osg::State*) const override;
protected:
virtual ~ChonkDrawable();
mutable Mutex _m;
// Keep me 16-byte aligned
struct Instance
{
osg::Matrixf xform; // local xform
osg::Vec2f uv; // tile-local UV
GLuint lod;
float visibility[2]; // per LOD
float radius; // per chonk
float alphaCutoff;
GLint first_lod_cmd_index = -1; // invalid instance
};
using Instances = std::vector<Instance>;
using Batches = std::unordered_map<Chonk::Ptr, Instances>;
Batches _batches;
bool _gpucull = true;
float _fadeNear = 0.0f, _fadeFar = 0.0f;
double _birthday = -1.0;
float _alphaCutoff = 0.0f;
int _renderBinNumber = 0;
//! GL objects (and supporting data structures) that must
//! be stored and managed for each unique OSG state,
//! since they will differ for each view based on the camera
//! location and will potentially change every frame.
struct GLObjects : public PerStateGLObjects
{
// GPU variant/lod def. Keep me 16-byte aligned.
struct ChonkLOD
{
osg::Vec3f center;
GLfloat radius;
GLfloat far_pixel_scale;
GLfloat near_pixel_scale;
GLfloat alpha_cutoff;
GLfloat birthday;
GLfloat fade_near;
GLfloat fade_far;
GLuint num_lods; // chonk-global
GLuint total_num_commands; // global
};
// re-usable arrays
std::vector<Chonk::DrawCommand> _commands;
std::vector<Instance> _all_instances;
std::vector<ChonkLOD> _chonk_lods;
std::size_t _numInstances;
std::size_t _maxNumLODs;
osg::GLExtensions* _ext;
GLVAO::Ptr _vao;
GLBuffer::Ptr _commandBuf;
GLBuffer::Ptr _instanceInputBuf;
GLBuffer::Ptr _instanceOutputBuf;
GLBuffer::Ptr _chonkBuf;
bool _dirty = true;
bool _gpucull = true;
void(GL_APIENTRY * _glMultiDrawElementsIndirectBindlessNV)
(GLenum, GLenum, const GLvoid*, GLsizei, GLsizei, GLint);
struct PCPState {
GLint _passUL = -1;
};
mutable std::unordered_map<const void*, PCPState> _pcps;
void initialize(
const osg::Object* host, osg::State& state);
void update(
const Batches&, const osg::Object* host,
float fadeNear, float fadeFar,
double birthday, float alphaCutoff,
osg::State&);
void cull(osg::State& state);
void draw(osg::State& state);
void release();
};
mutable osg::buffered_object<GLObjects> _globjects;
void update_and_cull_batches(osg::State& state) const;
void draw_batches(osg::State& state) const;
void dirtyGLObjects();
public:
// support intersectors and stats visitors
bool supports(const osg::PrimitiveFunctor& f) const override { return true; }
void accept(osg::PrimitiveFunctor&) const override;
bool supports(const osg::PrimitiveIndexFunctor& f) const override { return true; }
void accept(osg::PrimitiveIndexFunctor&) const override;
private:
mutable bool _proxy_dirty = true;
mutable osg::Vec3Array* _proxy_verts = nullptr;
mutable osg::DrawElementsUInt* _proxy_indices = nullptr;
void refreshProxy() const;
void update_gl_objects(GLObjects&, osg::State&) const;
ChonkDrawable(const ChonkDrawable& rhs, const osg::CopyOp&) { }
friend class ChonkRenderBin;
};
/**
* Custom renderbin for rendering ChonkDrawables en masse
* Called "ChonkBin"
*/
class OSGEARTH_EXPORT ChonkRenderBin : public osgUtil::RenderBin
{
public:
ChonkRenderBin();
ChonkRenderBin(const ChonkRenderBin& rhs, const osg::CopyOp& op);
void drawImplementation(
osg::RenderInfo& renderInfo,
osgUtil::RenderLeaf*&) override;
virtual osg::Object* cloneType() const override { return new ChonkRenderBin(); }
virtual osg::Object* clone(const osg::CopyOp& copyop) const override { return new ChonkRenderBin(*this, copyop); } // note only implements a clone of type.
virtual bool isSameKindAs(const osg::Object* obj) const override { return dynamic_cast<const ChonkRenderBin*>(obj) != 0L; }
virtual const char* libraryName() const override { return "osgEarth"; }
virtual const char* className() const override { return "ChonkRenderBin"; }
static void releaseSharedGLObjects(osg::State* state);
private:
osg::ref_ptr<osg::StateSet> _cullSS;
friend class ChonkDrawable;
osg::ref_ptr<osgUtil::StateGraph> _cull_sg;
struct CullLeaf : public Util::CustomRenderLeaf {
CullLeaf(osgUtil::RenderLeaf*);
void draw(osg::State&) override;
};
struct DrawLeaf : public Util::CustomRenderLeaf {
DrawLeaf(osgUtil::RenderLeaf*, bool, bool);
void draw(osg::State&) override;
bool _first, _last;
};
};
}