PortalNode contributions by Erik Pojar

This commit is contained in:
David Rose 2009-09-28 11:51:01 +00:00
parent 81c2514bc4
commit fd305329c7
8 changed files with 252 additions and 432 deletions

View File

@ -118,11 +118,12 @@ ConfigVariableBool allow_portal_cull
"renderer to cull more objects that are clipped if not in the "
"current list of portals. This is still somewhat experimental."));
ConfigVariableBool show_portal_debug
("show-portal-debug", true,
PRC_DESC("Set this true to show debug lines for portals. This will draw "
"lines from the screen corners to the portal corners, this can "
"be useful when debugging."));
ConfigVariableBool debug_portal_cull
("debug-portal-cull", false,
PRC_DESC("Set this true to enable debug visualization during portal clipping."
"(You first need to enable portal culling, using the allow-portal-cull"
"variable.)"));
ConfigVariableBool unambiguous_graph
("unambiguous-graph", false,

View File

@ -33,7 +33,7 @@ NotifyCategoryDecl(portal, EXPCL_PANDA_PGRAPH, EXPTP_PANDA_PGRAPH);
extern ConfigVariableBool fake_view_frustum_cull;
extern ConfigVariableBool clip_plane_cull;
extern ConfigVariableBool allow_portal_cull;
extern ConfigVariableBool show_portal_debug;
extern ConfigVariableBool debug_portal_cull;
extern ConfigVariableBool unambiguous_graph;
extern ConfigVariableBool detect_graph_cycles;
extern ConfigVariableBool no_unsupported_copy;

View File

@ -121,7 +121,8 @@ traverse(const NodePath &root) {
if (allow_portal_cull) {
// This _view_frustum is in cull_center space
PT(GeometricBoundingVolume) vf = _view_frustum;
//Erik: obsolete?
//PT(GeometricBoundingVolume) vf = _view_frustum;
GeometricBoundingVolume *local_frustum = NULL;
PT(BoundingVolume) bv = _scene_setup->get_lens()->make_bounds();
@ -133,7 +134,7 @@ traverse(const NodePath &root) {
// This local_frustum is in camera space
PortalClipper portal_viewer(local_frustum, _scene_setup);
if (show_portal_debug) {
if (debug_portal_cull) {
portal_viewer.draw_camera_frustum();
}
@ -147,7 +148,7 @@ traverse(const NodePath &root) {
traverse(data);
// Finally add the lines to be drawn
if (show_portal_debug) {
if (debug_portal_cull) {
portal_viewer.draw_lines();
}

View File

@ -117,6 +117,56 @@ INLINE BoundingHexahedron *PortalClipper::
get_reduced_frustum() const {
return _reduced_frustum;
}
////////////////////////////////////////////////////////////////////
// Function: PortalClipper::set_clip_state
// Access: Public
// Description: Set the clip state of the current portal node
// This is done to remember the state for the child portal nodes
//
////////////////////////////////////////////////////////////////////
INLINE void PortalClipper::
set_clip_state(const RenderState* clip_state) {
_clip_state = clip_state;
}
////////////////////////////////////////////////////////////////////
// Function: PortalClipper::get_clip_state
// Access: Published
// Description: Returns the stored clip state
////////////////////////////////////////////////////////////////////
INLINE const RenderState *PortalClipper::
get_clip_state() const {
return _clip_state;
}
////////////////////////////////////////////////////////////////////
// Function: PortalClipper::set_reduced_viewport
// Access: Public
// Description: Set the current viewport that is being used
// by the portal clipper
//
////////////////////////////////////////////////////////////////////
INLINE void PortalClipper::
set_reduced_viewport(const LPoint2f& min, const LPoint2f& max) {
_reduced_viewport_min = min;
_reduced_viewport_max = max;
}
////////////////////////////////////////////////////////////////////
// Function: PortalClipper::get_reduced_viewport
// Access: Published
// Description: Return the reduced viewport
////////////////////////////////////////////////////////////////////
INLINE void PortalClipper::
get_reduced_viewport(LPoint2f& min, LPoint2f& max) const {
min = _reduced_viewport_min;
max = _reduced_viewport_max;
}
////////////////////////////////////////////////////////////////////
// Function: PortalClipper::is_facing_view
// Access: Public
@ -159,6 +209,7 @@ is_whole_portal_in_view(LMatrix4f cmat) {
return (result != 0);
}
/*
////////////////////////////////////////////////////////////////////
// Function: PortalClipper::is_partial_portal_in_view
// Access: Public
@ -178,7 +229,9 @@ is_partial_portal_in_view() {
return (result != 0);
}
*/
/*
////////////////////////////////////////////////////////////////////
// Function: PortalClipper::get_plane_depth
// Access: Public
@ -199,3 +252,4 @@ get_plane_depth(float x, float z, Planef *portal_plane) {
}
return y;
}
*/

View File

@ -39,11 +39,16 @@ TypeHandle PortalClipper::_type_handle;
// Description:
////////////////////////////////////////////////////////////////////
PortalClipper::
PortalClipper(GeometricBoundingVolume *frustum, SceneSetup *scene_setup) {
PortalClipper(GeometricBoundingVolume *frustum, SceneSetup *scene_setup):
_reduced_viewport_min(-1,-1),
_reduced_viewport_max(1,1),
_clip_state(0)
{
_previous = new GeomNode("my_frustum");
_view_frustum = _reduced_frustum = DCAST(BoundingHexahedron, frustum);
_scene_setup = scene_setup;
}
@ -142,13 +147,13 @@ draw_current_portal()
draw_to(_portal_node->get_vertex(2));
draw_to(_portal_node->get_vertex(3));
}
////////////////////////////////////////////////////////////////////
// Function: PortalClipper::draw the lines
// Access: Public
// Description: Draw all the lines in the buffer
// Yellow portal is the original geometry of the portal
// Cyan portal is the minmax adjusted portal
// Red portal is the clipped against frustum portal
// Cyan portal is the original geometry of the portal
// Yellow portal is the AA minmax & clipped portal
// Blue frustum is the frustum through portal
// White frustum is the camera frustum
////////////////////////////////////////////////////////////////////
@ -213,33 +218,19 @@ draw_lines() {
// Description: Given the portal draw the frustum with line segs
// for now. More functionalities coming up
////////////////////////////////////////////////////////////////////
void PortalClipper::
bool PortalClipper::
prepare_portal(const NodePath &node_path)
{
SegmentList segs;
// Get the Portal Node from this node_path
PandaNode *node = node_path.node();
_portal_node = NULL;
if (node->is_of_type(PortalNode::get_class_type())) {
_portal_node = DCAST(PortalNode, node);
// lets draw the portal anyway
//draw_current_portal();
}
// walk the portal
_num_vert = 0;
// Get the geometry from the portal
portal_cat.spam() << *_portal_node << endl;
/*
// Get the World transformation matrix
CPT(TransformState) wtransform = portal_nodepath.get_transform(_scene_setup->get_scene_root());
LMatrix4f wmat = wtransform->get_mat();
portal_cat.spam() << wmat << endl;
*/
// Get the camera transformation matrix
CPT(TransformState) ctransform = node_path.get_transform(_scene_setup->get_cull_center());
//CPT(TransformState) ctransform = node_path.get_transform(_scene_setup->get_camera_path());
@ -265,8 +256,8 @@ prepare_portal(const NodePath &node_path)
Planef portal_plane(temp[0], temp[1], temp[2]);
if (!is_facing_view(portal_plane)) {
portal_cat.debug() << "portal failed 1st level test \n";
return;
portal_cat.debug() << "portal failed 1st level test (isn't facing the camera)\n";
return false;
}
portal_cat.spam() << "after transformation to camera space" << endl;
@ -274,309 +265,92 @@ prepare_portal(const NodePath &node_path)
portal_cat.spam() << temp[1] << endl;
portal_cat.spam() << temp[2] << endl;
portal_cat.spam() << temp[3] << endl;
// check if the portal intersects with the cameras 0 point (center of projection). In that case the portal will invert itself.
// portals intersecting the near plane or the 0 point are a weird case anyhow, therefore we don't reduce the frustum any further
// and just return true. In effect the portal doesn't reduce visibility but will draw everything in its out cell
if ((temp[0][1] <= 0) || (temp[1][1] <= 0) || (temp[2][1] <= 0) || (temp[3][1] <= 0)) {
portal_cat.debug() << "portal intersects with center of projection.." << endl;
return true;
}
float min_x, max_x, min_z, max_z;
// project portal points, so they are in the -1..1 range
LPoint3f projected_coords[4];
const Lens *lens = _scene_setup->get_lens();
lens->project(temp[0], projected_coords[0]);
lens->project(temp[1], projected_coords[1]);
lens->project(temp[2], projected_coords[2]);
lens->project(temp[3], projected_coords[3]);
min_x = min(min(min(temp[0][0], temp[1][0]), temp[2][0]), temp[3][0]);
max_x = max(max(max(temp[0][0], temp[1][0]), temp[2][0]), temp[3][0]);
min_z = min(min(min(temp[0][2], temp[1][2]), temp[2][2]), temp[3][2]);
max_z = max(max(max(temp[0][2], temp[1][2]), temp[2][2]), temp[3][2]);
portal_cat.spam() << "after projection to 2d" << endl;
portal_cat.spam() << projected_coords[0] << endl;
portal_cat.spam() << projected_coords[1] << endl;
portal_cat.spam() << projected_coords[2] << endl;
portal_cat.spam() << projected_coords[3] << endl;
portal_cat.spam() << "min_x " << min_x << ";max_x " << max_x << ";min_z " << min_z << ";max_z " << max_z << endl;
// calculate axis aligned bounding box of the portal
float min_x, max_x, min_y, max_y;
min_x = min(min(min(projected_coords[0][0], projected_coords[1][0]), projected_coords[2][0]), projected_coords[3][0]);
max_x = max(max(max(projected_coords[0][0], projected_coords[1][0]), projected_coords[2][0]), projected_coords[3][0]);
min_y = min(min(min(projected_coords[0][1], projected_coords[1][1]), projected_coords[2][1]), projected_coords[3][1]);
max_y = max(max(max(projected_coords[0][1], projected_coords[1][1]), projected_coords[2][1]), projected_coords[3][1]);
float y;
portal_cat.spam() << "min_x " << min_x << ";max_x " << max_x << ";min_y " << min_y << ";max_y " << max_y << endl;
y = get_plane_depth(min_x, min_z, &portal_plane);
portal_cat.spam() << "plane's depth is " << y << endl;
_coords[0].set(min_x, y, min_z);
// clip the minima and maxima against the viewport
min_x = max(min_x, _reduced_viewport_min[0]);
min_y = max(min_y, _reduced_viewport_min[1]);
max_x = min(max_x, _reduced_viewport_max[0]);
max_y = min(max_y, _reduced_viewport_max[1]);
y = get_plane_depth(max_x, min_z, &portal_plane);
portal_cat.spam() << "plane's depth is " << y << endl;
_coords[1].set(max_x, y, min_z);
portal_cat.spam() << "after clipping: min_x " << min_x << ";max_x " << max_x << ";min_y " << min_y << ";max_y " << max_y << endl;
y = get_plane_depth(max_x, max_z, &portal_plane);
portal_cat.spam() << "plane's depth is " << y << endl;
_coords[2].set(max_x, y, max_z);
if ((min_x >= max_x) || (min_y >= max_y)) {
portal_cat.debug() << "portal got clipped away \n";
return false;
}
y = get_plane_depth(min_x, max_z, &portal_plane);
portal_cat.spam() << "plane's depth is " << y << endl;
_coords[3].set(min_x, y, max_z);
portal_cat.spam() << "after min max calculation" << endl;
portal_cat.spam() << _coords[0] << endl;
portal_cat.spam() << _coords[1] << endl;
portal_cat.spam() << _coords[2] << endl;
portal_cat.spam() << _coords[3] << endl;
// here we know the portal is in view and we have its clipped extents
_reduced_viewport_min.set(min_x, min_y);
_reduced_viewport_max.set(max_x, max_y);
// check if portal is in view
if (is_whole_portal_in_view(cmat)) {
// ok, now lets add the original portal
// calculate the near and far points so we can construct a frustum
LPoint3f near_point[4];
LPoint3f far_point[4];
lens->extrude(LPoint2f(min_x, min_y), near_point[0], far_point[0]);
lens->extrude(LPoint2f(max_x, min_y), near_point[1], far_point[1]);
lens->extrude(LPoint2f(max_x, max_y), near_point[2], far_point[2]);
lens->extrude(LPoint2f(min_x, max_y), near_point[3], far_point[3]);
// With these points, construct the new reduced frustum
_reduced_frustum = new BoundingHexahedron(far_point[0], far_point[1], far_point[2], far_point[3],
near_point[0], near_point[1], near_point[2], near_point[3]);
portal_cat.debug() << *_reduced_frustum << endl;
// do debug rendering, if requested
if (debug_portal_cull) {
// draw the reduced frustum
_color = Colorf(0,0,1,1);
draw_hexahedron(DCAST(BoundingHexahedron, _reduced_frustum));
// lets first add the clipped portal (in yellow)
_color = Colorf(1,1,0,1);
move_to((near_point[0]+far_point[0])/2.0); // I choose a point in the middle between near and far.. could also be some other z value..
draw_to((near_point[1]+far_point[1])/2.0);
draw_to((near_point[2]+far_point[2])/2.0);
draw_to((near_point[3]+far_point[3])/2.0);
draw_to((near_point[0]+far_point[0])/2.0);
// ok, now lets add the original portal (in cyan)
_color = Colorf(0,1,1,1);
move_to(temp[0]);
draw_to(temp[1]);
draw_to(temp[2]);
draw_to(temp[3]);
draw_to(temp[0]);
// ok, now lets add the min_max portal
_color = Colorf(1,1,0,1);
move_to(_coords[0]);
draw_to(_coords[1]);
draw_to(_coords[2]);
draw_to(_coords[3]);
draw_to(_coords[0]);
portal_cat.spam() << "assembled " << _portal_node->get_name() << ": frustum points" << endl;
_num_vert = _portal_node->get_num_vertices();
}
else
portal_cat.debug() << "portal failed 2nd level test \n";
return true;
}
////////////////////////////////////////////////////////////////////
// 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(const NodePath &node_path)
{
if (!_num_vert)
return;
// ViewFrustum -> Logical Planes -> Portal Edge
// Plane0 -> far plane -> None
// plane5 -> near plane -> None
// Plane1 -> bottom plane -> 0-1
// Plane3 -> top plane -> 1-2
// Plane2 -> right plane -> 2-3
// Plane4 -> left plane -> 3-0
int j;
float t;
Planef plane;
bool is_intersect;
unsigned int xect=0;
LPoint3f from_origin;
LPoint3f cut_point;
LVector3f from_direction;
// Look for intersection with the view frustum's bottom_plane and portal edges
plane = _reduced_frustum->get_plane(1);
for (j=0; j<_num_vert; ++j) {
from_origin = _coords[j];
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)) {
xect |= 1 << 0;
portal_cat.debug() << "bottom plane intersected segment " << j << "->"
<< (j+1)%_num_vert << " at t=" << t << endl;
cut_point = from_origin + t*from_direction;
portal_cat.spam() << "cut_point: " << cut_point << endl;
if (j == 1) {
// means bottom should cut 1->2 by moving 1 to the intersection point
_coords[1] = cut_point;
}
else if (j == 3) {
// means bottom should cut 3->0 by moving 0 to the intersection point
_coords[0] = cut_point;
}
else
portal_cat.debug() << "ignored for now for simplicity \n";
}
else
portal_cat.spam() << "is_intersect: " << is_intersect << " at t = " << t << endl;
}
// Look for intersection with the view frustum's top_plane and portal edges
plane = _reduced_frustum->get_plane(3);
for (j=0; j<_num_vert; ++j) {
from_origin = _coords[j];
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)) {
xect |= 1 << 1;
portal_cat.debug() << "top plane intersected segment " << j << "->"
<< (j+1)%_num_vert << " at t=" << t << endl;
cut_point = from_origin + t*from_direction;
portal_cat.spam() << "cut_point: " << cut_point << endl;
if (j == 1) {
// means top should cut 1->2 by moving 2 to the intersection point
_coords[2] = cut_point;
}
else if (j == 3) {
// means top should cut 3->0 by moving 3 to the intersection point
_coords[3] = cut_point;
}
else
portal_cat.debug() << "ignored for now for simplicity \n";
}
else
portal_cat.spam() << "is_intersect: " << is_intersect << " at t = " << t << endl;
}
// Look for intersection with the view frustum's right_plane and portal edges
plane = _reduced_frustum->get_plane(2);
for (j=0; j<_num_vert; ++j) {
from_origin = _coords[j];
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)) {
xect |= 1 << 2;
portal_cat.debug() << "right plane intersected segment " << j << "->"
<< (j+1)%_num_vert << " at t=" << t << endl;
cut_point = from_origin + t*from_direction;
portal_cat.spam() << "cut_point: " << cut_point << endl;
if (j == 0) {
// means right should cut 0->1 by moving 1 to the intersection point
_coords[1] = cut_point;
}
else if (j == 2) {
// means right should cut 2->3 by moving 2 to the intersection point
_coords[2] = cut_point;
}
else
portal_cat.debug() << "ignored for now for simplicity \n";
}
else
portal_cat.spam() << "is_intersect: " << is_intersect << " at t = " << t << endl;
}
// Look for intersection with the view frustum's left_plane and portal edges
plane = _reduced_frustum->get_plane(4);
for (j=0; j<_num_vert; ++j) {
from_origin = _coords[j];
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)) {
xect |= 1 << 3;
portal_cat.debug() << "left plane intersected segment " << j << "->"
<< (j+1)%_num_vert << " at t=" << t << endl;
cut_point = from_origin + t*from_direction;
portal_cat.spam() << "cut_point: " << cut_point << endl;
if (j == 0) {
// means left should cut 0->1 by moving 0 to the intersection point
_coords[0] = cut_point;
}
else if (j == 2) {
// means left should cut 2->3 by moving 3 to the intersection point
_coords[3] = cut_point;
}
else
portal_cat.debug() << "ignored for now for simplicity \n";
}
else
portal_cat.spam() << "is_intersect: " << is_intersect << " at t = " << t << endl;
}
// ok, now lets add the clipped 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]);
// 3rd level test, more accurate to determine if the portal is worth visiting
portal_cat.debug() << "portal clipper flag: " << xect << endl;
if (xect == 0xf) { //if all four planes intersected the portal, it is visible
return;
}
if (!is_partial_portal_in_view()) {
portal_cat.debug() << "portal failed 3rd level test \n";
_num_vert = 0;
}
}
////////////////////////////////////////////////////////////////////
// Function: PortalClipper::get_reduced_frustum
// Access: Public
// Description: After clipping the portal, form the new sides and
// fill in the new frustum. Return the new frustum
////////////////////////////////////////////////////////////////////
PT(BoundingVolume) PortalClipper::
get_reduced_frustum(const NodePath &node_path)
{
// int num_planes = 6;
LPoint3f intersect_points[4];
// 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 NULL;
float t;
bool visible = true;
// find intersection of 7->3 with far
LPoint3f from_origin = _reduced_frustum->get_point(7);
LVector3f from_direction = _coords[3] - from_origin;
bool is_intersect = _reduced_frustum->get_plane(0).intersects_line(t, from_origin, from_direction);
if (is_intersect && t >= 0.0) { // has to be positive, else camera is not looking at the portal
portal_cat.spam() << "far plane intersected 7->3 at t=" << t << endl;
intersect_points[0] = from_origin + t*from_direction;
portal_cat.spam() << intersect_points[0] << endl;
}
else
visible = false;
// find intersection of 4->0 with far
from_origin = _reduced_frustum->get_point(4);
from_direction = _coords[0] - from_origin;
is_intersect = _reduced_frustum->get_plane(0).intersects_line(t, from_origin, from_direction);
if (is_intersect && t >= 0.0) { // has to be positive, else camera is not looking at the portal
portal_cat.spam() << "far plane intersected 4->0 at t=" << t << endl;
intersect_points[1] = from_origin + t*from_direction;
portal_cat.spam() << intersect_points[1] << endl;
}
else
visible = false;
// find intersection of 5->1 with far
from_origin = _reduced_frustum->get_point(5);
from_direction = _coords[1] - from_origin;
is_intersect = _reduced_frustum->get_plane(0).intersects_line(t, from_origin, from_direction);
if (is_intersect && t >= 0.0) { // has to be positive, else camera is not looking at the portal
portal_cat.spam() << "far plane intersected 5->1 at t=" << t << endl;
intersect_points[2] = from_origin + t*from_direction;
portal_cat.spam() << intersect_points[2] << endl;
}
else
visible = false;
// find intersection of 6->2 with far
from_origin = _reduced_frustum->get_point(6);
from_direction = _coords[2] - from_origin;
is_intersect = _reduced_frustum->get_plane(0).intersects_line(t, from_origin, from_direction);
if (is_intersect && t >= 0.0) { // has to be positive, else camera is not looking at the portal
portal_cat.spam() << "far plane intersected 6->2 at t=" << t << endl;
intersect_points[3] = from_origin + t*from_direction;
portal_cat.spam() << intersect_points[3] << endl;
}
else
visible = false;
if (!visible) {
portal_cat.spam() << "portal is not visible from current camera look at" << endl;
return NULL;
}
// 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],
_reduced_frustum->get_point(4), _reduced_frustum->get_point(5),
_reduced_frustum->get_point(6), _reduced_frustum->get_point(7));
portal_cat.debug() << *reduced_frustum << endl;
// draw this hexahedron
_color = Colorf(0,0,1,1);
draw_hexahedron(DCAST(BoundingHexahedron, reduced_frustum));
return reduced_frustum;
}

