From: Mikko Rasa Date: Sat, 20 Feb 2010 19:08:43 +0000 (+0000) Subject: Add a Camera class X-Git-Url: http://git.tdb.fi/?p=libs%2Fgl.git;a=commitdiff_plain;h=8f2430208cfa7bb9dc5bd655dde88acc21db54d2 Add a Camera class Add Pipeline::camera pointer --- diff --git a/source/camera.cpp b/source/camera.cpp new file mode 100644 index 00000000..b392f672 --- /dev/null +++ b/source/camera.cpp @@ -0,0 +1,146 @@ +/* $Id$ + +This file is part of libmspgl +Copyright © 2010 Mikko Rasa, Mikkosoft Productions +Distributed under the LGPL +*/ + +#include +#include "camera.h" +#include "matrix.h" +#include "projection.h" + +namespace Msp { +namespace GL { + +Camera::Camera(): + fov(M_PI/4), + aspect(4.0/3.0), + clip_near(0.1), + clip_far(10), + position(0, 0, 0), + look_dir(0, 0, -1), + up_dir(0, 1, 0) +{ + for(unsigned i=0; i<16; ++i) + matrix[i] = (i%5 ? 0 : 1); + matrix[10] = -1; +} + +void Camera::set_field_of_view(float f) +{ + fov = f; +} + +void Camera::set_aspect(float a) +{ + aspect = a; +} + +void Camera::set_depth_clip(float n, float f) +{ + clip_near = n; + clip_far = f; +} + +void Camera::set_position(const Vector3 &p) +{ + position = p; + compute_matrix(); +} + +void Camera::set_up_direction(const Vector3 &u) +{ + float len = sqrt(u.x*u.x+u.y*u.y+u.z*u.z); + + up_dir.x = u.x/len; + up_dir.y = u.y/len; + up_dir.z = u.z/len; + + compute_matrix(); +} + +void Camera::set_look_direction(const Vector3 &l) +{ + float len = sqrt(l.x*l.x+l.y*l.y+l.z*l.z); + + look_dir.x = l.x/len; + look_dir.y = l.y/len; + look_dir.z = l.z/len; + + compute_matrix(); +} + +void Camera::look_at(const Vector3 &p) +{ + set_look_direction(Vector3(p.x-position.x, p.y-position.y, p.z-position.z)); +} + +Vector3 Camera::project(const Vector4 &p) const +{ + float near_h = tan(fov/2)*clip_near; + float near_w = near_h*aspect; + float z_range = clip_far-clip_near; + + float eye_x = matrix[0]*p.x+matrix[4]*p.y+matrix[8]*p.z+matrix[12]*p.w; + float eye_y = matrix[1]*p.x+matrix[5]*p.y+matrix[9]*p.z+matrix[13]*p.w; + float eye_z = matrix[2]*p.x+matrix[6]*p.y+matrix[10]*p.z+matrix[14]*p.w; + + return Vector3(eye_x/near_w/-eye_z, eye_y/near_h/-eye_z, + (clip_far+clip_near)/z_range+2*clip_far*clip_near/(eye_z*z_range)); +} + +Vector4 Camera::unproject(const Vector4 &p) const +{ + float near_h = tan(fov/2)*clip_near; + float near_w = near_h*aspect; + float z_range = clip_far-clip_near; + + float z = (2*clip_far*clip_near)/(p.z*z_range-(clip_far+clip_near))-matrix[14]*p.w; + float x = p.x*-z*near_w-matrix[12]*p.w; + float y = p.y*-z*near_h-matrix[13]*p.w; + + return Vector4(matrix[0]*x+matrix[1]*y+matrix[2]*z, + matrix[4]*x+matrix[5]*y+matrix[6]*z, + matrix[8]*x+matrix[9]*y+matrix[10]*z, + p.w); +} + +void Camera::apply() const +{ + float h = tan(fov/2)*2*clip_near; + + matrix_mode(PROJECTION); + load_identity(); + frustum_centered(h*aspect, h, clip_near, clip_far); + + matrix_mode(MODELVIEW); + load_matrix(matrix); +} + +void Camera::compute_matrix() +{ + float x = look_dir.y*up_dir.z-look_dir.z*up_dir.y; + float y = look_dir.z*up_dir.x-look_dir.x*up_dir.z; + float z = look_dir.x*up_dir.y-look_dir.y*up_dir.x; + float len = sqrt(x*x+y*y+z*z); + + matrix[0] = x/len; + matrix[4] = y/len; + matrix[8] = z/len; + + matrix[1] = matrix[4]*look_dir.z-matrix[8]*look_dir.y; + matrix[5] = matrix[8]*look_dir.x-matrix[0]*look_dir.z; + matrix[9] = matrix[0]*look_dir.y-matrix[4]*look_dir.x; + + matrix[2] = -look_dir.x; + matrix[6] = -look_dir.y; + matrix[10] = -look_dir.z; + + matrix[12] = -position.x; + matrix[13] = -position.y; + matrix[14] = -position.z; +} + +} // namespace GL +} // namespace Msp diff --git a/source/camera.h b/source/camera.h new file mode 100644 index 00000000..8be79abf --- /dev/null +++ b/source/camera.h @@ -0,0 +1,56 @@ +/* $Id$ + +This file is part of libmspgl +Copyright © 2010 Mikko Rasa, Mikkosoft Productions +Distributed under the LGPL +*/ + +#ifndef MSP_GL_CAMERA_H_ +#define MSP_GL_CAMERA_H_ + +#include "vector.h" + +namespace Msp { +namespace GL { + +class Camera +{ +private: + float fov; + float aspect; + // Some compilers have "near" and "far" keywords + float clip_near; + float clip_far; + Vector3 position; + Vector3 look_dir; + Vector3 up_dir; + float matrix[16]; + +public: + Camera(); + + void set_field_of_view(float); + void set_aspect(float); + void set_depth_clip(float, float); + + void set_position(const Vector3 &); + void set_look_direction(const Vector3 &); + void look_at(const Vector3 &); + void set_up_direction(const Vector3 &); + const Vector3 &get_position() const { return position; } + const Vector3 &get_look_direction() const { return look_dir; } + const Vector3 &get_up_direction() const { return up_dir; } + + Vector3 project(const Vector4 &) const; + Vector4 unproject(const Vector4 &) const; + + void apply() const; + +private: + void compute_matrix(); +}; + +} // namespace GL +} // namespcae Msp + +#endif diff --git a/source/pipeline.cpp b/source/pipeline.cpp index 9d5870cd..02568508 100644 --- a/source/pipeline.cpp +++ b/source/pipeline.cpp @@ -5,6 +5,7 @@ Copyright © 2009 Mikko Rasa, Mikkosoft Productions Distributed under the LGPL */ +#include "camera.h" #include "effect.h" #include "except.h" #include "framebuffer.h" @@ -20,6 +21,7 @@ namespace Msp { namespace GL { Pipeline::Pipeline(unsigned w, unsigned h, bool d): + camera(0), width(w), height(h), hdr(d), @@ -35,6 +37,11 @@ Pipeline::~Pipeline() delete depth_buf; } +void Pipeline::set_camera(const Camera *c) +{ + camera = c; +} + PipelinePass &Pipeline::add_pass(const Tag &tag) { if(passes.count(tag)) @@ -107,19 +114,25 @@ void Pipeline::render(const Tag &tag) const void Pipeline::render_all() const { + if(camera) + camera->apply(); + if(fbo) { fbo->bind(); clear(COLOR_BUFFER_BIT|DEPTH_BUFFER_BIT); } + for(vector::const_iterator i=effects.begin(); i!=effects.end(); ++i) (*i)->prepare(); for(vector::const_iterator i=pass_order.begin(); i!=pass_order.end(); ++i) render(*i); for(vector::const_iterator i=effects.end(); i--!=effects.begin();) (*i)->cleanup(); + if(fbo) Framebuffer::unbind(); + // XXX Need two color buffer textures to handle multiple post-processors correctly for(vector::const_iterator i=postproc.begin(); i!=postproc.end(); ++i) (*i)->render(*color_buf); diff --git a/source/pipeline.h b/source/pipeline.h index 8edd6795..592c3cae 100644 --- a/source/pipeline.h +++ b/source/pipeline.h @@ -15,6 +15,7 @@ Distributed under the LGPL namespace Msp { namespace GL { +class Camera; class Effect; class Framebuffer; class PostProcessor; @@ -28,6 +29,7 @@ private: PassMap passes; std::vector pass_order; + const Camera *camera; std::vector renderables; std::vector effects; std::vector postproc; @@ -42,6 +44,8 @@ public: Pipeline(unsigned, unsigned, bool); ~Pipeline(); + void set_camera(const Camera *); + PipelinePass &add_pass(const Tag &tag); PipelinePass &get_pass(const Tag &tag); const PipelinePass &get_pass(const Tag &tag) const;