mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-01 01:07:51 -04:00
PortalNode contributions by Erik Pojar
This commit is contained in:
parent
81c2514bc4
commit
fd305329c7
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
*/
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user