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
Geom
A container for geometry primitives.
Definition: geom.h:54
geomVertexData.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
clipPlaneAttrib.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
LightMutexHolder
Similar to MutexHolder, but for a light mutex.
Definition: lightMutexHolder.h:25
cullTraverser.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
geomVertexWriter.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
CullableObject
The smallest atom of cull.
Definition: cullableObject.h:41
GeomVertexData
This defines the actual numeric vertex data stored in a Geom, in the structure defined by a particula...
Definition: geomVertexData.h:68
CollisionEntry
Defines a single collision event.
Definition: collisionEntry.h:42
cullableObject.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
GeomPoints
Defines a series of disconnected points.
Definition: geomPoints.h:23
GeomVertexWriter
This object provides a high-level interface for quickly writing a sequence of numeric values from a v...
Definition: geomVertexWriter.h:55
collisionVisualizer.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
CullTraverser
This object performs a depth-first traversal of the scene graph, with optional view-frustum culling,...
Definition: cullTraverser.h:45
CollisionEntry::get_into_node_path
get_into_node_path
Returns the NodePath that represents the specific CollisionNode or GeomNode instance that was collide...
Definition: collisionEntry.h:102
geomLines.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
geomVertexArrayFormat.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
RenderState
This represents a unique collection of RenderAttrib objects that correspond to a particular renderabl...
Definition: renderState.h:47
renderState.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
TypeHandle
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
cullTraverserData.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
renderModeAttrib.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
depthOffsetAttrib.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
CullHandler::record_object
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
colorScaleAttrib.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
TransformState
Indicates a coordinate-system transform on vertices.
Definition: transformState.h:54
CollisionEntry::has_surface_point
bool has_surface_point() const
Returns true if the surface point has been specified, false otherwise.
Definition: collisionEntry.I:192
CullTraverserData
This collects together the pieces of data that are accumulated for each node while walking the scene ...
Definition: cullTraverserData.h:40
transparencyAttrib.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
OmniBoundingVolume
This is a special kind of GeometricBoundingVolume that fills all of space.
Definition: omniBoundingVolume.h:24
geom.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
GeomVertexFormat
This class defines the physical layout of the vertex data stored within a Geom.
Definition: geomVertexFormat.h:55
CollisionSolid
The abstract base class for all things that can collide with other things in the world,...
Definition: collisionSolid.h:45
collisionEntry.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
NodePath
NodePath is the fundamental system for disambiguating instances, and also provides a higher-level int...
Definition: nodePath.h:159
CullTraverser::get_view_frustum
GeometricBoundingVolume * get_view_frustum() const
Returns the bounding volume that corresponds to the view frustum, or NULL if the view frustum is not ...
Definition: cullTraverser.I:135
omniBoundingVolume.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
GeomLines
Defines a series of disconnected line segments.
Definition: geomLines.h:23
CollisionEntry::get_into
get_into
Returns the CollisionSolid pointer for the particular solid was collided into.
Definition: collisionEntry.h:98
CollisionEntry::get_all
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...
Definition: collisionEntry.cxx:120
geomPoints.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
geomVertexFormat.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
CullTraverser::traverse
void traverse(const NodePath &root)
Begins the traversal from the indicated node.
Definition: cullTraverser.cxx:106
PandaNode
A basic node of the scene graph or data graph.
Definition: pandaNode.h:65
CullTraverser::get_cull_handler
CullHandler * get_cull_handler() const
Returns the object that will receive the culled Geoms.
Definition: cullTraverser.I:152
cullHandler.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
GeomVertexFormat::get_v3cp
static const GeomVertexFormat * get_v3cp()
Returns a standard vertex format with a packed color and a 3-component vertex position.
Definition: geomVertexFormat.I:287
GeomVertexArrayFormat
This describes the structure of a single array within a Geom data.
Definition: geomVertexArrayFormat.h:47