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