Panda3D
Loading...
Searching...
No Matches
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 */
78apply_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 */
115PT(NodePathComponent) CullTraverserData::
116r_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 */
148bool CullTraverserData::
149is_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 */
252const RenderState *CullTraverserData::
253get_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,...
const std::string & get_tag_state_key() const
Returns the tag state key that has been specified for the scene's camera, if any.
bool has_tag_state_key() const
Returns true if a nonempty tag state key has been specified for the scene's camera,...
SceneSetup * get_scene() const
Returns the SceneSetup object.
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:1513
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.
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:1502
bool is_final() const
Returns the current state of the "final" flag.
Definition pandaNode.I:1539
This represents a unique collection of RenderEffect objects that correspond to a particular renderabl...
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.
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.