Recursive portal culling is implemented. This is the 3rd phase. There is one bug where portals are behaving weird when camera is right on the portal plane

This commit is contained in:
Asad M. Zaman 2004-06-07 23:40:20 +00:00
parent 9ede67f706
commit bd2a0ea086
4 changed files with 72 additions and 52 deletions

View File

@ -101,24 +101,43 @@ draw_camera_frustum() {
}
////////////////////////////////////////////////////////////////////
// Function: PortalClipper::set_reduced_frustum
// Function: PortalClipper::set_view_frustum
// Access: Public
// Description: set the current reduced frustum before traversing
// Description: set the current view frustum before traversing
//
////////////////////////////////////////////////////////////////////
INLINE void PortalClipper::
set_reduced_frustum(BoundingHexahedron *frustum) {
_reduced_frustum = frustum;
set_view_frustum(BoundingHexahedron *frustum) {
_view_frustum = frustum;
}
////////////////////////////////////////////////////////////////////
// Function: PortalClipper::is_in_view
// Function: PortalClipper::is_facing_view
// Access: Public
// Description: checks if the portal plane (in camera space)
// is facing the camera's near plane
////////////////////////////////////////////////////////////////////
INLINE bool PortalClipper::
is_facing_view(Planef portal_plane)
{
Planef view_plane(_view_frustum->get_point(4), _view_frustum->get_point(5), _view_frustum->get_point(6));
// use the view_frustum's near plane to calculate direction
pgraph_cat.debug() << portal_plane.get_normal() << "; " << -view_plane.get_normal() << endl;
float direction = portal_plane.get_normal().dot(-view_plane.get_normal());
pgraph_cat.debug() << "Found direction of " << direction << endl;
return (direction < _FACING_THRESHOLD);
}
////////////////////////////////////////////////////////////////////
// Function: PortalClipper::is_whole_portal_in_view
// Access: Public
// Description: checks if portal_node is within the view frustum.
// If so, then the portal is worth considering. This
// is a 1st level test to weed out most of the portals
////////////////////////////////////////////////////////////////////
INLINE bool PortalClipper::
is_in_view(const NodePath &node_path) {
is_whole_portal_in_view(const NodePath &node_path) {
const BoundingVolume *bv = &_portal_node->get_bound();
@ -130,27 +149,28 @@ is_in_view(const NodePath &node_path) {
CPT(TransformState) ctransform = node_path.get_transform(_scene_setup->get_cull_center());
gbv->xform(ctransform->get_mat());
int result = _reduced_frustum->contains(gbv);
pgraph_cat.debug() << "1st level test if portal is in view " << result << endl;
int result = _view_frustum->contains(gbv);
pgraph_cat.debug() << "1st level test if portal: " << *_view_frustum << " is in view " << result << endl;
return (result != 0);
}
////////////////////////////////////////////////////////////////////
// Function: PortalClipper::facing_camera
// Function: PortalClipper::is_partial_portal_in_view
// Access: Public
// Description: checks if any of the _coords is within the view frustum.
// If so, then the portal is facing the camera. 2nd level
// test to make sure this portal is worth visiting
////////////////////////////////////////////////////////////////////
INLINE bool PortalClipper::
is_facing_camera(const NodePath &node_path) {
is_partial_portal_in_view(const NodePath &node_path) {
int result = 0;
// check if the camera_center to portal_center lineseg is in view
// check if any of the _coords in tested frustum
for (int j=0; j<_num_vert; ++j) {
result |= _reduced_frustum->contains(_coords[j]);
result |= _view_frustum->contains(_coords[j]);
}
pgraph_cat.debug() << "frustum->contains(coord) result = " << result << endl;
pgraph_cat.debug() << "frustum: " << *_view_frustum << " contains(coord) result = " << result << endl;
return (result != 0);
}

View File

@ -47,7 +47,7 @@ PortalClipper(GeometricBoundingVolume *frustum, SceneSetup *scene_setup) {
_geom_point = new GeomPoint;
_geom_linestrip = new GeomLinestrip;
_view_frustum = _reduced_frustum = DCAST(BoundingHexahedron, frustum);
_view_frustum = DCAST(BoundingHexahedron, frustum);
_scene_setup = scene_setup;
}
@ -260,6 +260,10 @@ prepare_portal(const NodePath &node_path)
temp[2] = temp[2]*cmat;
temp[3] = temp[3]*cmat;
Planef portal_plane(temp[0], temp[1], temp[2]);
if (!is_facing_view(portal_plane))
return;
pgraph_cat.spam() << "after transformation to camera space" << endl;
pgraph_cat.spam() << temp[0] << endl;
pgraph_cat.spam() << temp[1] << endl;
@ -275,9 +279,6 @@ prepare_portal(const NodePath &node_path)
pgraph_cat.spam() << "min_x " << min_x << ";max_x " << max_x << ";min_z " << min_z << ";max_z " << max_z << endl;
Planef portal_plane(temp[0], temp[1], temp[2]);
float y;
y = get_plane_depth(min_x, min_z, &portal_plane);
@ -303,7 +304,7 @@ prepare_portal(const NodePath &node_path)
pgraph_cat.spam() << _coords[3] << endl;
// check if portal is in view
if (is_in_view(node_path)) {
if (is_whole_portal_in_view(node_path)) {
pgraph_cat.debug() << "portal passed 1st level test \n";
// ok, now lets add the original portal
@ -376,7 +377,7 @@ clip_portal(const NodePath &node_path)
from_direction = _coords[(j+1)%_num_vert] - _coords[j];
is_intersect = plane.intersects_line(t, from_origin, from_direction);
if (is_intersect && (t > 0.0 && t < 1.0)) {
pgraph_cat.debug() << "bottom plane intersected segement " << j << "->"
pgraph_cat.debug() << "bottom plane intersected segment " << j << "->"
<< (j+1)%_num_vert << " at t=" << t << endl;
cut_point = from_origin + t*from_direction;
pgraph_cat.debug() << "cut_point: " << cut_point << endl;
@ -400,7 +401,7 @@ clip_portal(const NodePath &node_path)
from_direction = _coords[(j+1)%_num_vert] - _coords[j];
is_intersect = plane.intersects_line(t, from_origin, from_direction);
if (is_intersect && (t > 0.0 && t < 1.0)) {
pgraph_cat.debug() << "top plane intersected segement " << j << "->"
pgraph_cat.debug() << "top plane intersected segment " << j << "->"
<< (j+1)%_num_vert << " at t=" << t << endl;
cut_point = from_origin + t*from_direction;
pgraph_cat.debug() << "cut_point: " << cut_point << endl;
@ -424,7 +425,7 @@ clip_portal(const NodePath &node_path)
from_direction = _coords[(j+1)%_num_vert] - _coords[j];
is_intersect = plane.intersects_line(t, from_origin, from_direction);
if (is_intersect && (t > 0.0 && t < 1.0)) {
pgraph_cat.debug() << "right plane intersected segement " << j << "->"
pgraph_cat.debug() << "right plane intersected segment " << j << "->"
<< (j+1)%_num_vert << " at t=" << t << endl;
cut_point = from_origin + t*from_direction;
pgraph_cat.debug() << "cut_point: " << cut_point << endl;
@ -448,7 +449,7 @@ clip_portal(const NodePath &node_path)
from_direction = _coords[(j+1)%_num_vert] - _coords[j];
is_intersect = plane.intersects_line(t, from_origin, from_direction);
if (is_intersect && (t > 0.0 && t < 1.0)) {
pgraph_cat.debug() << "left plane intersected segement " << j << "->"
pgraph_cat.debug() << "left plane intersected segment " << j << "->"
<< (j+1)%_num_vert << " at t=" << t << endl;
cut_point = from_origin + t*from_direction;
pgraph_cat.debug() << "cut_point: " << cut_point << endl;
@ -473,7 +474,7 @@ clip_portal(const NodePath &node_path)
draw_to(_coords[0]);
// 2nd level test, more accurate to determine if the portal is worth visiting
if (!is_facing_camera(node_path)) {
if (!is_partial_portal_in_view(node_path)) {
pgraph_cat.debug() << "portal failed 2nd level test \n";
_num_vert = 0;
}
@ -562,13 +563,11 @@ get_reduced_frustum(const NodePath &node_path)
_view_frustum->get_point(4), _view_frustum->get_point(5),
_view_frustum->get_point(6), _view_frustum->get_point(7));
pgraph_cat.spam() << *reduced_frustum << endl;
pgraph_cat.debug() << *reduced_frustum << endl;
// draw this hexahedron
_color = Colorf(0,0,1,1);
draw_hexahedron(DCAST(BoundingHexahedron, reduced_frustum));
_reduced_frustum = DCAST(BoundingHexahedron, reduced_frustum);
return reduced_frustum;
}

View File

@ -63,12 +63,12 @@ public:
PortalClipper(GeometricBoundingVolume *frustum, SceneSetup *scene_setup);
~PortalClipper();
INLINE bool is_in_view(const NodePath &node_path);
INLINE bool is_facing_camera(const NodePath &node_path);
INLINE bool is_whole_portal_in_view(const NodePath &node_path);
INLINE bool is_partial_portal_in_view(const NodePath &node_path);
INLINE bool is_facing_view(Planef portal_plane);
void prepare_portal(const NodePath &node_path);
void clip_portal(const NodePath &node_path);
PT(BoundingVolume) get_reduced_frustum(const NodePath &node_path);
void draw_lines();
@ -83,7 +83,7 @@ public:
INLINE float get_plane_depth(float x, float z, Planef *portal_plane);
INLINE void set_reduced_frustum(BoundingHexahedron *frustum);
INLINE void set_view_frustum(BoundingHexahedron *frustum);
public:
static TypeHandle get_class_type() {
@ -129,7 +129,6 @@ private:
PT(GeomLinestrip) _geom_linestrip;
BoundingHexahedron *_view_frustum;
BoundingHexahedron *_reduced_frustum;
PortalNode *_portal_node; // current working portal for dereference ease

View File

@ -48,7 +48,7 @@ PortalNode(const string &name) :
{
_zone_in = NULL;
_zone_out = NULL;
_visible = false;
_visible = true;
}
////////////////////////////////////////////////////////////////////
@ -65,7 +65,7 @@ PortalNode(const PortalNode &copy) :
{
_zone_in = NULL;
_zone_out = NULL;
_visible = false;
_visible = true;
}
////////////////////////////////////////////////////////////////////
@ -180,28 +180,30 @@ cull_callback(CullTraverser *trav, CullTraverserData &data) {
PortalClipper *portal_viewer = trav->get_portal_clipper();
if (!_zone_out.is_empty() && portal_viewer) {
//CullTraverserData next_data(data, _zone_out);
if (is_visible()) {
pgraph_cat.debug() << "portal node visible " << *this << endl;
PT(GeometricBoundingVolume) vf = trav->get_view_frustum();
PT(BoundingVolume) reduced_frustum;
pgraph_cat.debug() << "checking portal node " << *this << endl;
PT(GeometricBoundingVolume) vf = trav->get_view_frustum();
PT(BoundingVolume) reduced_frustum;
// following three functions do nothing, if the portal is not visible
portal_viewer->prepare_portal(data._node_path.get_node_path());
portal_viewer->clip_portal(data._node_path.get_node_path());
if ((reduced_frustum = portal_viewer->get_reduced_frustum(data._node_path.get_node_path()))) {
// This reduced frustum is in camera space
pgraph_cat.debug() << "got reduced frustum " << reduced_frustum << endl;
vf = DCAST(GeometricBoundingVolume, reduced_frustum);
portal_viewer->set_view_frustum(DCAST(BoundingHexahedron,vf->make_copy()));
// trasform it to cull_center space
CPT(TransformState) cull_center_transform =
portal_viewer->_scene_setup->get_cull_center().get_transform(_zone_out);
vf->xform(cull_center_transform->get_mat());
portal_viewer->prepare_portal(data._node_path.get_node_path());
portal_viewer->clip_portal(data._node_path.get_node_path());
if ((reduced_frustum = portal_viewer->get_reduced_frustum(data._node_path.get_node_path()))) {
// This reduced frustum is in camera space
pgraph_cat.debug() << "got reduced frustum " << reduced_frustum << endl;
vf = DCAST(GeometricBoundingVolume, reduced_frustum);
// trasform it to cull_center space
CPT(TransformState) cull_center_transform =
portal_viewer->_scene_setup->get_cull_center().get_transform(_zone_out);
vf->xform(cull_center_transform->get_mat());
}
pgraph_cat.spam() << "vf is " << *vf << "\n";
// Get the net trasform of the _zone_out
CPT(TransformState) zone_transform = _zone_out.get_net_transform();
CullTraverserData next_data(_zone_out, trav->get_render_transform()->compose(zone_transform),
zone_transform,
trav->get_initial_state(), vf,