View File

@ -41,8 +41,6 @@ class CullTraverserData;
class CullableObject;
class NodePath;
//#define _FACING_THRESHOLD -0.7 //about 45 degrees with the camera
//#define _FACING_THRESHOLD -0.5 //about 60 degrees with the camera
#define _FACING_THRESHOLD 0.0 //about 90 degrees with the camera
////////////////////////////////////////////////////////////////////
@ -62,10 +60,8 @@ public:
INLINE bool is_facing_view(Planef portal_plane);
INLINE bool is_whole_portal_in_view(LMatrix4f cmat);
void prepare_portal(const NodePath &node_path);
void clip_portal(const NodePath &node_path);
PT(BoundingVolume) get_reduced_frustum(const NodePath &node_path);
bool prepare_portal(const NodePath &node_path);
void draw_lines();
INLINE void draw_camera_frustum();
void draw_hexahedron(BoundingHexahedron *frustum);
@ -78,10 +74,12 @@ public:
void draw_current_portal();
INLINE float get_plane_depth(float x, float z, Planef *portal_plane);
INLINE BoundingHexahedron *get_reduced_frustum() const;
INLINE void set_reduced_frustum(BoundingHexahedron *bh);
INLINE void get_reduced_viewport(LPoint2f& min, LPoint2f& max) const;
INLINE void set_reduced_viewport(const LPoint2f& min, const LPoint2f& max);
INLINE const RenderState* get_clip_state() const;
INLINE void set_clip_state(const RenderState* clip_state);
public:
static TypeHandle get_class_type() {
@ -122,11 +120,14 @@ private:
BoundingHexahedron *_view_frustum;
BoundingHexahedron *_reduced_frustum;
LPoint2f _reduced_viewport_min;
LPoint2f _reduced_viewport_max;
CPT(RenderState) _clip_state; // each portal node needs to know the clip state of its "parent" portal Node
PortalNode *_portal_node; // current working portal for dereference ease
int _num_vert;
Vertexf _coords[4];
//int _num_vert;
//Vertexf _coords[4];
public:
PT(GeomNode) _previous;

View File

@ -29,12 +29,6 @@
#include "plane.h"
/*
#ifndef CPPPARSER
#include "../collide/collisionPlane.h"
#endif
*/
TypeHandle PortalNode::_type_handle;
@ -146,32 +140,21 @@ preserve_name() const {
////////////////////////////////////////////////////////////////////
void PortalNode::
enable_clipping_planes() {
_top_plane_node = new PlaneNode("top");
NodePath top_plane_np = NodePath(this).attach_new_node(_top_plane_node);
_bottom_plane_node = new PlaneNode("bottom");
NodePath bottom_plane_np = NodePath(this).attach_new_node(_bottom_plane_node);
_left_plane_node = new PlaneNode("left");
NodePath left_plane_np = NodePath(this).attach_new_node(_left_plane_node);
_right_plane_node = new PlaneNode("right");
NodePath right_plane_np = NodePath(this).attach_new_node(_right_plane_node);
/*
// for debugging visialization, attach a collsion plane to left and right each
_left_coll_node = new CollisionNode("left_coll");
_left_coll_node->set_into_collide_mask(CollideMask::all_off());
// prepare a collision plane to be set later
PT(CollisionPlane) left_coll_plane = new CollisionPlane(Planef());
_left_coll_node->add_solid(left_coll_plane);
// attach it onto the _left_plane_np
left_plane_np.attach_new_node(_left_coll_node);
_right_coll_node = new CollisionNode("right_coll");
_right_coll_node->set_into_collide_mask(CollideMask::all_off());
// prepare a collision plane to be set later
PT(CollisionPlane) right_coll_plane = new CollisionPlane(Planef());
_right_coll_node->add_solid(right_coll_plane);
// attach it onto the _left_plane_np
right_plane_np.attach_new_node(_right_coll_node);
*/
CPT(RenderAttrib) plane_attrib = ClipPlaneAttrib::make();
plane_attrib = DCAST(ClipPlaneAttrib, plane_attrib)->add_on_plane(NodePath(top_plane_np));
plane_attrib = DCAST(ClipPlaneAttrib, plane_attrib)->add_on_plane(NodePath(bottom_plane_np));
plane_attrib = DCAST(ClipPlaneAttrib, plane_attrib)->add_on_plane(NodePath(left_plane_np));
plane_attrib = DCAST(ClipPlaneAttrib, plane_attrib)->add_on_plane(NodePath(right_plane_np));
@ -244,81 +227,97 @@ cull_callback(CullTraverser *trav, CullTraverserData &data) {
PortalClipper *portal_viewer = trav->get_portal_clipper();
set_visible(false);
if (is_open() && !_cell_out.is_empty() && portal_viewer) {
//CullTraverserData next_data(data, _cell_out);
portal_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()))) {
set_visible(true);
// This reduced frustum is in camera space
portal_cat.debug() << "got reduced frustum " << reduced_frustum << endl;
vf = DCAST(GeometricBoundingVolume, reduced_frustum);
// keep a copy of this reduced frustum
PT(BoundingHexahedron) new_bh = DCAST(BoundingHexahedron, vf->make_copy());
if (_clip_plane) {
// make a temp copy of this reduced frustum
PT(BoundingHexahedron) temp_bh = DCAST(BoundingHexahedron, vf->make_copy());
CPT(TransformState) ftransform =
_cell_in.get_net_transform()->invert_compose(portal_viewer->_scene_setup->get_cull_center().get_net_transform());
// remember old viewport and frustum, so we can restore them for the siblings. (it gets changed by the prepare_portal call)
LPoint2f old_reduced_viewport_min, old_reduced_viewport_max;
portal_viewer->get_reduced_viewport(old_reduced_viewport_min, old_reduced_viewport_max);
PT(BoundingHexahedron) old_bh = portal_viewer->get_reduced_frustum();
temp_bh->xform(ftransform->get_mat());
if (portal_viewer->prepare_portal(data._node_path.get_node_path())) {
if ((reduced_frustum = portal_viewer->get_reduced_frustum())) {
// remember current clip state, we might change it
CPT(RenderState) old_clip_state = portal_viewer->get_clip_state();
set_visible(true);
// The frustum is in camera space
vf = DCAST(GeometricBoundingVolume, reduced_frustum);
// set left/right clipping plane
_left_plane_node->set_plane(-temp_bh->get_plane(4)); // left plane of bh
_right_plane_node->set_plane(-temp_bh->get_plane(2));// right plane of bh
// create a copy of this reduced frustum, we'll transform it from camera space to the cell_out space
PT(BoundingHexahedron) new_bh = DCAST(BoundingHexahedron, vf->make_copy());
// Get the net trasform of the _cell_out as seen from the camera.
CPT(TransformState) cell_transform = _cell_out.get_net_transform();
CPT(TransformState) frustum_transform = cell_transform ->invert_compose(portal_viewer->_scene_setup->get_cull_center().get_net_transform());
/*
// set this plane at the collision plane too for debugging
((CollisionPlane*)_left_coll_node->get_solid(0))->set_plane(-temp_bh->get_plane(4));
((CollisionPlane*)_right_coll_node->get_solid(0))->set_plane(-temp_bh->get_plane(2));
*/
// transform to _cell_out space
new_bh->xform(frustum_transform->get_mat());
CPT(RenderState) next_state = data._state;
// set clipping planes, if desired..
if (_clip_plane) {
// create a copy of this reduced frustum, we'll transform it from camera space to this portal node's space (because the clip planes are attached to this node)
PT(BoundingHexahedron) temp_bh = DCAST(BoundingHexahedron, vf->make_copy());
CPT(TransformState) temp_frustum_transform = data._node_path.get_node_path().get_net_transform()->invert_compose(portal_viewer->_scene_setup->get_cull_center().get_net_transform());
portal_cat.spam() << "clipping plane frustum transform " << *temp_frustum_transform << endl;
portal_cat.spam() << "frustum before transform " << *temp_bh << endl;
// transform to portalNode space
temp_bh->xform(temp_frustum_transform->get_mat());
portal_cat.spam() << "frustum after transform " << *temp_bh << endl;
_left_plane_node->set_plane(-temp_bh->get_plane(4)); // left plane of bh
_right_plane_node->set_plane(-temp_bh->get_plane(2));// right plane of bh
_top_plane_node->set_plane(-temp_bh->get_plane(3)); // top plane of bh
_bottom_plane_node->set_plane(-temp_bh->get_plane(1));// bottom plane of bh
portal_cat.spam() << "left plane " << *_left_plane_node << endl;
portal_cat.spam() << "right plane " << *_right_plane_node << endl;
portal_cat.spam() << "top plane " << *_top_plane_node << endl;
portal_cat.spam() << "bottom plane " << *_bottom_plane_node << endl;
// remember the clip state we just generated
portal_viewer->set_clip_state(_clip_state);
if (old_clip_state) {
portal_cat.spam() << "parent clip state " << *old_clip_state << endl;
} else {
portal_cat.spam() << "parent clip state None" << endl;
}
portal_cat.spam() << "own clip state " << *_clip_state << endl;
portal_cat.spam() << "next state " << *next_state << endl;
// undo parent clip state and compose our new clip state ito the new state
if (old_clip_state != NULL) {
next_state = old_clip_state->invert_compose(next_state);
portal_cat.spam() << "next state after removing parent state " << *next_state << endl;
}
next_state = next_state->compose(_clip_state);
portal_cat.spam() << "next state after composition " << *next_state << endl;
}
CullTraverserData next_data(_cell_out,
cell_transform,
next_state, new_bh,
current_thread);
portal_viewer->set_reduced_frustum(new_bh);
portal_cat.spam() << "cull_callback: before traversing " << _cell_out.get_name() << endl;
trav->traverse_below(next_data);
portal_cat.spam() << "cull_callback: after traversing " << _cell_out.get_name() << endl;
// restore clip state
portal_viewer->set_clip_state(old_clip_state);
}
// Get the net trasform of the _cell_out as seen from the camera.
CPT(TransformState) cell_transform =
// trav->get_camera_transform()->invert_compose(_cell_out.get_net_transform());
_cell_out.get_net_transform();
CPT(TransformState) frustum_transform =
_cell_out.get_net_transform()->invert_compose(portal_viewer->_scene_setup->get_cull_center().get_net_transform());
new_bh->xform(frustum_transform->get_mat());
portal_cat.spam() << "new_bh is " << *new_bh << "\n";
CPT(RenderState) next_state = data._state;
// attach clipping state if there is any
if (_clip_plane) {
next_state = next_state->compose(_clip_state);
}
CullTraverserData next_data(_cell_out,
cell_transform,
next_state, new_bh,
current_thread);
// data._state, new_bh, NULL);
// Make this cell show with the reduced frustum
// _cell_out.show();
// all nodes visible through this portal, should have this node's frustum
PT(BoundingHexahedron) old_bh = portal_viewer->get_reduced_frustum();
portal_viewer->set_reduced_frustum(new_bh);
portal_cat.spam() << "cull_callback: before traversing " << _cell_out.get_name() << endl;
trav->traverse_below(next_data);
portal_cat.spam() << "cull_callback: after traversing " << _cell_out.get_name() << endl;
// make sure traverser is not drawing this node again
// _cell_out.hide();
// reset portal viewer frustum for the siblings;
portal_viewer->set_reduced_frustum(old_bh);
}
// reset portal viewer frustum for the siblings;
portal_viewer->set_reduced_frustum(old_bh);
// reset portal viewer viewport for the siblings;
portal_viewer->set_reduced_viewport(old_reduced_viewport_min, old_reduced_viewport_max);
}
// Now carry on to render our child nodes.
return true;

View File

@ -23,12 +23,6 @@
#include "nodePath.h"
#include "pvector.h"
/*
//#ifndef CPPPARSER
//#include "../collide/collisionSolid.h"
//#include "../collide/collisionNode.h"
//#endif
*/
////////////////////////////////////////////////////////////////////
// Class : PortalNode
// Description : A node in the scene graph that can hold a
@ -121,15 +115,11 @@ private:
NodePath _cell_out; // This is the cell it leads out to
// enable plane clipping on this portal
/*
#ifndef CPPPARSER
PT(CollisionNode) _left_coll_node; // for debugging visualization
PT(CollisionNode) _right_coll_node;// for debugging visualization
#endif
*/
bool _clip_plane;
PT(PlaneNode) _left_plane_node;
PT(PlaneNode) _right_plane_node;
PT(PlaneNode) _top_plane_node;
PT(PlaneNode) _bottom_plane_node;
CPT(RenderState) _clip_state;
bool _visible;