X-Git-Url: http://git.tdb.fi/?p=libs%2Fgl.git;a=blobdiff_plain;f=source%2Frender%2Fcamera.cpp;h=9ecb79cd80643d4ce4e4d77f045d4354aebb37af;hp=8b966464fd14d2ed42eb478d4b025f95bc1fbcfa;hb=HEAD;hpb=344bb25a8314811f6591111f10777635feb6fd36 diff --git a/source/render/camera.cpp b/source/render/camera.cpp index 8b966464..bc8de57e 100644 --- a/source/render/camera.cpp +++ b/source/render/camera.cpp @@ -7,22 +7,29 @@ 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; @@ -103,7 +110,7 @@ Vector3 Camera::project(const Vector4 &p) const Vector3 Camera::project(const Vector3 &p) const { - return project(Vector4(p.x, p.y, p.z, 1.0)); + return project(compose(p, 1.0f)); } Vector4 Camera::unproject(const Vector4 &p) const @@ -115,25 +122,48 @@ Vector4 Camera::unproject(const Vector4 &p) const Vector3 Camera::unproject(const Vector3 &p) const { - return unproject(Vector4(p.x, p.y, p.z, 1.0f)).slice<3>(0); + return unproject(compose(p, 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); + float frustum_h = (is_orthographic() ? height/2 : tan(fov/2.0f)*clip_near); float frustum_w = frustum_h*aspect; float left = frustum_w*(frustum_x-1.0f); float right = frustum_w*(frustum_x+1.0f); float bottom = frustum_h*(frustum_y-1.0f); float top = frustum_h*(frustum_y+1.0f); - if(fov>Geometry::Angle::zero()) - proj_matrix = Matrix::frustum(left, right, bottom, top, clip_near, clip_far); - else + if(is_orthographic()) proj_matrix = Matrix::ortho(left, right, bottom, top, clip_near, clip_far); + else + proj_matrix = Matrix::frustum(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() @@ -149,6 +179,43 @@ 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)