215 lines
6.4 KiB
C
215 lines
6.4 KiB
C
|
/**
|
||
|
* PANDA 3D SOFTWARE
|
||
|
* Copyright (c) Carnegie Mellon University. All rights reserved.
|
||
|
*
|
||
|
* All use of this software is subject to the terms of the revised BSD
|
||
|
* license. You should have received a copy of this license along
|
||
|
* with this source code in a file named "LICENSE."
|
||
|
*
|
||
|
* @file shaderTerrainMesh.h
|
||
|
* @author tobspr
|
||
|
* @date 2016-02-16
|
||
|
*/
|
||
|
|
||
|
#ifndef SHADER_TERRAIN_MESH_H
|
||
|
#define SHADER_TERRAIN_MESH_H
|
||
|
|
||
|
#include "pandabase.h"
|
||
|
#include "luse.h"
|
||
|
#include "pnmImage.h"
|
||
|
#include "geom.h"
|
||
|
#include "pandaNode.h"
|
||
|
#include "texture.h"
|
||
|
#include "texturePeeker.h"
|
||
|
#include "configVariableBool.h"
|
||
|
#include "configVariableInt.h"
|
||
|
#include "pStatCollector.h"
|
||
|
#include "filename.h"
|
||
|
#include "pmutex.h"
|
||
|
#include "mutexHolder.h"
|
||
|
#include <stdint.h>
|
||
|
|
||
|
extern ConfigVariableBool stm_use_hexagonal_layout;
|
||
|
extern ConfigVariableInt stm_max_chunk_count;
|
||
|
extern ConfigVariableInt stm_max_views;
|
||
|
|
||
|
|
||
|
NotifyCategoryDecl(shader_terrain, EXPCL_PANDA_GRUTIL, EXPTP_PANDA_GRUTIL);
|
||
|
|
||
|
|
||
|
/**
|
||
|
* @brief Terrain Renderer class utilizing the GPU
|
||
|
* @details This class provides functionality to render heightfields of large
|
||
|
* sizes utilizing the GPU. Internally a quadtree is used to generate the LODs.
|
||
|
* The final terrain is then rendered using instancing on the GPU. This makes
|
||
|
* it possible to use very large heightfields (8192+) with very reasonable
|
||
|
* performance. The terrain provides options to control the LOD using a
|
||
|
* target triangle width, see ShaderTerrainMesh::set_target_triangle_width().
|
||
|
*
|
||
|
* Because the Terrain is rendered entirely on the GPU, it needs a special
|
||
|
* vertex shader. There is a default vertex shader available, which you can
|
||
|
* use in your own shaders. IMPORTANT: If you don't set an appropriate shader
|
||
|
* on the terrain, nothing will be visible.
|
||
|
*/
|
||
|
class EXPCL_PANDA_GRUTIL ShaderTerrainMesh : public PandaNode {
|
||
|
|
||
|
PUBLISHED:
|
||
|
|
||
|
ShaderTerrainMesh();
|
||
|
|
||
|
INLINE void set_heightfield(Texture* heightfield);
|
||
|
INLINE Texture* get_heightfield() const;
|
||
|
MAKE_PROPERTY(heightfield, get_heightfield, set_heightfield);
|
||
|
|
||
|
INLINE void set_chunk_size(size_t chunk_size);
|
||
|
INLINE size_t get_chunk_size() const;
|
||
|
MAKE_PROPERTY(chunk_size, get_chunk_size, set_chunk_size);
|
||
|
|
||
|
INLINE void set_generate_patches(bool generate_patches);
|
||
|
INLINE bool get_generate_patches() const;
|
||
|
MAKE_PROPERTY(generate_patches, get_generate_patches, set_generate_patches);
|
||
|
|
||
|
INLINE void set_update_enabled(bool update_enabled);
|
||
|
INLINE bool get_update_enabled() const;
|
||
|
MAKE_PROPERTY(update_enabled, get_update_enabled, set_update_enabled);
|
||
|
|
||
|
INLINE void set_target_triangle_width(PN_stdfloat target_triangle_width);
|
||
|
INLINE PN_stdfloat get_target_triangle_width() const;
|
||
|
MAKE_PROPERTY(target_triangle_width, get_target_triangle_width, set_target_triangle_width);
|
||
|
|
||
|
LPoint3 uv_to_world(const LTexCoord& coord) const;
|
||
|
INLINE LPoint3 uv_to_world(PN_stdfloat u, PN_stdfloat v) const;
|
||
|
|
||
|
bool generate();
|
||
|
|
||
|
public:
|
||
|
|
||
|
// Methods derived from PandaNode
|
||
|
virtual bool is_renderable() const;
|
||
|
virtual bool safe_to_flatten() const;
|
||
|
virtual bool safe_to_combine() const;
|
||
|
virtual void add_for_draw(CullTraverser *trav, CullTraverserData &data);
|
||
|
|
||
|
private:
|
||
|
virtual CPT(TransformState)
|
||
|
calc_tight_bounds(LPoint3 &min_point, LPoint3 &max_point,
|
||
|
bool &found_any,
|
||
|
const TransformState *transform,
|
||
|
Thread *current_thread = Thread::get_current_thread()) const;
|
||
|
|
||
|
virtual void compute_internal_bounds(CPT(BoundingVolume) &internal_bounds,
|
||
|
int &internal_vertices,
|
||
|
int pipeline_stage,
|
||
|
Thread *current_thread) const;
|
||
|
|
||
|
// Chunk data
|
||
|
struct Chunk {
|
||
|
// Depth, starting at 0
|
||
|
size_t depth;
|
||
|
|
||
|
// Chunk position in heightfield space
|
||
|
size_t x, y;
|
||
|
|
||
|
// Chunk size in heightfield space
|
||
|
size_t size;
|
||
|
|
||
|
// Children, in the order (0, 0) (1, 0) (0, 1) (1, 1)
|
||
|
Chunk* children[4];
|
||
|
|
||
|
// Chunk heights, used for culling
|
||
|
PN_stdfloat avg_height, min_height, max_height;
|
||
|
|
||
|
// Edge heights, used for lod computation, in the same order as the children
|
||
|
LVector4 edges;
|
||
|
|
||
|
// Last CLOD factor, stored while computing LOD, used for seamless transitions between lods
|
||
|
PN_stdfloat last_clod;
|
||
|
|
||
|
INLINE void clear_children();
|
||
|
INLINE Chunk();
|
||
|
INLINE ~Chunk();
|
||
|
};
|
||
|
|
||
|
|
||
|
// Single entry in the data block
|
||
|
struct ChunkDataEntry {
|
||
|
// float x, y, size, clod;
|
||
|
|
||
|
// Panda uses BGRA, the above layout shows how its actually in texture memory,
|
||
|
// the layout below makes it work with BGRA.
|
||
|
PN_float32 size, y, x, clod;
|
||
|
};
|
||
|
|
||
|
// Data used while traversing all chunks
|
||
|
struct TraversalData {
|
||
|
// Global MVP used for LOD
|
||
|
LMatrix4 mvp_mat;
|
||
|
|
||
|
// Local model matrix used for culling
|
||
|
LMatrix4 model_mat;
|
||
|
|
||
|
// Camera bounds in world space
|
||
|
BoundingVolume* cam_bounds;
|
||
|
|
||
|
// Amount of emitted chunks so far
|
||
|
int emitted_chunks;
|
||
|
|
||
|
// Screen resolution, used for LOD
|
||
|
LVector2i screen_size;
|
||
|
|
||
|
// Pointer to the texture memory, where each chunk is written to
|
||
|
ChunkDataEntry* storage_ptr;
|
||
|
};
|
||
|
|
||
|
bool do_check_heightfield();
|
||
|
void do_extract_heightfield();
|
||
|
void do_init_data_texture();
|
||
|
void do_create_chunks();
|
||
|
void do_init_chunk(Chunk* chunk);
|
||
|
void do_compute_bounds(Chunk* chunk);
|
||
|
void do_create_chunk_geom();
|
||
|
void do_traverse(Chunk* chunk, TraversalData* data, bool fully_visible = false);
|
||
|
void do_emit_chunk(Chunk* chunk, TraversalData* data);
|
||
|
bool do_check_lod_matches(Chunk* chunk, TraversalData* data);
|
||
|
|
||
|
Mutex _lock;
|
||
|
Chunk _base_chunk;
|
||
|
size_t _size;
|
||
|
size_t _chunk_size;
|
||
|
bool _generate_patches;
|
||
|
PNMImage _heightfield;
|
||
|
PT(Texture) _heightfield_tex;
|
||
|
PT(Geom) _chunk_geom;
|
||
|
PT(Texture) _data_texture;
|
||
|
size_t _current_view_index;
|
||
|
int _last_frame_count;
|
||
|
PN_stdfloat _target_triangle_width;
|
||
|
bool _update_enabled;
|
||
|
|
||
|
// PStats stuff
|
||
|
static PStatCollector _lod_collector;
|
||
|
static PStatCollector _basic_collector;
|
||
|
|
||
|
|
||
|
// Type handle stuff
|
||
|
public:
|
||
|
static TypeHandle get_class_type() {
|
||
|
return _type_handle;
|
||
|
}
|
||
|
static void init_type() {
|
||
|
PandaNode::init_type();
|
||
|
register_type(_type_handle, "ShaderTerrainMesh", PandaNode::get_class_type());
|
||
|
}
|
||
|
virtual TypeHandle get_type() const {
|
||
|
return get_class_type();
|
||
|
}
|
||
|
virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
|
||
|
|
||
|
private:
|
||
|
static TypeHandle _type_handle;
|
||
|
};
|
||
|
|
||
|
#include "shaderTerrainMesh.I"
|
||
|
|
||
|
#endif // SHADER_TERRAIN_MESH_H
|