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 mViewport = new Viewport;
00054
00055 mProjectionMatrix = mat4::getPerspective(fov(), 640.0f/480.0f, nearPlane(), farPlane());
00056 }
00057
00058 void Camera::applyModelViewMatrix(const mat4& model_matrix) const
00059 {
00060
00061 mat4 viewm = viewMatrix();
00062 viewm.e(3,0) = 0.0;
00063 viewm.e(3,1) = 0.0;
00064 viewm.e(3,2) = 0.0;
00065 viewm.e(3,3) = 1.0;
00066
00067 glMatrixMode(GL_MODELVIEW);
00068 #if 0
00069 VL_glLoadMatrix( viewm.ptr() );
00070 VL_glMultMatrix( matrix.ptr() );
00071 #elif 0
00072 viewm = viewm * matrix;
00073 VL_glLoadMatrix( viewm.ptr() );
00074 #else
00075 VL_glLoadMatrix( (viewm * model_matrix).ptr() );
00076 #endif
00077 }
00078
00079 void Camera::applyProjMatrix() const
00080 {
00081
00082 glMatrixMode( GL_PROJECTION );
00083 VL_glLoadMatrix( projectionMatrix().ptr() );
00084 }
00085
00086 void Camera::applyViewMatrix() const
00087 {
00088
00089 mat4 viewm = viewMatrix();
00090 viewm.e(3,0) = 0.0;
00091 viewm.e(3,1) = 0.0;
00092 viewm.e(3,2) = 0.0;
00093 viewm.e(3,3) = 1.0;
00094 glMatrixMode(GL_MODELVIEW);
00095 VL_glLoadMatrix( viewm.ptr() );
00096 }
00097
00098 void Camera::computeNearFarOptimizedProjMatrix(const Sphere& scene_bounding_sphere)
00099 {
00100
00101 if (!scene_bounding_sphere.isNull())
00102 {
00103
00104 Sphere camera_sphere;
00105 scene_bounding_sphere.transformed(camera_sphere, viewMatrix());
00106 mNearPlane = -(camera_sphere.center().z() + camera_sphere.radius() * (Real)1.01);
00107 mFarPlane = -(camera_sphere.center().z() - camera_sphere.radius() * (Real)1.01);
00108 #if 0
00109 far = max(far, (Real)1.0e-5);
00110 near = max(near, (Real)1.0e-6);
00111 #else
00112
00113 Real ratio = camera_sphere.radius() * (Real)2.01 / (Real)2000.0;
00114 mNearPlane = max(mNearPlane, ratio*1);
00115 mFarPlane = max(mFarPlane, ratio*2);
00116 #endif
00117
00118 setProjectionAsPerspective();
00119 }
00120 }
00121
00122 void Camera::adjustView(const AABB& aabb, const vec3& dir, const vec3& up, Real bias)
00123 {
00124 VL_CHECK(bias >= 0)
00125 if (bias < 0)
00126 vl::Log::bug("Camera::adjustView(): 'bias' must be >= 0.\n");
00127
00128 vec3 center = aabb.center();
00129
00130 Sphere sphere(aabb);
00131 const vec3& C = inverseViewMatrix().getT();
00132 const vec3& V = -inverseViewMatrix().getZ();
00133 const Real R = sphere.radius();
00134
00135
00136 mat4 viewproj = projectionMatrix() * viewMatrix();
00137 Frustum frustum; frustum.planes().resize(6);
00138 extractPlanes( &frustum.planes()[0], viewproj );
00139
00140 Real max_t = 0;
00141 for(int i=0; i<4; ++i)
00142 {
00143 const vec3& O = frustum.plane(i).origin() * frustum.plane(i).normal();
00144 const vec3& N = frustum.plane(i).normal();
00145 Real t = - (R + dot(O,N) - dot(C,N)) / dot(N,V);
00146 VL_CHECK(t>=0)
00147 if (t > max_t)
00148 max_t = t;
00149 }
00150 Real dist = max_t;
00151 mat4 m = mat4::getLookAt(center+dir*dist*bias,center,up);
00152 setInverseViewMatrix(m);
00153 }
00154
00155 void Camera::computeFrustumPlanes()
00156 {
00157
00158 mat4 viewproj = projectionMatrix() * viewMatrix();
00159
00160 mFrustum.planes().resize(6);
00161 extractPlanes( &mFrustum.planes()[0], viewproj );
00162 }
00163
00164 void Camera::setProjectionAsFrustum(Real left, Real right, Real bottom, Real top, Real near, Real far)
00165 {
00166 setFOV(-1);
00167 setNearPlane(near);
00168 setFarPlane(far);
00169 mProjectionMatrix = mat4::getFrustum(left, right, bottom, top, near, far);
00170 }
00171
00172 void Camera::setProjectionAsPerspective(Real fov, Real near, Real far)
00173 {
00174 setFOV(fov);
00175 setNearPlane(near);
00176 setFarPlane(far);
00177 mProjectionMatrix = mat4::getPerspective(fov, aspectRatio(), near, far);
00178 }
00179
00180 void Camera::setProjectionAsPerspective()
00181 {
00182 mProjectionMatrix = mat4::getPerspective(fov(), aspectRatio(), nearPlane(), farPlane());
00183 }
00184
00185 void Camera::setProjectionAsOrtho(Real offset)
00186 {
00187 setProjectionMatrix(
00188 mat4::getOrtho(
00189 offset, (Real)mViewport->width() + offset,
00190 offset, (Real)mViewport->height() + offset,
00191 nearPlane(), farPlane())
00192 );
00193 }
00194
00195 void Camera::setProjectionAsOrtho2D(Real offset)
00196 {
00197 setProjectionMatrix(
00198 mat4::getOrtho(
00199 offset, (Real)mViewport->width() + offset,
00200 offset, (Real)mViewport->height() + offset,
00201 -1, +1)
00202 );
00203 }
00204
00205 void Camera::setViewMatrixAsLookAt( const vec3& eye, const vec3& center, const vec3& up)
00206 {
00207 mat4 m = mat4::getLookAt(eye, center, up);
00208
00209 setInverseViewMatrix(m);
00210 }
00211
00212 void Camera::getViewMatrixAsLookAt( vec3& eye, vec3& look, vec3& up, vec3& right) const
00213 {
00214 mInverseViewMatrix.getAsLookAt(eye,look,up,right);
00215 }
00216
00217 bool Camera::project(const vec4& in, vec4& out) const
00218 {
00219 out = mProjectionMatrix * mViewMatrix * in;
00220
00221 if (out.w() == 0.0f)
00222 return false;
00223
00224 out.x() /= out.w();
00225 out.y() /= out.w();
00226 out.z() /= out.w();
00227
00228
00229 out.x() = out.x() * 0.5f + 0.5f;
00230 out.y() = out.y() * 0.5f + 0.5f;
00231 out.z() = out.z() * 0.5f + 0.5f;
00232
00233
00234 out.x() = out.x() * mViewport->width() + mViewport->x();
00235 out.y() = out.y() * mViewport->height() + mViewport->y();
00236 return true;
00237 }
00238
00239 bool Camera::unproject(const vec3& win, vec4& out) const
00240 {
00241 vec4 v;
00242 v.x() = win.x();
00243 v.y() = win.y();
00244 v.z() = win.z();
00245 v.w() = 1.0;
00246
00247
00248 v.x() = (v.x() - mViewport->x()) / mViewport->width();
00249 v.y() = (v.y() - mViewport->y()) / mViewport->height();
00250
00251
00252 v.x() = v.x() * 2.0f - 1.0f;
00253 v.y() = v.y() * 2.0f - 1.0f;
00254 v.z() = v.z() * 2.0f - 1.0f;
00255
00256 Real det=0;
00257 mat4 inverse = (mProjectionMatrix * mViewMatrix).getInverse(&det);
00258 if (!det)
00259 return false;
00260
00261 v = inverse * v;
00262 if (v.w() == 0.0)
00263 return false;
00264
00265 out = v / v.w();
00266 return true;
00267 }
00268
00269 bool Camera::unproject(std::vector<vec3>& win) const
00270 {
00271 Real det=0;
00272 mat4 inverse = (mProjectionMatrix * mViewMatrix).getInverse(&det);
00273 if (!det)
00274 return false;
00275
00276 bool ok = true;
00277 for(unsigned i=0; i<win.size(); ++i)
00278 {
00279 vec4 v;
00280 v = vec4( win[i], 1.0 );
00281
00282
00283 v.x() = (v.x() - mViewport->x()) / mViewport->width();
00284 v.y() = (v.y() - mViewport->y()) / mViewport->height();
00285
00286
00287 v.x() = v.x() * 2.0f - 1.0f;
00288 v.y() = v.y() * 2.0f - 1.0f;
00289 v.z() = v.z() * 2.0f - 1.0f;
00290
00291 v = inverse * v;
00292 if (v.w() == 0.0)
00293 {
00294 ok = false;
00295 continue;
00296 }
00297
00298 v = v / v.w();
00299 win[i] = v.xyz();
00300 }
00301 return ok;
00302 }
00303
00304 Ray Camera::computeRay(int winx, int winy)
00305 {
00306 vl::vec4 out;
00307 if (!unproject( vl::vec3((Real)winx,(Real)winy,0), out ))
00308 return Ray();
00309 else
00310 {
00311 vl::Ray ray;
00312 ray.setOrigin(out.xyz());
00313 ray.setDirection( (out.xyz() - inverseViewMatrix().getT()).normalize() );
00314 return ray;
00315 }
00316 }
00317
00318 Frustum Camera::computeRayFrustum(int winx, int winy)
00319 {
00320
00321
00322
00323
00324
00325
00326
00327
00328
00329
00330 vl::vec4 A1,B1,C1,D1;
00331 vl::vec4 A2,B2,C2,D2;
00332 unproject( vl::vec3((Real)winx-1,(Real)winy-1,0), A1 );
00333 unproject( vl::vec3((Real)winx+1,(Real)winy-1,0), B1 );
00334 unproject( vl::vec3((Real)winx+1,(Real)winy+1,0), C1 );
00335 unproject( vl::vec3((Real)winx-1,(Real)winy+1,0), D1 );
00336 unproject( vl::vec3((Real)winx-1,(Real)winy-1,0.1f), A2 );
00337 unproject( vl::vec3((Real)winx+1,(Real)winy-1,0.1f), B2 );
00338 unproject( vl::vec3((Real)winx+1,(Real)winy+1,0.1f), C2 );
00339 unproject( vl::vec3((Real)winx-1,(Real)winy+1,0.1f), D2 );
00340
00341 vec3 n1 = -cross(A2.xyz()-A1.xyz(),B1.xyz()-A1.xyz());
00342 vec3 n2 = -cross(B2.xyz()-B1.xyz(),C1.xyz()-B1.xyz());
00343 vec3 n3 = -cross(C2.xyz()-C1.xyz(),D1.xyz()-C1.xyz());
00344 vec3 n4 = -cross(D2.xyz()-D1.xyz(),A1.xyz()-D1.xyz());
00345 Frustum frustum;
00346 frustum.planes().push_back( Plane( A1.xyz(), n1 ) );
00347 frustum.planes().push_back( Plane( B1.xyz(), n2 ) );
00348 frustum.planes().push_back( Plane( C1.xyz(), n3 ) );
00349 frustum.planes().push_back( Plane( D1.xyz(), n4 ) );
00350 return frustum;
00351 }
00352