3 #include "occludedscene.h"
13 OccludedScene::OccludedScene():
14 bounding_mesh(Resources::get_global().get<Mesh>("_occluder.mesh")),
15 bounding_shader(Resources::get_global().get<Program>("_occluder.glsl.shader")),
16 no_depth_write(LEQUAL, false),
17 occluder_min_size(0.25f),
18 queries(OCCLUSION_QUERY, 0),
21 no_color_write.write_mask = WRITE_NONE;
24 void OccludedScene::add(Renderable &r)
26 renderables.insert(&r);
30 void OccludedScene::remove(Renderable &r)
32 renderables.erase(&r);
36 void OccludedScene::populate_cache() const
41 if(queries.get_size()<renderables.size())
42 queries.resize(renderables.size());
43 if(occluded_cache.size()<renderables.size())
44 occluded_cache.resize(renderables.size());
46 auto j = occluded_cache.begin();
47 for(Renderable *r: renderables)
49 for(; j!=occluded_cache.end(); ++j)
52 j->in_frustum = false;
58 void OccludedScene::setup_frame(Renderer &renderer)
61 for(const OccludedRenderable &o: occluded_cache)
62 o.renderable->setup_frame(renderer);
65 void OccludedScene::finish_frame()
67 for(const OccludedRenderable &o: occluded_cache)
68 o.renderable->finish_frame();
71 void OccludedScene::render(Renderer &renderer, Tag tag) const
73 if(renderables.empty())
78 const Camera *camera = renderer.get_camera();
81 for(const OccludedRenderable &o: occluded_cache)
82 renderer.render(*o.renderable, tag);
86 const Vector3 &camera_pos = camera->get_position();
87 const Vector3 &look_dir = camera->get_look_direction();
88 float near_clip = camera->get_near_clip();
89 float frustum_h = tan(camera->get_field_of_view()/2.0f)*2.0f;
91 // Perform frustum culling and render any major occluders
92 bool use_frustum = setup_frustum(renderer);
93 for(auto i=occluded_cache.begin(); (i!=occluded_cache.end() && i->renderable); ++i)
95 i->in_frustum = (!use_frustum || !frustum_cull(*i->renderable));
99 const Matrix *matrix = i->renderable->get_matrix();
100 i->bounding_sphere = i->renderable->get_bounding_sphere();
101 if(matrix && i->bounding_sphere)
103 float depth = dot(*matrix*i->bounding_sphere->get_center()-camera_pos, look_dir);
104 float size = i->bounding_sphere->get_radius()*2/max(depth, near_clip);
105 i->occluder = (size>frustum_h*occluder_min_size);
108 // If the size can't be calculated, treat it as occluder
112 renderer.render(*i->renderable, tag);
115 // Move all objects within the frustum to the beginning of the array
116 for(auto i=occluded_cache.begin(), j=i+renderables.size()-1; i!=j; )
120 else if(j->in_frustum)
127 Renderer::Push push(renderer);
128 renderer.set_shader_program(&bounding_shader);
130 renderer.set_blend(&no_color_write);
131 // XXX Preserve existing depth test predicate
132 renderer.set_depth_test(&no_depth_write);
134 // Fire off the occlusion queries
135 for(auto i=occluded_cache.begin(); (i!=occluded_cache.end() && i->in_frustum); ++i)
138 QueryPool::Activate activate_query(renderer, queries, i-occluded_cache.begin());
139 Renderer::Push push2(renderer);
140 renderer.transform(Matrix(*i->renderable->get_matrix())
141 .translate(i->bounding_sphere->get_center())
142 .scale(i->bounding_sphere->get_radius()));
143 bounding_mesh.draw(renderer);
147 // Render anything that has a chance of being visible
148 for(auto i=occluded_cache.begin(); (i!=occluded_cache.end() && i->in_frustum); ++i)
149 if(!i->occluder && queries.get_result(i-occluded_cache.begin()))
150 renderer.render(*i->renderable, tag);
154 OccludedScene::OccludedRenderable::OccludedRenderable():