1 #include <msp/core/algorithm.h>
4 #include "occludedscene.h"
14 OccludedScene::OccludedScene():
15 bounding_mesh(Resources::get_global().get<Mesh>("_occluder.mesh")),
16 bounding_shader(Resources::get_global().get<Program>("occluder.glsl.shader")),
17 queries(OCCLUSION_QUERY, 0)
19 no_color_write.write_mask = WRITE_NONE;
22 void OccludedScene::add(Renderable &r)
24 auto i = lower_bound(content, &r);
25 if(i==content.end() || *i!=&r)
27 content.insert(i, &r);
32 void OccludedScene::remove(Renderable &r)
34 auto i = lower_bound(content, &r);
35 if(i!=content.end() && *i==&r)
42 void OccludedScene::populate_cache() const
47 if(queries.get_size()<content.size())
48 queries.resize(content.size());
49 if(occluded_cache.size()<content.size())
50 occluded_cache.resize(content.size());
52 auto j = occluded_cache.begin();
53 for(Renderable *r: content)
55 for(; j!=occluded_cache.end(); ++j)
58 j->in_frustum = false;
64 void OccludedScene::setup_frame(Renderer &renderer)
67 for(const OccludedRenderable &o: occluded_cache)
68 o.renderable->setup_frame(renderer);
71 void OccludedScene::finish_frame()
73 for(const OccludedRenderable &o: occluded_cache)
74 o.renderable->finish_frame();
77 void OccludedScene::render(Renderer &renderer, Tag tag) const
84 const Camera *camera = renderer.get_camera();
87 for(const OccludedRenderable &o: occluded_cache)
88 o.renderable->render(renderer, tag);
92 const Vector3 &camera_pos = camera->get_position();
93 const Vector3 &look_dir = camera->get_look_direction();
94 float near_clip = camera->get_near_clip();
95 float frustum_h = tan(camera->get_field_of_view()/2.0f)*2.0f;
97 // Perform frustum culling and render any major occluders
98 for(auto i=occluded_cache.begin(); (i!=occluded_cache.end() && i->renderable); ++i)
100 i->in_frustum = camera->is_in_frustum(*i->renderable);
104 const Matrix *matrix = i->renderable->get_matrix();
105 i->bounding_sphere = i->renderable->get_bounding_sphere();
106 if(matrix && i->bounding_sphere)
108 float depth = dot(*matrix*i->bounding_sphere->get_center()-camera_pos, look_dir);
109 float size = i->bounding_sphere->get_radius()*2/max(depth, near_clip);
110 i->occluder = (size>frustum_h*occluder_min_size);
113 // If the size can't be calculated, treat it as occluder
117 i->renderable->render(renderer, tag);
120 // Move all objects within the frustum to the beginning of the array
121 for(auto i=occluded_cache.begin(), j=i+content.size()-1; i!=j; )
125 else if(j->in_frustum)
132 Renderer::Push push(renderer);
133 renderer.set_shader_program(&bounding_shader);
135 renderer.set_blend(&no_color_write);
136 // XXX Preserve existing depth test predicate
137 renderer.set_depth_test(&no_depth_write);
139 // Fire off the occlusion queries
140 for(auto i=occluded_cache.begin(); (i!=occluded_cache.end() && i->in_frustum); ++i)
143 QueryPool::Activate activate_query(renderer, queries, i-occluded_cache.begin());
144 Renderer::Push push2(renderer);
145 renderer.set_matrix(Matrix(*i->renderable->get_matrix())
146 .translate(i->bounding_sphere->get_center())
147 .scale(i->bounding_sphere->get_radius()));
148 bounding_mesh.draw(renderer);
152 // Render anything that has a chance of being visible
153 for(auto i=occluded_cache.begin(); (i!=occluded_cache.end() && i->in_frustum); ++i)
154 if(!i->occluder && queries.get_result(i-occluded_cache.begin()))
155 i->renderable->render(renderer, tag);