X-Git-Url: http://git.tdb.fi/?a=blobdiff_plain;f=source%2Frender%2Fcamera.cpp;h=7ffe0c155e60f6a6b968869901485a2c399fd7e6;hb=4f2f558123db15393607d8b21b949d7798561dec;hp=3bba0eaf38e00385e68a077474095a980a10f340;hpb=7aaec9a70b8d7733429bec043f8e33e02956f266;p=libs%2Fgl.git diff --git a/source/render/camera.cpp b/source/render/camera.cpp index 3bba0eaf..7ffe0c15 100644 --- a/source/render/camera.cpp +++ b/source/render/camera.cpp @@ -2,25 +2,34 @@ #include "camera.h" #include "matrix.h" +using namespace std; + namespace Msp { namespace GL { -Camera::Camera(): - fov(Geometry::Angle::from_turns(0.125)), - height(0), - aspect(4.0/3.0), - clip_near(0.1), - clip_far(10), - frustum_x(0), - frustum_y(0), - position(0, 0, 0), - look_dir(0, 0, -1), - up_dir(0, 1, 0) +Camera::Camera() { update_projection_matrix(); update_object_matrix(); } +void Camera::copy_parameters(const Camera &source) +{ + fov = source.fov; + height = source.height; + aspect = source.aspect; + clip_near = source.clip_near; + clip_far = source.clip_far; + frustum_x = source.frustum_x; + frustum_y = source.frustum_y; + rotate = source.rotate; + position = source.position; + look_dir = source.look_dir; + up_dir = source.up_dir; + update_projection_matrix(); + update_object_matrix(); +} + void Camera::set_field_of_view(const Geometry::Angle &f) { fov = f; @@ -116,6 +125,27 @@ Vector3 Camera::unproject(const Vector3 &p) const 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 *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::zero() ? tan(fov/2.0f)*clip_near : height/2); @@ -129,6 +159,11 @@ void Camera::update_projection_matrix() else proj_matrix = Matrix::ortho(left, right, bottom, top, clip_near, clip_far); proj_matrix = Matrix::rotation(rotate, Vector3(0, 0, 1))*proj_matrix; + + shdata.uniform("clip_eye_matrix", proj_matrix); + shdata.uniform("eye_clip_matrix", invert(proj_matrix)); + + update_frustum_planes(); } void Camera::update_object_matrix() @@ -141,6 +176,55 @@ void Camera::update_object_matrix() columns[3] = compose(position, 1.0f); matrix = Matrix::from_columns(columns); view_matrix = invert(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) +{ +#ifdef DEBUG + shdata.set_debug_name(name+" [UBO]"); +#else + (void)name; +#endif }