camera.cpp 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  1. #include "camera.h"
  2. #include "renderer.h"
  3. //=====================================================================================================================================
  4. // SetAll =
  5. //=====================================================================================================================================
  6. void camera_t::SetAll( float fovx_, float fovy_, float znear_, float zfar_ )
  7. {
  8. fovx = fovx_;
  9. fovy = fovy_;
  10. znear = znear_;
  11. zfar = zfar_;
  12. CalcProjectionMatrix();
  13. CalcLSpaceFrustumPlanes();
  14. }
  15. //=====================================================================================================================================
  16. // Render =
  17. //=====================================================================================================================================
  18. void camera_t::Render()
  19. {
  20. glPushMatrix();
  21. r::MultMatrix( transformation_wspace );
  22. const float cam_len = 1.0;
  23. float tmp0 = cam_len / tan( (PI - fovx)*0.5 ) + 0.001;
  24. float tmp1 = cam_len * tan(fovy*0.5) + 0.001;
  25. float points [][3] = {
  26. {0.0, 0.0, 0.0}, // 0: eye point
  27. {-tmp0, tmp1, -cam_len}, // 1: top left
  28. {-tmp0, -tmp1, -cam_len}, // 2: bottom left
  29. {tmp0, -tmp1, -cam_len}, // 3: bottom right
  30. {tmp0, tmp1, -cam_len}, // 4: top right
  31. };
  32. //glLineWidth( 2.0 );
  33. glColor3fv( &vec3_t(1.0,0.0,1.0)[0] );
  34. glBegin( GL_LINES );
  35. glVertex3fv( &points[0][0] );
  36. glVertex3fv( &points[1][0] );
  37. glVertex3fv( &points[0][0] );
  38. glVertex3fv( &points[2][0] );
  39. glVertex3fv( &points[0][0] );
  40. glVertex3fv( &points[3][0] );
  41. glVertex3fv( &points[0][0] );
  42. glVertex3fv( &points[4][0] );
  43. glEnd();
  44. glBegin( GL_LINE_STRIP );
  45. glVertex3fv( &points[1][0] );
  46. glVertex3fv( &points[2][0] );
  47. glVertex3fv( &points[3][0] );
  48. glVertex3fv( &points[4][0] );
  49. glVertex3fv( &points[1][0] );
  50. glEnd();
  51. glPopMatrix();
  52. // if( !strcmp( camera_data_user_class_t::GetName(), "main_cam") ) return;
  53. // //for( uint i=0; i<2; i++ )
  54. // wspace_frustum_planes[TOP].Render();
  55. }
  56. //=====================================================================================================================================
  57. // LookAtPoint =
  58. //=====================================================================================================================================
  59. void camera_t::LookAtPoint( const vec3_t& point )
  60. {
  61. const vec3_t& j = vec3_t( 0.0, 1.0, 0.0 );
  62. vec3_t vdir = (point - translation_lspace).GetNormalized();
  63. vec3_t vup = j - vdir * j.Dot(vdir);
  64. vec3_t vside = vdir.Cross( vup );
  65. rotation_lspace.SetColumns( vside, vup, -vdir );
  66. }
  67. //=====================================================================================================================================
  68. // CalcLSpaceFrustumPlanes =
  69. //=====================================================================================================================================
  70. void camera_t::CalcLSpaceFrustumPlanes()
  71. {
  72. float c, s; // cos & sine
  73. SinCos( PI+fovx/2, s, c );
  74. // right
  75. lspace_frustum_planes[FP_RIGHT] = plane_t( vec3_t(c, 0.0, s), 0.0 );
  76. // left
  77. lspace_frustum_planes[FP_LEFT] = plane_t( vec3_t(-c, 0.0, s), 0.0 );
  78. SinCos( (3*PI-fovy)*0.5, s, c );
  79. // top
  80. lspace_frustum_planes[FP_TOP] = plane_t( vec3_t(0.0, s, c), 0.0 );
  81. // bottom
  82. lspace_frustum_planes[FP_BOTTOM] = plane_t( vec3_t(0.0, -s, c), 0.0 );
  83. // near
  84. lspace_frustum_planes[FP_NEAR] = plane_t( vec3_t( 0.0, 0.0, -1.0 ), znear );
  85. // far
  86. lspace_frustum_planes[FP_FAR] = plane_t( vec3_t( 0.0, 0.0, 1.0 ), -zfar );
  87. }
  88. //=====================================================================================================================================
  89. // UpdateWSpaceFrustumPlanes =
  90. //=====================================================================================================================================
  91. void camera_t::UpdateWSpaceFrustumPlanes()
  92. {
  93. for( uint i=0; i<6; i++ )
  94. wspace_frustum_planes[i] = lspace_frustum_planes[i].Transformed( translation_wspace, rotation_wspace, scale_wspace );
  95. }
  96. //=====================================================================================================================================
  97. // InsideFrustum =
  98. //=====================================================================================================================================
  99. /// Check if the volume is inside the frustum cliping planes
  100. bool camera_t::InsideFrustum( const bvolume_t& bvol ) const
  101. {
  102. for( uint i=0; i<6; i++ )
  103. if( bvol.PlaneTest( wspace_frustum_planes[i] ) < 0.0 )
  104. return false;
  105. return true;
  106. }
  107. //=====================================================================================================================================
  108. // InsideFrustum =
  109. //=====================================================================================================================================
  110. /// Check if the given camera is inside the frustum cliping planes. This is used mainly to test if the projected lights are visible
  111. bool camera_t::InsideFrustum( const camera_t& cam ) const
  112. {
  113. //** get five points. These points are the tips of the given camera **
  114. vec3_t points[5];
  115. // get 3 sample floats
  116. float x = cam.GetZFar() / tan( (PI-cam.GetFovX())/2 );
  117. float y = tan( cam.GetFovY()/2 ) * cam.GetZFar();
  118. float z = -cam.GetZFar();
  119. // the actual points in local space
  120. points[0] = vec3_t( x, y, z ); // top right
  121. points[1] = vec3_t( -x, y, z ); // top left
  122. points[2] = vec3_t( -x, -y, z ); // bottom left
  123. points[3] = vec3_t( x, -y, z ); // bottom right
  124. points[4] = vec3_t( cam.translation_wspace ); // eye (allready in world space)
  125. // transform them to the given camera's world space (exept the eye)
  126. for( uint i=0; i<4; i++ )
  127. points[i].Transform( cam.translation_wspace, cam.rotation_wspace, cam.scale_wspace );
  128. //** the collision code **
  129. for( uint i=0; i<6; i++ ) // for the 6 planes
  130. {
  131. int failed = 0;
  132. for( uint j=0; j<5; j++ ) // for the 5 points
  133. {
  134. if( wspace_frustum_planes[i].Test( points[j] ) < 0.0 )
  135. ++failed;
  136. }
  137. if( failed == 5 ) return false; // if all points are behind the plane then the cam is not in frustum
  138. }
  139. return true;
  140. }
  141. //=====================================================================================================================================
  142. // CalcProjectionMatrix =
  143. //=====================================================================================================================================
  144. void camera_t::CalcProjectionMatrix()
  145. {
  146. float f = 1.0/tan( fovy*0.5f ); // f = cot(fovy/2)
  147. projection_mat(0,0) = f*fovy/fovx; // = f/aspect_ratio;
  148. projection_mat(0,1) = 0.0;
  149. projection_mat(0,2) = 0.0;
  150. projection_mat(0,3) = 0.0;
  151. projection_mat(1,0) = 0.0;
  152. projection_mat(1,1) = f;
  153. projection_mat(1,2) = 0.0;
  154. projection_mat(1,3) = 0.0;
  155. projection_mat(2,0) = 0.0;
  156. projection_mat(2,1) = 0.0;
  157. projection_mat(2,2) = (zfar+znear) / (znear-zfar);
  158. projection_mat(2,3) = (2.0f*zfar*znear) / (znear-zfar);
  159. projection_mat(3,0) = 0.0;
  160. projection_mat(3,1) = 0.0;
  161. projection_mat(3,2) = -1.0;
  162. projection_mat(3,3) = 0.0;
  163. inv_projection_mat = projection_mat.GetInverse();
  164. }
  165. //=====================================================================================================================================
  166. // UpdateViewMatrix =
  167. //=====================================================================================================================================
  168. void camera_t::UpdateViewMatrix()
  169. {
  170. /* The point at which the camera looks:
  171. vec3_t viewpoint = translation_lspace + z_axis;
  172. as we know the up vector, we can easily use gluLookAt:
  173. gluLookAt( translation_lspace.x, translation_lspace.x, translation_lspace.z, z_axis.x, z_axis.y, z_axis.z, y_axis.x, y_axis.y, y_axis.z );
  174. */
  175. // The view matrix is: Mview = camera.world_transform.Inverted(). Bus instead of inverting we do the following:
  176. mat3_t cam_inverted_rot = rotation_wspace.GetTransposed();
  177. vec3_t cam_inverted_tsl = -( cam_inverted_rot * translation_wspace );
  178. view_mat = mat4_t( cam_inverted_tsl, cam_inverted_rot );
  179. }
  180. //=====================================================================================================================================
  181. // UpdateWorldStuff =
  182. //=====================================================================================================================================
  183. void camera_t::UpdateWorldStuff()
  184. {
  185. UpdateWorldTransform();
  186. UpdateViewMatrix();
  187. UpdateWSpaceFrustumPlanes();
  188. }