From f1de5451a39bc1ec1b807a6b7405cdb1596aba94 Mon Sep 17 00:00:00 2001 From: "Asad M. Zaman" Date: Thu, 13 May 2004 22:12:57 +0000 Subject: [PATCH] first pass prototype of portal culling system --- panda/src/pgraph/Sources.pp | 3 + panda/src/pgraph/camera.I | 27 ++ panda/src/pgraph/camera.h | 4 + panda/src/pgraph/config_pgraph.cxx | 7 + panda/src/pgraph/config_pgraph.h | 1 + panda/src/pgraph/cullTraverser.cxx | 90 ++++- panda/src/pgraph/cullTraverser.h | 3 +- panda/src/pgraph/cullTraverserData.I | 5 + panda/src/pgraph/cullTraverserData.cxx | 7 + panda/src/pgraph/cullTraverserData.h | 2 + panda/src/pgraph/pgraph_composite2.cxx | 1 + panda/src/pgraph/portalClipper.I | 119 +++++++ panda/src/pgraph/portalClipper.cxx | 445 +++++++++++++++++++++++++ panda/src/pgraph/portalClipper.h | 136 ++++++++ panda/src/pgraph/sceneSetup.I | 17 + panda/src/pgraph/sceneSetup.h | 2 + panda/src/pgraph/workingNodePath.cxx | 9 +- 17 files changed, 868 insertions(+), 10 deletions(-) create mode 100755 panda/src/pgraph/portalClipper.I create mode 100755 panda/src/pgraph/portalClipper.cxx create mode 100755 panda/src/pgraph/portalClipper.h diff --git a/panda/src/pgraph/Sources.pp b/panda/src/pgraph/Sources.pp index a1fde712d1..4d331cb1da 100644 --- a/panda/src/pgraph/Sources.pp +++ b/panda/src/pgraph/Sources.pp @@ -69,6 +69,7 @@ pandaNode.I pandaNode.h \ planeNode.I planeNode.h \ pointLight.I pointLight.h \ + portalClipper.I portalClipper.h \ renderAttrib.I renderAttrib.h \ renderEffect.I renderEffect.h \ renderEffects.I renderEffects.h \ @@ -153,6 +154,7 @@ pandaNode.cxx \ planeNode.cxx \ pointLight.cxx \ + portalClipper.cxx \ renderAttrib.cxx \ renderEffect.cxx \ renderEffects.cxx \ @@ -233,6 +235,7 @@ pandaNode.I pandaNode.h \ planeNode.I planeNode.h \ pointLight.I pointLight.h \ + portalClipper.I portalClipper.h \ renderAttrib.I renderAttrib.h \ renderEffect.I renderEffect.h \ renderEffects.I renderEffects.h \ diff --git a/panda/src/pgraph/camera.I b/panda/src/pgraph/camera.I index 34aa2b19ec..e651f24a3a 100644 --- a/panda/src/pgraph/camera.I +++ b/panda/src/pgraph/camera.I @@ -115,3 +115,30 @@ INLINE DrawMask Camera:: get_camera_mask() const { return _camera_mask; } + +//////////////////////////////////////////////////////////////////// +// Function: Camera::set_cull_center +// Access: Public +// Description: Specifies the point from which the culling operations +// are performed. Normally, this is the same as the +// camera, and that is the default if this is not +// specified; but it may sometimes be useful to perform +// the culling from some other viewpoint, particularly +// when you are debugging the culling itself. +//////////////////////////////////////////////////////////////////// +INLINE void Camera:: +set_cull_center(const NodePath &cull_center) { + _cull_center = cull_center; +} + +//////////////////////////////////////////////////////////////////// +// Function: Camera::get_cull_center +// Access: Public +// Description: Returns the point from which the culling operations +// will be performed, if it was set by +// set_cull_center(), or the empty NodePath otherwise. +//////////////////////////////////////////////////////////////////// +INLINE const NodePath &Camera:: +get_cull_center() const { + return _cull_center; +} diff --git a/panda/src/pgraph/camera.h b/panda/src/pgraph/camera.h index f60ac05b99..2e5543b663 100644 --- a/panda/src/pgraph/camera.h +++ b/panda/src/pgraph/camera.h @@ -59,12 +59,16 @@ PUBLISHED: INLINE void set_camera_mask(DrawMask mask); INLINE DrawMask get_camera_mask() const; + INLINE void set_cull_center(const NodePath &cull_center); + INLINE const NodePath &get_cull_center() const; + private: void add_display_region(DisplayRegion *display_region); void remove_display_region(DisplayRegion *display_region); bool _active; NodePath _scene; + NodePath _cull_center; DrawMask _camera_mask; diff --git a/panda/src/pgraph/config_pgraph.cxx b/panda/src/pgraph/config_pgraph.cxx index caaa43884d..fe15fa4c14 100644 --- a/panda/src/pgraph/config_pgraph.cxx +++ b/panda/src/pgraph/config_pgraph.cxx @@ -62,6 +62,7 @@ #include "pandaNode.h" #include "planeNode.h" #include "pointLight.h" +#include "portalClipper.h" #include "renderAttrib.h" #include "renderEffect.h" #include "renderEffects.h" @@ -95,6 +96,10 @@ ConfigureFn(config_pgraph) { // helps make culling errors obvious. const bool fake_view_frustum_cull = config_pgraph.GetBool("fake-view-frustum-cull", false); +// Set this true to enable portal clipping. This will enable the renderer to cull +// more objects that are clipped if not in the current list ot portals +const bool allow_portal_cull = config_pgraph.GetBool("allow-portal-cull", false); + // Set this true to make ambiguous path warning messages generate an // assertion failure instead of just a warning (which can then be // trapped with assert-abort). @@ -203,6 +208,7 @@ init_libpgraph() { PandaNode::init_type(); PlaneNode::init_type(); PointLight::init_type(); + PortalClipper::init_type(); RenderAttrib::init_type(); RenderEffect::init_type(); RenderEffects::init_type(); @@ -256,6 +262,7 @@ init_libpgraph() { PandaNode::register_with_read_factory(); PlaneNode::register_with_read_factory(); PointLight::register_with_read_factory(); + //PortalClipper::register_with_read_factory(); RenderEffects::register_with_read_factory(); RenderModeAttrib::register_with_read_factory(); RenderState::register_with_read_factory(); diff --git a/panda/src/pgraph/config_pgraph.h b/panda/src/pgraph/config_pgraph.h index e19f702f67..e8fef5b703 100644 --- a/panda/src/pgraph/config_pgraph.h +++ b/panda/src/pgraph/config_pgraph.h @@ -30,6 +30,7 @@ NotifyCategoryDecl(pgraph, EXPCL_PANDA, EXPTP_PANDA); NotifyCategoryDecl(loader, EXPCL_PANDA, EXPTP_PANDA); extern const bool fake_view_frustum_cull; +extern const bool allow_portal_cull; extern const bool unambiguous_graph; extern const bool allow_unrelated_wrt; extern const bool paranoid_compose; diff --git a/panda/src/pgraph/cullTraverser.cxx b/panda/src/pgraph/cullTraverser.cxx index 36d2b25021..a4dafb1114 100644 --- a/panda/src/pgraph/cullTraverser.cxx +++ b/panda/src/pgraph/cullTraverser.cxx @@ -26,11 +26,9 @@ #include "geomNode.h" #include "config_pgraph.h" #include "boundingSphere.h" +#include "boundingHexahedron.h" #include "geomSphere.h" -#include "colorAttrib.h" -#include "renderModeAttrib.h" -#include "cullFaceAttrib.h" -#include "depthOffsetAttrib.h" +#include "portalClipper.h" #ifndef CPPPARSER PStatCollector CullTraverser::_nodes_pcollector("Nodes"); @@ -79,10 +77,65 @@ traverse(const NodePath &root) { nassertv(_cull_handler != (CullHandler *)NULL); nassertv(_scene_setup != (SceneSetup *)NULL); - CullTraverserData data(root, get_render_transform(), - TransformState::make_identity(), - _initial_state, _view_frustum, _guard_band); - traverse(data); + if (allow_portal_cull) { + PT(GeometricBoundingVolume) vf = _view_frustum; + pgraph_cat.spam() << "_view_frustum is " << *_view_frustum << "\n"; + + GeometricBoundingVolume *local_frustum = NULL; + PT(BoundingVolume) bv = _scene_setup->get_lens()->make_bounds(); + if (bv != (BoundingVolume *)NULL && + bv->is_of_type(GeometricBoundingVolume::get_class_type())) { + + local_frustum = DCAST(GeometricBoundingVolume, bv); + } + pgraph_cat.spam() << "local_frustum is " << *local_frustum << "\n"; + + PortalClipper portal_viewer(local_frustum, _scene_setup); + portal_viewer.draw_camera_frustum(); + + // for each portal draw its frustum + for (int portal_idx=1; portal_idx<2; ++portal_idx) { + PT(BoundingVolume) reduced_frustum; + + portal_viewer.prepare_portal(portal_idx); + portal_viewer.clip_portal(portal_idx); + if ((reduced_frustum = portal_viewer.get_reduced_frustum(portal_idx))) { + pgraph_cat.debug() << "got reduced frustum " << reduced_frustum << endl; + vf = DCAST(GeometricBoundingVolume, reduced_frustum); + CPT(TransformState) cull_center_transform = + _scene_setup->get_cull_center().get_transform(_scene_setup->get_scene_root()); + vf->xform(cull_center_transform->get_mat()); + } + } + pgraph_cat.spam() << "vf is " << *vf << "\n"; + + CullTraverserData data(root, get_render_transform(), + TransformState::make_identity(), + _initial_state, _view_frustum, + vf, _guard_band); + + traverse(data); + + // finally add the lines to be drawn + portal_viewer.draw_lines(); + + // Render the frustum relative to the cull center. + NodePath cull_center = _scene_setup->get_cull_center(); + CPT(TransformState) transform = cull_center.get_transform(root); + + CullTraverserData my_data(data, portal_viewer._previous); + my_data._render_transform = my_data._render_transform->compose(transform); + traverse(my_data); + pgraph_cat.debug() << "finished portal culling\n"; + } + else { + CullTraverserData data(root, get_render_transform(), + TransformState::make_identity(), + _initial_state, _view_frustum, + NULL, _guard_band); + + traverse(data); + } } //////////////////////////////////////////////////////////////////// @@ -98,9 +151,29 @@ traverse(CullTraverserData &data) { // contain decals or require a special cull callback. As an // optimization, we should tag nodes with these properties as // being "fancy", and skip this processing for non-fancy nodes. + if (data.is_in_view(_camera_mask)) { PandaNode *node = data.node(); + pgraph_cat.spam() << "\n" << data._node_path << "\n"; + + // let me see the names, curious + unsigned int loc = node->get_name().find("pTypeArchway"); + if (loc != string::npos) { + node->output(pgraph_cat.debug()); + pgraph_cat.spam() << endl; + if (data._reduced_frustum) { + pgraph_cat.debug() << "setting reduced frustum to this node\n"; + if (data._view_frustum) { + pgraph_cat.spam() << *data._view_frustum << endl; + } + pgraph_cat.spam() << *data._reduced_frustum << endl; + + data._view_frustum = data._reduced_frustum; + data._reduced_frustum = NULL; + } + } + const RenderEffects *node_effects = node->get_effects(); if (node_effects->has_show_bounds()) { // If we should show the bounding volume for this node, make it @@ -141,6 +214,7 @@ void CullTraverser:: traverse_below(CullTraverserData &data) { _nodes_pcollector.add_level(1); PandaNode *node = data.node(); + const RenderEffects *node_effects = node->get_effects(); bool has_decal = node_effects->has_decal(); if (has_decal && !_depth_offset_decals) { diff --git a/panda/src/pgraph/cullTraverser.h b/panda/src/pgraph/cullTraverser.h index c142971923..40444918eb 100644 --- a/panda/src/pgraph/cullTraverser.h +++ b/panda/src/pgraph/cullTraverser.h @@ -33,8 +33,9 @@ class PandaNode; class CullHandler; -class CullTraverserData; class CullableObject; +class CullTraverserData; +class PortalClipper; class NodePath; //////////////////////////////////////////////////////////////////// diff --git a/panda/src/pgraph/cullTraverserData.I b/panda/src/pgraph/cullTraverserData.I index c3dd138bc1..f3442bb826 100644 --- a/panda/src/pgraph/cullTraverserData.I +++ b/panda/src/pgraph/cullTraverserData.I @@ -28,12 +28,14 @@ CullTraverserData(const NodePath &start, const TransformState *net_transform, const RenderState *state, GeometricBoundingVolume *view_frustum, + GeometricBoundingVolume *reduced_frustum, GeometricBoundingVolume *guard_band) : _node_path(start), _render_transform(render_transform), _net_transform(net_transform), _state(state), _view_frustum(view_frustum), + _reduced_frustum(reduced_frustum), _guard_band(guard_band) { } @@ -50,6 +52,7 @@ CullTraverserData(const CullTraverserData ©) : _net_transform(copy._net_transform), _state(copy._state), _view_frustum(copy._view_frustum), + _reduced_frustum(copy._reduced_frustum), _guard_band(copy._guard_band) { } @@ -66,6 +69,7 @@ operator = (const CullTraverserData ©) { _net_transform = copy._net_transform; _state = copy._state; _view_frustum = copy._view_frustum; + _reduced_frustum = copy._reduced_frustum; _guard_band = copy._guard_band; } @@ -82,6 +86,7 @@ CullTraverserData(const CullTraverserData &parent, PandaNode *child) : _net_transform(parent._net_transform), _state(parent._state), _view_frustum(parent._view_frustum), + _reduced_frustum(parent._reduced_frustum), _guard_band(parent._guard_band) { } diff --git a/panda/src/pgraph/cullTraverserData.cxx b/panda/src/pgraph/cullTraverserData.cxx index 19431b0d96..ef1dcf30cd 100644 --- a/panda/src/pgraph/cullTraverserData.cxx +++ b/panda/src/pgraph/cullTraverserData.cxx @@ -62,6 +62,7 @@ apply_transform_and_state(CullTraverser *trav, _render_transform = _render_transform->compose(node_transform); if ((_view_frustum != (GeometricBoundingVolume *)NULL) || + (_reduced_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. @@ -70,6 +71,7 @@ apply_transform_and_state(CullTraverser *trav, // trying, we'll just give up on frustum culling from this // point down. _view_frustum = (GeometricBoundingVolume *)NULL; + _reduced_frustum = (GeometricBoundingVolume *)NULL; _guard_band = (GeometricBoundingVolume *)NULL; } else { @@ -82,6 +84,11 @@ apply_transform_and_state(CullTraverser *trav, _view_frustum = DCAST(GeometricBoundingVolume, _view_frustum->make_copy()); _view_frustum->xform(inv_transform->get_mat()); } + + if (_reduced_frustum != (GeometricBoundingVolume *)NULL) { + _reduced_frustum = DCAST(GeometricBoundingVolume, _reduced_frustum->make_copy()); + _reduced_frustum->xform(inv_transform->get_mat()); + } if (_guard_band != (GeometricBoundingVolume *)NULL) { _guard_band = DCAST(GeometricBoundingVolume, _guard_band->make_copy()); diff --git a/panda/src/pgraph/cullTraverserData.h b/panda/src/pgraph/cullTraverserData.h index 32f318bb89..3dc245bb90 100644 --- a/panda/src/pgraph/cullTraverserData.h +++ b/panda/src/pgraph/cullTraverserData.h @@ -52,6 +52,7 @@ public: const TransformState *net_transform, const RenderState *state, GeometricBoundingVolume *view_frustum, + GeometricBoundingVolume *reduced_frustum, GeometricBoundingVolume *guard_band); INLINE CullTraverserData(const CullTraverserData ©); INLINE void operator = (const CullTraverserData ©); @@ -73,6 +74,7 @@ public: CPT(TransformState) _net_transform; CPT(RenderState) _state; PT(GeometricBoundingVolume) _view_frustum; + PT(GeometricBoundingVolume) _reduced_frustum; PT(GeometricBoundingVolume) _guard_band; private: diff --git a/panda/src/pgraph/pgraph_composite2.cxx b/panda/src/pgraph/pgraph_composite2.cxx index 39e891b0d4..4305f840d3 100644 --- a/panda/src/pgraph/pgraph_composite2.cxx +++ b/panda/src/pgraph/pgraph_composite2.cxx @@ -18,6 +18,7 @@ #include "pandaNode.cxx" #include "planeNode.cxx" #include "pointLight.cxx" +#include "portalClipper.cxx" #include "renderAttrib.cxx" #include "renderEffect.cxx" #include "renderEffects.cxx" diff --git a/panda/src/pgraph/portalClipper.I b/panda/src/pgraph/portalClipper.I new file mode 100755 index 0000000000..048b6ecd59 --- /dev/null +++ b/panda/src/pgraph/portalClipper.I @@ -0,0 +1,119 @@ +// Filename: portalClipper.I +// Created by: masad (4May04) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://etc.cmu.edu/panda3d/docs/license/ . +// +// To contact the maintainers of this program write to +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////// +// Function: PortalClipper::Point::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE PortalClipper::Point:: +Point() { +} + +//////////////////////////////////////////////////////////////////// +// Function: PortalClipper::Point::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE PortalClipper::Point:: +Point(const LVecBase3f &point, const Colorf &color) : + _point(point[0], point[1], point[2]), + _color(color) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: PortalClipper::Point::Copy Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE PortalClipper::Point:: +Point(const PortalClipper::Point ©) : + _point(copy._point), + _color(copy._color) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: PortalClipper::Point::Copy Assignment Operator +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE void PortalClipper::Point:: +operator = (const PortalClipper::Point ©) { + _point = copy._point; + _color = copy._color; +} + +//////////////////////////////////////////////////////////////////// +// Function: PortalClipper::move_to +// Access: Public +// Description: Moves the pen to the given point without drawing a +// line. When followed by draw_to(), this marks the +// first point of a line segment; when followed by +// move_to() or create(), this creates a single point. +//////////////////////////////////////////////////////////////////// +INLINE void PortalClipper:: +move_to(float x, float y, float z) { + move_to(Vertexf(x, y, z)); +} + +//////////////////////////////////////////////////////////////////// +// Function: PortalClipper::draw_to +// Access: Public +// Description: Draws a line segment from the pen's last position +// (the last call to move_to or draw_to) to the +// indicated point. move_to() and draw_to() only update +// tables; the actual drawing is performed when create() +// is called. +//////////////////////////////////////////////////////////////////// +INLINE void PortalClipper:: +draw_to(float x, float y, float z) { + draw_to(Vertexf(x, y, z)); +} + +//////////////////////////////////////////////////////////////////// +// Function: PortalClipper::draw_camera_frustum +// Access: Public +// Description: Draw the current camera frustum in white color +// +//////////////////////////////////////////////////////////////////// +void PortalClipper:: +draw_camera_frustum() +{ + _color = Colorf(1,1,1,1); + draw_hexahedron(_hex_frustum); +} + +//////////////////////////////////////////////////////////////////// +// Function: PortalClipper::facing_camera +// Access: Public +// Description: checks if the _coords that forms the plane is +// facing the camera +//////////////////////////////////////////////////////////////////// +bool PortalClipper:: +is_facing_camera() +{ + Planef portal_plane(_coords[0], _coords[1], _coords[2]); + Planef camera_plane(_hex_frustum->get_point(4), _hex_frustum->get_point(5), _hex_frustum->get_point(6)); + + float direction = portal_plane.get_normal().dot(camera_plane.get_normal()); + pgraph_cat.debug() << "Found direction of " << direction << endl; + return (direction > 0); +} diff --git a/panda/src/pgraph/portalClipper.cxx b/panda/src/pgraph/portalClipper.cxx new file mode 100755 index 0000000000..be3a9fc187 --- /dev/null +++ b/panda/src/pgraph/portalClipper.cxx @@ -0,0 +1,445 @@ +// Filename: portalClipper.cxx +// Created by: masad (4May04) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://etc.cmu.edu/panda3d/docs/license/ . +// +// To contact the maintainers of this program write to +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + +#include "portalClipper.h" +#include "cullTraverser.h" +#include "cullTraverserData.h" +#include "transformState.h" +#include "renderState.h" +#include "fogAttrib.h" +#include "cullHandler.h" +#include "dcast.h" +#include "geomNode.h" +#include "config_pgraph.h" +#include "boundingSphere.h" +#include "geomSphere.h" +#include "colorAttrib.h" +#include "renderModeAttrib.h" +#include "cullFaceAttrib.h" +#include "depthOffsetAttrib.h" + +TypeHandle PortalClipper::_type_handle; + +//////////////////////////////////////////////////////////////////// +// Function: PortalClipper::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +PortalClipper:: +PortalClipper(GeometricBoundingVolume *frustum, SceneSetup *scene_setup) { + _previous = new GeomNode("my_frustum"); + _geom_line = new GeomLine; + _geom_point = new GeomPoint; + _geom_linestrip = new GeomLinestrip; + + _hex_frustum = DCAST(BoundingHexahedron, frustum); + + _scene_setup = scene_setup; +} + +//////////////////////////////////////////////////////////////////// +// Function: PortalClipper::Destructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +PortalClipper:: +~PortalClipper() { +} + +//////////////////////////////////////////////////////////////////// +// Function: PortalClipper::move_to +// Access: Public +// Description: Moves the pen to the given point without drawing a +// line. When followed by draw_to(), this marks the +// first point of a line segment; when followed by +// move_to() or create(), this creates a single point. +//////////////////////////////////////////////////////////////////// +void PortalClipper:: +move_to(const LVecBase3f &v) { + // We create a new SegmentList with the initial point in it. + SegmentList segs; + segs.push_back(Point(v, _color)); + + // And add this list to the list of segments. + _list.push_back(segs); +} + +//////////////////////////////////////////////////////////////////// +// Function: PortalClipper::draw_to +// Access: Public +// Description: Draws a line segment from the pen's last position +// (the last call to move_to or draw_to) to the +// indicated point. move_to() and draw_to() only update +// tables; the actual drawing is performed when create() +// is called. +//////////////////////////////////////////////////////////////////// +void PortalClipper:: +draw_to(const LVecBase3f &v) { + if (_list.empty()) { + // Let our first call to draw_to() be an implicit move_to(). + move_to(v); + + } else { + // Get the current SegmentList, which was the last one we added to + // the LineList. + SegmentList &segs = _list.back(); + + // Add the new point. + segs.push_back(Point(v, _color)); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: PortalClipper::draw a portal frustum +// Access: Public +// Description: Given the BoundingHexahedron draw it using lines +// +//////////////////////////////////////////////////////////////////// +void PortalClipper:: +draw_hexahedron(BoundingHexahedron *frustum) +{ + /* + pgraph_cat.debug() << "frustum points " << frustum->get_num_points() << endl; + + pgraph_cat.debug() << frustum->get_point(0) << endl; + pgraph_cat.debug() << frustum->get_point(1) << endl; + pgraph_cat.debug() << frustum->get_point(2) << endl; + pgraph_cat.debug() << frustum->get_point(3) << endl; + pgraph_cat.debug() << frustum->get_point(4) << endl; + pgraph_cat.debug() << frustum->get_point(5) << endl; + pgraph_cat.debug() << frustum->get_point(6) << endl; + pgraph_cat.debug() << frustum->get_point(7) << endl; + */ + + // walk the view frustum as it should be drawn + move_to(frustum->get_point(0)); + draw_to(frustum->get_point(1)); + draw_to(frustum->get_point(2)); + draw_to(frustum->get_point(3)); + + move_to(frustum->get_point(4)); + draw_to(frustum->get_point(0)); + draw_to(frustum->get_point(3)); + draw_to(frustum->get_point(7)); + + move_to(frustum->get_point(5)); + draw_to(frustum->get_point(4)); + draw_to(frustum->get_point(7)); + draw_to(frustum->get_point(6)); + + move_to(frustum->get_point(1)); + draw_to(frustum->get_point(5)); + draw_to(frustum->get_point(6)); + draw_to(frustum->get_point(2)); + +} +//////////////////////////////////////////////////////////////////// +// Function: PortalClipper::draw the lines +// Access: Public +// Description: Draw all the lines in the buffer +// +//////////////////////////////////////////////////////////////////// +void PortalClipper:: +draw_lines() +{ + if (!_list.empty()) { + _created_verts.clear(); + _created_colors.clear(); + + // One array each for the indices into these arrays for points + // and lines, and one for our line-segment lengths array. + PTA_ushort point_index; + PTA_ushort line_index; + PTA_int lengths; + + // Now fill up the arrays. + int v = 0; + LineList::const_iterator ll; + SegmentList::const_iterator sl; + + for (ll = _list.begin(); ll != _list.end(); ll++) { + const SegmentList &segs = (*ll); + + if (segs.size() < 2) { + point_index.push_back(v); + } else { + lengths.push_back(segs.size()); + } + + for (sl = segs.begin(); sl != segs.end(); sl++) { + if (segs.size() >= 2) { + line_index.push_back(v); + } + _created_verts.push_back((*sl)._point); + _created_colors.push_back((*sl)._color); + v++; + //nassertr(v == (int)_created_verts.size(), previous); + } + } + + + // Now create the lines. + Geom *geom; + if (line_index.size() > 0) { + // Create a new Geom and add the line segments. + if (line_index.size() <= 2) { + // Here's a special case: just one line segment. + _geom_line->set_num_prims(1); + _geom_line->set_width(_thick); + geom = _geom_line; + + } else { + // The more normal case: multiple line segments, connected + // end-to-end like a series of linestrips. + _geom_linestrip->set_num_prims(lengths.size()); + _geom_linestrip->set_lengths(lengths); + _geom_linestrip->set_width(_thick); + geom = _geom_linestrip; + } + + geom->set_colors(_created_colors, G_PER_VERTEX, line_index); + geom->set_coords(_created_verts, line_index); + + //geom->write_verbose(cerr, 0); + + _previous->add_geom(geom); + pgraph_cat.debug() << "added geometry" << endl; + } + } +} +//////////////////////////////////////////////////////////////////// +// Function: PortalClipper::prepare the portal +// Access: Public +// Description: Given the portal draw the frustum with line segs +// for now. More functionalities coming up +//////////////////////////////////////////////////////////////////// +void PortalClipper:: +prepare_portal(int idx) +{ + SegmentList segs; + char portal_name[128]; + + // print some messages to see if i am getting to this part + pgraph_cat.debug() << "creating portal clipper " << idx << endl; + + // walk the portal + sprintf(portal_name, "**/portal%d", idx); + NodePath portal_nodepath = _scene_setup->get_scene_root().find(portal_name); + if (!portal_nodepath.is_empty()) { + pgraph_cat.debug() << "portal nodepath " << portal_nodepath << endl; + + /* + // Get the World transformation matrix + CPT(TransformState) wtransform = portal_nodepath.get_transform(_scene_setup->get_scene_root()); + LMatrix4f wmat = wtransform->get_mat(); + pgraph_cat.debug() << wmat << endl; + */ + + // Get the camera transformation matrix + CPT(TransformState) ctransform = portal_nodepath.get_transform(_scene_setup->get_cull_center()); + //CPT(TransformState) ctransform = portal_nodepath.get_transform(_scene_setup->get_camera_path()); + LMatrix4f cmat = ctransform->get_mat(); + pgraph_cat.debug() << cmat << endl; + + // Get the geometry from the portal + PandaNode *portal_node = portal_nodepath.node(); + GeomNode *portal_geom = DCAST(GeomNode, portal_node); + + //portal_geom->write_verbose(pgraph_cat.debug(false), 0); + + int num_geoms = portal_geom->get_num_geoms(); + pgraph_cat.debug() << "num geometry in portal " << num_geoms << endl; + + PTA_ushort index; + PT(Geom) geom = portal_geom->get_geom(0); + _num_vert = geom->get_num_vertices(); + PTA_Vertexf coords; + geom->get_coords(coords, index); + + /* + pgraph_cat.debug() << "before transformation to camera space" << endl; + pgraph_cat.debug() << coords[0] << endl; + pgraph_cat.debug() << coords[1] << endl; + pgraph_cat.debug() << coords[2] << endl; + pgraph_cat.debug() << coords[3] << endl; + */ + + _coords[0] = coords[0]*cmat; + _coords[1] = coords[1]*cmat; + _coords[2] = coords[3]*cmat; // flip with 3rd vertex + _coords[3] = coords[2]*cmat; // flip with 2nd vertex + + /* + pgraph_cat.debug() << "after transformation to camera space" << endl; + pgraph_cat.debug() << _coords[0] << endl; + pgraph_cat.debug() << _coords[1] << endl; + pgraph_cat.debug() << _coords[2] << endl; + pgraph_cat.debug() << _coords[3] << endl; + */ + + //geom->write_verbose(pgraph_cat.debug(false), 0); + + // check if facing camera + if (is_facing_camera()) { + + // ok, now lets add the near plane to this portal + _color = Colorf(1,0,0,1); + move_to(_coords[0]); + draw_to(_coords[1]); + draw_to(_coords[2]); + draw_to(_coords[3]); + draw_to(_coords[0]); + + pgraph_cat.debug() << "assembled portal" << idx << " frustum points" << endl; + } + else { + _num_vert = 0; + } + } + else { + _num_vert = 0; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: PortalClipper::clip the portal +// Access: Public +// Description: From the frustum clip the portal against the frustum +// and form the new planes of the reduced view frustum +//////////////////////////////////////////////////////////////////// +void PortalClipper:: +clip_portal(int idx) +{ + int num_planes = _hex_frustum->get_num_planes(); + + /* + pgraph_cat.debug() << "Number of planes " << num_planes << endl; + + // print out the planes. plane 0 should be far and plane 5 should be near + // so we are only concerned with the 4 side planes. + for (int i=0; iget_plane(i); + plane.output(pgraph_cat.debug()); + pgraph_cat.debug() << endl; + } + */ + + for (int i=1; iget_plane(i); + for (int j=0; j<_num_vert; ++j) { + float t; + LPoint3f from_origin = _coords[j]; + LVector3f from_direction = _coords[(j+1)%_num_vert] - _coords[j]; + bool is_intersect = plane.intersects_line(t, from_origin, from_direction); + if (is_intersect) { + pgraph_cat.debug() << "plane " << i << " intersected segement " << j << "->" << (j+1)%_num_vert << " at t=" << t << endl; + } + } + } +} + + +//////////////////////////////////////////////////////////////////// +// Function: PortalClipper::get_reduced_frustum +// Access: Public +// Description: After clipping the portal, form the new sides and +// fill in the new frustum. Return true if success +//////////////////////////////////////////////////////////////////// +PT(BoundingVolume) PortalClipper:: +get_reduced_frustum(int idx) +{ + int num_planes = 6; + LPoint3f intersect_points[4]; + +#if 0 + // calculate the new side planes + for (int i=0; i<_num_vert; ++i) { + // get the vectors, Vi+1 and Vi + LVector3f front(_coords[(i+1)%_num_vert]); + LVector3f back(_coords[i]); + // get the cross product of these two vectors + LVector3f normal = front.cross(back); + normal.normalize(); + frustum_planes[i+1] = Planef(normal, LPoint3f(0,0,0)); + frustum_planes[i+1].output(pgraph_cat.debug()); + pgraph_cat.debug() << endl; + } +#else + // another approach to actually finding the points, so that + // I can reuse the current BoundingHexahedron object. Apparently, + // it is better to construct this BH with bounding points, rather + // than bounding planes (which I might have to implement soon) + + if (!_num_vert) + return false; + + float t; + // find intersection of 7->0 with far + LPoint3f from_origin = _hex_frustum->get_point(7); + LVector3f from_direction = _coords[0] - from_origin; + bool is_intersect = _hex_frustum->get_plane(0).intersects_line(t, from_origin, from_direction); + if (is_intersect) { + pgraph_cat.debug() << "far plane intersected 7->0 at t=" << t << endl; + intersect_points[0] = from_origin + t*from_direction; + pgraph_cat.debug() << intersect_points[0] << endl; + } + + // find intersection of 4->1 with far + from_origin = _hex_frustum->get_point(4); + from_direction = _coords[1] - from_origin; + is_intersect = _hex_frustum->get_plane(0).intersects_line(t, from_origin, from_direction); + if (is_intersect) { + pgraph_cat.debug() << "far plane intersected 4->1 at t=" << t << endl; + intersect_points[1] = from_origin + t*from_direction; + pgraph_cat.debug() << intersect_points[1] << endl; + } + // find intersection of 5->2 with far + from_origin = _hex_frustum->get_point(5); + from_direction = _coords[2] - from_origin; + is_intersect = _hex_frustum->get_plane(0).intersects_line(t, from_origin, from_direction); + if (is_intersect) { + pgraph_cat.debug() << "far plane intersected 5->2 at t=" << t << endl; + intersect_points[2] = from_origin + t*from_direction; + pgraph_cat.debug() << intersect_points[2] << endl; + } + // find intersection of 6->3 with far + from_origin = _hex_frustum->get_point(6); + from_direction = _coords[3] - from_origin; + is_intersect = _hex_frustum->get_plane(0).intersects_line(t, from_origin, from_direction); + if (is_intersect) { + pgraph_cat.debug() << "far plane intersected 6->3 at t=" << t << endl; + intersect_points[3] = from_origin + t*from_direction; + pgraph_cat.debug() << intersect_points[3] << endl; + } + + // With these intersect_points, construct the new reduced frustum + PT(BoundingVolume) reduced_frustum = new + BoundingHexahedron(intersect_points[1], intersect_points[2], + intersect_points[3], intersect_points[0], + _hex_frustum->get_point(4), _hex_frustum->get_point(5), + _hex_frustum->get_point(6), _hex_frustum->get_point(7)); + + pgraph_cat.debug() << *reduced_frustum << endl; + + // draw this hexahedron + _color = Colorf(0,0,1,1); + draw_hexahedron(DCAST(BoundingHexahedron, reduced_frustum)); + +#endif + return reduced_frustum; +} diff --git a/panda/src/pgraph/portalClipper.h b/panda/src/pgraph/portalClipper.h new file mode 100755 index 0000000000..fbac39ce69 --- /dev/null +++ b/panda/src/pgraph/portalClipper.h @@ -0,0 +1,136 @@ +// Filename: portalClipper.h +// Created by: masad (4May04) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://etc.cmu.edu/panda3d/docs/license/ . +// +// To contact the maintainers of this program write to +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + +#ifndef PORTALCLIPPER_H +#define PORTALCLIPPER_H + +#include "pandabase.h" + +#include "geom.h" +#include "sceneSetup.h" +#include "renderState.h" +#include "transformState.h" +#include "geometricBoundingVolume.h" +#include "boundingHexahedron.h" +#include "pointerTo.h" +#include "drawMask.h" +#include "typedObject.h" +#include "pStatCollector.h" + +#include "geom.h" +#include "geomPoint.h" +#include "geomLine.h" +#include "geomLinestrip.h" +#include "geomNode.h" + +class PandaNode; +class CullHandler; +class CullTraverserData; +class CullableObject; +class NodePath; + +//////////////////////////////////////////////////////////////////// +// Class : PortalClipper +// Description : This object performs a depth-first traversal of the +// scene graph, with optional view-frustum culling, +// collecting CullState and searching for GeomNodes. +// Each renderable Geom encountered is passed along with +// its associated RenderState to the CullHandler object. +//////////////////////////////////////////////////////////////////// +class EXPCL_PANDA PortalClipper : public TypedObject { +public: + PortalClipper(GeometricBoundingVolume *frustum, SceneSetup *scene_setup); + ~PortalClipper(); + + INLINE bool is_facing_camera(); + void prepare_portal(int idx); + + void clip_portal(int idx); + + PT(BoundingVolume) get_reduced_frustum(int idx); + + void draw_lines(); + INLINE void draw_camera_frustum(); + void draw_hexahedron(BoundingHexahedron *frustum); + + INLINE void move_to(float x, float y, float z); + void move_to(const LVecBase3f &v); + + INLINE void draw_to(float x, float y, float z); + void draw_to(const LVecBase3f &v); + + +public: + static TypeHandle get_class_type() { + return _type_handle; + } + static void init_type() { + TypedObject::init_type(); + register_type(_type_handle, "PortalClipper", + TypedObject::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; + +private: + class Point { + public: + INLINE Point(); + INLINE Point(const LVecBase3f &point, const Colorf &color); + INLINE Point(const Point ©); + INLINE void operator = (const Point ©); + + Vertexf _point; + Colorf _color; + }; + + typedef pvector SegmentList; + typedef pvector LineList; + + LineList _list; + Colorf _color; + float _thick; + + PTA_Vertexf _created_verts; + PTA_Colorf _created_colors; + + PT(GeomLine) _geom_line; + PT(GeomPoint) _geom_point; + PT(GeomLinestrip) _geom_linestrip; + + BoundingHexahedron *_hex_frustum; + SceneSetup *_scene_setup; + + int _num_vert; + Vertexf _coords[4]; + +public: + PT(GeomNode) _previous; +}; + +#include "portalClipper.I" + +#endif + + + diff --git a/panda/src/pgraph/sceneSetup.I b/panda/src/pgraph/sceneSetup.I index b1c5823a11..8ec2047d21 100644 --- a/panda/src/pgraph/sceneSetup.I +++ b/panda/src/pgraph/sceneSetup.I @@ -109,6 +109,23 @@ get_lens() const { return _lens; } +//////////////////////////////////////////////////////////////////// +// Function: SceneSetup::get_cull_center +// Access: Public +// Description: Returns the point from which the culling operations +// will be performed. This is normally the camera, but +// if camera->set_cull_center() has been specified, it +// will be that special node instead. +//////////////////////////////////////////////////////////////////// +INLINE const NodePath &SceneSetup:: +get_cull_center() const { + if (_camera_node->get_cull_center().is_empty()) { + return _camera_path; + } else { + return _camera_node->get_cull_center(); + } +} + //////////////////////////////////////////////////////////////////// // Function: SceneSetup::set_camera_transform // Access: Public diff --git a/panda/src/pgraph/sceneSetup.h b/panda/src/pgraph/sceneSetup.h index a5ec172ac5..6fae974bf0 100644 --- a/panda/src/pgraph/sceneSetup.h +++ b/panda/src/pgraph/sceneSetup.h @@ -50,6 +50,8 @@ public: INLINE void set_lens(const Lens *lens); INLINE const Lens *get_lens() const; + INLINE const NodePath &get_cull_center() const; + INLINE void set_camera_transform(const TransformState *camera_transform); INLINE const TransformState *get_camera_transform() const; diff --git a/panda/src/pgraph/workingNodePath.cxx b/panda/src/pgraph/workingNodePath.cxx index 51048d2653..f99d7b52bd 100644 --- a/panda/src/pgraph/workingNodePath.cxx +++ b/panda/src/pgraph/workingNodePath.cxx @@ -111,6 +111,13 @@ r_get_node_path() const { nassertr(comp != (NodePathComponent *)NULL, NULL); PT(NodePathComponent) result = PandaNode::get_component(comp, _node); - nassertr(result != (NodePathComponent *)NULL, NULL); + if (result == (NodePathComponent *)NULL) { + // This means we found a disconnected chain in the + // WorkingNodePath's ancestry: the node above this node isn't + // connected. In this case, don't attempt to go higher; just + // truncate the NodePath at the bottom of the disconnect. + return PandaNode::get_top_component(_node, true); + } + return result; }