first pass prototype of portal culling system

This commit is contained in:
Asad M. Zaman 2004-05-13 22:12:57 +00:00
parent c7cd81edcc
commit f1de5451a3
17 changed files with 868 additions and 10 deletions

View File

@ -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 \

View File

@ -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;
}

View File

@ -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;

View File

@ -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();

View File

@ -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;

View File

@ -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) {

View File

@ -33,8 +33,9 @@
class PandaNode;
class CullHandler;
class CullTraverserData;
class CullableObject;
class CullTraverserData;
class PortalClipper;
class NodePath;
////////////////////////////////////////////////////////////////////

View File

@ -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 &copy) :
_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 &copy) {
_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)
{
}

View File

@ -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());

View File

@ -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 &copy);
INLINE void operator = (const CullTraverserData &copy);
@ -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:

View File

@ -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"

119
panda/src/pgraph/portalClipper.I Executable file
View File

@ -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 &copy) :
_point(copy._point),
_color(copy._color)
{
}
////////////////////////////////////////////////////////////////////
// Function: PortalClipper::Point::Copy Assignment Operator
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE void PortalClipper::Point::
operator = (const PortalClipper::Point &copy) {
_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);
}

View File

@ -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; i<num_planes; ++i) {
Planef plane = _hex_frustum->get_plane(i);
plane.output(pgraph_cat.debug());
pgraph_cat.debug() << endl;
}
*/
for (int i=1; i<num_planes-1; ++i) {
Planef plane = _hex_frustum->get_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;
}

136
panda/src/pgraph/portalClipper.h Executable file
View File

@ -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 &copy);
INLINE void operator = (const Point &copy);
Vertexf _point;
Colorf _color;
};
typedef pvector<Point> SegmentList;
typedef pvector<SegmentList> 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

View File

@ -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

View File

@ -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;

View File

@ -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;
}