Panda3D

Loading...
Searching...
No Matches
pipeOcclusionCullTraverser.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 pipeOcclusionCullTraverser.cxx
10 * @author drose
11 * @date 2007-05-29
12 */
13
14#include "pipeOcclusionCullTraverser.h"
15#include "graphicsEngine.h"
16#include "graphicsPipe.h"
17#include "drawCullHandler.h"
18#include "boundingSphere.h"
19#include "boundingBox.h"
20#include "geomVertexWriter.h"
21#include "geomTristrips.h"
22#include "geomTriangles.h"
23#include "pStatTimer.h"
24#include "depthWriteAttrib.h"
25#include "depthTestAttrib.h"
26#include "colorWriteAttrib.h"
27#include "colorAttrib.h"
28#include "cullBinManager.h"
29#include "configVariableInt.h"
30#include "config_grutil.h"
31#include "pnmImage.h"
32
33 PStatCollector PipeOcclusionCullTraverser::_setup_occlusion_pcollector("Cull:Occlusion:Setup");
34 PStatCollector PipeOcclusionCullTraverser::_draw_occlusion_pcollector("Cull:Occlusion:Occluders");
35 PStatCollector PipeOcclusionCullTraverser::_test_occlusion_pcollector("Cull:Occlusion:Test");
36 PStatCollector PipeOcclusionCullTraverser::_finish_occlusion_pcollector("Cull:Occlusion:Finish");
37
38 PStatCollector PipeOcclusionCullTraverser::_occlusion_untested_pcollector("Occlusion results:Not tested");
39 PStatCollector PipeOcclusionCullTraverser::_occlusion_passed_pcollector("Occlusion results:Visible");
40 PStatCollector PipeOcclusionCullTraverser::_occlusion_failed_pcollector("Occlusion results:Occluded");
41 PStatCollector PipeOcclusionCullTraverser::_occlusion_tests_pcollector("Occlusion tests");
42
43 TypeHandle PipeOcclusionCullTraverser::_type_handle;
44
45 static ConfigVariableInt min_occlusion_vertices
46("min-occlusion-vertices", 300,
47 PRC_DESC("The minimum number of vertices a PandaNode or Geom must contain "
48 "in order to perform an occlusion query for it. Nodes and Geoms "
49 "smaller than this will be rendered directly, without bothering "
50 "with an occlusion query."));
51
52 static ConfigVariableInt max_occlusion_vertices
53("max-occlusion-vertices", 3000,
54 PRC_DESC("The maximum number of vertices that may be included in a PandaNode "
55 "and its descendents in order to perform an occlusion query for "
56 "it. Subgraphs whose total vertex count exceeds this number will "
57 "be subdivided further before performing an occlusion test--the "
58 "hope is that we can eventually get to a finer-grained answer. "
59 "GeomNodes and Geoms will not be subdivided, regardless of this "
60 "limit."));
61
62 static ConfigVariableBool show_occlusion
63("show-occlusion", false,
64 PRC_DESC("Set this true to visualize the efforts of the occlusion test."));
65
66 static ConfigVariableInt occlusion_size
67("occlusion-size", "256 256",
68 PRC_DESC("Specify the x y size of the buffer used for occlusion testing."));
69
70 static ConfigVariableInt occlusion_depth_bits
71("occlusion-depth-bits", 1,
72 PRC_DESC("The minimum number of depth bits requested for the occlusion "
73 "buffer."));
74
75/**
76 *
77 */
78PipeOcclusionCullTraverser::
79PipeOcclusionCullTraverser(GraphicsOutput *host) {
80 _live = false;
81 GraphicsStateGuardian *gsg = host->get_gsg();
82
83 GraphicsThreadingModel threading_model = gsg->get_threading_model();
84 nassertv(threading_model.get_cull_name() == threading_model.get_draw_name());
85 if (!gsg->get_supports_occlusion_query()) {
86 grutil_cat.info()
87 << "Occlusion queries are not supported by graphics pipe.\n";
88 return;
89 }
90
91 GraphicsEngine *engine = gsg->get_engine();
92 GraphicsPipe *pipe = gsg->get_pipe();
93
94 FrameBufferProperties fb_prop;
95 fb_prop.set_depth_bits(occlusion_depth_bits);
96 WindowProperties win_prop;
97 if (occlusion_size.get_num_words() < 2) {
98 win_prop.set_size(occlusion_size, occlusion_size);
99 } else {
100 win_prop.set_size(occlusion_size[0], occlusion_size[1]);
101 }
102
103 _buffer = engine->make_output(pipe, "occlusion", 0, fb_prop, win_prop,
104 GraphicsPipe::BF_refuse_window,
105 gsg, host->get_host());
106 nassertv(_buffer != nullptr);
107
108 // This buffer isn't really active--we render it by hand; we don't want the
109 // GraphicsEngine to render it.
110 _buffer->set_active(0);
111
112 _display_region = _buffer->make_display_region();
113 _internal_cull_handler = nullptr;
114
115 make_sphere();
116 make_box();
117 make_solid_test_state();
118
119 _live = true;
120}
121
122/**
123 *
124 */
125 void PipeOcclusionCullTraverser::
126 set_scene(SceneSetup *scene_setup, GraphicsStateGuardianBase *gsgbase,
127 bool dr_incomplete_render) {
128 CullTraverser::set_scene(scene_setup, gsgbase, dr_incomplete_render);
129 if (!_live) {
130 return;
131 }
132
133 PStatTimer timer(_setup_occlusion_pcollector);
134
135 GraphicsStateGuardian *gsg = _buffer->get_gsg();
136 nassertv(gsg == gsgbase);
137
138 Thread *current_thread = get_current_thread();
139 if (!_buffer->begin_frame(GraphicsOutput::FM_render, current_thread)) {
140 grutil_cat.error() << "begin_frame failed\n";
141 return;
142 }
143 _buffer->clear(current_thread);
144
145 DisplayRegionPipelineReader dr_reader(_display_region, current_thread);
146
147 _buffer->change_scenes(&dr_reader);
148 gsg->prepare_display_region(&dr_reader);
149
150 _scene = new SceneSetup(*scene_setup);
151 _scene->set_display_region(_display_region);
152 _scene->set_viewport_size(_display_region->get_pixel_width(),
153 _display_region->get_pixel_height());
154
155 if (_scene->get_cull_center() != _scene->get_camera_path()) {
156 // This camera has a special cull center set. For the purposes of
157 // occlusion culling, we want to render the scene from the cull center,
158 // not from the camera root.
159 NodePath cull_center = _scene->get_cull_center();
160 NodePath scene_parent = _scene->get_scene_root().get_parent(current_thread);
161 CPT(TransformState) camera_transform = cull_center.get_transform(scene_parent, current_thread);
162 CPT(TransformState) world_transform = scene_parent.get_transform(cull_center, current_thread);
163 CPT(TransformState) cs_world_transform = _scene->get_cs_transform()->compose(world_transform);
164 _scene->set_camera_transform(camera_transform);
165 _scene->set_world_transform(world_transform);
166 _scene->set_cs_world_transform(cs_world_transform);
167
168 // We use this to recover the original net_transform.
169 _inv_cs_world_transform = cs_world_transform->get_inverse();
170 } else {
171 _inv_cs_world_transform = _scene->get_cs_world_transform()->get_inverse();
172 }
173
174 nassertv(_scene->get_cs_transform() == scene_setup->get_cs_transform());
175
176 gsg->set_scene(_scene);
177 if (!gsg->begin_scene()) {
178 grutil_cat.error() << "begin_scene failed\n";
179 return;
180 }
181
182 // Hijack the default cull handler so we can perform all of the occlusion
183 // tests on a per-object basis, and then query the results at the end of the
184 // traversal.
185 _true_cull_handler = get_cull_handler();
186 set_cull_handler(this);
187
188 _internal_cull_handler = new DrawCullHandler(gsg);
189 _internal_trav = new CullTraverser;
190 _internal_trav->set_cull_handler(_internal_cull_handler);
191 _internal_trav->set_scene(_scene, gsg, dr_incomplete_render);
192 _internal_trav->set_view_frustum(get_view_frustum());
193 _internal_trav->set_camera_mask(_occlusion_mask);
194
195 _current_query = nullptr;
196 _next_query = nullptr;
197
198 // Begin by rendering all the occluders into our internal scene.
199 PStatTimer timer2(_draw_occlusion_pcollector);
200 _internal_trav->traverse(_scene->get_scene_root());
201}
202
203/**
204 * Should be called when the traverser has finished traversing its scene, this
205 * gives it a chance to do any necessary finalization.
206 */
207 void PipeOcclusionCullTraverser::
208 end_traverse() {
209 if (!_live) {
210 return;
211 }
212
213 PStatTimer timer(_finish_occlusion_pcollector);
214 GraphicsStateGuardian *gsg = _buffer->get_gsg();
215 Thread *current_thread = get_current_thread();
216
217 _current_query = nullptr;
218 _next_query = nullptr;
219
220 PendingObjects::iterator oi;
221 for (oi = _pending_objects.begin(); oi != _pending_objects.end(); ++oi) {
222 PendingObject &pobj = (*oi);
223 if (pobj._query == nullptr) {
224 _occlusion_untested_pcollector.add_level(1);
225 _true_cull_handler->record_object(pobj._object, this);
226 } else {
227 int num_fragments = pobj._query->get_num_fragments();
228 if (num_fragments != 0) {
229 _occlusion_passed_pcollector.add_level(1);
230 _true_cull_handler->record_object(pobj._object, this);
231 } else {
232 _occlusion_failed_pcollector.add_level(1);
233 delete pobj._object;
234 }
235 }
236
237 // The CullableObject has by now either been recorded (which will
238 // eventually delete it) or deleted directly.
239#ifndef NDEBUG
240 pobj._object = nullptr;
241#endif // NDEBUG
242 }
243 _pending_objects.clear();
244 CullTraverser::end_traverse();
245
246 gsg->end_scene();
247 _buffer->end_frame(GraphicsOutput::FM_render, current_thread);
248
249 _buffer->begin_flip();
250 _buffer->end_flip();
251
252 delete _internal_cull_handler;
253 _internal_cull_handler = nullptr;
254
255 _occlusion_untested_pcollector.flush_level();
256 _occlusion_passed_pcollector.flush_level();
257 _occlusion_failed_pcollector.flush_level();
258 _occlusion_tests_pcollector.flush_level();
259}
260
261/**
262 * Returns a Texture that can be used to visualize the efforts of the
263 * occlusion cull.
264 */
265 Texture *PipeOcclusionCullTraverser::
266 get_texture() {
267 if (_texture != nullptr) {
268 return _texture;
269 }
270
271 _texture = new Texture("occlusion");
272
273 if (!_live) {
274 // If we're not live, just create a default, black texture.
275 PNMImage image(1, 1);
276 _texture->load(image);
277
278 } else {
279 // Otherwise, create a render-to-texture.
280 _buffer->add_render_texture(_texture, GraphicsOutput::RTM_bind_or_copy);
281 }
282
283 return _texture;
284}
285
286/**
287 *
288 */
289 bool PipeOcclusionCullTraverser::
290is_in_view(CullTraverserData &data) {
291 _next_query = nullptr;
292
293 if (!CullTraverser::is_in_view(data)) {
294 return false;
295 }
296 if (!_live) {
297 return true;
298 }
299
300 if (_current_query != nullptr) {
301 // We've already performed an occlusion test for some ancestor of this
302 // node; no need to perform another.
303 return true;
304 }
305
306 PandaNode *node = data.node();
307 PandaNodePipelineReader *node_reader = data.node_reader();
308
309 if (node_reader->get_nested_vertices() < min_occlusion_vertices) {
310 // Never mind; let this puny one slide.
311 return true;
312 }
313
314 if (node->is_geom_node() ||
315 node_reader->is_final() ||
316 node_reader->get_effects()->has_show_bounds() ||
317 node_reader->get_nested_vertices() <= max_occlusion_vertices) {
318 // In any of these cases, there's sufficient reason to perform an
319 // occlusion test on this particular node. Do it.
320
321 CPT(BoundingVolume) vol = node_reader->get_bounds();
322 CPT(TransformState) net_transform = data.get_net_transform(this);
323 CPT(TransformState) internal_transform;
324
325 CPT(Geom) geom;
326 if (get_volume_viz(vol, geom, net_transform, internal_transform)) {
327 _next_query =
328 perform_occlusion_test(geom, net_transform, internal_transform);
329 }
330 }
331
332 return true;
333}
334
335/**
336 * Traverses all the children of the indicated node, with the given data,
337 * which has been converted into the node's space.
338 */
339 void PipeOcclusionCullTraverser::
340traverse_below(CullTraverserData &data) {
341 // Save and restore _current_query, and clear _next_query, for traversing
342 // the children of this node.
343 PT(OcclusionQueryContext) prev_query = _current_query;
344 if (_next_query != nullptr) {
345 _current_query = _next_query;
346 }
347 _next_query = nullptr;
348
349 CullTraverser::traverse_below(data);
350
351 _current_query = prev_query;
352 _next_query = nullptr;
353}
354
355/**
356 * This callback function is intended to be overridden by a derived class.
357 * This is called as each Geom is discovered by the CullTraverser.
358 *
359 * We do a sneaky trick in making PipeOcclusionCullTraverser inherit from both
360 * CullTraverser and CullHandler--the traverser is its own handler! This is
361 * the normal callback into the traverser for rendering objects. We respond
362 * to this by firing off an occlusion test, and queuing up the object until
363 * the end of the scene.
364 */
365 void PipeOcclusionCullTraverser::
366record_object(CullableObject *object, const CullTraverser *traverser) {
367 nassertv(traverser == this);
368 PendingObject pobj(object);
369
370 Thread *current_thread = get_current_thread();
371
372 if (_next_query != nullptr) {
373 // We have just performed an occlusion query for this node. Don't perform
374 // another one.
375 pobj._query = _next_query;
376
377 } else if (_current_query != nullptr) {
378 // We have previously performed an occlusion query for this node or some
379 // ancestor. Don't perform another one.
380 pobj._query = _current_query;
381
382 } else if (object->_geom->get_nested_vertices(current_thread) < min_occlusion_vertices) {
383 // This object is too small to bother testing for occlusions.
384
385 } else {
386 // Issue an occlusion test for this object.
387 CPT(BoundingVolume) vol = object->_geom->get_bounds(current_thread);
388 CPT(TransformState) net_transform = _inv_cs_world_transform->compose(object->_internal_transform);
389 CPT(TransformState) internal_transform;
390 CPT(Geom) geom;
391 if (get_volume_viz(vol, geom, net_transform, internal_transform)) {
392 pobj._query =
393 perform_occlusion_test(geom, net_transform, internal_transform);
394 }
395 }
396
397 _pending_objects.push_back(pobj);
398}
399
400/**
401 * Constructs a unit sphere for testing visibility of bounding spheres.
402 */
403 void PipeOcclusionCullTraverser::
404make_sphere() {
405 ConfigVariableInt num_slices("num-slices", 16);
406 ConfigVariableInt num_stacks("num-stacks", 8);
407
408 // static const int num_slices = 16; static const int num_stacks = 8;
409
410 PT(GeomVertexData) vdata = new GeomVertexData
411 ("occlusion_sphere", GeomVertexFormat::get_v3(), Geom::UH_static);
412 GeomVertexWriter vertex(vdata, InternalName::get_vertex());
413
414 PT(GeomTristrips) strip = new GeomTristrips(Geom::UH_stream);
415 for (int sl = 0; sl < num_slices; ++sl) {
416 PN_stdfloat longitude0 = (PN_stdfloat)sl / (PN_stdfloat)num_slices;
417 PN_stdfloat longitude1 = (PN_stdfloat)(sl + 1) / (PN_stdfloat)num_slices;
418 vertex.add_data3(compute_sphere_point(0.0, longitude0));
419 for (int st = 1; st < num_stacks; ++st) {
420 PN_stdfloat latitude = (PN_stdfloat)st / (PN_stdfloat)num_stacks;
421 vertex.add_data3(compute_sphere_point(latitude, longitude0));
422 vertex.add_data3(compute_sphere_point(latitude, longitude1));
423 }
424 vertex.add_data3(compute_sphere_point(1.0, longitude0));
425
426 strip->add_next_vertices(num_stacks * 2);
427 strip->close_primitive();
428 }
429
430 _sphere_geom = new Geom(vdata);
431 _sphere_geom->add_primitive(strip);
432}
433
434/**
435 * Returns a point on the surface of the unit sphere. latitude and longitude
436 * range from 0.0 to 1.0.
437 */
438LVertex PipeOcclusionCullTraverser::
439compute_sphere_point(PN_stdfloat latitude, PN_stdfloat longitude) {
440 PN_stdfloat s1, c1;
441 csincos(latitude * MathNumbers::pi, &s1, &c1);
442
443 PN_stdfloat s2, c2;
444 csincos(longitude * 2.0f * MathNumbers::pi, &s2, &c2);
445
446 LVertex p(s1 * c2, s1 * s2, c1);
447 return p;
448}
449
450/**
451 * Constructs a unit box for testing visibility of bounding boxes.
452 */
453 void PipeOcclusionCullTraverser::
454make_box() {
455 PT(GeomVertexData) vdata = new GeomVertexData
456 ("occlusion_box", GeomVertexFormat::get_v3(), Geom::UH_static);
457 vdata->unclean_set_num_rows(8);
458
459 {
460 GeomVertexWriter vertex(vdata, InternalName::get_vertex());
461 vertex.set_data3(0.0f, 0.0f, 0.0f);
462 vertex.set_data3(0.0f, 0.0f, 1.0f);
463 vertex.set_data3(0.0f, 1.0f, 0.0f);
464 vertex.set_data3(0.0f, 1.0f, 1.0f);
465 vertex.set_data3(1.0f, 0.0f, 0.0f);
466 vertex.set_data3(1.0f, 0.0f, 1.0f);
467 vertex.set_data3(1.0f, 1.0f, 0.0f);
468 vertex.set_data3(1.0f, 1.0f, 1.0f);
469 }
470
471 PT(GeomTriangles) tris = new GeomTriangles(Geom::UH_static);
472 tris->add_vertices(0, 4, 5);
473 tris->add_vertices(0, 5, 1);
474 tris->add_vertices(4, 6, 7);
475 tris->add_vertices(4, 7, 5);
476 tris->add_vertices(6, 2, 3);
477 tris->add_vertices(6, 3, 7);
478 tris->add_vertices(2, 0, 1);
479 tris->add_vertices(2, 1, 3);
480 tris->add_vertices(1, 5, 7);
481 tris->add_vertices(1, 7, 3);
482 tris->add_vertices(2, 6, 4);
483 tris->add_vertices(2, 4, 0);
484
485 _box_geom = new Geom(vdata);
486 _box_geom->add_primitive(tris);
487}
488
489/**
490 * Creates the RenderState appropriate to rendering the occlusion test
491 * geometry invisibly.
492 */
493 void PipeOcclusionCullTraverser::
494make_solid_test_state() {
495 _solid_test_state = RenderState::make
496 (DepthWriteAttrib::make(DepthWriteAttrib::M_off),
497 DepthTestAttrib::make(DepthTestAttrib::M_less),
498 ColorWriteAttrib::make(ColorWriteAttrib::C_off));
499}
500
501/**
502 * Chooses a suitable Geom to render the indicated bounding volume, and fills
503 * geom and local_transform with the appropriate values. Returns true if the
504 * bounding volume can be rendered, false if there is no suitable
505 * visualization for it.
506 *
507 * On entry, net_transform should be filled with the net transform to the
508 * bounding volume. On exit (when return value is true), it will be composed
509 * with a suitable local transform to render the bounding volume properly, and
510 * internal_transform will also be filled with the appropriate transform.
511 */
512 bool PipeOcclusionCullTraverser::
513get_volume_viz(const BoundingVolume *vol,
514 CPT(Geom) &geom, // OUT
515 CPT(TransformState) &net_transform, // IN-OUT
516 CPT(TransformState) &internal_transform // OUT
517 ) {
518 if (vol->is_infinite() || vol->is_empty()) {
519 return false;
520 }
521
522 if (vol->is_exact_type(BoundingSphere::get_class_type())) {
523 const BoundingSphere *sphere = DCAST(BoundingSphere, vol);
524 CPT(TransformState) local_transform =
525 TransformState::make_pos_hpr_scale(sphere->get_center(),
526 LVecBase3(0, 0, 0),
527 sphere->get_radius());
528 net_transform = net_transform->compose(local_transform);
529
530 CPT(TransformState) modelview_transform =
531 _internal_trav->get_world_transform()->compose(net_transform);
532
533 // See if the bounding sphere is clipped by the near plane. If it is, the
534 // occlusion test may fail, so we won't bother performing it for this
535 // object. Anyway, it's not occluded by anything, since it's intersecting
536 // the near plane.
537 const LPoint3 &center = modelview_transform->get_pos();
538 const LVecBase3 &radius = modelview_transform->get_scale();
539 if (center[1] - radius[1] < 0.0f) {
540 return false;
541 }
542
543 // Construct the internal transform for the internal traverser.
544 internal_transform = _internal_trav->get_scene()->
545 get_cs_transform()->compose(modelview_transform);
546
547 // The sphere looks good.
548 geom = _sphere_geom;
549 return true;
550
551 } else if (vol->is_exact_type(BoundingBox::get_class_type())) {
552 const BoundingBox *box = DCAST(BoundingBox, vol);
553 CPT(TransformState) local_transform =
554 TransformState::make_pos_hpr_scale(box->get_minq(),
555 LVecBase3(0, 0, 0),
556 box->get_maxq() - box->get_minq());
557 net_transform = net_transform->compose(local_transform);
558
559 CPT(TransformState) modelview_transform =
560 _internal_trav->get_world_transform()->compose(net_transform);
561
562 // See if the bounding box is clipped by the near plane. If it is, the
563 // occlusion test may fail, so we won't bother performing it for this
564 // object. Anyway, it's not occluded by anything, since it's intersecting
565 // the near plane.
566 static const LPoint3 points[8] = {
567 LPoint3(0.0f, 0.0f, 0.0f),
568 LPoint3(0.0f, 0.0f, 1.0f),
569 LPoint3(0.0f, 1.0f, 0.0f),
570 LPoint3(0.0f, 1.0f, 1.0f),
571 LPoint3(1.0f, 0.0f, 0.0f),
572 LPoint3(1.0f, 0.0f, 1.0f),
573 LPoint3(1.0f, 1.0f, 0.0f),
574 LPoint3(1.0f, 1.0f, 1.0f),
575 };
576 const LMatrix4 &mat = modelview_transform->get_mat();
577 for (int i = 0; i < 8; ++i) {
578 LPoint3 p = points[i] * mat;
579 if (p[1] < 0.0f) {
580 return false;
581 }
582 }
583
584 // Construct the internal transform for the internal traverser.
585 internal_transform = _internal_trav->get_scene()->
586 get_cs_transform()->compose(modelview_transform);
587
588 // The box looks good.
589 geom = _box_geom;
590 return true;
591 }
592
593 // Don't have a suitable representation for this bounding volume.
594 return false;
595}
596
597/**
598 * Renders the indicated geometry in the internal scene to test its
599 * visibility.
600 */
601PT(OcclusionQueryContext) PipeOcclusionCullTraverser::
602perform_occlusion_test(const Geom *geom, const TransformState *net_transform,
603 const TransformState *internal_transform) {
604 _occlusion_tests_pcollector.add_level(1);
605 PStatTimer timer(_test_occlusion_pcollector);
606
607 GraphicsStateGuardian *gsg = _buffer->get_gsg();
608
609 gsg->begin_occlusion_query();
610
611 CullableObject *viz =
612 new CullableObject(geom, _solid_test_state, internal_transform);
613
614 static ConfigVariableBool test_occlude("test-occlude", false);
615 if (test_occlude) {
616 _true_cull_handler->record_object(viz, _internal_trav);
617 } else {
618 _internal_cull_handler->record_object(viz, _internal_trav);
619 }
620
621 PT(OcclusionQueryContext) query = gsg->end_occlusion_query();
622
623 if (show_occlusion) {
624 // Show the results of the occlusion. To do this, we need to get the
625 // results of the query immediately. This will stall the pipe, but we're
626 // rendering a debug effect, so we don't mind too much.
627 int num_fragments = query->get_num_fragments();
628 show_results(num_fragments, geom, net_transform, internal_transform);
629 }
630
631 return query;
632}
633
634/**
635 * Draws a visualization of the results of occlusion test for a particular
636 * bounding volume.
637 */
638 void PipeOcclusionCullTraverser::
639show_results(int num_fragments, const Geom *geom,
640 const TransformState *net_transform,
641 const TransformState *internal_transform) {
642 LColor color;
643 if (num_fragments == 0) {
644 // Magenta: culled
645 color.set(0.8f, 0.0f, 1.0f, 0.4f);
646 } else {
647 // Yellow: visible
648 color.set(1.0f, 1.0f, 0.5f, 0.4f);
649 }
650
651 CPT(RenderState) state = RenderState::make
652 (DepthWriteAttrib::make(DepthWriteAttrib::M_off),
653 DepthTestAttrib::make(DepthTestAttrib::M_less),
654 TransparencyAttrib::make(TransparencyAttrib::M_alpha),
655 ColorAttrib::make_flat(color));
656
657 CullableObject *internal_viz =
658 new CullableObject(geom, state, internal_transform);
659 _internal_cull_handler->record_object(internal_viz, _internal_trav);
660
661 // Also render the viz in the main scene.
662 internal_transform = get_scene()->get_cs_world_transform()->compose(net_transform);
663 CullableObject *main_viz =
664 new CullableObject(geom, state, internal_transform);
665 _true_cull_handler->record_object(main_viz, this);
666}
boundingBox.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
boundingSphere.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
BoundingBox::get_minq
const LPoint3 & get_minq() const
An inline accessor for the minimum value.
Definition boundingBox.I:41
BoundingBox::get_maxq
const LPoint3 & get_maxq() const
An inline accessor for the maximum value.
Definition boundingBox.I:52
BoundingVolume
This is an abstract class for any volume in any sense which can be said to define the locality of ref...
Definition boundingVolume.h:41
BoundingVolume::is_empty
bool is_empty() const
Any kind of volume might be empty.
Definition boundingVolume.I:29
BoundingVolume::is_infinite
bool is_infinite() const
The other side of the empty coin is an infinite volume.
Definition boundingVolume.I:44
ColorAttrib::make_flat
static ConstPointerTo< RenderAttrib > make_flat(const LColor &color)
Constructs a new ColorAttrib object that indicates geometry should be rendered in the indicated color...
Definition colorAttrib.cxx:46
ColorWriteAttrib::make
static ConstPointerTo< RenderAttrib > make(unsigned int channels)
Constructs a new ColorWriteAttrib object.
Definition colorWriteAttrib.cxx:29
ConfigVariableBool
This is a convenience class to specialize ConfigVariable as a boolean type.
Definition configVariableBool.h:23
ConfigVariableInt
This is a convenience class to specialize ConfigVariable as an integer type.
Definition configVariableInt.h:24
ConfigVariable::get_num_words
size_t get_num_words() const
Returns the number of words in the variable's value.
Definition configVariable.I:100
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
CullTraverserData
This collects together the pieces of data that are accumulated for each node while walking the scene ...
Definition cullTraverserData.h:40
CullTraverser
This object performs a depth-first traversal of the scene graph, with optional view-frustum culling,...
Definition cullTraverser.h:45
CullTraverser::get_cull_handler
CullHandler * get_cull_handler() const
Returns the object that will receive the culled Geoms.
Definition cullTraverser.I:152
CullTraverser::get_current_thread
Thread * get_current_thread() const
Returns the currently-executing thread object, as passed to the CullTraverser constructor.
Definition cullTraverser.I:27
CullTraverser::end_traverse
virtual void end_traverse()
Should be called when the traverser has finished traversing its scene, this gives it a chance to do a...
Definition cullTraverser.cxx:220
CullTraverser::set_scene
virtual void set_scene(SceneSetup *scene_setup, GraphicsStateGuardianBase *gsg, bool dr_incomplete_render)
Sets the SceneSetup object that indicates the initial camera position, etc.
Definition cullTraverser.cxx:85
CullTraverser::traverse_below
virtual void traverse_below(CullTraverserData &data)
Traverses all the children of the indicated node, with the given data, which has been converted into ...
Definition cullTraverser.cxx:172
CullTraverser::set_cull_handler
void set_cull_handler(CullHandler *cull_handler)
Specifies the object that will receive the culled Geoms.
Definition cullTraverser.I:144
CullTraverser::get_scene
SceneSetup * get_scene() const
Returns the SceneSetup object.
Definition cullTraverser.I:35
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
CullableObject
The smallest atom of cull.
Definition cullableObject.h:41
DepthTestAttrib::make
static ConstPointerTo< RenderAttrib > make(PandaCompareFunc mode)
Constructs a new DepthTestAttrib object.
Definition depthTestAttrib.cxx:29
DepthWriteAttrib::make
static ConstPointerTo< RenderAttrib > make(Mode mode)
Constructs a new DepthWriteAttrib object.
Definition depthWriteAttrib.cxx:29
DisplayRegionPipelineReader
Encapsulates the data from a DisplayRegion, pre-fetched for one stage of the pipeline.
Definition displayRegion.h:312
DrawCullHandler
This special kind of CullHandler immediately draws its contents as soon as it receives them.
Definition drawCullHandler.h:30
GeomVertexFormat::get_v3
static const GeomVertexFormat * get_v3()
Returns a standard vertex format with just a 3-component vertex position.
Definition geomVertexFormat.I:251
Geom
A container for geometry primitives.
Definition geom.h:54
GraphicsEngine::make_output
GraphicsOutput * make_output(GraphicsPipe *pipe, const std::string &name, int sort, const FrameBufferProperties &fb_prop, const WindowProperties &win_prop, int flags, GraphicsStateGuardian *gsg=nullptr, GraphicsOutput *host=nullptr)
Creates a new window (or buffer) and returns it.
Definition graphicsEngine.cxx:268
GraphicsOutput
This is a base class for the various different classes that represent the result of a frame of render...
Definition graphicsOutput.h:63
GraphicsOutput::get_gsg
get_gsg
Returns the GSG that is associated with this window.
Definition graphicsOutput.h:117
GraphicsOutput::get_host
virtual GraphicsOutput * get_host()
This is normally called only from within make_texture_buffer().
Definition graphicsOutput.cxx:1064
GraphicsStateGuardianBase
This is a base class for the GraphicsStateGuardian class, which is itself a base class for the variou...
Definition graphicsStateGuardianBase.h:110
GraphicsStateGuardianBase::get_gsg
get_gsg
Returns the nth GSG in the universe.
Definition graphicsStateGuardianBase.h:247
GraphicsStateGuardian
Encapsulates all the communication with a particular instance of a given rendering backend.
Definition graphicsStateGuardian.h:65
GraphicsStateGuardian::get_pipe
get_pipe
Returns the graphics pipe on which this GSG was created.
Definition graphicsStateGuardian.h:117
GraphicsStateGuardian::set_scene
set_scene
Sets the SceneSetup object that indicates the initial camera position, etc.
Definition graphicsStateGuardian.h:290
GraphicsStateGuardian::get_engine
GraphicsEngine * get_engine() const
Returns the graphics engine that created this GSG.
Definition graphicsStateGuardian.cxx:319
GraphicsStateGuardian::get_supports_occlusion_query
get_supports_occlusion_query
Returns true if this GSG supports an occlusion query.
Definition graphicsStateGuardian.h:220
GraphicsStateGuardian::prepare_display_region
virtual void prepare_display_region(DisplayRegionPipelineReader *dr)
Makes the specified DisplayRegion current.
Definition graphicsStateGuardian.cxx:2148
GraphicsStateGuardian::end_scene
virtual void end_scene()
Called between begin_frame() and end_frame() to mark the end of drawing commands for a "scene" (usual...
Definition graphicsStateGuardian.cxx:2332
GraphicsStateGuardian::end_occlusion_query
virtual PointerTo< OcclusionQueryContext > end_occlusion_query()
Ends a previous call to begin_occlusion_query().
Definition graphicsStateGuardian.cxx:727
GraphicsStateGuardian::begin_occlusion_query
virtual void begin_occlusion_query()
Begins a new occlusion query.
Definition graphicsStateGuardian.cxx:716
GraphicsStateGuardian::get_threading_model
const GraphicsThreadingModel & get_threading_model() const
Returns the threading model that was used to create this GSG.
Definition graphicsStateGuardian.I:206
GraphicsStateGuardian::begin_scene
virtual bool begin_scene()
Called between begin_frame() and end_frame() to mark the beginning of drawing commands for a "scene" ...
Definition graphicsStateGuardian.cxx:2321
NodePath
NodePath is the fundamental system for disambiguating instances, and also provides a higher-level int...
Definition nodePath.h:159
NodePath::get_parent
get_parent
Returns the NodePath to the parent of the referenced node: that is, this NodePath,...
Definition nodePath.h:242
NodePath::get_transform
const TransformState * get_transform(Thread *current_thread=Thread::get_current_thread()) const
Returns the complete transform object set on this node.
Definition nodePath.cxx:794
OcclusionQueryContext
Returned from a GSG in response to begin_occlusion_query() .
Definition occlusionQueryContext.h:25
PNMImage
The name of this class derives from the fact that we originally implemented it as a layer on top of t...
Definition pnmImage.h:58
PStatCollector
A lightweight class that represents a single element that may be timed and/or counted via stats.
Definition pStatCollector.h:43
PStatTimer
A lightweight class that can be used to automatically start and stop a PStatCollector around a sectio...
Definition pStatTimer.h:30
PandaNodePipelineReader::get_effects
const RenderEffects * get_effects() const
Returns the complete RenderEffects that will be applied to this node.
Definition pandaNode.I:1431
PandaNodePipelineReader::get_bounds
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
PandaNodePipelineReader::get_nested_vertices
int get_nested_vertices() const
Returns the total number of vertices that will be rendered by this node and all of its descendents.
Definition pandaNode.I:1528
PandaNodePipelineReader::is_final
bool is_final() const
Returns the current state of the "final" flag.
Definition pandaNode.I:1539
PandaNode::is_geom_node
virtual bool is_geom_node() const
A simple downcast check.
Definition pandaNode.cxx:2062
PipeOcclusionCullTraverser::get_texture
Texture * get_texture()
Returns a Texture that can be used to visualize the efforts of the occlusion cull.
Definition pipeOcclusionCullTraverser.cxx:266
PipeOcclusionCullTraverser::end_traverse
virtual void end_traverse()
Should be called when the traverser has finished traversing its scene, this gives it a chance to do a...
Definition pipeOcclusionCullTraverser.cxx:208
PipeOcclusionCullTraverser::set_scene
virtual void set_scene(SceneSetup *scene_setup, GraphicsStateGuardianBase *gsg, bool dr_incomplete_render)
Sets the SceneSetup object that indicates the initial camera position, etc.
Definition pipeOcclusionCullTraverser.cxx:126
RenderEffects::has_show_bounds
bool has_show_bounds() const
This function is provided as an optimization, to speed up the render-time checking for the existance ...
Definition renderEffects.I:166
RenderState::make
static ConstPointerTo< RenderState > make(const RenderAttrib *attrib, int override=0)
Returns a RenderState with one attribute set.
Definition renderState.cxx:235
SceneSetup
This object holds the camera position, etc., and other general setup information for rendering a part...
Definition sceneSetup.h:32
SceneSetup::get_cs_transform
const TransformState * get_cs_transform() const
Returns the transform from the camera's coordinate system to the GSG's internal coordinate system.
Definition sceneSetup.I:250
SceneSetup::get_cs_world_transform
const TransformState * get_cs_world_transform() const
Returns the position from the starting node relative to the camera, in the GSG's internal coordinate ...
Definition sceneSetup.I:268
Texture
Represents a texture object, which is typically a single 2-d image but may also represent a 1-d or 3-...
Definition texture.h:72
Thread
A thread; that is, a lightweight process.
Definition thread.h:46
TransformState
Indicates a coordinate-system transform on vertices.
Definition transformState.h:54
TransparencyAttrib::make
static ConstPointerTo< RenderAttrib > make(Mode mode)
Constructs a new TransparencyAttrib object.
Definition transparencyAttrib.cxx:29
TypeHandle
TypeHandle is the identifier used to differentiate C++ class types.
Definition typeHandle.h:81
TypedObject::is_exact_type
bool is_exact_type(TypeHandle handle) const
Returns true if the current object is the indicated type exactly.
Definition typedObject.I:38
WindowProperties::set_size
set_size
Specifies the requested size of the window, in pixels.
Definition windowProperties.h:93
colorAttrib.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
colorWriteAttrib.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
configVariableInt.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
config_grutil.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
cullBinManager.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
depthTestAttrib.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
depthWriteAttrib.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
drawCullHandler.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
geomTriangles.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
geomTristrips.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
geomVertexWriter.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
graphicsEngine.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
graphicsPipe.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
pStatTimer.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
pipeOcclusionCullTraverser.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
pnmImage.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
TransformState
STTransform::operator CPT TransformState() const
This is used internally to convert an STTransform into a TransformState pointer.
Definition stTransform.I:98