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);
virtual void set_scene(SceneSetup *scene_setup, GraphicsStateGuardianBase *gsg, bool dr_incomplete_render)
Sets the SceneSetup object that indicates the initial camera position, etc.
set_scene
Sets the SceneSetup object that indicates the initial camera position, etc.
bool is_final() const
Returns the current state of the "final" flag.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
A basic node of the scene graph or data graph.
This object provides a high-level interface for quickly writing a sequence of numeric values from a v...
An axis-aligned bounding box; that is, a minimum and maximum coordinate triple.
CullHandler * get_cull_handler() const
Returns the object that will receive the culled Geoms.
Encapsulates the data from a DisplayRegion, pre-fetched for one stage of the pipeline.
bool is_exact_type(TypeHandle handle) const
Returns true if the current object is the indicated type exactly.
virtual GraphicsOutput * get_host()
This is normally called only from within make_texture_buffer().
get_pipe
Returns the graphics pipe on which this GSG was created.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
virtual void end_traverse()
Should be called when the traverser has finished traversing its scene, this gives it a chance to do a...
const RenderEffects * get_effects() const
Returns the complete RenderEffects that will be applied to this node.
The name of this class derives from the fact that we originally implemented it as a layer on top of t...
set_size
Specifies the requested size of the window, in pixels.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
get_gsg
Returns the nth GSG in the universe.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
virtual void traverse_below(CullTraverserData &data)
Traverses all the children of the indicated node, with the given data, which has been converted into ...
bool is_empty() const
Any kind of volume might be empty.
virtual void prepare_display_region(DisplayRegionPipelineReader *dr)
Makes the specified DisplayRegion current.
Thread * get_current_thread() const
Returns the currently-executing thread object, as passed to the CullTraverser constructor.
This is a convenience class to specialize ConfigVariable as a boolean type.
This defines a bounding sphere, consisting of a center and a radius.
bool is_infinite() const
The other side of the empty coin is an infinite volume.
Represents a texture object, which is typically a single 2-d image but may also represent a 1-d or 3-...
int get_nested_vertices() const
Returns the total number of vertices that will be rendered by this node and all of its descendents.
This collects together the pieces of data that are accumulated for each node while walking the scene ...
get_parent
Returns the NodePath to the parent of the referenced node: that is, this NodePath,...
Defines a series of triangle strips.
A lightweight class that can be used to automatically start and stop a PStatCollector around a sectio...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
virtual void end_traverse()
Should be called when the traverser has finished traversing its scene, this gives it a chance to do a...
const TransformState * get_cs_world_transform() const
Returns the position from the starting node relative to the camera, in the GSG's internal coordinate ...
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.
get_supports_occlusion_query
Returns true if this GSG supports an occlusion query.
GraphicsEngine * get_engine() const
Returns the graphics engine that created this GSG.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
const TransformState * get_cs_transform() const
Returns the transform from the camera's coordinate system to the GSG's internal coordinate system.
This is an abstract class for any volume in any sense which can be said to define the locality of ref...
A lightweight class that represents a single element that may be timed and/or counted via stats.
size_t get_num_words() const
Returns the number of words in the variable's value.
bool has_show_bounds() const
This function is provided as an optimization, to speed up the render-time checking for the existance ...
A container for the various kinds of properties we might ask to have on a graphics window before we o...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
The smallest atom of cull.
Texture * get_texture()
Returns a Texture that can be used to visualize the efforts of the occlusion cull.
virtual void record_object(CullableObject *object, const CullTraverser *traverser)
This callback function is intended to be overridden by a derived class.
This defines the actual numeric vertex data stored in a Geom, in the structure defined by a particula...
An object to create GraphicsOutputs that share a particular 3-D API.
const LPoint3 & get_maxq() const
An inline accessor for the maximum value.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
A container for geometry primitives.
virtual void begin_occlusion_query()
Begins a new occlusion query.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
const BoundingVolume * get_bounds() const
Returns the external bounding volume of this node: a bounding volume that contains the user bounding ...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This is a base class for the various different classes that represent the result of a frame of render...
This represents the user's specification of how a particular frame is handled by the various threads.
This represents a unique collection of RenderAttrib objects that correspond to a particular renderabl...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This special kind of CullHandler immediately draws its contents as soon as it receives them.
This is a base class for the GraphicsStateGuardian class, which is itself a base class for the variou...
A thread; that is, a lightweight process.
GeometricBoundingVolume * get_view_frustum() const
Returns the bounding volume that corresponds to the view frustum, or NULL if the view frustum is not ...
Encapsulates the data from a PandaNode, pre-fetched for one stage of the pipeline.
SceneSetup * get_scene() const
Returns the SceneSetup object.
Encapsulates all the communication with a particular instance of a given rendering backend.
This is a convenience class to specialize ConfigVariable as an integer type.
Defines a series of disconnected triangles.
virtual void end_scene()
Called between begin_frame() and end_frame() to mark the end of drawing commands for a "scene" (usual...
Returned from a GSG in response to begin_occlusion_query() .
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This class is the main interface to controlling the render process.
TypeHandle is the identifier used to differentiate C++ class types.
const TransformState * get_transform(Thread *current_thread=Thread::get_current_thread()) const
Returns the complete transform object set on this node.
This object holds the camera position, etc., and other general setup information for rendering a part...
A container for the various kinds of properties we might ask to have on a graphics frameBuffer before...
PT(OcclusionQueryContext) PipeOcclusionCullTraverser
Renders the indicated geometry in the internal scene to test its visibility.
virtual bool is_geom_node() const
A simple downcast check.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
get_gsg
Returns the GSG that is associated with this window.
NodePath is the fundamental system for disambiguating instances, and also provides a higher-level int...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This object performs a depth-first traversal of the scene graph, with optional view-frustum culling,...
virtual void set_scene(SceneSetup *scene_setup, GraphicsStateGuardianBase *gsg, bool dr_incomplete_render)
Sets the SceneSetup object that indicates the initial camera position, etc.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
const GraphicsThreadingModel & get_threading_model() const
Returns the threading model that was used to create this GSG.
virtual bool begin_scene()
Called between begin_frame() and end_frame() to mark the beginning of drawing commands for a "scene" ...
const LPoint3 & get_minq() const
An inline accessor for the minimum value.
void set_cull_handler(CullHandler *cull_handler)
Specifies the object that will receive the culled Geoms.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.