Panda3D
cullTraverserData.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 cullTraverserData.cxx
10  * @author drose
11  * @date 2002-03-06
12  */
13 
14 #include "cullTraverserData.h"
15 #include "cullTraverser.h"
16 #include "config_pgraph.h"
17 #include "pandaNode.h"
18 #include "colorAttrib.h"
19 #include "textureAttrib.h"
20 #include "renderModeAttrib.h"
21 #include "clipPlaneAttrib.h"
22 #include "boundingPlane.h"
23 #include "billboardEffect.h"
24 #include "compassEffect.h"
25 #include "occluderEffect.h"
26 #include "polylightEffect.h"
27 #include "renderState.h"
28 
29 
30 /**
31  * Applies the transform and state from the current node onto the current
32  * data. This also evaluates billboards, etc.
33  */
36  CPT(RenderState) node_state = _node_reader.get_state();
37 
38  if (trav->has_tag_state_key() &&
39  _node_reader.has_tag(trav->get_tag_state_key())) {
40  // Here's a node that has been tagged with the special key for our current
41  // camera. This indicates some special state transition for this node,
42  // which is unique to this camera.
43  const Camera *camera = trav->get_scene()->get_camera_node();
44  std::string tag_state = _node_reader.get_tag(trav->get_tag_state_key());
45  node_state = node_state->compose(camera->get_tag_state(tag_state));
46  }
47  _node_reader.compose_draw_mask(_draw_mask);
48 
49  const RenderEffects *node_effects = _node_reader.get_effects();
50  if (!node_effects->has_cull_callback()) {
51  apply_transform(_node_reader.get_transform());
52  } else {
53  // The cull callback may decide to modify the node_transform.
54  CPT(TransformState) node_transform = _node_reader.get_transform();
55  node_effects->cull_callback(trav, *this, node_transform, node_state);
56  apply_transform(node_transform);
57 
58  // The cull callback may have changed the node properties.
59  _node_reader.check_cached(false);
60  }
61 
62  if (!node_state->is_empty()) {
63  _state = _state->compose(node_state);
64  }
65 
66  if (clip_plane_cull) {
67  _cull_planes = _cull_planes->apply_state(trav, this,
68  (const ClipPlaneAttrib *)node_state->get_attrib(ClipPlaneAttrib::get_class_slot()),
69  (const ClipPlaneAttrib *)_node_reader.get_off_clip_planes(),
70  (const OccluderEffect *)node_effects->get_effect(OccluderEffect::get_class_type()));
71  }
72 }
73 
74 /**
75  * Applies the indicated transform changes onto the current data.
76  */
78 apply_transform(const TransformState *node_transform) {
79  if (!node_transform->is_identity()) {
80  _net_transform = _net_transform->compose(node_transform);
81 
82  if ((_view_frustum != nullptr) ||
83  (!_cull_planes->is_empty())) {
84  // We need to move the viewing frustums into the node's coordinate space
85  // by applying the node's inverse transform.
86  if (node_transform->is_singular()) {
87  // But we can't invert a singular transform! Instead of trying, we'll
88  // just give up on frustum culling from this point down.
89  _view_frustum = nullptr;
90  _cull_planes = CullPlanes::make_empty();
91 
92  } else {
93  CPT(TransformState) inv_transform =
94  node_transform->invert_compose(TransformState::make_identity());
95 
96  // Copy the bounding volumes for the frustums so we can transform
97  // them.
98  if (_view_frustum != nullptr) {
99  _view_frustum = _view_frustum->make_copy()->as_geometric_bounding_volume();
100  nassertv(_view_frustum != nullptr);
101 
102  _view_frustum->xform(inv_transform->get_mat());
103  }
104 
105  _cull_planes = _cull_planes->xform(inv_transform->get_mat());
106  }
107  }
108  }
109 }
110 
111 /**
112  * The private, recursive implementation of get_node_path(), this returns the
113  * NodePathComponent representing the NodePath.
114  */
115 PT(NodePathComponent) CullTraverserData::
116 r_get_node_path() const {
117  if (_next == nullptr) {
118  nassertr(_start != nullptr, nullptr);
119  return _start;
120  }
121 
122 #ifdef _DEBUG
123  nassertr(_start == nullptr, nullptr);
124 #endif
125  nassertr(node() != nullptr, nullptr);
126 
127  PT(NodePathComponent) comp = _next->r_get_node_path();
128  nassertr(comp != nullptr, nullptr);
129 
130  Thread *current_thread = Thread::get_current_thread();
131  int pipeline_stage = current_thread->get_pipeline_stage();
132  PT(NodePathComponent) result =
133  PandaNode::get_component(comp, node(), pipeline_stage, current_thread);
134  if (result == nullptr) {
135  // This means we found a disconnected chain in the CullTraverserData's
136  // ancestry: the node above this node isn't connected. In this case,
137  // don't attempt to go higher; just truncate the NodePath at the bottom of
138  // the disconnect.
139  return PandaNode::get_top_component(node(), true, pipeline_stage, current_thread);
140  }
141 
142  return result;
143 }
144 
145 /**
146  * The private implementation of is_in_view().
147  */
148 bool CullTraverserData::
149 is_in_view_impl() {
150  const GeometricBoundingVolume *node_gbv = nullptr;
151 
152  if (_view_frustum != nullptr) {
153  node_gbv = _node_reader.get_bounds()->as_geometric_bounding_volume();
154  nassertr(node_gbv != nullptr, false);
155 
156  int result = _view_frustum->contains(node_gbv);
157 
158  if (pgraph_cat.is_spam()) {
159  pgraph_cat.spam()
160  << get_node_path() << " cull result = " << std::hex << result << std::dec << "\n";
161  }
162 
163  if (result == BoundingVolume::IF_no_intersection) {
164  // No intersection at all. Cull.
165 #ifdef NDEBUG
166  return false;
167 #else
168  if (!fake_view_frustum_cull) {
169  return false;
170  }
171 
172  // If we have fake view-frustum culling enabled, instead of actually
173  // culling an object we simply force it to be drawn in red wireframe.
174  _view_frustum = nullptr;
175  _state = _state->compose(get_fake_view_frustum_cull_state());
176 #endif
177 
178  } else if ((result & BoundingVolume::IF_all) != 0) {
179  // The node and its descendents are completely enclosed within the
180  // frustum. No need to cull further.
181  _view_frustum = nullptr;
182 
183  } else {
184  // The node is partially, but not completely, within the viewing
185  // frustum.
186  if (_node_reader.is_final()) {
187  // Normally we'd keep testing child bounding volumes as we continue
188  // down. But this node has the "final" flag, so the user is claiming
189  // that there is some important reason we should consider everything
190  // visible at this point. So be it.
191  _view_frustum = nullptr;
192  }
193  }
194  }
195 
196  if (!_cull_planes->is_empty()) {
197  if (node_gbv == nullptr) {
198  node_gbv = _node_reader.get_bounds()->as_geometric_bounding_volume();
199  nassertr(node_gbv != nullptr, false);
200  }
201 
202  // Also cull against the current clip planes.
203  int result;
204  _cull_planes = _cull_planes->do_cull(result, _state, node_gbv);
205 
206  if (pgraph_cat.is_spam()) {
207  pgraph_cat.spam()
208  << get_node_path() << " cull planes cull result = " << std::hex
209  << result << std::dec << "\n";
210  _cull_planes->write(pgraph_cat.spam(false));
211  }
212 
213  if (_node_reader.is_final()) {
214  // Even though the node may be partially within the clip planes, do no
215  // more culling against them below this node.
216  _cull_planes = CullPlanes::make_empty();
217 
218  if (pgraph_cat.is_spam()) {
219  pgraph_cat.spam()
220  << get_node_path() << " is_final, cull planes disabled, state:\n";
221  _state->write(pgraph_cat.spam(false), 2);
222  }
223  }
224 
225  if (result == BoundingVolume::IF_no_intersection) {
226  // No intersection at all. Cull.
227 #ifdef NDEBUG
228  return false;
229 #else
230  if (!fake_view_frustum_cull) {
231  return false;
232  }
233  _cull_planes = CullPlanes::make_empty();
234  _state = _state->compose(get_fake_view_frustum_cull_state());
235 #endif
236 
237  } else if ((result & BoundingVolume::IF_all) != 0) {
238  // The node and its descendents are completely in front of all of the
239  // clip planes and occluders. The do_cull() call should therefore have
240  // removed all of the clip planes and occluders.
241  nassertr(_cull_planes->is_empty(), true);
242  }
243  }
244 
245  return true;
246 }
247 
248 /**
249  * Returns a RenderState for rendering stuff in red wireframe, strictly for
250  * the fake_view_frustum_cull effect.
251  */
252 const RenderState *CullTraverserData::
253 get_fake_view_frustum_cull_state() {
254 #ifdef NDEBUG
255  return nullptr;
256 #else
257  // Once someone asks for this pointer, we hold its reference count and never
258  // free it.
259  static CPT(RenderState) state;
260  if (state == nullptr) {
261  state = RenderState::make
262  (ColorAttrib::make_flat(LColor(1.0f, 0.0f, 0.0f, 1.0f)),
263  TextureAttrib::make_all_off(),
264  RenderModeAttrib::make(RenderModeAttrib::M_wireframe),
265  RenderState::get_max_priority());
266  }
267  return state;
268 #endif
269 }
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
virtual GeometricBoundingVolume * as_geometric_bounding_volume()
Virtual downcast method.
A node that can be positioned around in the scene graph to represent a point of view for rendering a ...
Definition: camera.h:35
This functions similarly to a LightAttrib.
PandaNode * node() const
Returns the node traversed to so far.
get_node_path
Constructs and returns an actual NodePath that represents the same path we have just traversed.
void apply_transform_and_state(CullTraverser *trav)
Applies the transform and state from the current node onto the current data.
void apply_transform(const TransformState *node_transform)
Applies the indicated transform changes onto the current data.
This object performs a depth-first traversal of the scene graph, with optional view-frustum culling,...
Definition: cullTraverser.h:45
const std::string & get_tag_state_key() const
Returns the tag state key that has been specified for the scene's camera, if any.
Definition: cullTraverser.I:53
bool has_tag_state_key() const
Returns true if a nonempty tag state key has been specified for the scene's camera,...
Definition: cullTraverser.I:44
SceneSetup * get_scene() const
Returns the SceneSetup object.
Definition: cullTraverser.I:35
This is another abstract class, for a general class of bounding volumes that actually enclose points ...
This is one component of a NodePath.
This functions similarly to a LightAttrib or ClipPlaneAttrib.
const TransformState * get_transform() const
Returns the transform that has been set on this particular node.
Definition: pandaNode.I:1441
const RenderEffects * get_effects() const
Returns the complete RenderEffects that will be applied to this node.
Definition: pandaNode.I:1431
const BoundingVolume * get_bounds() const
Returns the external bounding volume of this node: a bounding volume that contains the user bounding ...
Definition: pandaNode.I:1505
const RenderState * get_state() const
Returns the complete RenderState that will be applied to all nodes at this level and below,...
Definition: pandaNode.I:1423
void check_cached(bool update_bounds) const
Ensures that the draw masks etc.
Definition: pandaNode.cxx:4100
void compose_draw_mask(DrawMask &running_draw_mask) const
Computes the result of applying this node's draw masks to a running draw mask, as during a traversal.
Definition: pandaNode.I:1256
bool has_tag(const std::string &key) const
Returns true if a value has been defined on this node for the particular key (even if that value is t...
Definition: pandaNode.I:1475
std::string get_tag(const std::string &key) const
Retrieves the user-defined value that was previously set on this node for the particular key,...
Definition: pandaNode.I:1460
const RenderAttrib * get_off_clip_planes() const
Returns a ClipPlaneAttrib which represents the union of all of the clip planes that have been turned ...
Definition: pandaNode.I:1494
bool is_final() const
Returns the current state of the "final" flag.
Definition: pandaNode.I:1531
This represents a unique collection of RenderEffect objects that correspond to a particular renderabl...
Definition: renderEffects.h:41
bool has_cull_callback() const
This function is provided as an optimization, to speed up the render-time checking for the existance ...
const RenderEffect * get_effect(size_t n) const
Returns the nth effect in the state.
void cull_callback(CullTraverser *trav, CullTraverserData &data, CPT(TransformState) &node_transform, CPT(RenderState) &node_state) const
Calls cull_callback() on all effects.
This represents a unique collection of RenderAttrib objects that correspond to a particular renderabl...
Definition: renderState.h:47
Camera * get_camera_node() const
Returns the camera used to render the scene.
Definition: sceneSetup.I:115
A thread; that is, a lightweight process.
Definition: thread.h:46
get_pipeline_stage
Returns the Pipeline stage number associated with this thread.
Definition: thread.h:105
get_current_thread
Returns a pointer to the currently-executing Thread object.
Definition: thread.h:109
Indicates a coordinate-system transform on vertices.
bool is_singular() const
Returns true if the transform represents a singular transform (that is, it has a zero scale,...
bool is_identity() const
Returns true if the transform represents the identity matrix, false otherwise.
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.
PT(NodePathComponent) CullTraverserData
The private, recursive implementation of get_node_path(), this returns the NodePathComponent represen...
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.