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  */
68 void PortalClipper::
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  */
83 void PortalClipper::
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  */
103 void PortalClipper::
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  */
130 void PortalClipper::
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  */
144 void PortalClipper::
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  */
202 bool PortalClipper::
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 }
A basic node of the scene graph or data graph.
Definition: pandaNode.h:64
This object provides a high-level interface for quickly writing a sequence of numeric values from a v...
Indicates a coordinate-system transform on vertices.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
bool prepare_portal(const NodePath &node_path)
Given the portal draw the frustum with line segs for now.
A base class for any number of different kinds of lenses, linear and otherwise.
Definition: lens.h:41
Defines a series of disconnected points.
Definition: geomPoints.h:23
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
static const GeomVertexFormat * get_v3cp()
Returns a standard vertex format with a packed color and a 3-component vertex position.
void draw_lines()
Draw all the lines in the buffer Cyan portal is the original geometry of the portal Yellow portal is ...
bool is_facing_view(const LPlane &portal_plane)
checks if the portal plane (in camera space) is facing the camera's near plane
const Lens * get_lens() const
Returns the particular Lens used for rendering.
Definition: sceneSetup.I:131
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void draw_current_portal()
_portal_node is the current portal, draw it.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
get_mat
Returns the matrix that describes the transform.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This is our own Panda specialization on the default STL vector.
Definition: pvector.h:42
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void draw_hexahedron(BoundingHexahedron *frustum)
Given the BoundingHexahedron draw it using lines.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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
This is another abstract class, for a general class of bounding volumes that actually enclose points ...
A node in the scene graph that can hold a Portal Polygon, which is a rectangle.
Definition: portalNode.h:30
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This defines the actual numeric vertex data stored in a Geom, in the structure defined by a particula...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
A container for geometry primitives.
Definition: geom.h:54
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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.
get_coordinate_system
Returns the coordinate system that all 3-d computations are performed within for this Lens.
Definition: lens.h:74
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
const NodePath & get_cull_center() const
Returns the point from which the culling operations will be performed.
Definition: sceneSetup.I:161
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
PandaNode * node() const
Returns the referenced node of the path.
Definition: nodePath.I:227
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
Defines a series of line strips.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
bool is_of_type(TypeHandle handle) const
Returns true if the current object is or derives from the indicated type.
Definition: typedObject.I:28
get_point
Returns the nth vertex of the hexahedron.
get_vertex
Returns the nth vertex of the portal polygon.
Definition: portalNode.h:67
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
const TransformState * get_transform(Thread *current_thread=Thread::get_current_thread()) const
Returns the complete transform object set on this node.
Definition: nodePath.cxx:758
This object holds the camera position, etc., and other general setup information for rendering a part...
Definition: sceneSetup.h:32
NodePath is the fundamental system for disambiguating instances, and also provides a higher-level int...
Definition: nodePath.h:161
A node that holds Geom objects, renderable pieces of geometry.
Definition: geomNode.h:34
This defines a bounding convex hexahedron.