Panda3D
portalClipper.cxx
Go to the documentation of this file.
1 /**
2  * PANDA 3D SOFTWARE
3  * Copyright (c) Carnegie Mellon University. All rights reserved.
4  *
5  * All use of this software is subject to the terms of the revised BSD
6  * license. You should have received a copy of this license along
7  * with this source code in a file named "LICENSE."
8  *
9  * @file portalClipper.cxx
10  * @author masad
11  * @date 2004-05-04
12  */
13 
14 #include "portalClipper.h"
15 #include "cullTraverser.h"
16 #include "cullTraverserData.h"
17 #include "transformState.h"
18 #include "renderState.h"
19 #include "fogAttrib.h"
20 #include "cullHandler.h"
21 #include "dcast.h"
22 #include "geomNode.h"
23 #include "config_pgraph.h"
24 #include "boundingSphere.h"
25 #include "colorAttrib.h"
26 #include "renderModeAttrib.h"
27 #include "cullFaceAttrib.h"
28 #include "depthOffsetAttrib.h"
29 #include "geomVertexWriter.h"
30 #include "geomLinestrips.h"
31 #include "geomPoints.h"
32 
33 using std::endl;
34 using std::max;
35 using std::min;
36 
37 TypeHandle PortalClipper::_type_handle;
38 
39 /**
40  *
41  */
42 PortalClipper::
43 PortalClipper(GeometricBoundingVolume *frustum, SceneSetup *scene_setup):
44 _reduced_viewport_min(-1,-1),
45 _reduced_viewport_max(1,1),
46 _clip_state(nullptr)
47 {
48  _previous = new GeomNode("my_frustum");
49 
50  _view_frustum = _reduced_frustum = DCAST(BoundingHexahedron, frustum);
51 
52 
53  _scene_setup = scene_setup;
54 }
55 
56 /**
57  *
58  */
59 PortalClipper::
60 ~PortalClipper() {
61 }
62 
63 /**
64  * Moves the pen to the given point without drawing a line. When followed by
65  * draw_to(), this marks the first point of a line segment; when followed by
66  * move_to() or create(), this creates a single point.
67  */
69 move_to(const LVecBase3 &v) {
70  // We create a new SegmentList with the initial point in it.
71  SegmentList segs;
72  segs.push_back(Point(v, _color));
73 
74  // And add this list to the list of segments.
75  _list.push_back(segs);
76 }
77 
78 /**
79  * Draws a line segment from the pen's last position (the last call to move_to
80  * or draw_to) to the indicated point. move_to() and draw_to() only update
81  * tables; the actual drawing is performed when create() is called.
82  */
84 draw_to(const LVecBase3 &v) {
85  if (_list.empty()) {
86  // Let our first call to draw_to() be an implicit move_to().
87  move_to(v);
88 
89  } else {
90  // Get the current SegmentList, which was the last one we added to the
91  // LineList.
92  SegmentList &segs = _list.back();
93 
94  // Add the new point.
95  segs.push_back(Point(v, _color));
96  }
97 }
98 
99 /**
100  * Given the BoundingHexahedron draw it using lines
101  *
102  */
105  // walk the view frustum as it should be drawn
106  move_to(frustum->get_point(0));
107  draw_to(frustum->get_point(1));
108  draw_to(frustum->get_point(2));
109  draw_to(frustum->get_point(3));
110 
111  move_to(frustum->get_point(4));
112  draw_to(frustum->get_point(0));
113  draw_to(frustum->get_point(3));
114  draw_to(frustum->get_point(7));
115 
116  move_to(frustum->get_point(5));
117  draw_to(frustum->get_point(4));
118  draw_to(frustum->get_point(7));
119  draw_to(frustum->get_point(6));
120 
121  move_to(frustum->get_point(1));
122  draw_to(frustum->get_point(5));
123  draw_to(frustum->get_point(6));
124  draw_to(frustum->get_point(2));
125 }
126 /**
127  * _portal_node is the current portal, draw it.
128  *
129  */
132 {
133  move_to(_portal_node->get_vertex(0));
134  draw_to(_portal_node->get_vertex(1));
135  draw_to(_portal_node->get_vertex(2));
136  draw_to(_portal_node->get_vertex(3));
137 }
138 
139 /**
140  * Draw all the lines in the buffer Cyan portal is the original geometry of
141  * the portal Yellow portal is the AA minmax & clipped portal Blue frustum is
142  * the frustum through portal White frustum is the camera frustum
143  */
145 draw_lines() {
146  if (!_list.empty()) {
147  _created_data = nullptr;
148 
149  PT(GeomVertexData) vdata = new GeomVertexData
150  ("portal", GeomVertexFormat::get_v3cp(), Geom::UH_static);
151  GeomVertexWriter vertex(vdata, InternalName::get_vertex());
152  GeomVertexWriter color(vdata, InternalName::get_color());
153 
154  PT(GeomLinestrips) lines = new GeomLinestrips(Geom::UH_static);
155  PT(GeomPoints) points = new GeomPoints(Geom::UH_static);
156 
157  int v = 0;
158  LineList::const_iterator ll;
159  SegmentList::const_iterator sl;
160 
161  for (ll = _list.begin(); ll != _list.end(); ll++) {
162  const SegmentList &segs = (*ll);
163 
164  if (segs.size() < 2) {
165  // A segment of length 1 is just a point.
166  for (sl = segs.begin(); sl != segs.end(); sl++) {
167  points->add_vertex(v);
168  vertex.add_data3((*sl)._point);
169  color.add_data4((*sl)._color);
170  v++;
171  }
172  points->close_primitive();
173 
174  } else {
175  // A segment of length 2 or more is a line segment or segments.
176  for (sl = segs.begin(); sl != segs.end(); sl++) {
177  lines->add_vertex(v);
178  vertex.add_data3((*sl)._point);
179  color.add_data4((*sl)._color);
180  v++;
181  }
182  lines->close_primitive();
183  }
184  }
185 
186  if (lines->get_num_vertices() != 0) {
187  PT(Geom) geom = new Geom(vdata);
188  geom->add_primitive(lines);
189  _previous->add_geom(geom);
190  }
191  if (points->get_num_vertices() != 0) {
192  PT(Geom) geom = new Geom(vdata);
193  geom->add_primitive(points);
194  _previous->add_geom(geom);
195  }
196  }
197 }
198 /**
199  * Given the portal draw the frustum with line segs for now. More
200  * functionalities coming up
201  */
203 prepare_portal(const NodePath &node_path)
204 {
205  // Get the Portal Node from this node_path
206  PandaNode *node = node_path.node();
207  _portal_node = nullptr;
208  if (node->is_of_type(PortalNode::get_class_type())) {
209  _portal_node = DCAST(PortalNode, node);
210  }
211 
212  // Get the geometry from the portal
213  portal_cat.spam() << *_portal_node << endl;
214 
215  // Get the camera transformation matrix
216  CPT(TransformState) ctransform = node_path.get_transform(_scene_setup->get_cull_center());
217  // CPT(TransformState) ctransform =
218  // node_path.get_transform(_scene_setup->get_camera_path());
219  LMatrix4 cmat = ctransform->get_mat();
220  portal_cat.spam() << cmat << endl;
221 
222  LVertex temp[4];
223  temp[0] = _portal_node->get_vertex(0);
224  temp[1] = _portal_node->get_vertex(1);
225  temp[2] = _portal_node->get_vertex(2);
226  temp[3] = _portal_node->get_vertex(3);
227 
228  portal_cat.spam() << "before transformation to camera space" << endl;
229  portal_cat.spam() << temp[0] << endl;
230  portal_cat.spam() << temp[1] << endl;
231  portal_cat.spam() << temp[2] << endl;
232  portal_cat.spam() << temp[3] << endl;
233 
234  temp[0] = temp[0]*cmat;
235  temp[1] = temp[1]*cmat;
236  temp[2] = temp[2]*cmat;
237  temp[3] = temp[3]*cmat;
238 
239  LPlane portal_plane(temp[0], temp[1], temp[2]);
240  if (!is_facing_view(portal_plane)) {
241  portal_cat.debug() << "portal failed 1st level test (isn't facing the camera)\n";
242  return false;
243  }
244 
245  portal_cat.spam() << "after transformation to camera space" << endl;
246  portal_cat.spam() << temp[0] << endl;
247  portal_cat.spam() << temp[1] << endl;
248  portal_cat.spam() << temp[2] << endl;
249  portal_cat.spam() << temp[3] << endl;
250 
251  // check if the portal intersects with the cameras 0 point (center of
252  // projection). In that case the portal will invert itself. portals
253  // intersecting the near plane or the 0 point are a weird case anyhow,
254  // therefore we don't reduce the frustum any further and just return true.
255  // In effect the portal doesn't reduce visibility but will draw everything
256  // in its out cell
257  const Lens *lens = _scene_setup->get_lens();
258  LVector3 forward = LVector3::forward(lens->get_coordinate_system());
259  int forward_axis;
260  if (forward[1]) {
261  forward_axis = 1;
262  }
263  else if (forward[2]) {
264  forward_axis = 2;
265  }
266  else {
267  forward_axis = 0;
268  }
269  if ((temp[0][forward_axis] * forward[forward_axis] <= 0) ||
270  (temp[1][forward_axis] * forward[forward_axis] <= 0) ||
271  (temp[2][forward_axis] * forward[forward_axis] <= 0) ||
272  (temp[3][forward_axis] * forward[forward_axis] <= 0)) {
273  portal_cat.debug() << "portal intersects with center of projection.." << endl;
274  return true;
275  }
276 
277  // project portal points, so they are in the -1..1 range
278  LPoint3 projected_coords[4];
279  lens->project(temp[0], projected_coords[0]);
280  lens->project(temp[1], projected_coords[1]);
281  lens->project(temp[2], projected_coords[2]);
282  lens->project(temp[3], projected_coords[3]);
283 
284  portal_cat.spam() << "after projection to 2d" << endl;
285  portal_cat.spam() << projected_coords[0] << endl;
286  portal_cat.spam() << projected_coords[1] << endl;
287  portal_cat.spam() << projected_coords[2] << endl;
288  portal_cat.spam() << projected_coords[3] << endl;
289 
290  // calculate axis aligned bounding box of the portal
291  PN_stdfloat min_x, max_x, min_y, max_y;
292  min_x = min(min(min(projected_coords[0][0], projected_coords[1][0]), projected_coords[2][0]), projected_coords[3][0]);
293  max_x = max(max(max(projected_coords[0][0], projected_coords[1][0]), projected_coords[2][0]), projected_coords[3][0]);
294  min_y = min(min(min(projected_coords[0][1], projected_coords[1][1]), projected_coords[2][1]), projected_coords[3][1]);
295  max_y = max(max(max(projected_coords[0][1], projected_coords[1][1]), projected_coords[2][1]), projected_coords[3][1]);
296 
297  portal_cat.spam() << "min_x " << min_x << ";max_x " << max_x << ";min_y " << min_y << ";max_y " << max_y << endl;
298 
299  // clip the minima and maxima against the viewport
300  min_x = max(min_x, _reduced_viewport_min[0]);
301  min_y = max(min_y, _reduced_viewport_min[1]);
302  max_x = min(max_x, _reduced_viewport_max[0]);
303  max_y = min(max_y, _reduced_viewport_max[1]);
304 
305  portal_cat.spam() << "after clipping: min_x " << min_x << ";max_x " << max_x << ";min_y " << min_y << ";max_y " << max_y << endl;
306 
307  if ((min_x >= max_x) || (min_y >= max_y)) {
308  portal_cat.debug() << "portal got clipped away \n";
309  return false;
310  }
311 
312  // here we know the portal is in view and we have its clipped extents
313  _reduced_viewport_min.set(min_x, min_y);
314  _reduced_viewport_max.set(max_x, max_y);
315 
316  // calculate the near and far points so we can construct a frustum
317  LPoint3 near_point[4];
318  LPoint3 far_point[4];
319  lens->extrude(LPoint2(min_x, min_y), near_point[0], far_point[0]);
320  lens->extrude(LPoint2(max_x, min_y), near_point[1], far_point[1]);
321  lens->extrude(LPoint2(max_x, max_y), near_point[2], far_point[2]);
322  lens->extrude(LPoint2(min_x, max_y), near_point[3], far_point[3]);
323 
324  // With these points, construct the new reduced frustum
325  _reduced_frustum = new BoundingHexahedron(far_point[0], far_point[1], far_point[2], far_point[3],
326  near_point[0], near_point[1], near_point[2], near_point[3]);
327 
328  portal_cat.debug() << *_reduced_frustum << endl;
329 
330  // do debug rendering, if requested
331  if (debug_portal_cull) {
332  // draw the reduced frustum
333  _color = LColor(0,0,1,1);
334  draw_hexahedron(DCAST(BoundingHexahedron, _reduced_frustum));
335 
336  // lets first add the clipped portal (in yellow)
337  _color = LColor(1,1,0,1);
338  move_to((near_point[0]*0.99+far_point[0]*0.01)); // I choose a point in the middle between near and far.. could also be some other z value..
339  draw_to((near_point[1]*0.99+far_point[1]*0.01));
340  draw_to((near_point[2]*0.99+far_point[2]*0.01));
341  draw_to((near_point[3]*0.99+far_point[3]*0.01));
342  draw_to((near_point[0]*0.99+far_point[0]*0.01));
343 
344  // ok, now lets add the original portal (in cyan)
345  _color = LColor(0,1,1,1);
346  move_to(temp[0]);
347  draw_to(temp[1]);
348  draw_to(temp[2]);
349  draw_to(temp[3]);
350  draw_to(temp[0]);
351  }
352 
353  return true;
354 }
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This defines a bounding convex hexahedron.
get_point
Returns the nth vertex of the hexahedron.
Defines a series of line strips.
A node that holds Geom objects, renderable pieces of geometry.
Definition: geomNode.h:34
Defines a series of disconnected points.
Definition: geomPoints.h:23
This defines the actual numeric vertex data stored in a Geom, in the structure defined by a particula...
static const GeomVertexFormat * get_v3cp()
Returns a standard vertex format with a packed color and a 3-component vertex position.
This object provides a high-level interface for quickly writing a sequence of numeric values from a v...
void add_data4(PN_stdfloat x, PN_stdfloat y, PN_stdfloat z, PN_stdfloat w)
Sets the write row to a particular 4-component value, and advances the write row.
void add_data3(PN_stdfloat x, PN_stdfloat y, PN_stdfloat z)
Sets the write row to a particular 3-component value, and advances the write row.
A container for geometry primitives.
Definition: geom.h:54
This is another abstract class, for a general class of bounding volumes that actually enclose points ...
A base class for any number of different kinds of lenses, linear and otherwise.
Definition: lens.h:41
bool project(const LPoint3 &point3d, LPoint3 &point2d) const
Given a 3-d point in space, determine the 2-d point this maps to, in the range (-1,...
Definition: lens.I:131
bool extrude(const LPoint2 &point2d, LPoint3 &near_point, LPoint3 &far_point) const
Given a 2-d point in the range (-1,1) in both dimensions, where (0,0) is the center of the lens and (...
Definition: lens.I:24
get_coordinate_system
Returns the coordinate system that all 3-d computations are performed within for this Lens.
Definition: lens.h:74
NodePath is the fundamental system for disambiguating instances, and also provides a higher-level int...
Definition: nodePath.h:159
PandaNode * node() const
Returns the referenced node of the path.
Definition: nodePath.I:227
const TransformState * get_transform(Thread *current_thread=Thread::get_current_thread()) const
Returns the complete transform object set on this node.
Definition: nodePath.cxx:795
A basic node of the scene graph or data graph.
Definition: pandaNode.h:65
void move_to(PN_stdfloat x, PN_stdfloat y, PN_stdfloat z)
Moves the pen to the given point without drawing a line.
Definition: portalClipper.I:56
void draw_current_portal()
_portal_node is the current portal, draw it.
bool is_facing_view(const LPlane &portal_plane)
checks if the portal plane (in camera space) is facing the camera's near plane
void draw_hexahedron(BoundingHexahedron *frustum)
Given the BoundingHexahedron draw it using lines.
void draw_to(PN_stdfloat x, PN_stdfloat y, PN_stdfloat z)
Draws a line segment from the pen's last position (the last call to move_to or draw_to) to the indica...
Definition: portalClipper.I:66
void draw_lines()
Draw all the lines in the buffer Cyan portal is the original geometry of the portal Yellow portal is ...
bool prepare_portal(const NodePath &node_path)
Given the portal draw the frustum with line segs for now.
A node in the scene graph that can hold a Portal Polygon, which is a rectangle.
Definition: portalNode.h:30
get_vertex
Returns the nth vertex of the portal polygon.
Definition: portalNode.h:67
This object holds the camera position, etc., and other general setup information for rendering a part...
Definition: sceneSetup.h:32
const Lens * get_lens() const
Returns the particular Lens used for rendering.
Definition: sceneSetup.I:131
const NodePath & get_cull_center() const
Returns the point from which the culling operations will be performed.
Definition: sceneSetup.I:161
Indicates a coordinate-system transform on vertices.
get_mat
Returns the matrix that describes the transform.
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
bool is_of_type(TypeHandle handle) const
Returns true if the current object is or derives from the indicated type.
Definition: typedObject.I:28
This is our own Panda specialization on the default STL vector.
Definition: pvector.h:42
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.