Counter Strike : Global Offensive Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

733 lines
25 KiB

  1. //====== Copyright � 1996-2004, Valve Corporation, All rights reserved. =======
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================
  6. #include "mathlib/camera.h"
  7. #include "tier0/dbg.h"
  8. #include "mathlib/vector.h"
  9. #include "mathlib/vmatrix.h"
  10. #include "tier2/tier2.h"
  11. // memdbgon must be the last include file in a .cpp file!!!
  12. #include "tier0/memdbgon.h"
  13. #define FORWARD_AXIS 0
  14. #define LEFT_AXIS 1
  15. #define UP_AXIS 2
  16. /// matrix to align our Valve coordinate system camera space with a standard viewing coordinate system
  17. /// x-axis goes from left to right in view space (right in camera space)
  18. /// y-axis goes from bottom to top in view space (up in camera space)
  19. /// z-axis goes from far to near in view space (-forward in camera space)
  20. /// The constructor takes sequential matrix rows, which are basis vectors in view space (so transposed from the init)
  21. #ifdef YUP_ACTIVE
  22. #error YUP_ACTIVE is not supported on this branch.
  23. #endif
  24. /// g_ViewAlignMatrix.Init( Vector(0,-1,0), Vector(0,0,1), Vector(-1,0,0), vec3_origin );
  25. static matrix3x4_t g_ViewAlignMatrix( 0, 0, -1, 0, -1, 0, 0, 0, 0, 1, 0, 0 );
  26. VMatrix g_matViewToCameraMatrix( 0, 0, -1, 0, -1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1 );
  27. VMatrix g_matCameraToViewMatrix( 0, -1, 0, 0, 0, 0, 1, 0, -1, 0, 0, 0, 0, 0, 0, 1 );
  28. //--------------------------------------------------------------------------------------------------
  29. // Extract the direction vectors from the a matrix
  30. //--------------------------------------------------------------------------------------------------
  31. void ExtractDirectionVectors( Vector *pForward, Vector *pLeft, Vector *pUp, const matrix3x4_t &mMatrix )
  32. {
  33. MatrixGetColumn( mMatrix, FORWARD_AXIS, *pForward );
  34. MatrixGetColumn( mMatrix, LEFT_AXIS, *pLeft );
  35. MatrixGetColumn( mMatrix, UP_AXIS, *pUp );
  36. }
  37. // Returns points in this order:
  38. // 2--3
  39. // | |
  40. // 0--1
  41. void CalcFarPlaneCameraRelativePoints( Vector *p4PointsOut, Vector &vForward, Vector &vUp, Vector &vLeft, float flFarPlane,
  42. float flFovX, float flAspect,
  43. float flClipSpaceBottomLeftX /*= -1.0f*/, float flClipSpaceBottomLeftY /*= -1.0f*/,
  44. float flClipSpaceTopRightX /*= 1.0f*/, float flClipSpaceTopRightY /*= 1.0f*/ )
  45. {
  46. Vector vFowardShift = flFarPlane * vForward;
  47. Vector vUpShift;
  48. Vector vRightShift;
  49. if ( flFovX == -1 )
  50. {
  51. vUpShift = vUp;
  52. vRightShift = -vLeft;
  53. }
  54. else
  55. {
  56. float flTanX = tanf( DEG2RAD( flFovX * 0.5f ) );
  57. float flTanY = flTanX / flAspect;
  58. vUpShift = flFarPlane * flTanY * vUp;
  59. vRightShift = flFarPlane * flTanX * -vLeft;
  60. }
  61. p4PointsOut[0] = vFowardShift + flClipSpaceBottomLeftX * vRightShift + flClipSpaceBottomLeftY * vUpShift;
  62. p4PointsOut[1] = vFowardShift + flClipSpaceTopRightX * vRightShift + flClipSpaceBottomLeftY * vUpShift;
  63. p4PointsOut[2] = vFowardShift + flClipSpaceBottomLeftX * vRightShift + flClipSpaceTopRightY * vUpShift;
  64. p4PointsOut[3] = vFowardShift + flClipSpaceTopRightX * vRightShift + flClipSpaceTopRightY * vUpShift;
  65. }
  66. //-----------------------------------------------------------------------------
  67. // accessors for generated matrices
  68. //-----------------------------------------------------------------------------
  69. void ComputeViewMatrix( matrix3x4_t *pWorldToView, matrix3x4_t *pCameraToWorld, const Camera_t &camera )
  70. {
  71. AngleMatrix( camera.m_angles, camera.m_origin, *pCameraToWorld );
  72. matrix3x4_t tmp;
  73. ConcatTransforms( *pCameraToWorld, g_ViewAlignMatrix, tmp );
  74. MatrixInvert( tmp, *pWorldToView );
  75. }
  76. void ComputeViewMatrix( matrix3x4_t *pWorldToView, matrix3x4_t *pCameraToWorld,
  77. Vector const &vecOrigin,
  78. Vector const &vecForward, Vector const &vecLeft, Vector const &vecUp )
  79. {
  80. MatrixSetColumn( vecForward, FORWARD_AXIS, *pCameraToWorld );
  81. MatrixSetColumn( vecLeft, LEFT_AXIS, *pCameraToWorld );
  82. MatrixSetColumn( vecUp, UP_AXIS, *pCameraToWorld );
  83. MatrixSetColumn( vecOrigin, ORIGIN, *pCameraToWorld );
  84. matrix3x4_t tmp;
  85. ConcatTransforms( *pCameraToWorld, g_ViewAlignMatrix, tmp );
  86. MatrixInvert( tmp, *pWorldToView );
  87. }
  88. void ComputeViewMatrix( matrix3x4_t *pWorldToView, const Camera_t &camera )
  89. {
  90. matrix3x4_t cameraToWorld;
  91. ComputeViewMatrix( pWorldToView, &cameraToWorld, camera );
  92. }
  93. void ComputeViewMatrix( VMatrix *pWorldToView, const Camera_t &camera )
  94. {
  95. matrix3x4_t transform, invTransform;
  96. AngleMatrix( camera.m_angles, camera.m_origin, transform );
  97. VMatrix matRotate( transform );
  98. #ifndef YUP_ACTIVE
  99. VMatrix matRotateZ;
  100. MatrixBuildRotationAboutAxis( matRotateZ, Vector(0,0,1), -90 );
  101. MatrixMultiply( matRotate, matRotateZ, matRotate );
  102. VMatrix matRotateX;
  103. MatrixBuildRotationAboutAxis( matRotateX, Vector(1,0,0), 90 );
  104. MatrixMultiply( matRotate, matRotateX, matRotate );
  105. transform = matRotate.As3x4();
  106. #else
  107. VMatrix matRotateUp;
  108. MatrixBuildRotationAboutAxis( matRotateUp, Vector(0,1,0), -180 );
  109. transform = matRotate.As3x4();
  110. #endif
  111. MatrixInvert( transform, invTransform );
  112. pWorldToView->Init( invTransform );
  113. }
  114. void ComputeViewMatrix( VMatrix *pViewMatrix, const Vector &origin, const QAngle &angles )
  115. {
  116. static VMatrix baseRotation;
  117. static bool bDidInit;
  118. if ( !bDidInit )
  119. {
  120. MatrixBuildRotationAboutAxis( baseRotation, Vector( 1, 0, 0 ), -90 );
  121. MatrixRotate( baseRotation, Vector( 0, 0, 1 ), 90 );
  122. bDidInit = true;
  123. }
  124. *pViewMatrix = baseRotation;
  125. MatrixRotate( *pViewMatrix, Vector( 1, 0, 0 ), -angles[2] );
  126. MatrixRotate( *pViewMatrix, Vector( 0, 1, 0 ), -angles[0] );
  127. MatrixRotate( *pViewMatrix, Vector( 0, 0, 1 ), -angles[1] );
  128. MatrixTranslate( *pViewMatrix, -origin );
  129. }
  130. void ComputeViewMatrix( VMatrix *pViewMatrix, const matrix3x4_t &matGameCustom )
  131. {
  132. //translate game coordinates to rendering coordinates. Basically does the same as baseRotation in the other version of ComputeViewMatrix()
  133. pViewMatrix->m[0][0] = -matGameCustom.m_flMatVal[1][0];
  134. pViewMatrix->m[0][1] = -matGameCustom.m_flMatVal[1][1];
  135. pViewMatrix->m[0][2] = -matGameCustom.m_flMatVal[1][2];
  136. pViewMatrix->m[0][3] = -matGameCustom.m_flMatVal[1][3];
  137. pViewMatrix->m[1][0] = matGameCustom.m_flMatVal[2][0];
  138. pViewMatrix->m[1][1] = matGameCustom.m_flMatVal[2][1];
  139. pViewMatrix->m[1][2] = matGameCustom.m_flMatVal[2][2];
  140. pViewMatrix->m[1][3] = matGameCustom.m_flMatVal[2][3];
  141. pViewMatrix->m[2][0] = -matGameCustom.m_flMatVal[0][0];
  142. pViewMatrix->m[2][1] = -matGameCustom.m_flMatVal[0][1];
  143. pViewMatrix->m[2][2] = -matGameCustom.m_flMatVal[0][2];
  144. pViewMatrix->m[2][3] = -matGameCustom.m_flMatVal[0][3];
  145. //standard 4th row
  146. pViewMatrix->m[3][0] = pViewMatrix->m[3][1] = pViewMatrix->m[3][2] = 0.0f;
  147. pViewMatrix->m[3][3] = 1.0f;
  148. }
  149. void ComputeProjectionMatrix( VMatrix *pCameraToProjection, const Camera_t &camera, int width, int height )
  150. {
  151. float flApsectRatio = (float)width / (float)height;
  152. ComputeProjectionMatrix( pCameraToProjection, camera.m_flZNear, camera.m_flZFar, camera.m_flFOVX, flApsectRatio );
  153. }
  154. void ComputeProjectionMatrix( VMatrix *pCameraToProjection, float flZNear, float flZFar, float flFOVX, float flAspectRatio )
  155. {
  156. float halfWidth = tan( flFOVX * M_PI / 360.0 );
  157. float halfHeight = halfWidth / flAspectRatio;
  158. memset( pCameraToProjection, 0, sizeof( VMatrix ) );
  159. pCameraToProjection->m[0][0] = 1.0f / halfWidth;
  160. pCameraToProjection->m[1][1] = 1.0f / halfHeight;
  161. pCameraToProjection->m[2][2] = flZFar / ( flZNear - flZFar );
  162. pCameraToProjection->m[3][2] = -1.0f;
  163. pCameraToProjection->m[2][3] = flZNear * flZFar / ( flZNear - flZFar );
  164. }
  165. void ComputeProjectionMatrix( VMatrix *pCameraToProjection, float flZNear, float flZFar, float flFOVX, float flAspectRatio,
  166. float flClipSpaceBottomLeftX, float flClipSpaceBottomLeftY,
  167. float flClipSpaceTopRightX, float flClipSpaceTopRightY )
  168. {
  169. Vector pNearPoints[ 4 ];
  170. Vector vForward( 0, 0, 1 );
  171. Vector vUp( 0, 1, 0 );
  172. Vector vLeft( -1, 0, 0 );
  173. CalcFarPlaneCameraRelativePoints( pNearPoints, vForward, vUp, vLeft, flZNear,
  174. flFOVX, flAspectRatio,
  175. flClipSpaceBottomLeftX, flClipSpaceBottomLeftY,
  176. flClipSpaceTopRightX, flClipSpaceTopRightY );
  177. float l = pNearPoints[ 0 ].x;
  178. float r = pNearPoints[ 1 ].x;
  179. float b = pNearPoints[ 0 ].y;
  180. float t = pNearPoints[ 2 ].y;
  181. float zn = flZNear;
  182. float zf = flZFar;
  183. float flWidth = r - l;
  184. float flHeight = t - b;
  185. float flReverseDepth = zn - zf;
  186. memset( pCameraToProjection, 0, sizeof( VMatrix ) );
  187. pCameraToProjection->m[0][0] = ( 2.0f * zn ) / flWidth;
  188. pCameraToProjection->m[1][1] = ( 2.0f * zn ) / flHeight;
  189. pCameraToProjection->m[2][2] = zf / flReverseDepth;
  190. pCameraToProjection->m[0][2] = ( l + r ) / flWidth;
  191. pCameraToProjection->m[1][2] = ( t + b ) / flHeight;
  192. pCameraToProjection->m[2][3] = ( zn * zf ) / flReverseDepth;
  193. pCameraToProjection->m[3][2] = -1.0f;
  194. /*
  195. // this is the matrix we're going for here
  196. 2*zn/(r-l) 0 0 0
  197. 0 2*zn/(t-b) 0 0
  198. (l+r)/(r-l) (t+b)/(t-b) zf/(zn-zf) -1
  199. 0 0 zn*zf/(zn-zf) 0
  200. */
  201. }
  202. //-----------------------------------------------------------------------------
  203. // Computes the screen space position given a screen size
  204. //-----------------------------------------------------------------------------
  205. void ComputeScreenSpacePosition( Vector2D *pScreenPosition, const Vector &vecWorldPosition,
  206. const Camera_t &camera, int width, int height )
  207. {
  208. VMatrix view, proj, viewproj;
  209. ComputeViewMatrix( &view, camera );
  210. ComputeProjectionMatrix( &proj, camera, width, height );
  211. MatrixMultiply( proj, view, viewproj );
  212. Vector vecScreenPos;
  213. Vector3DMultiplyPositionProjective( viewproj, vecWorldPosition, vecScreenPos );
  214. pScreenPosition->x = ( vecScreenPos.x + 1.0f ) * width / 2.0f;
  215. pScreenPosition->y = ( -vecScreenPos.y + 1.0f ) * height / 2.0f;
  216. }
  217. VMatrix ViewMatrixRH( Vector &vEye, Vector &vAt, Vector &vUp )
  218. {
  219. Vector xAxis, yAxis;
  220. Vector zAxis = vEye - vAt;
  221. xAxis = CrossProduct( vUp, zAxis );
  222. yAxis = CrossProduct( zAxis, xAxis );
  223. xAxis.NormalizeInPlace();
  224. yAxis.NormalizeInPlace();
  225. zAxis.NormalizeInPlace();
  226. float flDotX = -DotProduct( xAxis, vEye );
  227. float flDotY = -DotProduct( yAxis, vEye );
  228. float flDotZ = -DotProduct( zAxis, vEye );
  229. // YUP_ACTIVE: This is ok
  230. VMatrix mRet(
  231. xAxis.x, yAxis.x, zAxis.x, 0,
  232. xAxis.y, yAxis.y, zAxis.y, 0,
  233. xAxis.z, yAxis.z, zAxis.z, 0,
  234. flDotX, flDotY, flDotZ, 1 );
  235. return mRet.Transpose();
  236. }
  237. // Given populated camera params, generate view and proj matrices.
  238. void MatricesFromCamera( VMatrix &mWorldToView, VMatrix &mProjection, const Camera_t &camera,
  239. float flClipSpaceBottomLeftX, float flClipSpaceBottomLeftY,
  240. float flClipSpaceTopRightX, float flClipSpaceTopRightY )
  241. {
  242. matrix3x4_t cameraToWorld;
  243. ComputeViewMatrix( &mWorldToView.As3x4(), &cameraToWorld, camera );
  244. if ( camera.IsOrthographic() )
  245. {
  246. mProjection = OrthoMatrixRH( camera.m_flWidth, camera.m_flHeight, camera.m_flZNear, camera.m_flZFar );
  247. }
  248. else
  249. {
  250. ComputeProjectionMatrix( &mProjection, camera.m_flZNear, camera.m_flZFar, camera.m_flFOVX, camera.m_flAspect,
  251. flClipSpaceBottomLeftX, flClipSpaceBottomLeftY, flClipSpaceTopRightX, flClipSpaceTopRightY );
  252. }
  253. }
  254. // Generate frustum planes from viewproj matrix
  255. void FrustumFromViewProj( Frustum_t *pFrustum, const VMatrix &mViewProj, const Vector &origin, bool bD3DClippingRange )
  256. {
  257. VPlane planes[FRUSTUM_NUMPLANES];
  258. ExtractClipPlanesFromNonTransposedMatrix( mViewProj, planes, bD3DClippingRange );
  259. // Subtract the origin.
  260. for ( int i = 0; i < FRUSTUM_NUMPLANES; ++i )
  261. {
  262. planes[i].m_Dist = planes[i].m_Dist + DotProduct( planes[i].m_Normal, -origin );
  263. }
  264. pFrustum->SetPlanes( planes );
  265. }
  266. // Generate frustum planes given view and proj matrices
  267. void FrustumFromMatrices( Frustum_t *pFrustum, const VMatrix &mWorldToView, const VMatrix &mProjection, const Vector &origin, bool bD3DClippingRange )
  268. {
  269. VMatrix viewProj;
  270. viewProj = ( mProjection * mWorldToView );
  271. FrustumFromViewProj( pFrustum, viewProj, origin, bD3DClippingRange );
  272. }
  273. VMatrix ViewProjFromVectors( const Vector &origin, float flNear, float flFar, float flFOV, float flAspect,
  274. Vector const &vecForward, Vector const &vecLeft, Vector const &vecUp )
  275. {
  276. matrix3x4_t mCameraToWorld;
  277. matrix3x4_t mWorldToView;
  278. ComputeViewMatrix( &mWorldToView, &mCameraToWorld, origin, vecForward, vecLeft, vecUp );
  279. VMatrix mProjection;
  280. ComputeProjectionMatrix( &mProjection, flNear, flFar, flFOV, flAspect );
  281. VMatrix mViewProj;
  282. mViewProj = (mProjection * VMatrix(mWorldToView));
  283. return mViewProj;
  284. }
  285. int CFrustum::CheckBoxAgainstNearAndFarPlanes( const VectorAligned &minBounds, const VectorAligned &maxBounds ) const
  286. {
  287. // !!speed!! not super fast. change to use simd, inlining
  288. float flNear = 0;
  289. float flFar = 0;
  290. AABB_t aabb;
  291. aabb.m_vMinBounds = minBounds;
  292. aabb.m_vMaxBounds = maxBounds;
  293. Vector vZero( 0, 0, 0 );
  294. GetNearAndFarPlanesAroundBox( &flNear, &flFar, aabb, vZero );
  295. int nRet = 0;
  296. if ( flNear <= m_camera.m_flZNear )
  297. {
  298. nRet |= BOXCHECK_FLAGS_OVERLAPS_NEAR;
  299. }
  300. if ( flFar >= m_camera.m_flZFar )
  301. {
  302. nRet |= BOXCHECK_FLAGS_OVERLAPS_FAR;
  303. }
  304. return nRet;
  305. }
  306. void CFrustum::GetNearAndFarPlanesAroundBox( float *pNear, float *pFar, AABB_t const &inBox, Vector &vOriginShift ) const
  307. {
  308. AABB_t box = inBox;
  309. box.m_vMinBounds -= vOriginShift;
  310. box.m_vMaxBounds -= vOriginShift;
  311. Vector vCorners[8];
  312. vCorners[0] = box.m_vMinBounds;
  313. vCorners[1] = Vector( box.m_vMinBounds.x, box.m_vMinBounds.y, box.m_vMaxBounds.z );
  314. vCorners[2] = Vector( box.m_vMinBounds.x, box.m_vMaxBounds.y, box.m_vMinBounds.z );
  315. vCorners[3] = Vector( box.m_vMinBounds.x, box.m_vMaxBounds.y, box.m_vMaxBounds.z );
  316. vCorners[4] = Vector( box.m_vMaxBounds.x, box.m_vMinBounds.y, box.m_vMinBounds.z );
  317. vCorners[5] = Vector( box.m_vMaxBounds.x, box.m_vMinBounds.y, box.m_vMaxBounds.z );
  318. vCorners[6] = Vector( box.m_vMaxBounds.x, box.m_vMaxBounds.y, box.m_vMinBounds.z );
  319. vCorners[7] = box.m_vMaxBounds;
  320. float flNear = FLT_MAX;//m_camera.m_flZNear;
  321. float flFar = -FLT_MAX;//m_camera.m_flZFar;
  322. for ( int i=0; i<8; ++i )
  323. {
  324. Vector vDelta = vCorners[i] - m_camera.m_origin;
  325. float flDist = DotProduct( m_forward, vDelta );
  326. flNear = MIN( flNear, flDist );
  327. flFar = MAX( flFar, flDist );
  328. }
  329. *pNear = flNear;
  330. *pFar = flFar;
  331. }
  332. void CFrustum::UpdateFrustumFromCamera()
  333. {
  334. if ( !m_bDirty )
  335. return;
  336. ComputeViewMatrix( &m_worldToView, &m_cameraToWorld, m_camera );
  337. if ( m_camera.IsOrthographic() )
  338. {
  339. MatrixBuildOrtho( m_projection,
  340. m_camera.m_flWidth * m_flClipSpaceBottomLeftX * 0.5f,
  341. m_camera.m_flHeight * m_flClipSpaceTopRightY * 0.5f,
  342. m_camera.m_flWidth * m_flClipSpaceTopRightX * 0.5f,
  343. m_camera.m_flHeight * m_flClipSpaceBottomLeftY * 0.5f,
  344. m_camera.m_flZNear, m_camera.m_flZFar );
  345. }
  346. else
  347. {
  348. // Determine the extents
  349. ComputeProjectionMatrix( &m_projection, m_camera.m_flZNear, m_camera.m_flZFar, m_camera.m_flFOVX, m_camera.m_flAspect,
  350. m_flClipSpaceBottomLeftX, m_flClipSpaceBottomLeftY, m_flClipSpaceTopRightX, m_flClipSpaceTopRightY );
  351. }
  352. CalcViewProj();
  353. ExtractDirectionVectors( &m_forward, &m_left, &m_up, m_cameraToWorld );
  354. FrustumFromViewProj( &m_frustumStruct, m_viewProj, m_camera.m_origin, true );
  355. m_bDirty = false;
  356. }
  357. void CFrustum::BuildFrustumFromVectors( const Vector &origin, float flNear, float flFar, float flFOV, float flAspect,
  358. Vector const &vecForward, Vector const &vecLeft, Vector const &vecUp )
  359. {
  360. InitCamera( origin, QAngle( 0, 0, 0 ), flNear, flFar, flFOV, flAspect );
  361. ComputeViewMatrix( &m_worldToView, &m_cameraToWorld, origin, vecForward, vecLeft, vecUp );
  362. ComputeProjectionMatrix( &m_projection, flNear, flFar, flFOV, flAspect );
  363. m_viewProj = (m_projection * VMatrix(m_worldToView));
  364. ExtractDirectionVectors( &m_forward, &m_left, &m_up, m_cameraToWorld );
  365. m_frustumStruct.CreatePerspectiveFrustum( vec3_origin, m_forward, -m_left, m_up,
  366. flNear, flFar, flFOV, flAspect );
  367. MatrixInverseGeneral( m_viewProj, m_invViewProj );
  368. MatrixInverseGeneral( m_projection, m_invProjection );
  369. VMatrix worldToView( m_worldToView );
  370. VMatrix viewToWorld;
  371. worldToView.InverseGeneral( viewToWorld );
  372. m_cameraToWorld = viewToWorld.As3x4();
  373. viewToWorld.GetTranslation( m_camera.m_origin );
  374. }
  375. /// Given only the world->view and an ortho view->proj matrices, this helper method computes
  376. /// the implied frustum values needed for orthographic shadow buffer rendering (but
  377. /// should work with perspective projections too). This is slow and general, but
  378. /// it should guarantee a frustum in a consistent/sane state given any world->view and
  379. /// view->proj matrices.
  380. void CFrustum::BuildShadowFrustum( VMatrix &newWorldToView, VMatrix &newProj )
  381. {
  382. SetView( newWorldToView );
  383. SetProj( newProj );
  384. CalcViewProj();
  385. VMatrix &viewToProj = m_projection;
  386. Assert( ( viewToProj.m[3][0] == 0.0f ) && ( viewToProj.m[3][1] == 0.0f ) && ( viewToProj.m[3][2] == 0.0f ) && ( viewToProj[3][3] == 1.0f ) );
  387. VMatrix worldToView( m_worldToView );
  388. VMatrix worldToCamera;
  389. MatrixMultiply( g_matViewToCameraMatrix, worldToView, worldToCamera );
  390. VMatrix cameraToWorld;
  391. MatrixInverseGeneral( worldToCamera, cameraToWorld );
  392. m_cameraToWorld = cameraToWorld.As3x4();
  393. // Compute camera location in world space.
  394. VMatrix viewToWorld;
  395. MatrixInverseGeneral( worldToView, viewToWorld );
  396. viewToWorld.GetTranslation( m_camera.m_origin );
  397. cameraToWorld.GetTranslation( m_camera.m_origin );
  398. MatrixToAngles( cameraToWorld, m_camera.m_angles );
  399. // forward/left/up - world relative coordinates, assuming an FPS camera sitting on an XY plane, Z is up
  400. MatrixGetRow( worldToCamera, FORWARD_AXIS, &m_forward );
  401. MatrixGetRow( worldToCamera, LEFT_AXIS, &m_left );
  402. MatrixGetRow( worldToCamera, UP_AXIS, &m_up );
  403. // Compute near/far planes, assuming D3D-style clipping range of [0,1]
  404. VMatrix projToView;
  405. viewToProj.InverseGeneral( projToView );
  406. Vector vNearPoint, vFarPoint;
  407. projToView.V3Mul( Vector( 0.0f, 0.0f, 0.0f ), vNearPoint );
  408. projToView.V3Mul( Vector( 0.0f, 0.0f, 1.0f ), vFarPoint );
  409. m_camera.m_flZNear = fabs( vNearPoint.z );
  410. m_camera.m_flZFar = fabs( vFarPoint.z );
  411. m_camera.m_flAspect = 1.0f;
  412. m_camera.m_flFOVX = -1.0f;
  413. Vector vCornerPoints[2];
  414. // Y's are negated here because MatrixBuildOrtho() flips top/bottom!
  415. projToView.V3Mul( Vector( -1.0f, 1.0f, 0.0f ), vCornerPoints[0] ); // left/bottom
  416. projToView.V3Mul( Vector( 1.0f, -1.0f, 0.0f ), vCornerPoints[1] ); // right/top
  417. m_flClipSpaceBottomLeftX = vCornerPoints[0].x;
  418. m_flClipSpaceBottomLeftY = vCornerPoints[0].y;
  419. m_flClipSpaceTopRightX = vCornerPoints[1].x;
  420. m_flClipSpaceTopRightY = vCornerPoints[1].y;
  421. m_camera.m_flWidth = 2.0f;
  422. m_camera.m_flHeight = 2.0f;
  423. // Now compute the frustum planes used for culling purposes. These planes are computed assuming the camera is already at the origin.
  424. VMatrix worldToCamLocalWorld;
  425. // This is confusing - vShadowCamPos is not negated here, because we need to compensate for the fact that the
  426. // frustum culling code makes the cam pos the origin before culling by subtracting the camera's origin - so undo it.
  427. // Calc a viewproj matrix that has no g_ViewAlignMatrix matrix in it.
  428. MatrixBuildTranslation( worldToCamLocalWorld, m_camera.m_origin.x, m_camera.m_origin.y, m_camera.m_origin.z );
  429. VMatrix worldToCamLocalWorldToView( worldToView * worldToCamLocalWorld );
  430. VMatrix shadowCamLocalWorldToViewProj( viewToProj * worldToCamLocalWorldToView );
  431. VPlane pSixPlanes[FRUSTUM_NUMPLANES];
  432. #if 0
  433. Vector actualOriginProjSpace( 0.0f, 0.0f, .5f );
  434. Vector actualOriginWorldSpace;
  435. VMatrix projToWorld;
  436. m_viewProj.InverseGeneral( projToWorld );
  437. projToWorld.V3Mul( actualOriginProjSpace, actualOriginWorldSpace );
  438. ExtractClipPlanesFromNonTransposedMatrix( m_viewProj, pSixPlanes, true );
  439. // Testing
  440. float flDots[6];
  441. for (uint i = 0; i < 6; i++)
  442. {
  443. flDots[i] = pSixPlanes[i].DistTo( actualOriginWorldSpace );
  444. }
  445. #endif
  446. ExtractClipPlanesFromNonTransposedMatrix( shadowCamLocalWorldToViewProj, pSixPlanes, true );
  447. m_frustumStruct.SetPlanes( pSixPlanes );
  448. MatrixInverseGeneral( m_viewProj, m_invViewProj );
  449. MatrixInverseGeneral( m_projection, m_invProjection );
  450. m_bDirty = false;
  451. // This should be a no-op (ignoring FP precision) if all the above stuff was done right.
  452. //m_bDirty = true;
  453. //UpdateFrustumFromCamera();
  454. }
  455. void CFrustum::CalcFarPlaneCameraRelativePoints( Vector *p4PointsOut, float flFarPlane,
  456. float flClipSpaceBottomLeftX, float flClipSpaceBottomLeftY,
  457. float flClipSpaceTopRightX, float flClipSpaceTopRightY ) const
  458. {
  459. Vector vForward = CameraForward();
  460. Vector vUp = CameraUp();
  461. Vector vLeft = CameraLeft();
  462. float flFovX = GetCameraFOV();
  463. ::CalcFarPlaneCameraRelativePoints( p4PointsOut, vForward, vUp, vLeft, flFarPlane,
  464. flFovX, GetCameraAspect(),
  465. flClipSpaceBottomLeftX, flClipSpaceBottomLeftY,
  466. flClipSpaceTopRightX, flClipSpaceTopRightY );
  467. }
  468. // generates 8 vertices of the frustum
  469. void Camera_t::ComputeGeometry( Vector *pVertsOut8, const Vector &vForward, const Vector &vLeft, const Vector &vUp ) const
  470. {
  471. Vector vNearLeft, vFarLeft;
  472. Vector vNearUp, vFarUp;
  473. Vector vNear = m_origin + m_flZNear * vForward;
  474. Vector vFar = m_origin + m_flZFar * vForward;
  475. if ( IsOrthographic() )
  476. {
  477. vNearLeft = vLeft * m_flWidth;
  478. vNearUp = vUp * m_flHeight;
  479. vFarLeft = vNearLeft;
  480. vFarUp = vNearUp;
  481. }
  482. else
  483. {
  484. float flTanX = tan( DEG2RAD(m_flFOVX) * 0.5f );
  485. float flooAspect = 1.0f / m_flAspect;
  486. float flWidth = m_flZNear * flTanX;
  487. float flHeight = flWidth * flooAspect;
  488. vNearLeft = vLeft * flWidth;
  489. vNearUp = vUp * flHeight;
  490. float flFarWidth = m_flZFar * flTanX;
  491. float flFarHeight = flFarWidth * flooAspect;
  492. vFarLeft = vLeft * flFarWidth;
  493. vFarUp = vUp * flFarHeight;
  494. }
  495. pVertsOut8[0] = vNear + vNearLeft - vNearUp;
  496. pVertsOut8[1] = vNear - vNearLeft - vNearUp;
  497. pVertsOut8[2] = vNear + vNearLeft + vNearUp;
  498. pVertsOut8[3] = vNear - vNearLeft + vNearUp;
  499. pVertsOut8[4] = vFar + vFarLeft - vFarUp;
  500. pVertsOut8[5] = vFar - vFarLeft - vFarUp;
  501. pVertsOut8[6] = vFar + vFarLeft + vFarUp;
  502. pVertsOut8[7] = vFar - vFarLeft + vFarUp;
  503. }
  504. void Camera_t::ComputeGeometry( Vector *pVertsOut8 ) const
  505. {
  506. Vector vForward, vLeft, vUp;
  507. AngleVectorsFLU( m_angles, &vForward, &vLeft, &vUp );
  508. ComputeGeometry( pVertsOut8, vForward, vLeft, vUp );
  509. }
  510. // generates 8 vertices of the frustum as bounds
  511. void CFrustum::ComputeBounds( Vector *pMins, Vector *pMaxs ) const
  512. {
  513. ClearBounds( *pMins, *pMaxs );
  514. Vector vPts[8];
  515. m_camera.ComputeGeometry( vPts, m_forward, m_left, m_up );
  516. for ( int i = 0; i < 8; i++ )
  517. {
  518. AddPointToBounds( vPts[i], *pMins, *pMaxs );
  519. }
  520. }
  521. static inline void InvertVMatrix( const VMatrix &src, VMatrix &dst )
  522. {
  523. src.InverseGeneral( dst );
  524. }
  525. void CFrustum::CalcViewProj()
  526. {
  527. m_viewProj = ( m_projection * VMatrix( m_worldToView ) );
  528. InvertVMatrix( m_viewProj, m_invViewProj );
  529. InvertVMatrix( m_projection, m_invProjection );
  530. }
  531. float CFrustum::ComputeScreenSize( Vector vecOrigin, float flRadius ) const
  532. {
  533. vecOrigin -= GetCameraPosition();
  534. float flDist = vecOrigin.Length();
  535. if ( flDist < flRadius )
  536. {
  537. return 1.0; // eye inside sphere
  538. }
  539. float flSin = sin( DEG2RAD( MIN( GetCameraFOV(), 90.0 ) ) );
  540. return MIN( 1.0, flSin * ( flRadius / flDist ) );
  541. }
  542. void CFrustum::ViewToWorld( const Vector2D &vViewMinusOneToOne, Vector *pOutWorld )
  543. {
  544. Vector vView3D;
  545. vView3D.x = vViewMinusOneToOne.x;
  546. vView3D.y = vViewMinusOneToOne.y;
  547. vView3D.z = 0;
  548. const VMatrix &invViewProjMatrix = GetInvViewProj();
  549. Vector3DMultiplyPositionProjective( invViewProjMatrix, vView3D, *pOutWorld );
  550. }
  551. void CFrustum::BuildRay( const Vector2D &vViewMinusOneToOne, Vector *pOutRayStart, Vector *pOutRayDirection )
  552. {
  553. Vector vClickPoint;
  554. ViewToWorld( vViewMinusOneToOne, &vClickPoint );
  555. if ( !IsOrthographic() )
  556. {
  557. Camera_t camera = GetCameraStruct();
  558. Vector vRay = vClickPoint - camera.m_origin;
  559. VectorNormalize( vRay );
  560. *pOutRayStart = camera.m_origin;
  561. *pOutRayDirection = vRay;
  562. }
  563. else
  564. {
  565. *pOutRayStart = vClickPoint;
  566. ViewForward( *pOutRayDirection );
  567. }
  568. }
  569. void CFrustum::BuildFrustumFromParameters(
  570. const Vector &origin, const QAngle &angles,
  571. float flNear, float flFar, float flFOV, float flAspect,
  572. const VMatrix &worldToView, const VMatrix &viewToProj )
  573. {
  574. InitCamera( origin, angles, flNear, flFar, flFOV, flAspect );
  575. m_worldToView = worldToView.As3x4();
  576. VMatrix worldToCamera;
  577. MatrixMultiply( g_matViewToCameraMatrix, worldToView, worldToCamera );
  578. VMatrix cameraToWorld;
  579. MatrixInverseGeneral( worldToCamera, cameraToWorld );
  580. m_cameraToWorld = cameraToWorld.As3x4();
  581. m_projection = viewToProj;
  582. CalcViewProj();
  583. // forward/left/up - world relative coordinates, assuming an FPS camera sitting on an XY plane, Z is up
  584. MatrixGetRow( worldToCamera, FORWARD_AXIS, &m_forward );
  585. MatrixGetRow( worldToCamera, LEFT_AXIS, &m_left );
  586. MatrixGetRow( worldToCamera, UP_AXIS, &m_up );
  587. // Now compute the frustum planes used for culling purposes. These planes are computed assuming the camera is already at the origin.
  588. VMatrix worldToCamLocalWorld;
  589. // This is confusing - vShadowCamPos is not negated here, because we need to compensate for the fact that the
  590. // frustum culling code makes the cam pos the origin before culling by subtracting the camera's origin - so undo it.
  591. MatrixBuildTranslation( worldToCamLocalWorld, m_camera.m_origin.x, m_camera.m_origin.y, m_camera.m_origin.z );
  592. VMatrix worldToCamLocalWorldToView( worldToView * worldToCamLocalWorld );
  593. VMatrix shadowCamLocalWorldToViewProj( viewToProj * worldToCamLocalWorldToView );
  594. VPlane pSixPlanes[FRUSTUM_NUMPLANES];
  595. ExtractClipPlanesFromNonTransposedMatrix( shadowCamLocalWorldToViewProj, pSixPlanes, true );
  596. m_frustumStruct.SetPlanes( pSixPlanes );
  597. m_bDirty = false;
  598. // This should be a no-op (ignoring FP precision) if all the above stuff was done right.
  599. //m_bDirty = true;
  600. //UpdateFrustumFromCamera();
  601. }