return unproject(Vector4(p.x, p.y, p.z, 1.0f)).slice<3>(0);
}
+bool Camera::is_in_frustum(const Renderable &renderable) const
+{
+ const Matrix *rmatrix = renderable.get_matrix();
+ const Geometry::BoundingSphere<float, 3> *bsphere = renderable.get_bounding_sphere();
+ if(!rmatrix || !bsphere)
+ return true;
+
+ Vector4 center = *rmatrix*compose(bsphere->get_center(), 1.0f);
+ Vector3 x_axis = (rmatrix->column(0)*bsphere->get_radius()).slice<3>(0);
+ float radius_sq = inner_product(x_axis, x_axis);
+
+ for(unsigned i=0; i<6; ++i)
+ {
+ float distance = inner_product(center, frustum_planes[i]);
+ if(distance<0 && distance*distance>radius_sq)
+ return false;
+ }
+
+ return true;
+}
+
void Camera::update_projection_matrix()
{
float frustum_h = (fov!=Geometry::Angle<float>::zero() ? tan(fov/2.0f)*clip_near : height/2);
shdata.uniform("clip_eye_matrix", proj_matrix);
shdata.uniform("eye_clip_matrix", invert(proj_matrix));
+
+ update_frustum_planes();
}
void Camera::update_object_matrix()
shdata.uniform("world_eye_matrix", matrix);
shdata.uniform("eye_world_matrix", view_matrix);
+
+ update_frustum_planes();
+}
+
+void Camera::update_frustum_planes()
+{
+ // TODO Handle off-center and rotated frustums
+ if(is_orthographic())
+ {
+ frustum_planes[0] = Vector4(0, 1, 0, height);
+ frustum_planes[1] = Vector4(0, -1, 0, height);
+
+ frustum_planes[2] = Vector4(1, 0, 0, height*aspect);
+ frustum_planes[3] = Vector4(-1, 0, 0, height*aspect);
+ }
+ else
+ {
+ float y = tan(fov/2.0f);
+ float s = sqrt(y*y+1);
+ frustum_planes[0] = Vector4(0, 1/s, -y/s, 0);
+ frustum_planes[1] = Vector4(0, -1/s, -y/s, 0);
+
+ float x = y*aspect;
+ s = sqrt(x*x+1);
+ frustum_planes[2] = Vector4(1/s, 0, -x/s, 0);
+ frustum_planes[3] = Vector4(-1/s, 0, -x/s, 0);
+ }
+
+ frustum_planes[4] = Vector4(0, 0, 1, clip_far);
+ frustum_planes[5] = Vector4(0, 0, -1, -clip_near);
+
+ for(unsigned i=0; i<6; ++i)
+ {
+ Vector3 normal = frustum_planes[i].slice<3>(0);
+ normal = (matrix*compose(normal, 0.0f)).slice<3>(0);
+ frustum_planes[i] = compose(normal, frustum_planes[i].w-dot(normal, matrix.column(3).slice<3>(0)));
+ }
}
void Camera::set_debug_name(const string &name)
Matrix view_matrix;
Matrix proj_matrix;
ProgramData shdata;
+ Vector4 frustum_planes[6];
public:
Camera();
/** Returns a ProgramData object containing the camera matrices. */
const ProgramData &get_shader_data() const { return shdata; }
+ bool is_in_frustum(const Renderable &) const;
+
private:
void update_projection_matrix();
void update_object_matrix();
+ void update_frustum_planes();
public:
void set_debug_name(const std::string &);
float frustum_h = tan(camera->get_field_of_view()/2.0f)*2.0f;
// Perform frustum culling and render any major occluders
- bool use_frustum = setup_frustum(renderer);
for(auto i=occluded_cache.begin(); (i!=occluded_cache.end() && i->renderable); ++i)
{
- i->in_frustum = (!use_frustum || !frustum_cull(*i->renderable));
+ i->in_frustum = camera->is_in_frustum(*i->renderable);
if(!i->in_frustum)
continue;
#include <msp/core/algorithm.h>
+#include "camera.h"
#include "orderedscene.h"
#include "renderer.h"
void OrderedScene::render(Renderer &renderer, Tag tag) const
{
- if(setup_frustum(renderer))
+ if(const Camera *camera = renderer.get_camera())
{
for(Renderable *r: content)
- if(!frustum_cull(*r))
+ if(camera->is_in_frustum(*r))
r->render(renderer, tag);
}
else
namespace Msp {
namespace GL {
-bool Scene::setup_frustum(const Renderer &renderer) const
-{
- const Camera *camera = renderer.get_camera();
- if(!camera)
- return false;
-
- culling_matrix = camera->get_view_matrix()*renderer.get_matrix();
-
- if(camera->is_orthographic())
- {
- float h = camera->get_orthographic_height();
- frustum_edges[0] = Vector4(0, 1, 0, -h);
- frustum_edges[1] = Vector4(0, -1, 0, -h);
-
- float w = camera->get_orthographic_width();
- frustum_edges[2] = Vector4(1, 0, 0, -w);
- frustum_edges[3] = Vector4(-1, 0, 0, -w);
- }
- else
- {
- float y = tan(camera->get_field_of_view()/2.0f);
- float s = sqrt(y*y+1);
- frustum_edges[0] = Vector4(0, 1/s, y/s, 0);
- frustum_edges[1] = Vector4(0, -1/s, y/s, 0);
-
- float x = y*camera->get_aspect_ratio();
- s = sqrt(x*x+1);
- frustum_edges[2] = Vector4(1/s, 0, x/s, 0);
- frustum_edges[3] = Vector4(-1/s, 0, x/s, 0);
- }
-
- frustum_edges[4] = Vector4(0, 0, -1, -camera->get_far_clip());
- frustum_edges[5] = Vector4(0, 0, 1, camera->get_near_clip());
-
- return true;
-}
-
-bool Scene::frustum_cull(const Renderable &renderable) const
-{
- const Matrix *matrix = renderable.get_matrix();
- const Geometry::BoundingSphere<float, 3> *bsphere = renderable.get_bounding_sphere();
- if(!matrix || !bsphere)
- return false;
-
- Vector4 center = culling_matrix*(*matrix*compose(bsphere->get_center(), 1.0f));
- Vector3 x_axis = (matrix->column(0)*bsphere->get_radius()).slice<3>(0);
- float radius_sq = inner_product(x_axis, x_axis);
-
- for(unsigned i=0; i<6; ++i)
- {
- float distance = inner_product(center, frustum_edges[i]);
- if(distance>0 && distance*distance>radius_sq)
- return true;
- }
-
- return false;
-}
-
Scene::GenericLoader::TypeRegistry &Scene::get_scene_registry()
{
static Scene::GenericLoader::TypeRegistry registry;
protected:
mutable Matrix culling_matrix;
- mutable Vector4 frustum_edges[6];
Scene() = default;
public:
virtual void add(Renderable &) = 0;
virtual void remove(Renderable &) = 0;
-protected:
- bool setup_frustum(const Renderer &) const;
- bool frustum_cull(const Renderable &) const;
-
-public:
template<typename T>
static void register_type(const std::string &);
private:
#include <msp/core/algorithm.h>
+#include "camera.h"
#include "renderer.h"
#include "simplescene.h"
void SimpleScene::render(Renderer &renderer, Tag tag) const
{
- if(setup_frustum(renderer))
+ if(const Camera *camera = renderer.get_camera())
{
for(Renderable *r: content)
- if(!frustum_cull(*r))
+ if(camera->is_in_frustum(*r))
r->render(renderer, tag);
}
else
float radius_factor = reference-1.0f;
float sign = 1.0f-order*2.0f;
- bool use_frustum = setup_frustum(renderer);
for(SortedRenderable &r: sorted_cache)
{
- r.in_frustum = (!use_frustum || !frustum_cull(*r.renderable));
+ r.in_frustum = camera->is_in_frustum(*r.renderable);
if(!r.in_frustum)
continue;