Panda3D
collisionVisualizer.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 collisionVisualizer.cxx
10  * @author drose
11  * @date 2003-04-16
12  */
13 
14 #include "collisionVisualizer.h"
15 #include "collisionEntry.h"
16 #include "cullTraverser.h"
17 #include "cullTraverserData.h"
18 #include "cullableObject.h"
19 #include "cullHandler.h"
20 #include "renderState.h"
21 #include "renderModeAttrib.h"
22 #include "geomVertexData.h"
23 #include "geomVertexFormat.h"
24 #include "geomVertexArrayFormat.h"
25 #include "geom.h"
26 #include "geomPoints.h"
27 #include "geomLines.h"
28 #include "omniBoundingVolume.h"
29 #include "depthOffsetAttrib.h"
30 #include "colorScaleAttrib.h"
31 #include "transparencyAttrib.h"
32 #include "clipPlaneAttrib.h"
33 #include "geomVertexWriter.h"
34 
35 
36 #ifdef DO_COLLISION_RECORDING
37 
38 TypeHandle CollisionVisualizer::_type_handle;
39 
40 /**
41  *
42  */
43 CollisionVisualizer::
44 CollisionVisualizer(const std::string &name) : PandaNode(name), _lock("CollisionVisualizer") {
45  set_cull_callback();
46 
47  // We always want to render the CollisionVisualizer node itself (even if it
48  // doesn't appear to have any geometry within it).
49  set_internal_bounds(new OmniBoundingVolume());
50  _point_scale = 1.0f;
51  _normal_scale = 1.0f;
52 }
53 
54 /**
55  * Copy constructor.
56  */
57 CollisionVisualizer::
58 CollisionVisualizer(const CollisionVisualizer &copy) :
59  PandaNode(copy),
60  _lock("CollisionVisualizer"),
61  _point_scale(copy._point_scale),
62  _normal_scale(copy._normal_scale) {
63 
64  set_cull_callback();
65 
66  // We always want to render the CollisionVisualizer node itself (even if it
67  // doesn't appear to have any geometry within it).
68  set_internal_bounds(new OmniBoundingVolume());
69 }
70 
71 /**
72  *
73  */
74 CollisionVisualizer::
75 ~CollisionVisualizer() {
76 }
77 
78 /**
79  * Removes all the visualization data from a previous traversal and resets the
80  * visualizer to empty.
81  */
82 void CollisionVisualizer::
83 clear() {
84  LightMutexHolder holder(_lock);
85  _data.clear();
86 }
87 
88 /**
89  * Returns a newly-allocated Node that is a shallow copy of this one. It will
90  * be a different Node pointer, but its internal data may or may not be shared
91  * with that of the original Node.
92  */
93 PandaNode *CollisionVisualizer::
94 make_copy() const {
95  return new CollisionVisualizer(*this);
96 }
97 
98 /**
99  * This function will be called during the cull traversal to perform any
100  * additional operations that should be performed at cull time. This may
101  * include additional manipulation of render state or additional
102  * visible/invisible decisions, or any other arbitrary operation.
103  *
104  * Note that this function will *not* be called unless set_cull_callback() is
105  * called in the constructor of the derived class. It is necessary to call
106  * set_cull_callback() to indicated that we require cull_callback() to be
107  * called.
108  *
109  * By the time this function is called, the node has already passed the
110  * bounding-volume test for the viewing frustum, and the node's transform and
111  * state have already been applied to the indicated CullTraverserData object.
112  *
113  * The return value is true if this node should be visible, or false if it
114  * should be culled.
115  */
116 bool CollisionVisualizer::
117 cull_callback(CullTraverser *trav, CullTraverserData &data) {
118  // Now we go through and actually draw our visualized collision solids.
119 
120  LightMutexHolder holder(_lock);
121 
122  Data::const_iterator di;
123  for (di = _data.begin(); di != _data.end(); ++di) {
124  const TransformState *net_transform = (*di).first;
125  const VizInfo &viz_info = (*di).second;
126 
127  CullTraverserData xform_data(data);
128 
129  // We don't want to inherit the transform from above! We ignore whatever
130  // transforms were above the CollisionVisualizer node; it always renders
131  // its objects according to their appropriate net transform.
132  xform_data._net_transform = TransformState::make_identity();
133  xform_data._view_frustum = trav->get_view_frustum();
134  xform_data.apply_transform(net_transform);
135 
136  // Draw all the collision solids.
137  Solids::const_iterator si;
138  for (si = viz_info._solids.begin(); si != viz_info._solids.end(); ++si) {
139  // Note that we don't preserve the clip plane attribute from the
140  // collision solid. We always draw the whole polygon (or whatever) in
141  // the CollisionVisualizer. This is a deliberate decision; clipping the
142  // polygons may obscure many collision tests that are being made.
143  const CollisionSolid *solid = (*si).first;
144  const SolidInfo &solid_info = (*si).second;
145  bool was_detected = (solid_info._detected_count > 0);
146  PT(PandaNode) node = solid->get_viz(trav, xform_data, !was_detected);
147  if (node != nullptr) {
148  CullTraverserData next_data(xform_data, node);
149 
150  // We don't want to inherit the render state from above for these
151  // guys.
152  next_data._state = get_viz_state();
153  trav->traverse(next_data);
154  }
155  }
156 
157  // Now draw all of the detected points.
158  if (!viz_info._points.empty()) {
159  CPT(RenderState) empty_state = RenderState::make_empty();
160  CPT(RenderState) point_state = RenderState::make(RenderModeAttrib::make(RenderModeAttrib::M_unchanged, 1.0f, false));
161 
162  PT(GeomVertexArrayFormat) point_array_format =
163  new GeomVertexArrayFormat(InternalName::get_vertex(), 3,
164  Geom::NT_stdfloat, Geom::C_point,
165  InternalName::get_color(), 1,
166  Geom::NT_packed_dabc, Geom::C_color,
167  InternalName::get_size(), 1,
168  Geom::NT_stdfloat, Geom::C_other);
169  CPT(GeomVertexFormat) point_format =
170  GeomVertexFormat::register_format(point_array_format);
171 
172  Points::const_iterator pi;
173  for (pi = viz_info._points.begin(); pi != viz_info._points.end(); ++pi) {
174  const CollisionPoint &point = (*pi);
175 
176  // Draw a small red point at the surface point, and a smaller white
177  // point at the interior point.
178  {
179  PT(GeomVertexData) point_vdata =
180  new GeomVertexData("viz", point_format, Geom::UH_stream);
181 
182  PT(GeomPoints) points = new GeomPoints(Geom::UH_stream);
183 
184  GeomVertexWriter vertex(point_vdata, InternalName::get_vertex());
185  GeomVertexWriter color(point_vdata, InternalName::get_color());
186  GeomVertexWriter size(point_vdata, InternalName::get_size());
187 
188  vertex.add_data3(point._surface_point);
189  color.add_data4(1.0f, 0.0f, 0.0f, 1.0f);
190  size.add_data1f(16.0f * _point_scale);
191  points->add_next_vertices(1);
192  points->close_primitive();
193 
194  if (point._interior_point != point._surface_point) {
195  vertex.add_data3(point._interior_point);
196  color.add_data4(1.0f, 1.0f, 1.0f, 1.0f);
197  size.add_data1f(8.0f * _point_scale);
198  points->add_next_vertices(1);
199  points->close_primitive();
200  }
201 
202  PT(Geom) geom = new Geom(point_vdata);
203  geom->add_primitive(points);
204 
205  CullableObject *object =
206  new CullableObject(geom, point_state,
207  xform_data.get_internal_transform(trav));
208 
209  trav->get_cull_handler()->record_object(object, trav);
210  }
211 
212  // Draw the normal vector at the surface point.
213  if (!point._surface_normal.almost_equal(LVector3::zero())) {
214  PT(GeomVertexData) line_vdata =
216  Geom::UH_stream);
217 
218  PT(GeomLines) lines = new GeomLines(Geom::UH_stream);
219 
220  GeomVertexWriter vertex(line_vdata, InternalName::get_vertex());
221  GeomVertexWriter color(line_vdata, InternalName::get_color());
222 
223  vertex.add_data3(point._surface_point);
224  vertex.add_data3(point._surface_point +
225  point._surface_normal * _normal_scale);
226  color.add_data4(1.0f, 0.0f, 0.0f, 1.0f);
227  color.add_data4(1.0f, 1.0f, 1.0f, 1.0f);
228  lines->add_next_vertices(2);
229  lines->close_primitive();
230 
231  PT(Geom) geom = new Geom(line_vdata);
232  geom->add_primitive(lines);
233 
234  CullableObject *object =
235  new CullableObject(geom, empty_state,
236  xform_data.get_internal_transform(trav));
237 
238  trav->get_cull_handler()->record_object(object, trav);
239  }
240  }
241  }
242  }
243 
244  // Now carry on to render our child nodes.
245  return true;
246 }
247 
248 /**
249  * Returns true if there is some value to visiting this particular node during
250  * the cull traversal for any camera, false otherwise. This will be used to
251  * optimize the result of get_net_draw_show_mask(), so that any subtrees that
252  * contain only nodes for which is_renderable() is false need not be visited.
253  */
254 bool CollisionVisualizer::
255 is_renderable() const {
256  return true;
257 }
258 
259 
260 /**
261  * Writes a brief description of the node to the indicated output stream.
262  * This is invoked by the << operator. It may be overridden in derived
263  * classes to include some information relevant to the class.
264  */
265 void CollisionVisualizer::
266 output(std::ostream &out) const {
267  PandaNode::output(out);
268  out << " ";
269  CollisionRecorder::output(out);
270 }
271 
272 /**
273  * This method is called at the beginning of a CollisionTraverser::traverse()
274  * call. It is provided as a hook for the derived class to reset its state as
275  * appropriate.
276  */
277 void CollisionVisualizer::
278 begin_traversal() {
279  CollisionRecorder::begin_traversal();
280  LightMutexHolder holder(_lock);
281  _data.clear();
282 }
283 
284 /**
285  * This method is called when a pair of collision solids have passed all
286  * bounding-volume tests and have been tested for a collision. The detected
287  * value is set true if a collision was detected, false otherwise.
288  */
289 void CollisionVisualizer::
290 collision_tested(const CollisionEntry &entry, bool detected) {
291  CollisionRecorder::collision_tested(entry, detected);
292 
293  NodePath node_path = entry.get_into_node_path();
294  CPT(TransformState) net_transform = node_path.get_net_transform();
295  CPT(CollisionSolid) solid = entry.get_into();
296  nassertv(!solid.is_null());
297 
298  LightMutexHolder holder(_lock);
299  VizInfo &viz_info = _data[std::move(net_transform)];
300  if (detected) {
301  viz_info._solids[std::move(solid)]._detected_count++;
302 
303  if (entry.has_surface_point()) {
304  CollisionPoint p;
305  entry.get_all(entry.get_into_node_path(),
306  p._surface_point, p._surface_normal, p._interior_point);
307  viz_info._points.push_back(p);
308  }
309 
310  } else {
311  viz_info._solids[std::move(solid)]._missed_count++;
312  }
313 }
314 
315 
316 /**
317  * Returns a RenderState suitable for rendering the collision solids with
318  * which a collision was detected.
319  */
320 CPT(RenderState) CollisionVisualizer::
321 get_viz_state() {
322  // Once someone asks for this pointer, we hold its reference count and never
323  // free it.
324  static CPT(RenderState) state = nullptr;
325  if (state == nullptr) {
326  state = RenderState::make
327  (DepthOffsetAttrib::make());
328  }
329 
330  return state;
331 }
332 
333 #endif // DO_COLLISION_RECORDING
bool has_surface_point() const
Returns true if the surface point has been specified, false otherwise.
bool get_all(const NodePath &space, LPoint3 &surface_point, LVector3 &surface_normal, LPoint3 &interior_point) const
Simultaneously transforms the surface point, surface normal, and interior point of the collision into...
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...
CullHandler * get_cull_handler() const
Returns the object that will receive the culled Geoms.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
Indicates a coordinate-system transform on vertices.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
Defines a series of disconnected points.
Definition: geomPoints.h:23
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
The abstract base class for all things that can collide with other things in the world,...
static const GeomVertexFormat * get_v3cp()
Returns a standard vertex format with a packed color and a 3-component vertex position.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This collects together the pieces of data that are accumulated for each node while walking the scene ...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
get_into_node_path
Returns the NodePath that represents the specific CollisionNode or GeomNode instance that was collide...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void traverse(const NodePath &root)
Begins the traversal from the indicated node.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
The smallest atom of cull.
virtual void record_object(CullableObject *object, const CullTraverser *traverser)
This callback function is intended to be overridden by a derived class.
Definition: cullHandler.cxx:43
Similar to MutexHolder, but for a light mutex.
Defines a single collision event.
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:54
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This represents a unique collection of RenderAttrib objects that correspond to a particular renderabl...
Definition: renderState.h:47
Defines a series of disconnected line segments.
Definition: geomLines.h:23
This class defines the physical layout of the vertex data stored within a Geom.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
get_into
Returns the CollisionSolid pointer for the particular solid was collided into.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
GeometricBoundingVolume * get_view_frustum() const
Returns the bounding volume that corresponds to the view frustum, or NULL if the view frustum is not ...
This describes the structure of a single array within a Geom data.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This is a special kind of GeometricBoundingVolume that fills all of space.
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
NodePath is the fundamental system for disambiguating instances, and also provides a higher-level int...
Definition: nodePath.h:161
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This object performs a depth-first traversal of the scene graph, with optional view-frustum culling,...
Definition: cullTraverser.h:45
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.