mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-02 09:52:27 -04:00
pgraph view-frustum cull
This commit is contained in:
parent
11142324c1
commit
3200a5f929
@ -58,6 +58,16 @@ const bool pipe_spec_is_remote = config_display.Defined("pipe-machine")
|
||||
const bool compare_state_by_pointer =
|
||||
config_display.GetBool("compare-state-by-pointer", true);
|
||||
|
||||
// This is normally true to enable the cull traversal to perform
|
||||
// state-sorting and alpha-sorting. Turn this false to disable these
|
||||
// features and likely improve cull performance at the expense of draw
|
||||
// (and at the expense of correct alpha).
|
||||
const bool cull_sorting = config_display.GetBool("cull-sorting", true);
|
||||
|
||||
// This is normally true; set it false to disable view-frustum culling
|
||||
// (primarily useful for debugging).
|
||||
const bool qpview_frustum_cull = config_display.GetBool("view-frustum-cull", true);
|
||||
|
||||
const float gsg_clear_r = config_display.GetFloat("gsg-clear-r", 0.0);
|
||||
const float gsg_clear_g = config_display.GetFloat("gsg-clear-g", 0.0);
|
||||
const float gsg_clear_b = config_display.GetFloat("gsg-clear-b", 0.0);
|
||||
|
@ -36,6 +36,8 @@ extern const bool pipe_spec_is_file;
|
||||
extern const bool pipe_spec_is_remote;
|
||||
|
||||
extern const bool compare_state_by_pointer;
|
||||
extern const bool cull_sorting;
|
||||
extern const bool qpview_frustum_cull;
|
||||
|
||||
extern const float gsg_clear_r;
|
||||
extern const float gsg_clear_g;
|
||||
|
@ -17,6 +17,7 @@
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "graphicsEngine.h"
|
||||
#include "config_display.h"
|
||||
#include "pipeline.h"
|
||||
#include "drawCullHandler.h"
|
||||
#include "binCullHandler.h"
|
||||
@ -79,8 +80,11 @@ remove_window(GraphicsWindow *window) {
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void GraphicsEngine::
|
||||
render_frame() {
|
||||
// cull_and_draw_together();
|
||||
cull_bin_draw();
|
||||
if (cull_sorting) {
|
||||
cull_bin_draw();
|
||||
} else {
|
||||
cull_and_draw_together();
|
||||
}
|
||||
|
||||
// **** This doesn't belong here; it really belongs in the Pipeline,
|
||||
// but here it is for now.
|
||||
@ -120,68 +124,18 @@ cull_and_draw_together() {
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void GraphicsEngine::
|
||||
cull_and_draw_together(GraphicsWindow *win, DisplayRegion *dr) {
|
||||
const NodeChain &camera = dr->get_qpcamera();
|
||||
if (camera.is_empty()) {
|
||||
// No camera, no draw.
|
||||
return;
|
||||
}
|
||||
|
||||
qpCamera *camera_node;
|
||||
DCAST_INTO_V(camera_node, camera.node());
|
||||
|
||||
if (!camera_node->is_active()) {
|
||||
// Camera inactive, no draw.
|
||||
return;
|
||||
}
|
||||
|
||||
Lens *lens = camera_node->get_lens();
|
||||
if (lens == (Lens *)NULL) {
|
||||
// No lens, no draw.
|
||||
return;
|
||||
}
|
||||
|
||||
NodeChain scene = camera_node->get_scene();
|
||||
if (scene.is_empty()) {
|
||||
// No scene, no draw.
|
||||
return;
|
||||
}
|
||||
|
||||
GraphicsStateGuardian *gsg = win->get_gsg();
|
||||
nassertv(gsg != (GraphicsStateGuardian *)NULL);
|
||||
|
||||
if (!gsg->set_lens(lens)) {
|
||||
// The lens is inappropriate somehow.
|
||||
display_cat.error()
|
||||
<< gsg->get_type() << " cannot render with " << lens->get_type()
|
||||
<< "\n";
|
||||
return;
|
||||
if (set_gsg_lens(gsg, dr)) {
|
||||
DisplayRegionStack old_dr = gsg->push_display_region(dr);
|
||||
gsg->prepare_display_region();
|
||||
|
||||
DrawCullHandler cull_handler(gsg);
|
||||
do_cull(&cull_handler, dr->get_qpcamera(), gsg);
|
||||
|
||||
gsg->pop_display_region(old_dr);
|
||||
}
|
||||
|
||||
DrawCullHandler cull_handler(gsg);
|
||||
qpCullTraverser trav;
|
||||
trav.set_cull_handler(&cull_handler);
|
||||
|
||||
// The world transform is computed from the camera's position; we
|
||||
// then might need to adjust it into the GSG's internal coordinate
|
||||
// system.
|
||||
trav.set_camera_transform(scene.get_rel_transform(camera));
|
||||
|
||||
CPT(TransformState) render_transform = camera.get_rel_transform(scene);
|
||||
CoordinateSystem external_cs = gsg->get_coordinate_system();
|
||||
CoordinateSystem internal_cs = gsg->get_internal_coordinate_system();
|
||||
if (internal_cs != CS_default && internal_cs != external_cs) {
|
||||
CPT(TransformState) cs_transform =
|
||||
TransformState::make_mat(LMatrix4f::convert_mat(external_cs, internal_cs));
|
||||
render_transform = cs_transform->compose(render_transform);
|
||||
}
|
||||
trav.set_render_transform(render_transform);
|
||||
|
||||
DisplayRegionStack old_dr = gsg->push_display_region(dr);
|
||||
gsg->prepare_display_region();
|
||||
|
||||
trav.traverse(scene.node());
|
||||
|
||||
gsg->pop_display_region(old_dr);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
@ -217,7 +171,34 @@ cull_bin_draw() {
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void GraphicsEngine::
|
||||
cull_bin_draw(GraphicsWindow *win, DisplayRegion *dr) {
|
||||
const NodeChain &camera = dr->get_qpcamera();
|
||||
GraphicsStateGuardian *gsg = win->get_gsg();
|
||||
nassertv(gsg != (GraphicsStateGuardian *)NULL);
|
||||
|
||||
PT(CullResult) cull_result = dr->_cull_result;
|
||||
if (cull_result == (CullResult *)NULL) {
|
||||
cull_result = new CullResult(gsg);
|
||||
}
|
||||
|
||||
BinCullHandler cull_handler(cull_result);
|
||||
do_cull(&cull_handler, dr->get_qpcamera(), gsg);
|
||||
|
||||
cull_result->finish_cull();
|
||||
|
||||
// Save the results for next frame.
|
||||
dr->_cull_result = cull_result->make_next();
|
||||
|
||||
// Now draw.
|
||||
do_draw(cull_result, gsg, dr);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: GraphicsEngine::do_cull
|
||||
// Access: Private
|
||||
// Description: Fires off a cull traversal using the indicated camera.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void GraphicsEngine::
|
||||
do_cull(CullHandler *cull_handler, const NodeChain &camera,
|
||||
GraphicsStateGuardian *gsg) {
|
||||
if (camera.is_empty()) {
|
||||
// No camera, no draw.
|
||||
return;
|
||||
@ -243,32 +224,21 @@ cull_bin_draw(GraphicsWindow *win, DisplayRegion *dr) {
|
||||
return;
|
||||
}
|
||||
|
||||
GraphicsStateGuardian *gsg = win->get_gsg();
|
||||
nassertv(gsg != (GraphicsStateGuardian *)NULL);
|
||||
|
||||
if (!gsg->set_lens(lens)) {
|
||||
// The lens is inappropriate somehow.
|
||||
display_cat.error()
|
||||
<< gsg->get_type() << " cannot render with " << lens->get_type()
|
||||
<< "\n";
|
||||
return;
|
||||
}
|
||||
|
||||
PT(CullResult) cull_result = dr->_cull_result;
|
||||
if (cull_result == (CullResult *)NULL) {
|
||||
cull_result = new CullResult(gsg);
|
||||
}
|
||||
|
||||
BinCullHandler cull_handler(cull_result);
|
||||
qpCullTraverser trav;
|
||||
trav.set_cull_handler(&cull_handler);
|
||||
trav.set_cull_handler(cull_handler);
|
||||
|
||||
// The world transform is computed from the camera's position; we
|
||||
// then might need to adjust it into the GSG's internal coordinate
|
||||
// system.
|
||||
trav.set_camera_transform(scene.get_rel_transform(camera));
|
||||
// We will need both the camera transform (the net transform from
|
||||
// the scene to the camera) and the world transform (the camera
|
||||
// transform inverse, or the net transform from the camera to the
|
||||
// scene).
|
||||
CPT(TransformState) camera_transform = scene.get_rel_transform(camera);
|
||||
CPT(TransformState) world_transform = camera.get_rel_transform(scene);
|
||||
|
||||
// The render transform is the same as the world transform, except
|
||||
// it is converted into the GSG's internal coordinate system. This
|
||||
// is the transform that the GSG will apply to all of its vertices.
|
||||
CPT(TransformState) render_transform = world_transform;
|
||||
|
||||
CPT(TransformState) render_transform = camera.get_rel_transform(scene);
|
||||
CoordinateSystem external_cs = gsg->get_coordinate_system();
|
||||
CoordinateSystem internal_cs = gsg->get_internal_coordinate_system();
|
||||
if (internal_cs != CS_default && internal_cs != external_cs) {
|
||||
@ -276,17 +246,80 @@ cull_bin_draw(GraphicsWindow *win, DisplayRegion *dr) {
|
||||
TransformState::make_mat(LMatrix4f::convert_mat(external_cs, internal_cs));
|
||||
render_transform = cs_transform->compose(render_transform);
|
||||
}
|
||||
|
||||
trav.set_camera_transform(scene.get_rel_transform(camera));
|
||||
trav.set_render_transform(render_transform);
|
||||
|
||||
if (qpview_frustum_cull) {
|
||||
// If we're to be performing view-frustum culling, determine the
|
||||
// bounding volume associated with the current viewing frustum.
|
||||
|
||||
// First, we have to get the current viewing frustum, which comes
|
||||
// from the lens.
|
||||
PT(BoundingVolume) bv = lens->make_bounds();
|
||||
|
||||
if (bv != (BoundingVolume *)NULL &&
|
||||
bv->is_of_type(GeometricBoundingVolume::get_class_type())) {
|
||||
// Transform it into the appropriate coordinate space.
|
||||
PT(GeometricBoundingVolume) local_frustum;
|
||||
local_frustum = DCAST(GeometricBoundingVolume, bv->make_copy());
|
||||
local_frustum->xform(camera_transform->get_mat());
|
||||
|
||||
trav.set_view_frustum(local_frustum);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
trav.traverse(scene.node());
|
||||
cull_result->finish_cull();
|
||||
|
||||
// Save the results for next frame.
|
||||
dr->_cull_result = cull_result->make_next();
|
||||
|
||||
// Now draw.
|
||||
DisplayRegionStack old_dr = gsg->push_display_region(dr);
|
||||
gsg->prepare_display_region();
|
||||
cull_result->draw();
|
||||
gsg->pop_display_region(old_dr);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: GraphicsEngine::do_draw
|
||||
// Access: Private
|
||||
// Description: Draws the previously-culled scene.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void GraphicsEngine::
|
||||
do_draw(CullResult *cull_result, GraphicsStateGuardian *gsg,
|
||||
DisplayRegion *dr) {
|
||||
if (set_gsg_lens(gsg, dr)) {
|
||||
DisplayRegionStack old_dr = gsg->push_display_region(dr);
|
||||
gsg->prepare_display_region();
|
||||
cull_result->draw();
|
||||
gsg->pop_display_region(old_dr);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: GraphicsEngine::set_gsg_lens
|
||||
// Access: Private
|
||||
// Description: Sets up the GSG to draw with the lens from the
|
||||
// indicated DisplayRegion. Returns true if the lens is
|
||||
// acceptable, false otherwise.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool GraphicsEngine::
|
||||
set_gsg_lens(GraphicsStateGuardian *gsg, DisplayRegion *dr) {
|
||||
const NodeChain &camera = dr->get_qpcamera();
|
||||
if (camera.is_empty()) {
|
||||
// No camera, no draw.
|
||||
return false;
|
||||
}
|
||||
|
||||
qpCamera *camera_node;
|
||||
DCAST_INTO_R(camera_node, camera.node(), false);
|
||||
|
||||
Lens *lens = camera_node->get_lens();
|
||||
if (lens == (Lens *)NULL) {
|
||||
// No lens, no draw.
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!gsg->set_lens(lens)) {
|
||||
// The lens is inappropriate somehow.
|
||||
display_cat.error()
|
||||
<< gsg->get_type() << " cannot render with " << lens->get_type()
|
||||
<< "\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -57,6 +57,13 @@ private:
|
||||
void cull_bin_draw();
|
||||
void cull_bin_draw(GraphicsWindow *win, DisplayRegion *dr);
|
||||
|
||||
void do_cull(CullHandler *cull_handler, const NodeChain &camera,
|
||||
GraphicsStateGuardian *gsg);
|
||||
void do_draw(CullResult *cull_result, GraphicsStateGuardian *gsg,
|
||||
DisplayRegion *dr);
|
||||
|
||||
bool set_gsg_lens(GraphicsStateGuardian *gsg, DisplayRegion *dr);
|
||||
|
||||
Pipeline *_pipeline;
|
||||
|
||||
typedef pset<PT(GraphicsWindow)> Windows;
|
||||
|
@ -47,6 +47,11 @@ ConfigureFn(config_pgraph) {
|
||||
init_libpgraph();
|
||||
}
|
||||
|
||||
// Set this true to cause culling to be performed by rendering the
|
||||
// object in red wireframe, rather than actually culling it. This
|
||||
// helps make culling errors obvious.
|
||||
const bool qpfake_view_frustum_cull = config_pgraph.GetBool("fake-view-frustum-cull", false);
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: init_libpgraph
|
||||
|
@ -26,6 +26,8 @@
|
||||
ConfigureDecl(config_pgraph, EXPCL_PANDA, EXPTP_PANDA);
|
||||
NotifyCategoryDecl(pgraph, EXPCL_PANDA, EXPTP_PANDA);
|
||||
|
||||
extern const bool qpfake_view_frustum_cull;
|
||||
|
||||
extern EXPCL_PANDA void init_libpgraph();
|
||||
|
||||
#endif
|
||||
|
@ -23,6 +23,9 @@
|
||||
#include "cullHandler.h"
|
||||
#include "dcast.h"
|
||||
#include "qpgeomNode.h"
|
||||
#include "colorAttrib.h"
|
||||
#include "textureAttrib.h"
|
||||
#include "config_pgraph.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpCullTraverser::Constructor
|
||||
@ -74,6 +77,39 @@ set_render_transform(const TransformState *render_transform) {
|
||||
_render_transform = render_transform;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpCullTraverser::set_view_frustum
|
||||
// Access: Public
|
||||
// Description: Specifies the bounding volume that corresponds to the
|
||||
// viewing frustum. Any primitives that fall entirely
|
||||
// outside of this volume are not drawn.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void qpCullTraverser::
|
||||
set_view_frustum(GeometricBoundingVolume *view_frustum) {
|
||||
_view_frustum = view_frustum;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpCullTraverser::set_guard_band
|
||||
// Access: Public
|
||||
// Description: Specifies the bounding volume to use for detecting
|
||||
// guard band clipping. This is a render optimization
|
||||
// for certain cards that support this feature; the
|
||||
// guard band is a 2-d area than the frame buffer.
|
||||
// If a primitive will appear entirely within the guard
|
||||
// band after perspective transform, it may be drawn
|
||||
// correctly with clipping disabled, for a small
|
||||
// performance gain.
|
||||
//
|
||||
// This is the bounding volume that corresponds to the
|
||||
// 2-d guard band. If a primitive is entirely within
|
||||
// this area, clipping will be disabled on the GSG.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void qpCullTraverser::
|
||||
set_guard_band(GeometricBoundingVolume *guard_band) {
|
||||
_guard_band = guard_band;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpCullTraverser::set_cull_handler
|
||||
// Access: Public
|
||||
@ -95,7 +131,7 @@ traverse(PandaNode *root) {
|
||||
nassertv(_cull_handler != (CullHandler *)NULL);
|
||||
|
||||
r_traverse(root, _render_transform, TransformState::make_identity(),
|
||||
_initial_state, 0);
|
||||
_initial_state, _view_frustum, _guard_band);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
@ -107,12 +143,93 @@ void qpCullTraverser::
|
||||
r_traverse(PandaNode *node,
|
||||
const TransformState *render_transform,
|
||||
const TransformState *net_transform,
|
||||
const RenderState *state, int flags) {
|
||||
CPT(TransformState) next_render_transform =
|
||||
render_transform->compose(node->get_transform());
|
||||
CPT(TransformState) next_net_transform =
|
||||
net_transform->compose(node->get_transform());
|
||||
CPT(RenderState) next_state = state->compose(node->get_state());
|
||||
const RenderState *state,
|
||||
GeometricBoundingVolume *view_frustum,
|
||||
GeometricBoundingVolume *guard_band) {
|
||||
CPT(RenderState) next_state = state;
|
||||
|
||||
if (view_frustum != (GeometricBoundingVolume *)NULL) {
|
||||
// If we have a viewing frustum, check to see if the node's
|
||||
// bounding volume falls within it.
|
||||
const BoundingVolume &node_volume = node->get_bound();
|
||||
nassertv(node_volume.is_of_type(GeometricBoundingVolume::get_class_type()));
|
||||
const GeometricBoundingVolume *node_gbv =
|
||||
DCAST(GeometricBoundingVolume, &node_volume);
|
||||
|
||||
int result = view_frustum->contains(node_gbv);
|
||||
if (result == BoundingVolume::IF_no_intersection) {
|
||||
// No intersection at all. Cull.
|
||||
if (!qpfake_view_frustum_cull) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If we have fake view-frustum culling enabled, instead of
|
||||
// actually culling an object we simply force it to be drawn in
|
||||
// red wireframe.
|
||||
view_frustum = (GeometricBoundingVolume *)NULL;
|
||||
CPT(RenderState) fake_effect = RenderState::make
|
||||
(ColorAttrib::make_flat(Colorf(1.0f, 0.0f, 0.0f, 1.0f)),
|
||||
TextureAttrib::make_off(),
|
||||
1000);
|
||||
next_state = next_state->compose(fake_effect);
|
||||
|
||||
} else if ((result & BoundingVolume::IF_all) != 0) {
|
||||
// The node and its descendants are completely enclosed within
|
||||
// the frustum. No need to cull further.
|
||||
view_frustum = (GeometricBoundingVolume *)NULL;
|
||||
|
||||
} else {
|
||||
if (node->is_final()) {
|
||||
// The bounding volume is partially, but not completely,
|
||||
// within the viewing frustum. Normally we'd keep testing
|
||||
// child bounded volumes as we continue down. But this node
|
||||
// has the "final" flag, so the user is claiming that there is
|
||||
// some important reason we should consider everything visible
|
||||
// at this point. So be it.
|
||||
view_frustum = (GeometricBoundingVolume *)NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CPT(TransformState) next_render_transform = render_transform;
|
||||
CPT(TransformState) next_net_transform = net_transform;
|
||||
PT(GeometricBoundingVolume) next_view_frustum = view_frustum;
|
||||
PT(GeometricBoundingVolume) next_guard_band = guard_band;
|
||||
|
||||
const TransformState *transform = node->get_transform();
|
||||
if (!transform->is_identity()) {
|
||||
next_render_transform = render_transform->compose(transform);
|
||||
next_net_transform = net_transform->compose(transform);
|
||||
|
||||
if ((view_frustum != (GeometricBoundingVolume *)NULL) ||
|
||||
(guard_band != (GeometricBoundingVolume *)NULL)) {
|
||||
// We need to move the viewing frustums into the node's
|
||||
// coordinate space by applying the node's inverse transform.
|
||||
if (transform->is_singular()) {
|
||||
// But we can't invert a singular transform! Instead of
|
||||
// trying, we'll just give up on frustum culling from this
|
||||
// point down.
|
||||
view_frustum = (GeometricBoundingVolume *)NULL;
|
||||
guard_band = (GeometricBoundingVolume *)NULL;
|
||||
|
||||
} else {
|
||||
CPT(TransformState) inv_transform =
|
||||
transform->invert_compose(TransformState::make_identity());
|
||||
|
||||
if (view_frustum != (GeometricBoundingVolume *)NULL) {
|
||||
next_view_frustum = DCAST(GeometricBoundingVolume, view_frustum->make_copy());
|
||||
next_view_frustum->xform(inv_transform->get_mat());
|
||||
}
|
||||
|
||||
if (guard_band != (GeometricBoundingVolume *)NULL) {
|
||||
next_guard_band = DCAST(GeometricBoundingVolume, guard_band->make_copy());
|
||||
next_guard_band->xform(inv_transform->get_mat());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
next_state = next_state->compose(node->get_state());
|
||||
|
||||
const BillboardAttrib *billboard = state->get_billboard();
|
||||
if (billboard != (const BillboardAttrib *)NULL) {
|
||||
@ -121,6 +238,11 @@ r_traverse(PandaNode *node,
|
||||
billboard->do_billboard(net_transform, _camera_transform);
|
||||
next_render_transform = next_render_transform->compose(billboard_transform);
|
||||
next_net_transform = next_net_transform->compose(billboard_transform);
|
||||
|
||||
// We can't reliably cull within a billboard, because the geometry
|
||||
// might get rotated out of its bounding volume. So once we get
|
||||
// within a billboard, we consider it all visible.
|
||||
next_view_frustum = (GeometricBoundingVolume *)NULL;
|
||||
}
|
||||
|
||||
if (node->is_geom_node()) {
|
||||
@ -140,6 +262,7 @@ r_traverse(PandaNode *node,
|
||||
PandaNode::Children cr = node->get_children();
|
||||
int num_children = cr.get_num_children();
|
||||
for (int i = 0; i < num_children; i++) {
|
||||
r_traverse(cr.get_child(i), next_render_transform, next_net_transform, next_state, flags);
|
||||
r_traverse(cr.get_child(i), next_render_transform, next_net_transform,
|
||||
next_state, next_view_frustum, next_guard_band);
|
||||
}
|
||||
}
|
||||
|
@ -23,6 +23,7 @@
|
||||
|
||||
#include "renderState.h"
|
||||
#include "transformState.h"
|
||||
#include "geometricBoundingVolume.h"
|
||||
#include "pointerTo.h"
|
||||
|
||||
class PandaNode;
|
||||
@ -43,6 +44,8 @@ public:
|
||||
void set_initial_state(const RenderState *initial_state);
|
||||
void set_camera_transform(const TransformState *camera_transform);
|
||||
void set_render_transform(const TransformState *render_transform);
|
||||
void set_view_frustum(GeometricBoundingVolume *view_frustum);
|
||||
void set_guard_band(GeometricBoundingVolume *guard_band);
|
||||
void set_cull_handler(CullHandler *cull_handler);
|
||||
|
||||
void traverse(PandaNode *root);
|
||||
@ -50,11 +53,15 @@ public:
|
||||
private:
|
||||
void r_traverse(PandaNode *node, const TransformState *render_transform,
|
||||
const TransformState *net_transform,
|
||||
const RenderState *state, int flags);
|
||||
const RenderState *state,
|
||||
GeometricBoundingVolume *view_frustum,
|
||||
GeometricBoundingVolume *guard_band);
|
||||
|
||||
CPT(RenderState) _initial_state;
|
||||
CPT(TransformState) _camera_transform;
|
||||
CPT(TransformState) _render_transform;
|
||||
PT(GeometricBoundingVolume) _view_frustum;
|
||||
PT(GeometricBoundingVolume) _guard_band;
|
||||
CullHandler *_cull_handler;
|
||||
};
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user