diff --git a/direct/src/showbase/ShowBase.py b/direct/src/showbase/ShowBase.py index 993b9c0086..1a671d4975 100644 --- a/direct/src/showbase/ShowBase.py +++ b/direct/src/showbase/ShowBase.py @@ -450,6 +450,7 @@ class ShowBase: self.oobeButtonEventsType = TypeRegistry.ptr().findType('ButtonEvents_ButtonEventDataTransition') self.oobeVis = loader.loadModelOnce('models/misc/camera') + self.oobeCullFrustum = None # Make sure the MouseValve is monitoring the Control key. mods = ModifierButtons(self.mouseValve.node().getModifierButtons()) @@ -458,13 +459,18 @@ class ShowBase: if self.oobeMode: # Disable OOBE mode. + + if self.oobeCullFrustum != None: + # First, disable OOBE cull mode. + self.oobeCull() + self.oobeControl.setOff() self.mouseControl.setOn() if self.oobeVis: self.oobeVis.reparentTo(self.hidden) self.cam.reparentTo(self.camera) self.oobeCamera.reparentTo(self.hidden) - self.oobeMode = 0 + self.oobeMode = 0 else: # Enable OOBE mode. mods = ModifierButtons(self.mouseValve.node().getModifierButtons()) @@ -488,7 +494,7 @@ class ShowBase: self.oobeCamera.clearMat() # Set our initial OOB position to be just behind the camera. - mat = Mat4.translateMat(0, -10, 3) * base.camera.getMat(cameraParent) + mat = Mat4.translateMat(0, -10, 3) * self.camera.getMat(cameraParent) mat.invertInPlace() self.oobeTrackball.node().setMat(mat) @@ -497,6 +503,45 @@ class ShowBase: self.oobeVis.reparentTo(self.camera) self.oobeMode = 1 + def oobeCull(self): + """ + While in OOBE mode (see above), cull the viewing frustum as if + it were still attached to our original camera. This allows us + to visualize the effectiveness of our bounding volumes. + """ + + # First, make sure OOBE mode is enabled. + try: + if not self.oobeMode: + self.oobe() + except: + self.oobe() + + if self.oobeCullFrustum == None: + # Enable OOBE culling. + pnode = ProjectionNode('oobeCull') + pnode.setProjection(self.camNode.getProjection()) + self.oobeCullFrustum = self.camera.attachNewNode(pnode) + + # Assign each DisplayRegion shared by the camera to use + # this cull frustum. + numDrs = self.camNode.getNumDrs() + for d in range(0, numDrs): + dr = self.camNode.getDr(d) + dr.setCullFrustum(pnode) + else: + # Disable OOBE culling. + + # Assign each DisplayRegion shared by the camera to use + # the default cull frustum, the camera itself. + numDrs = self.camNode.getNumDrs() + for d in range(0, numDrs): + dr = self.camNode.getDr(d) + dr.setCullFrustum(self.camNode) + + self.oobeCullFrustum.removeNode() + self.oobeCullFrustum = None + def screenshot(self, namePrefix='screenshot'): # Get the current date and time to uniquify the image (down to the second) date = time.ctime(time.time()) diff --git a/panda/src/cull/cullTraverser.cxx b/panda/src/cull/cullTraverser.cxx index fc0929b016..8b1146894a 100644 --- a/panda/src/cull/cullTraverser.cxx +++ b/panda/src/cull/cullTraverser.cxx @@ -41,6 +41,7 @@ #endif #include +#include #include #include #include @@ -270,8 +271,9 @@ traverse(Node *root, // culling. LMatrix4f rel_from_camera; NodeTransitionWrapper ntw(TransformTransition::get_class_type()); - wrt(_gsg->get_current_projection_node(), root, begin(), end(), - ntw, get_graph_type()); + const DisplayRegion *dr = _gsg->get_current_display_region(); + ProjectionNode *camera = dr->get_cull_frustum(); + wrt(camera, root, begin(), end(), ntw, get_graph_type()); const TransformTransition *tt; if (get_transition_into(tt, ntw)) { rel_from_camera = tt->get_matrix(); diff --git a/panda/src/display/displayRegion.I b/panda/src/display/displayRegion.I index 850e78487f..68f6e38f17 100644 --- a/panda/src/display/displayRegion.I +++ b/panda/src/display/displayRegion.I @@ -49,11 +49,40 @@ get_layer() const { // Description: Returns the camera associated with this // DisplayRegion, or NULL if no camera is associated. //////////////////////////////////////////////////////////////////// -INLINE PT(Camera) DisplayRegion:: +INLINE Camera *DisplayRegion:: get_camera() const { return _camera; } +//////////////////////////////////////////////////////////////////// +// Function: DisplayRegion::set_cull_frustum +// Access: Public +// Description: Sets the ProjectionNode that will be used to perform +// view-frustum culling for this particular +// DisplayRegion. Normally, this is the same as the +// camera (and is implicitly set when set_camera() is +// called). However, it may be useful to occasionally +// set it to a different node, particularly to enable a +// debugging mode where the culling effectiveness can be +// observed from a third-person perspective. +//////////////////////////////////////////////////////////////////// +void DisplayRegion:: +set_cull_frustum(ProjectionNode *cull_frustum) { + _cull_frustum = cull_frustum; +} + +//////////////////////////////////////////////////////////////////// +// Function: DisplayRegion::get_cull_frustum +// Access: Public +// Description: Returns the ProjectionNode that will be used to +// perform view-frustum culling for this particular +// DisplayRegion. See set_cull_frustum(). +//////////////////////////////////////////////////////////////////// +INLINE ProjectionNode *DisplayRegion:: +get_cull_frustum() const { + return _cull_frustum; +} + //////////////////////////////////////////////////////////////////// // Function: DisplayRegion::set_active // Access: Public diff --git a/panda/src/display/displayRegion.cxx b/panda/src/display/displayRegion.cxx index 576d6b3a37..e2430dc174 100644 --- a/panda/src/display/displayRegion.cxx +++ b/panda/src/display/displayRegion.cxx @@ -174,7 +174,7 @@ get_pipe() const { // between multiple DisplayRegions. //////////////////////////////////////////////////////////////////// void DisplayRegion:: -set_camera(const PT(Camera) &camera) { +set_camera(Camera *camera) { if (camera != _camera) { if (_camera != (Camera *)NULL) { // We need to tell the old camera we're not using him anymore. @@ -186,6 +186,7 @@ set_camera(const PT(Camera) &camera) { _camera->add_display_region(this); } } + set_cull_frustum(camera); } //////////////////////////////////////////////////////////////////// diff --git a/panda/src/display/displayRegion.h b/panda/src/display/displayRegion.h index 49051858b0..65dd85e6ff 100644 --- a/panda/src/display/displayRegion.h +++ b/panda/src/display/displayRegion.h @@ -58,8 +58,11 @@ PUBLISHED: GraphicsWindow *get_window() const; GraphicsPipe *get_pipe() const; - void set_camera(const PT(Camera) &camera); - INLINE PT(Camera) get_camera() const; + void set_camera(Camera *camera); + INLINE Camera *get_camera() const; + + INLINE void set_cull_frustum(ProjectionNode *cull_frustum); + INLINE ProjectionNode *get_cull_frustum() const; INLINE void set_active(bool active); INLINE bool is_active() const; @@ -87,6 +90,7 @@ protected: GraphicsLayer *_layer; PT(Camera) _camera; + PT(ProjectionNode) _cull_frustum; bool _active; diff --git a/panda/src/display/graphicsStateGuardian.I b/panda/src/display/graphicsStateGuardian.I index 158fcbbd47..dfc59ce403 100644 --- a/panda/src/display/graphicsStateGuardian.I +++ b/panda/src/display/graphicsStateGuardian.I @@ -88,7 +88,7 @@ get_current_root_node(void) const { // region will be made active (if it is not already) by // a call to prepare_display_region(). //////////////////////////////////////////////////////////////////// -INLINE CPT(DisplayRegion) GraphicsStateGuardian:: +INLINE const DisplayRegion *GraphicsStateGuardian:: get_current_display_region(void) const { return _current_display_region; } @@ -107,7 +107,7 @@ get_current_display_region(void) const { // optimization. //////////////////////////////////////////////////////////////////// INLINE DisplayRegionStack GraphicsStateGuardian:: -push_display_region(CPT(DisplayRegion) dr) { +push_display_region(const DisplayRegion *dr) { DisplayRegionStack old; old._display_region = _current_display_region; old._stack_level = _display_region_stack_level; @@ -147,7 +147,7 @@ pop_display_region(DisplayRegionStack &node) { //////////////////////////////////////////////////////////////////// INLINE FrameBufferStack GraphicsStateGuardian:: push_frame_buffer(const RenderBuffer &buffer, - CPT(DisplayRegion) dr) { + const DisplayRegion *dr) { FrameBufferStack old; old._frame_buffer = save_frame_buffer(buffer, dr); old._stack_level = _frame_buffer_stack_level; diff --git a/panda/src/display/graphicsStateGuardian.h b/panda/src/display/graphicsStateGuardian.h index 90b649f82b..bfb52eadd6 100644 --- a/panda/src/display/graphicsStateGuardian.h +++ b/panda/src/display/graphicsStateGuardian.h @@ -123,12 +123,12 @@ public: INLINE ProjectionNode *get_current_projection_node(void) const ; INLINE const Node* get_current_root_node(void) const; - INLINE CPT(DisplayRegion) get_current_display_region(void) const; + INLINE const DisplayRegion *get_current_display_region(void) const; - INLINE DisplayRegionStack push_display_region(CPT(DisplayRegion) dr); + INLINE DisplayRegionStack push_display_region(const DisplayRegion *dr); INLINE void pop_display_region(DisplayRegionStack &node); INLINE FrameBufferStack push_frame_buffer(const RenderBuffer &buffer, - CPT(DisplayRegion) dr); + const DisplayRegion *dr); INLINE void pop_frame_buffer(FrameBufferStack &node); INLINE void set_coordinate_system(CoordinateSystem cs); diff --git a/panda/src/sgattrib/billboardTransition.cxx b/panda/src/sgattrib/billboardTransition.cxx index 3520f9cdf6..dfcb753ecd 100644 --- a/panda/src/sgattrib/billboardTransition.cxx +++ b/panda/src/sgattrib/billboardTransition.cxx @@ -22,6 +22,7 @@ #include "renderRelation.h" #include +#include #include #include #include @@ -57,8 +58,12 @@ sub_render(NodeRelation *arc, const AllAttributesWrapper &, Node *node = arc->get_child(); GraphicsStateGuardian *gsg = trav->get_gsg(); - // Get the current camera from the gsg - const ProjectionNode *camera = gsg->get_current_projection_node(); + // First, we have to get the current viewing frustum. This is + // normally the same thing as the current camera, but the + // DisplayRegion may have some override in effect, so we ask the + // DisplayRegion instead of the GSG. + const DisplayRegion *dr = gsg->get_current_display_region(); + ProjectionNode *camera = dr->get_cull_frustum(); nassertr(camera != (ProjectionNode *)NULL, true); // And the relative coordinate space. diff --git a/panda/src/sgraph/projectionNode.cxx b/panda/src/sgraph/projectionNode.cxx index ea12782c60..c0f75d88ae 100644 --- a/panda/src/sgraph/projectionNode.cxx +++ b/panda/src/sgraph/projectionNode.cxx @@ -69,8 +69,8 @@ share_projection(Projection *projection) { //////////////////////////////////////////////////////////////////// // Function: get_projection // Access: Public -// Description: Returns a pointer to particular Projection associated -// with this ProjectionNode. +// Description: Returns a pointer to the particular Projection +// associated with this ProjectionNode. //////////////////////////////////////////////////////////////////// Projection *ProjectionNode:: get_projection() { diff --git a/panda/src/sgraphutil/directRenderTraverser.cxx b/panda/src/sgraphutil/directRenderTraverser.cxx index 42752971ac..ecfbf6665d 100644 --- a/panda/src/sgraphutil/directRenderTraverser.cxx +++ b/panda/src/sgraphutil/directRenderTraverser.cxx @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -103,8 +104,9 @@ traverse(Node *root, // culling. LMatrix4f rel_from_camera; NodeTransitionWrapper ntw(TransformTransition::get_class_type()); - wrt(_gsg->get_current_projection_node(), root, begin(), end(), - ntw, get_graph_type()); + const DisplayRegion *dr = _gsg->get_current_display_region(); + ProjectionNode *camera = dr->get_cull_frustum(); + wrt(camera, root, begin(), end(), ntw, get_graph_type()); const TransformTransition *tt; if (get_transition_into(tt, ntw)) { rel_from_camera = tt->get_matrix(); diff --git a/panda/src/sgraphutil/frustumCullTraverser.I b/panda/src/sgraphutil/frustumCullTraverser.I index 296a0b43e2..36f8b2759d 100644 --- a/panda/src/sgraphutil/frustumCullTraverser.I +++ b/panda/src/sgraphutil/frustumCullTraverser.I @@ -43,7 +43,12 @@ FrustumCullTraverser(ArcChain &arc_chain, Node *root, // If we're to be performing view-frustum culling, determine the // bounding volume associated with the current viewing frustum. - ProjectionNode *camera = _gsg->get_current_projection_node(); + // First, we have to get the current viewing frustum. This is + // normally the same thing as the current camera, but the + // DisplayRegion may have some override in effect, so we ask the + // DisplayRegion instead of the GSG. + const DisplayRegion *dr = _gsg->get_current_display_region(); + ProjectionNode *camera = dr->get_cull_frustum(); if (camera != (const ProjectionNode *)NULL) { const Projection *proj = camera->get_projection(); nassertv(proj != (const Projection *)NULL); @@ -188,7 +193,9 @@ traverse(NodeRelation *arc, AttributeWrapper render_state, DCAST(GeometricBoundingVolume, _view_frustum->make_copy()); NodeTransitionWrapper ntw(TransformTransition::get_class_type()); - wrt(_gsg->get_current_projection_node(), + const DisplayRegion *dr = _gsg->get_current_display_region(); + ProjectionNode *camera = dr->get_cull_frustum(); + wrt(camera, arc->get_child(), _arc_chain.begin(), _arc_chain.end(), ntw, _graph_type); diff --git a/panda/src/sgraphutil/frustumCullTraverser.h b/panda/src/sgraphutil/frustumCullTraverser.h index 754ab64aa3..26ddf3dbbb 100644 --- a/panda/src/sgraphutil/frustumCullTraverser.h +++ b/panda/src/sgraphutil/frustumCullTraverser.h @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include diff --git a/panda/src/switchnode/LODNode.cxx b/panda/src/switchnode/LODNode.cxx index 939e6f54ec..edb3178a98 100644 --- a/panda/src/switchnode/LODNode.cxx +++ b/panda/src/switchnode/LODNode.cxx @@ -20,6 +20,7 @@ #include "config_switchnode.h" #include +#include #include #include #include @@ -85,26 +86,32 @@ void LODNode:: compute_switch(RenderTraverser *trav) { GraphicsStateGuardian *gsg = trav->get_gsg(); - // Get the current camera position from the gsg - const ProjectionNode* camera = gsg->get_current_projection_node(); - LPoint3f camera_pos(0, 0, 0); + // First, we have to get the current viewing frustum. This is + // normally the same thing as the current camera, but the + // DisplayRegion may have some override in effect, so we ask the + // DisplayRegion instead of the GSG. + const DisplayRegion *dr = gsg->get_current_display_region(); + ProjectionNode *camera = dr->get_cull_frustum(); + if (camera != (ProjectionNode *)NULL) { + LPoint3f camera_pos(0, 0, 0); - // Get the LOD center in camera space - LPoint3f LOD_pos; + // Get the LOD center in camera space + LPoint3f LOD_pos; - NodeTransitionWrapper ntw(TransformTransition::get_class_type()); - wrt(this, trav->begin(), trav->end(), - camera, ntw, RenderRelation::get_class_type()); - const TransformTransition *tt; - if (get_transition_into(tt, ntw)) { - LOD_pos = _lod._center * tt->get_matrix(); - } else { - LOD_pos = _lod._center; + NodeTransitionWrapper ntw(TransformTransition::get_class_type()); + wrt(this, trav->begin(), trav->end(), + camera, ntw, RenderRelation::get_class_type()); + const TransformTransition *tt; + if (get_transition_into(tt, ntw)) { + LOD_pos = _lod._center * tt->get_matrix(); + } else { + LOD_pos = _lod._center; + } + + // Determine which child to traverse + int index = _lod.compute_child(camera_pos, LOD_pos); + select_child(index); } - - // Determine which child to traverse - int index = _lod.compute_child(camera_pos, LOD_pos); - select_child(index); } ////////////////////////////////////////////////////////////////////