mirror of
https://github.com/panda3d/panda3d.git
synced 2025-09-30 16:58:40 -04:00
first pass prototype of portal culling system
This commit is contained in:
parent
c7cd81edcc
commit
f1de5451a3
@ -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 \
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
|
@ -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) {
|
||||
|
@ -33,8 +33,9 @@
|
||||
|
||||
class PandaNode;
|
||||
class CullHandler;
|
||||
class CullTraverserData;
|
||||
class CullableObject;
|
||||
class CullTraverserData;
|
||||
class PortalClipper;
|
||||
class NodePath;
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
@ -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)
|
||||
{
|
||||
}
|
||||
|
@ -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());
|
||||
|
@ -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:
|
||||
|
@ -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
119
panda/src/pgraph/portalClipper.I
Executable 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 ©) :
|
||||
_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);
|
||||
}
|
445
panda/src/pgraph/portalClipper.cxx
Executable file
445
panda/src/pgraph/portalClipper.cxx
Executable 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
136
panda/src/pgraph/portalClipper.h
Executable 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 ©);
|
||||
INLINE void operator = (const Point ©);
|
||||
|
||||
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
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user