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");
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");
43 TypeHandle PipeOcclusionCullTraverser::_type_handle;
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."));
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 "
63 (
"show-occlusion",
false,
64 PRC_DESC(
"Set this true to visualize the efforts of the occlusion test."));
67 (
"occlusion-size",
"256 256",
68 PRC_DESC(
"Specify the x y size of the buffer used for occlusion testing."));
71 (
"occlusion-depth-bits", 1,
72 PRC_DESC(
"The minimum number of depth bits requested for the occlusion "
78 PipeOcclusionCullTraverser::
84 nassertv(threading_model.get_cull_name() == threading_model.get_draw_name());
87 <<
"Occlusion queries are not supported by graphics pipe.\n";
95 fb_prop.set_depth_bits(occlusion_depth_bits);
98 win_prop.
set_size(occlusion_size, occlusion_size);
100 win_prop.
set_size(occlusion_size[0], occlusion_size[1]);
103 _buffer = engine->
make_output(pipe,
"occlusion", 0, fb_prop, win_prop,
104 GraphicsPipe::BF_refuse_window,
106 nassertv(_buffer !=
nullptr);
110 _buffer->set_active(0);
112 _display_region = _buffer->make_display_region();
113 _internal_cull_handler =
nullptr;
117 make_solid_test_state();
127 bool dr_incomplete_render) {
133 PStatTimer timer(_setup_occlusion_pcollector);
136 nassertv(gsg == gsgbase);
139 if (!_buffer->begin_frame(GraphicsOutput::FM_render, current_thread)) {
140 grutil_cat.error() <<
"begin_frame failed\n";
143 _buffer->clear(current_thread);
147 _buffer->change_scenes(&dr_reader);
151 _scene->set_display_region(_display_region);
152 _scene->set_viewport_size(_display_region->get_pixel_width(),
153 _display_region->get_pixel_height());
155 if (_scene->get_cull_center() != _scene->get_camera_path()) {
159 NodePath cull_center = _scene->get_cull_center();
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);
169 _inv_cs_world_transform = cs_world_transform->get_inverse();
171 _inv_cs_world_transform = _scene->get_cs_world_transform()->get_inverse();
178 grutil_cat.error() <<
"begin_scene failed\n";
191 _internal_trav->set_scene(_scene, gsg, dr_incomplete_render);
193 _internal_trav->set_camera_mask(_occlusion_mask);
195 _current_query =
nullptr;
196 _next_query =
nullptr;
199 PStatTimer timer2(_draw_occlusion_pcollector);
200 _internal_trav->traverse(_scene->get_scene_root());
213 PStatTimer timer(_finish_occlusion_pcollector);
217 _current_query =
nullptr;
218 _next_query =
nullptr;
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);
227 int num_fragments = pobj._query->get_num_fragments();
228 if (num_fragments != 0) {
229 _occlusion_passed_pcollector.add_level(1);
232 _occlusion_failed_pcollector.add_level(1);
240 pobj._object =
nullptr;
243 _pending_objects.clear();
247 _buffer->end_frame(GraphicsOutput::FM_render, current_thread);
249 _buffer->begin_flip();
252 delete _internal_cull_handler;
253 _internal_cull_handler =
nullptr;
255 _occlusion_untested_pcollector.flush_level();
256 _occlusion_passed_pcollector.flush_level();
257 _occlusion_failed_pcollector.flush_level();
258 _occlusion_tests_pcollector.flush_level();
267 if (_texture !=
nullptr) {
271 _texture =
new Texture(
"occlusion");
276 _texture->load(image);
280 _buffer->add_render_texture(_texture, GraphicsOutput::RTM_bind_or_copy);
289 bool PipeOcclusionCullTraverser::
291 _next_query =
nullptr;
293 if (!CullTraverser::is_in_view(data)) {
300 if (_current_query !=
nullptr) {
326 if (get_volume_viz(vol, geom, net_transform, internal_transform)) {
328 perform_occlusion_test(geom, net_transform, internal_transform);
339 void PipeOcclusionCullTraverser::
344 if (_next_query !=
nullptr) {
345 _current_query = _next_query;
347 _next_query =
nullptr;
351 _current_query = prev_query;
352 _next_query =
nullptr;
365 void PipeOcclusionCullTraverser::
367 nassertv(traverser ==
this);
368 PendingObject pobj(
object);
372 if (_next_query !=
nullptr) {
375 pobj._query = _next_query;
377 }
else if (_current_query !=
nullptr) {
380 pobj._query = _current_query;
382 }
else if (object->_geom->get_nested_vertices(current_thread) < min_occlusion_vertices) {
387 CPT(
BoundingVolume) vol =
object->_geom->get_bounds(current_thread);
388 CPT(
TransformState) net_transform = _inv_cs_world_transform->compose(object->_internal_transform);
391 if (get_volume_viz(vol, geom, net_transform, internal_transform)) {
393 perform_occlusion_test(geom, net_transform, internal_transform);
397 _pending_objects.push_back(pobj);
403 void PipeOcclusionCullTraverser::
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));
424 vertex.add_data3(compute_sphere_point(1.0, longitude0));
426 strip->add_next_vertices(num_stacks * 2);
427 strip->close_primitive();
430 _sphere_geom =
new Geom(vdata);
431 _sphere_geom->add_primitive(strip);
438 LVertex PipeOcclusionCullTraverser::
439 compute_sphere_point(PN_stdfloat latitude, PN_stdfloat longitude) {
441 csincos(latitude * MathNumbers::pi, &s1, &c1);
444 csincos(longitude * 2.0f * MathNumbers::pi, &s2, &c2);
446 LVertex p(s1 * c2, s1 * s2, c1);
453 void PipeOcclusionCullTraverser::
457 vdata->unclean_set_num_rows(8);
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);
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);
485 _box_geom =
new Geom(vdata);
486 _box_geom->add_primitive(tris);
493 void PipeOcclusionCullTraverser::
494 make_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));
512 bool PipeOcclusionCullTraverser::
525 TransformState::make_pos_hpr_scale(sphere->get_center(),
527 sphere->get_radius());
528 net_transform = net_transform->compose(local_transform);
531 _internal_trav->get_world_transform()->compose(net_transform);
537 const LPoint3 ¢er = modelview_transform->get_pos();
538 const LVecBase3 &radius = modelview_transform->get_scale();
539 if (center[1] - radius[1] < 0.0f) {
544 internal_transform = _internal_trav->get_scene()->
545 get_cs_transform()->compose(modelview_transform);
551 }
else if (vol->
is_exact_type(BoundingBox::get_class_type())) {
554 TransformState::make_pos_hpr_scale(box->
get_minq(),
557 net_transform = net_transform->compose(local_transform);
560 _internal_trav->get_world_transform()->compose(net_transform);
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),
576 const LMatrix4 &mat = modelview_transform->get_mat();
577 for (
int i = 0; i < 8; ++i) {
578 LPoint3 p = points[i] * mat;
585 internal_transform = _internal_trav->get_scene()->
586 get_cs_transform()->compose(modelview_transform);
604 _occlusion_tests_pcollector.add_level(1);
623 if (show_occlusion) {
627 int num_fragments = query->get_num_fragments();
628 show_results(num_fragments, geom, net_transform, internal_transform);
638 void PipeOcclusionCullTraverser::
639 show_results(
int num_fragments,
const Geom *geom,
643 if (num_fragments == 0) {
645 color.set(0.8f, 0.0f, 1.0f, 0.4f);
648 color.set(1.0f, 1.0f, 0.5f, 0.4f);
652 (DepthWriteAttrib::make(DepthWriteAttrib::M_off),
653 DepthTestAttrib::make(DepthTestAttrib::M_less),
654 TransparencyAttrib::make(TransparencyAttrib::M_alpha),
655 ColorAttrib::make_flat(color));
659 _internal_cull_handler->
record_object(internal_viz, _internal_trav);