2 #include <msp/gl/extensions/arb_occlusion_query.h>
3 #include <msp/gl/extensions/arb_occlusion_query2.h>
5 #include "occludedscene.h"
6 #include "programbuilder.h"
15 OccludedScene::OccludedScene():
16 bounding_mesh((VERTEX3, NORMAL3)),
17 bounding_shader(ProgramBuilder::StandardFeatures()),
18 occluder_min_size(0.25f),
21 static Require req(ARB_occlusion_query);
22 static Require req2(ARB_occlusion_query2);
24 /* Use a slightly larger radius to ensure that all parts of the renderable
25 fit inside the icosahedron */
26 IcoSphereBuilder(1.26f, 1).build(bounding_mesh);
27 bounding_mesh.set_winding(&WindingTest::counterclockwise());
30 OccludedScene::~OccludedScene()
32 vector<unsigned> queries;
33 queries.reserve(occluded_cache.size());
34 for(OccludedArray::iterator i=occluded_cache.begin(); i!=occluded_cache.end(); ++i)
35 queries.push_back(i->query);
36 glDeleteQueries(queries.size(), &queries[0]);
39 void OccludedScene::add(Renderable &r)
41 renderables.insert(&r);
45 void OccludedScene::remove(Renderable &r)
47 renderables.erase(&r);
51 void OccludedScene::populate_cache() const
56 if(occluded_cache.size()<renderables.size())
58 unsigned old_size = occluded_cache.size();
59 occluded_cache.resize(renderables.size());
60 vector<unsigned> new_queries(occluded_cache.size()-old_size);
61 glGenQueries(new_queries.size(), &new_queries[0]);
62 for(unsigned i=0; i<new_queries.size(); ++i)
63 occluded_cache[old_size+i].query = new_queries[i];
66 OccludedArray::iterator j = occluded_cache.begin();
67 for(RenderableSet::iterator i=renderables.begin(); i!=renderables.end(); ++i, ++j)
69 for(; j!=occluded_cache.end(); ++j)
72 j->in_frustum = false;
78 void OccludedScene::setup_frame(Renderer &renderer)
81 for(OccludedArray::const_iterator i=occluded_cache.begin(); i!=occluded_cache.end(); ++i)
82 i->renderable->setup_frame(renderer);
85 void OccludedScene::finish_frame()
87 for(OccludedArray::const_iterator i=occluded_cache.begin(); i!=occluded_cache.end(); ++i)
88 i->renderable->finish_frame();
91 void OccludedScene::render(Renderer &renderer, const Tag &tag) const
93 if(renderables.empty())
98 const Camera *camera = renderer.get_camera();
101 for(OccludedArray::const_iterator i=occluded_cache.begin(); i!=occluded_cache.end(); ++i)
102 renderer.render(*i->renderable, tag);
106 const Vector3 &camera_pos = camera->get_position();
107 const Vector3 &look_dir = camera->get_look_direction();
108 float near_clip = camera->get_near_clip();
109 float frustum_h = tan(camera->get_field_of_view()/2.0f)*2.0f;
111 // Perform frustum culling and render any major occluders
112 bool use_frustum = setup_frustum(renderer);
113 for(OccludedArray::iterator i=occluded_cache.begin(); (i!=occluded_cache.end() && i->renderable); ++i)
115 i->in_frustum = (!use_frustum || !frustum_cull(*i->renderable));
119 const Matrix *matrix = i->renderable->get_matrix();
120 i->bounding_sphere = i->renderable->get_bounding_sphere();
121 if(matrix && i->bounding_sphere)
123 float depth = dot(*matrix*i->bounding_sphere->get_center()-camera_pos, look_dir);
124 float size = i->bounding_sphere->get_radius()*2/max(depth, near_clip);
125 i->occluder = (size>frustum_h*occluder_min_size);
128 // If the size can't be calculated, treat it as occluder
132 renderer.render(*i->renderable, tag);
135 // Move all objects within the frustum to the beginning of the array
136 for(OccludedArray::iterator i=occluded_cache.begin(), j=i+renderables.size()-1; i!=j; )
140 else if(j->in_frustum)
147 Renderer::Push push(renderer);
148 renderer.set_shader_program(&bounding_shader);
150 glColorMask(false, false, false, false);
153 // Fire off the occlusion queries
154 for(OccludedArray::const_iterator i=occluded_cache.begin(); (i!=occluded_cache.end() && i->in_frustum); ++i)
157 glBeginQuery(GL_ANY_SAMPLES_PASSED, i->query);
158 Renderer::Push push2(renderer);
159 renderer.transform(Matrix(*i->renderable->get_matrix())
160 .translate(i->bounding_sphere->get_center())
161 .scale(i->bounding_sphere->get_radius()));
162 bounding_mesh.draw(renderer);
163 glEndQuery(GL_ANY_SAMPLES_PASSED);
166 glColorMask(true, true, true, true);
170 // Render anything that has a chance of being visible
171 for(OccludedArray::const_iterator i=occluded_cache.begin(); (i!=occluded_cache.end() && i->in_frustum); ++i)
174 unsigned any_passed = 0;
175 glGetQueryObjectuiv(i->query, GL_QUERY_RESULT, &any_passed);
177 renderer.render(*i->renderable, tag);
182 OccludedScene::OccludedRenderable::OccludedRenderable():