00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032 #include <vlGraphics/Camera.hpp>
00033 #include <vlGraphics/OpenGL.hpp>
00034 #include <vlCore/AABB.hpp>
00035 #include <vlCore/Log.hpp>
00036 #include <vlCore/Say.hpp>
00037
00038 #undef near
00039 #undef far
00040
00041 using namespace vl;
00042
00043
00044
00045
00046 Camera::Camera()
00047 {
00048 VL_DEBUG_SET_OBJECT_NAME()
00049 mFrustum.planes().resize(6);
00050 mFOV = 60.0;
00051 mNearPlane = (real)0.05;
00052 mFarPlane = (real)10000.0;
00053 mLeft = mRight = mTop = mBottom = -1;
00054 mViewport = new Viewport;
00055
00056 mProjectionMatrix = mat4::getPerspective(fov(), 640.0f/480.0f, nearPlane(), farPlane());
00057 mProjectionType = PMT_PerspectiveProjection;
00058 }
00059
00060 void Camera::applyModelViewMatrix(const mat4& model_matrix) const
00061 {
00062
00063 mat4 viewm = viewMatrix();
00064 viewm.e(3,0) = 0.0;
00065 viewm.e(3,1) = 0.0;
00066 viewm.e(3,2) = 0.0;
00067 viewm.e(3,3) = 1.0;
00068
00069 glMatrixMode(GL_MODELVIEW);
00070 #if 0
00071 VL_glLoadMatrix( viewm.ptr() );
00072 VL_glMultMatrix( matrix.ptr() );
00073 #elif 0
00074 viewm = viewm * matrix;
00075 VL_glLoadMatrix( viewm.ptr() );
00076 #else
00077 VL_glLoadMatrix( (viewm * model_matrix).ptr() );
00078 #endif
00079 }
00080
00081 void Camera::applyProjMatrix() const
00082 {
00083
00084 glMatrixMode( GL_PROJECTION );
00085 VL_glLoadMatrix( projectionMatrix().ptr() );
00086 }
00087
00088 void Camera::applyViewMatrix() const
00089 {
00090
00091 mat4 viewm = viewMatrix();
00092 viewm.e(3,0) = 0.0;
00093 viewm.e(3,1) = 0.0;
00094 viewm.e(3,2) = 0.0;
00095 viewm.e(3,3) = 1.0;
00096 glMatrixMode(GL_MODELVIEW);
00097 VL_glLoadMatrix( viewm.ptr() );
00098 }
00099
00100 void Camera::computeNearFarOptimizedProjMatrix(const Sphere& scene_bounding_sphere)
00101 {
00102
00103 if (!scene_bounding_sphere.isNull())
00104 {
00105
00106 Sphere camera_sphere;
00107 scene_bounding_sphere.transformed(camera_sphere, viewMatrix());
00108
00109
00110 mNearPlane = -(camera_sphere.center().z() + camera_sphere.radius());
00111 mFarPlane = -(camera_sphere.center().z() - camera_sphere.radius());
00112
00113
00114 real epsilon = camera_sphere.radius() / 1000.0f;
00115 mFarPlane = max(mFarPlane, epsilon * 2);
00116 mNearPlane = max(mNearPlane, epsilon * 1);
00117
00118 switch(projectionMatrixType())
00119 {
00120 case PMT_OrthographicProjection: setProjectionOrtho(mLeft, mRight, mBottom, mTop, mNearPlane, mFarPlane);
00121 break;
00122 case PMT_PerspectiveProjection: setProjectionPerspective();
00123 break;
00124
00125
00126
00127
00128
00129 default:
00130 Log::bug("Camera::computeNearFarOptimizedProjMatrix() called on unsupported projection type.\n");
00131 }
00132 }
00133 }
00134
00135 void Camera::adjustView(const AABB& aabb, const vec3& dir, const vec3& up, real bias)
00136 {
00137 VL_CHECK(bias >= 0)
00138 VL_CHECK(!aabb.isNull())
00139 if (bias < 0)
00140 vl::Log::bug("Camera::adjustView(): 'bias' must be >= 0.\n");
00141
00142 vec3 center = aabb.center();
00143
00144 Sphere sphere(aabb);
00145 const vec3& C = modelingMatrix().getT();
00146 const vec3& V = -modelingMatrix().getZ();
00147 const real R = sphere.radius();
00148
00149
00150 mat4 viewproj = projectionMatrix() * viewMatrix();
00151 Frustum frustum; frustum.planes().resize(6);
00152 extractPlanes( &frustum.planes()[0], viewproj );
00153
00154 real max_t = 0;
00155 for(int i=0; i<4; ++i)
00156 {
00157 const vec3& O = frustum.plane(i).origin() * frustum.plane(i).normal();
00158 const vec3& N = frustum.plane(i).normal();
00159 real t = - (R + dot(O,N) - dot(C,N)) / dot(N,V);
00160 VL_CHECK(t>=0)
00161 if (t > max_t)
00162 max_t = t;
00163 }
00164 real dist = max_t;
00165 mat4 m = mat4::getLookAt(center+dir*dist*bias,center,up);
00166 setViewMatrix(m);
00167 }
00168
00169 void Camera::computeFrustumPlanes()
00170 {
00171
00172 mat4 viewproj = projectionMatrix() * viewMatrix();
00173
00174 mFrustum.planes().resize(6);
00175 extractPlanes( &mFrustum.planes()[0], viewproj );
00176 }
00177
00178 void Camera::setProjectionFrustum(real left, real right, real bottom, real top, real near, real far)
00179 {
00180
00181 setFOV( 2.0f*atan((top-bottom)*0.5f/near) );
00182 setNearPlane(near);
00183 setFarPlane(far);
00184 setProjectionMatrix(mat4::getFrustum(left, right, bottom, top, near, far), PMT_PerspectiveProjectionFrustum);
00185 }
00186
00187 void Camera::setProjectionPerspective(real fov, real near, real far)
00188 {
00189 setFOV(fov);
00190 setNearPlane(near);
00191 setFarPlane(far);
00192 setProjectionMatrix(mat4::getPerspective(fov, aspectRatio(), near, far), PMT_PerspectiveProjection);
00193 }
00194
00195 void Camera::setProjectionPerspective()
00196 {
00197 setProjectionMatrix(mat4::getPerspective(fov(), aspectRatio(), nearPlane(), farPlane()), PMT_PerspectiveProjection);
00198 }
00199
00200 void Camera::setProjectionOrtho()
00201 {
00202 mLeft = 0;
00203 mRight = (real)mViewport->width();
00204 mBottom = 0;
00205 mTop = (real)mViewport->height();
00206 mFOV = -1;
00207 setProjectionMatrix( mat4::getOrtho( mLeft, mRight, mBottom, mTop, mNearPlane, mFarPlane), PMT_OrthographicProjection );
00208 }
00209
00210 void Camera::setProjectionOrtho(real left, real right, real bottom, real top, real znear, real zfar)
00211 {
00212 mLeft = left;
00213 mRight = right;
00214 mBottom = bottom;
00215 mTop = top;
00216 mFOV = -1;
00217 mNearPlane = znear;
00218 mFarPlane = zfar;
00219 setProjectionMatrix( mat4::getOrtho( mLeft, mRight, mBottom, mTop, mNearPlane, mFarPlane), PMT_OrthographicProjection );
00220 }
00221
00222 void Camera::setProjectionOrtho(real offset)
00223 {
00224 mLeft = offset;
00225 mRight = viewport()->width() + offset;
00226 mBottom = offset;
00227 mTop = viewport()->height() + offset;
00228 mFOV = -1;
00229 mNearPlane = -1;
00230 mFarPlane = +1;
00231 setProjectionMatrix( mat4::getOrtho( mLeft, mRight, mBottom, mTop, mNearPlane, mFarPlane), PMT_OrthographicProjection );
00232 }
00233
00234 void Camera::setViewMatrixLookAt( const vec3& eye, const vec3& at, const vec3& up)
00235 {
00236
00237 setViewMatrix( mat4::getLookAt(eye, at, up) );
00238 }
00239
00240 void Camera::getViewMatrixAsLookAt( vec3& eye, vec3& at, vec3& up, vec3& right) const
00241 {
00242 mModelingMatrix.getAsLookAtModeling(eye, at, up, right);
00243 }
00244
00245 bool Camera::project(const vec4& in, vec4& out) const
00246 {
00247 out = mProjectionMatrix * mViewMatrix * in;
00248
00249 if (out.w() == 0.0f)
00250 return false;
00251
00252 out.x() /= out.w();
00253 out.y() /= out.w();
00254 out.z() /= out.w();
00255
00256
00257 out.x() = out.x() * 0.5f + 0.5f;
00258 out.y() = out.y() * 0.5f + 0.5f;
00259 out.z() = out.z() * 0.5f + 0.5f;
00260
00261
00262 out.x() = out.x() * mViewport->width() + mViewport->x();
00263 out.y() = out.y() * mViewport->height() + mViewport->y();
00264 return true;
00265 }
00266
00267 bool Camera::unproject(const vec3& win, vec4& out) const
00268 {
00269 vec4 v;
00270 v.x() = win.x();
00271 v.y() = win.y();
00272 v.z() = win.z();
00273 v.w() = 1.0;
00274
00275
00276 v.x() = (v.x() - mViewport->x()) / mViewport->width();
00277 v.y() = (v.y() - mViewport->y()) / mViewport->height();
00278
00279
00280 v.x() = v.x() * 2.0f - 1.0f;
00281 v.y() = v.y() * 2.0f - 1.0f;
00282 v.z() = v.z() * 2.0f - 1.0f;
00283
00284 real det=0;
00285 mat4 inverse = (mProjectionMatrix * mViewMatrix).getInverse(&det);
00286 if (!det)
00287 return false;
00288
00289 v = inverse * v;
00290 if (v.w() == 0.0)
00291 return false;
00292
00293 out = v / v.w();
00294 return true;
00295 }
00296
00297 bool Camera::unproject(std::vector<vec3>& win) const
00298 {
00299 real det=0;
00300 mat4 inverse = (mProjectionMatrix * mViewMatrix).getInverse(&det);
00301 if (!det)
00302 return false;
00303
00304 bool ok = true;
00305 for(unsigned i=0; i<win.size(); ++i)
00306 {
00307 vec4 v;
00308 v = vec4( win[i], 1.0 );
00309
00310
00311 v.x() = (v.x() - mViewport->x()) / mViewport->width();
00312 v.y() = (v.y() - mViewport->y()) / mViewport->height();
00313
00314
00315 v.x() = v.x() * 2.0f - 1.0f;
00316 v.y() = v.y() * 2.0f - 1.0f;
00317 v.z() = v.z() * 2.0f - 1.0f;
00318
00319 v = inverse * v;
00320 if (v.w() == 0.0)
00321 {
00322 ok = false;
00323 continue;
00324 }
00325
00326 v = v / v.w();
00327 win[i] = v.xyz();
00328 }
00329 return ok;
00330 }
00331
00332 Ray Camera::computeRay(int winx, int winy)
00333 {
00334 vl::vec4 out;
00335 if (!unproject( vl::vec3((real)winx,(real)winy,0), out ))
00336 return Ray();
00337 else
00338 {
00339 vl::Ray ray;
00340 ray.setOrigin(out.xyz());
00341 ray.setDirection( (out.xyz() - modelingMatrix().getT()).normalize() );
00342 return ray;
00343 }
00344 }
00345
00346 Frustum Camera::computeRayFrustum(int winx, int winy)
00347 {
00348
00349
00350
00351
00352
00353
00354
00355
00356
00357
00358 vl::vec4 A1,B1,C1,D1;
00359 vl::vec4 A2,B2,C2,D2;
00360 unproject( vl::vec3((real)winx-1,(real)winy-1,0), A1 );
00361 unproject( vl::vec3((real)winx+1,(real)winy-1,0), B1 );
00362 unproject( vl::vec3((real)winx+1,(real)winy+1,0), C1 );
00363 unproject( vl::vec3((real)winx-1,(real)winy+1,0), D1 );
00364 unproject( vl::vec3((real)winx-1,(real)winy-1,0.1f), A2 );
00365 unproject( vl::vec3((real)winx+1,(real)winy-1,0.1f), B2 );
00366 unproject( vl::vec3((real)winx+1,(real)winy+1,0.1f), C2 );
00367 unproject( vl::vec3((real)winx-1,(real)winy+1,0.1f), D2 );
00368
00369 vec3 n1 = -cross(A2.xyz()-A1.xyz(),B1.xyz()-A1.xyz());
00370 vec3 n2 = -cross(B2.xyz()-B1.xyz(),C1.xyz()-B1.xyz());
00371 vec3 n3 = -cross(C2.xyz()-C1.xyz(),D1.xyz()-C1.xyz());
00372 vec3 n4 = -cross(D2.xyz()-D1.xyz(),A1.xyz()-D1.xyz());
00373 Frustum frustum;
00374 frustum.planes().push_back( Plane( A1.xyz(), n1 ) );
00375 frustum.planes().push_back( Plane( B1.xyz(), n2 ) );
00376 frustum.planes().push_back( Plane( C1.xyz(), n3 ) );
00377 frustum.planes().push_back( Plane( D1.xyz(), n4 ) );
00378 return frustum;
00379 }
00380