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.

1777 lines
66 KiB

  1. //========= Copyright 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: Directional lighting with cascaded shadow mapping entity.
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include "cbase.h"
  8. #include "c_env_cascade_light.h"
  9. #include "engine/ivdebugoverlay.h"
  10. #include "materialsystem/imaterialvar.h"
  11. #include "view_shared.h"
  12. #include "iviewrender.h"
  13. #include "c_world.h"
  14. #include "materialsystem/materialsystem_config.h"
  15. #if defined (_PS3 )
  16. #include <algorithm>
  17. #endif
  18. // memdbgon must be the last include file in a .cpp file!!!
  19. #include "tier0/memdbgon.h"
  20. //#define CsmDbgMsg Msg
  21. #define CsmDbgMsg(x)
  22. #define MAX_CSM_CASCADES 3
  23. ConVar cl_csm_enabled( "cl_csm_enabled", "1", FCVAR_DEVELOPMENTONLY, "" );
  24. ConVar cl_csm_max_shadow_dist("cl_csm_max_shadow_dist", ( IsX360() ) ? "350" : IsPS3() ? "250" : "-1", FCVAR_DEVELOPMENTONLY, "" );
  25. ConVar cl_csm_capture_state( "cl_csm_capture_state", "0", FCVAR_DEVELOPMENTONLY, "" );
  26. ConVar cl_csm_clear_captured_state( "cl_csm_clear_captured_state", "0", FCVAR_DEVELOPMENTONLY, "" );
  27. ConVar cl_csm_debug_render_ztest( "cl_csm_debug_render_ztest", "1", FCVAR_DEVELOPMENTONLY, "" );
  28. ConVar cl_csm_max_visible_dist("cl_csm_max_visible_dist", "5000", FCVAR_DEVELOPMENTONLY, "" );
  29. ConVar cl_csm_debug_vis_lo_range("cl_csm_debug_vis_lo_range", ".35", FCVAR_DEVELOPMENTONLY, "" );
  30. ConVar cl_csm_debug_vis_hi_range("cl_csm_debug_vis_hi_range", "1.0", FCVAR_DEVELOPMENTONLY, "" );
  31. ConVar cl_csm_use_forced_view_matrices("cl_csm_use_forced_view_matrices", "1", FCVAR_DEVELOPMENTONLY, "" );
  32. ConVar cl_csm_debug_2d( "cl_csm_debug_2d", "0", FCVAR_DEVELOPMENTONLY );
  33. ConVar cl_csm_debug_3d( "cl_csm_debug_3d", "0", FCVAR_DEVELOPMENTONLY );
  34. ConVar cl_csm_debug_culling( "cl_csm_debug_culling", "0", FCVAR_DEVELOPMENTONLY );
  35. ConVar cl_csm_debug_culling_cascade( "cl_csm_debug_culling_cascade", "-1", FCVAR_DEVELOPMENTONLY );
  36. ConVar cl_csm_print_culling_planes( "cl_csm_print_culling_planes", "0", FCVAR_DEVELOPMENTONLY );
  37. ConVar cl_csm_viz_numplanes( "cl_csm_viz_numplanes", "-1", FCVAR_DEVELOPMENTONLY, "" );
  38. ConVar cl_csm_viz_polyhedron_quad_size( "cl_csm_viz_polyhedron_quad_size", "131072", FCVAR_DEVELOPMENTONLY, "" );
  39. ConVar cl_csm_use_env_light_direction( "cl_csm_use_env_light_direction", "1", FCVAR_DEVELOPMENTONLY );
  40. ConVar cl_csm_rot_override( "cl_csm_rot_override", "0", FCVAR_DEVELOPMENTONLY );
  41. // dust2's angles
  42. ConVar cl_csm_rot_x( "cl_csm_rot_x", "50", FCVAR_DEVELOPMENTONLY );
  43. ConVar cl_csm_rot_y( "cl_csm_rot_y", "43", FCVAR_DEVELOPMENTONLY );
  44. ConVar cl_csm_rot_z( "cl_csm_rot_z", "0", FCVAR_DEVELOPMENTONLY );
  45. ConVar cl_csm_disable_culling( "cl_csm_disable_culling", "0", FCVAR_DEVELOPMENTONLY );
  46. ConVar cl_csm_shadows( "cl_csm_shadows", "1", FCVAR_DEVELOPMENTONLY );
  47. ConVar cl_csm_entity_shadows( "cl_csm_entity_shadows", "1", FCVAR_DEVELOPMENTONLY );
  48. ConVar cl_csm_static_prop_shadows( "cl_csm_static_prop_shadows", "1", FCVAR_DEVELOPMENTONLY );
  49. ConVar cl_csm_world_shadows( "cl_csm_world_shadows", "1", FCVAR_DEVELOPMENTONLY );
  50. ConVar cl_csm_world_shadows_in_viewmodelcascade( "cl_csm_world_shadows_in_viewmodelcascade", ( IsGameConsole() || IsPlatformOSX() ) ? "0" : "1", FCVAR_DEVELOPMENTONLY );
  51. ConVar cl_csm_sprite_shadows( "cl_csm_sprite_shadows", "1", FCVAR_DEVELOPMENTONLY );
  52. ConVar cl_csm_rope_shadows( "cl_csm_rope_shadows", "1", FCVAR_DEVELOPMENTONLY );
  53. ConVar cl_csm_translucent_shadows( "cl_csm_translucent_shadows", ( IsGameConsole() || IsPlatformOSX() )? "0" : "1", FCVAR_DEVELOPMENTONLY );
  54. ConVar cl_csm_translucent_shadows_using_opaque_path( "cl_csm_translucent_shadows_using_opaque_path", "1", FCVAR_DEVELOPMENTONLY );
  55. ConVar cl_csm_ignore_disable_shadow_depth_rendering( "cl_csm_ignore_disable_shadow_depth_rendering", "0", FCVAR_DEVELOPMENTONLY );
  56. ConVar cl_csm_optimize_static_props( "cl_csm_optimize_static_props", "1", FCVAR_DEVELOPMENTONLY, "Enable/Disable optimal static prop rendering into CSM's (cull static props that make no visual contribution to shadows)" );
  57. ConVar cl_csm_viewmodel_shadows( "cl_csm_viewmodel_shadows", "1", FCVAR_DEVELOPMENTONLY );
  58. ConVar cl_csm_viewmodel_max_shadow_dist( "cl_csm_viewmodel_max_shadow_dist", "21", FCVAR_DEVELOPMENTONLY );
  59. ConVar cl_csm_viewmodel_farz( "cl_csm_viewmodel_farz", ( IsGameConsole() || IsPlatformOSX() ) ? "15" : "30", FCVAR_DEVELOPMENTONLY );
  60. ConVar cl_csm_viewmodel_max_visible_dist( "cl_csm_viewmodel_max_visible_dist", "1000", FCVAR_DEVELOPMENTONLY );
  61. ConVar cl_csm_slopescaledepthbias_c0( "cl_csm_slopescaledepthbias_c0", ( IsGameConsole() || IsPlatformOSX() ) ? "2" : "1.3", FCVAR_DEVELOPMENTONLY );
  62. ConVar cl_csm_slopescaledepthbias_c1( "cl_csm_slopescaledepthbias_c1", IsPlatformOSX() ? "4" : "2", FCVAR_DEVELOPMENTONLY );
  63. ConVar cl_csm_slopescaledepthbias_c2( "cl_csm_slopescaledepthbias_c2", IsPlatformOSX() ? "4" : "2", FCVAR_DEVELOPMENTONLY );
  64. ConVar cl_csm_slopescaledepthbias_c3( "cl_csm_slopescaledepthbias_c3", "2", FCVAR_DEVELOPMENTONLY );
  65. ConVar cl_csm_depthbias_c0( "cl_csm_depthbias_c0", ( IsGameConsole() || IsPlatformOSX() ) ? ".000005" : ".000025", FCVAR_DEVELOPMENTONLY );
  66. ConVar cl_csm_depthbias_c1( "cl_csm_depthbias_c1", IsPlatformOSX() ? "2" : ".000025", FCVAR_DEVELOPMENTONLY );
  67. ConVar cl_csm_depthbias_c2( "cl_csm_depthbias_c2", IsPlatformOSX() ? "2" : ".000025", FCVAR_DEVELOPMENTONLY );
  68. ConVar cl_csm_depthbias_c3( "cl_csm_depthbias_c3", ".000025", FCVAR_DEVELOPMENTONLY );
  69. ConVar cl_csm_viewmodel_slopescaledepthbias( "cl_csm_viewmodel_slopescaledepthbias", ( IsGameConsole() || IsPlatformOSX() ) ? "2" : "1.5", FCVAR_DEVELOPMENTONLY );
  70. ConVar cl_csm_viewmodel_depthbias( "cl_csm_viewmodel_depthbias", ( IsGameConsole() || IsPlatformOSX() ) ? ".000005" : ".00005", FCVAR_DEVELOPMENTONLY );
  71. ConVar cl_csm_hack_proj_matrices_for_cull_debugging( "cl_csm_hack_proj_matrices_for_cull_debugging", "0", FCVAR_DEVELOPMENTONLY );
  72. ConVar cl_csm_xlat_continuity( "cl_csm_xlat_continuity", "1", FCVAR_DEVELOPMENTONLY );
  73. ConVar cl_csm_force_no_csm_in_reflections( "cl_csm_force_no_csm_in_reflections", "0", FCVAR_DEVELOPMENTONLY );
  74. ConVar cl_csm_cull_small_prop_threshold_volume( "cl_csm_cull_small_prop_threshold_volume", "2000.0f ", FCVAR_DEVELOPMENTONLY );
  75. void CC_CSM_Status( const CCommand& args );
  76. static ConCommand cl_csm_status("cl_csm_status", CC_CSM_Status, "Usage:\n cl_csm_status\n", 0);
  77. CCascadeLightManager g_CascadeLightManager;
  78. IMPLEMENT_CLIENTCLASS_DT(C_CascadeLight, DT_CascadeLight, CCascadeLight)
  79. RecvPropVector(RECVINFO(m_shadowDirection)),
  80. RecvPropVector(RECVINFO(m_envLightShadowDirection)),
  81. RecvPropBool(RECVINFO(m_bEnabled)),
  82. RecvPropBool(RECVINFO(m_bUseLightEnvAngles)),
  83. RecvPropInt(RECVINFO(m_LightColor), 0, RecvProxy_Int32ToColor32),
  84. RecvPropInt(RECVINFO(m_LightColorScale), 0, RecvProxy_Int32ToInt32 ),
  85. RecvPropFloat(RECVINFO(m_flMaxShadowDist) )
  86. END_RECV_TABLE()
  87. LINK_ENTITY_TO_CLASS(env_cascade_light, C_CascadeLight);
  88. C_CascadeLight *C_CascadeLight::m_pCascadeLight;
  89. C_CascadeLight::C_CascadeLight() :
  90. C_BaseEntity(),
  91. m_shadowDirection( 0, 0, -1 ),
  92. m_envLightShadowDirection( 0, 0, -1 ),
  93. m_bEnabled( false ),
  94. m_bUseLightEnvAngles( true ),
  95. m_flMaxShadowDist( 400.0f )
  96. {
  97. CsmDbgMsg( "C_CascadeLight::C_CascadeLight\n" );
  98. m_LightColor.r = 255;
  99. m_LightColor.g = 255;
  100. m_LightColor.b = 255;
  101. m_LightColor.a = 255;
  102. m_LightColorScale = 255;
  103. }
  104. C_CascadeLight::~C_CascadeLight()
  105. {
  106. CsmDbgMsg( "C_CascadeLight::~C_CascadeLight\n" );
  107. }
  108. void C_CascadeLight::Spawn()
  109. {
  110. CsmDbgMsg( "C_CascadeLight::Spawn\n" );
  111. BaseClass::Spawn();
  112. SetNextClientThink( CLIENT_THINK_ALWAYS );
  113. m_pCascadeLight = this;
  114. }
  115. void C_CascadeLight::Release()
  116. {
  117. CsmDbgMsg( "C_CascadeLight::Release\n" );
  118. m_pCascadeLight = NULL;
  119. BaseClass::Release();
  120. }
  121. bool C_CascadeLight::ShouldDraw()
  122. {
  123. return false;
  124. }
  125. void C_CascadeLight::ClientThink()
  126. {
  127. VPROF("C_CascadeLight::ClientThink");
  128. BaseClass::ClientThink();
  129. }
  130. // 4 cascades plus 1 for the scene frustum itself
  131. static Vector g_vCascadeFrustumColors[ 4 + 1 ] =
  132. {
  133. Vector( 0, 1, 0 ),
  134. Vector( 0, 0, 1 ),
  135. Vector( 0, 1, 1 ),
  136. Vector( 1, 0, 0 ),
  137. Vector( .85f, .85f, .2f )
  138. };
  139. void CCascadeLightManager::RotXPlusDown( const CCommand &args ) { g_CascadeLightManager.m_flRotX[0] = 1.0f; }
  140. void CCascadeLightManager::RotXPlusUp( const CCommand &args ) { g_CascadeLightManager.m_flRotX[0] = 0.0f; }
  141. void CCascadeLightManager::RotXNegDown( const CCommand &args ) { g_CascadeLightManager.m_flRotX[1] = -1.0f; }
  142. void CCascadeLightManager::RotXNegUp( const CCommand &args ) { g_CascadeLightManager.m_flRotX[1] = 0.0f; }
  143. void CCascadeLightManager::RotYPlusDown( const CCommand &args ) { g_CascadeLightManager.m_flRotY[0] = 1.0f; }
  144. void CCascadeLightManager::RotYPlusUp( const CCommand &args ) { g_CascadeLightManager.m_flRotY[0] = 0.0f; }
  145. void CCascadeLightManager::RotYNegDown( const CCommand &args ) { g_CascadeLightManager.m_flRotY[1] = -1.0f; }
  146. void CCascadeLightManager::RotYNegUp( const CCommand &args ) { g_CascadeLightManager.m_flRotY[1] = 0.0f; }
  147. static ConCommand start_csm_rot_x_plus( "+csm_rot_x_plus", CCascadeLightManager::RotXPlusDown);
  148. static ConCommand end_csm_rot_x_plus( "-csm_rot_x_plus", CCascadeLightManager::RotXPlusUp);
  149. static ConCommand start_csm_rot_x_neg( "+csm_rot_x_neg", CCascadeLightManager::RotXNegDown);
  150. static ConCommand end_csm_rot_x_neg( "-csm_rot_x_neg", CCascadeLightManager::RotXNegUp);
  151. static ConCommand start_csm_rot_y_plus( "+csm_rot_y_plus", CCascadeLightManager::RotYPlusDown);
  152. static ConCommand end_csm_rot_y_plus( "-csm_rot_y_plus", CCascadeLightManager::RotYPlusUp);
  153. static ConCommand start_csm_rot_y_neg( "+csm_rot_y_neg", CCascadeLightManager::RotYNegDown);
  154. static ConCommand end_csm_rot_y_neg( "-csm_rot_y_neg", CCascadeLightManager::RotYNegUp);
  155. static void DebugRenderWireframeFrustum3D( const VMatrix &xform, const Vector &color, bool bDepthTest = false )
  156. {
  157. for ( uint i = 0; i < CCSMFrustumDefinition::NUM_FRUSTUM_LINES; ++i )
  158. {
  159. Vector4D s, e;
  160. xform.V4Mul( CCSMFrustumDefinition::g_vProjFrustumVerts[ CCSMFrustumDefinition::g_nFrustumLineVertIndices[ i * 2 + 0 ] ], s );
  161. xform.V4Mul( CCSMFrustumDefinition::g_vProjFrustumVerts[ CCSMFrustumDefinition::g_nFrustumLineVertIndices[ i * 2 + 1 ] ], e );
  162. s *= ( 1.0f / s.w );
  163. e *= ( 1.0f / e.w );
  164. NDebugOverlay::Line( Vector( s.x, s.y, s.z ), Vector( e.x, e.y, e.z ), (int)(color.x * 255.0f), (int)(color.y * 255.0f), (int)(color.z * 255.0f), !bDepthTest, NDEBUG_PERSIST_TILL_NEXT_SERVER );
  165. }
  166. }
  167. static void Add3DLineOverlay( const Vector &s, const Vector &e, const Vector &color, bool bDepthTest )
  168. {
  169. NDebugOverlay::Line( s, e, (int)(color.x * 255.0f), (int)(color.y * 255.0f), (int)(color.z * 255.0f), !bDepthTest, NDEBUG_PERSIST_TILL_NEXT_SERVER );
  170. }
  171. #if defined(_X360)
  172. template <class T> void _swap ( T& a, T& b )
  173. {
  174. T c(a); a=b; b=c;
  175. }
  176. #endif
  177. static void DebugRenderConvexPolyhedron( const Vector4D *pPlanes, uint nNumPlanes, const Vector &color, bool zTest )
  178. {
  179. #ifdef _DEBUG
  180. for ( uint nPlaneIndex = 0; nPlaneIndex < nNumPlanes; ++nPlaneIndex )
  181. {
  182. float l = pPlanes[nPlaneIndex].x*pPlanes[nPlaneIndex].x + pPlanes[nPlaneIndex].y*pPlanes[nPlaneIndex].y + pPlanes[nPlaneIndex].z*pPlanes[nPlaneIndex].z;
  183. l = sqrt( l );
  184. Assert( (fabs( l ) - 1.0f) < .00125f );
  185. }
  186. #endif
  187. uint nLastPlane = cl_csm_viz_numplanes.GetInt();
  188. if ( nLastPlane < 0 )
  189. nLastPlane = nNumPlanes;
  190. nLastPlane = MIN( nLastPlane, nNumPlanes );
  191. const float Q = cl_csm_viz_polyhedron_quad_size.GetFloat();
  192. for ( uint nPlaneIndex = 0; nPlaneIndex < nLastPlane; ++nPlaneIndex )
  193. {
  194. Vector4D plane( pPlanes[nPlaneIndex] );
  195. Vector vNormal( plane.x, plane.y, plane.z );
  196. float flDist = -plane.w;
  197. Vector vOrigin( vNormal * flDist );
  198. uint nMinorAxis = 0;
  199. float flMag = fabs( vNormal.x );
  200. if ( fabs( vNormal.y ) < flMag ) { flMag = fabs( vNormal.y ); nMinorAxis = 1; }
  201. if ( fabs( vNormal.z ) < flMag ) { flMag = fabs( vNormal.z ); nMinorAxis = 2; }
  202. Vector vU( 0.0f, 0.0f, 0.0f );
  203. vU.Base()[nMinorAxis] = 1.0f;
  204. float flDirAlong = vU.Dot( vNormal );
  205. vU -= flDirAlong * vNormal;
  206. vU.NormalizeInPlace();
  207. Vector vV( vNormal.Cross( vU ) );
  208. vV.NormalizeInPlace();
  209. double verts[2][64][3];
  210. verts[0][0][0] = vOrigin.x - vU.x * Q - vV.x * Q;
  211. verts[0][0][1] = vOrigin.y - vU.y * Q - vV.y * Q;
  212. verts[0][0][2] = vOrigin.z - vU.z * Q - vV.z * Q;
  213. verts[0][1][0] = vOrigin.x + vU.x * Q - vV.x * Q;
  214. verts[0][1][1] = vOrigin.y + vU.y * Q - vV.y * Q;
  215. verts[0][1][2] = vOrigin.z + vU.z * Q - vV.z * Q;
  216. verts[0][2][0] = vOrigin.x + vU.x * Q + vV.x * Q;
  217. verts[0][2][1] = vOrigin.y + vU.y * Q + vV.y * Q;
  218. verts[0][2][2] = vOrigin.z + vU.z * Q + vV.z * Q;
  219. verts[0][3][0] = vOrigin.x - vU.x * Q + vV.x * Q;
  220. verts[0][3][1] = vOrigin.y - vU.y * Q + vV.y * Q;
  221. verts[0][3][2] = vOrigin.z - vU.z * Q + vV.z * Q;
  222. uint nVerts = 4;
  223. double *pSrcVerts = &verts[0][0][0];
  224. double *pDstVerts = &verts[1][0][0];
  225. for ( uint nClipPlaneIndex = 0; nClipPlaneIndex < nLastPlane; ++nClipPlaneIndex )
  226. {
  227. if ( nPlaneIndex == nClipPlaneIndex )
  228. continue;
  229. Vector4D clipPlane( pPlanes[nClipPlaneIndex] );
  230. double vClipNormal[3] = { clipPlane.x, clipPlane.y, clipPlane.z };
  231. double flClipDist = -clipPlane.w;
  232. int nClipped = ClipPolyToPlane_Precise( pSrcVerts, nVerts, pDstVerts, vClipNormal, flClipDist, .000000125f );
  233. nVerts = nClipped;
  234. #if defined(_X360)
  235. _swap( pSrcVerts, pDstVerts );
  236. #else
  237. std::swap( pSrcVerts, pDstVerts );
  238. #endif
  239. if ( nVerts < 3 )
  240. break;
  241. }
  242. if ( nVerts >= 3 )
  243. {
  244. Vector vAvg( 0.0f, 0.0f, 0.0f );
  245. for ( uint i = 0; i < nVerts; ++i )
  246. {
  247. const uint j = ( i + 1 ) % nVerts;
  248. Vector s( pSrcVerts[i*3+0], pSrcVerts[i*3+1], pSrcVerts[i*3+2] );
  249. Vector e( pSrcVerts[j*3+0], pSrcVerts[j*3+1], pSrcVerts[j*3+2] );
  250. Add3DLineOverlay( s, e, color, zTest );
  251. vAvg += s;
  252. }
  253. vAvg /= nVerts;
  254. Vector2D vLo( 1e+10f, 1e+10f );
  255. Vector2D vHi( -1e+10f, -1e+10f );
  256. for ( uint i = 0; i < nVerts; ++i )
  257. {
  258. Vector p( pSrcVerts[i*3+0], pSrcVerts[i*3+1], pSrcVerts[i*3+2] );
  259. p -= vAvg;
  260. Vector2D p2D( p.Dot( vU ), p.Dot( vV ) );
  261. vLo = vLo.Min( p2D );
  262. vHi = vHi.Max( p2D );
  263. }
  264. float L = 75.0f;
  265. Add3DLineOverlay( vAvg, vAvg + vNormal * L, Vector( .1f, .1f, 1.0f ), true );
  266. Add3DLineOverlay( vAvg, vAvg + vU * L, Vector( 1.0f, .1f, .1f ), true );
  267. Add3DLineOverlay( vAvg, vAvg + vV * L, Vector( 0.1f, 1.0f, .1f ), true );
  268. float flXD = ( vHi.x - vLo.x ) / 24.0f;
  269. float flYD = ( vHi.y - vLo.y ) / 24.0f;
  270. for ( float flX = vLo.x; flX < vHi.x; flX += flXD )
  271. {
  272. for ( float flY = vLo.y; flY < vHi.y; flY += flYD )
  273. {
  274. Vector p( vAvg + vU * flX + vV * flY );
  275. uint i;
  276. for ( i = 0; i < nLastPlane; ++i )
  277. {
  278. if ( i == nPlaneIndex )
  279. continue;
  280. float flDist = pPlanes[i].x * p.x + pPlanes[i].y * p.y + pPlanes[i].z * p.z + pPlanes[i].w;
  281. if ( flDist < -.25f )
  282. break;
  283. }
  284. if ( i == nLastPlane )
  285. {
  286. Add3DLineOverlay( p, p + vNormal * 4.0f, Vector( .1f, .1f, 1.0f ), true );
  287. }
  288. }
  289. }
  290. }
  291. }
  292. }
  293. static void ScreenText( int x, int y, int r, int g, int b, int a, const char *text, ...)
  294. {
  295. char buf[256];
  296. va_list args;
  297. va_start( args, text );
  298. V_vsnprintf( buf, sizeof( buf ), text, args );
  299. va_end( args );
  300. const float flTextColWidth = 0.0044f; // 227
  301. const float flTextRowHeight = 0.0083f; // 120
  302. NDebugOverlay::ScreenText( x * flTextColWidth, y * flTextRowHeight, buf, r, g, b, a, NDEBUG_PERSIST_TILL_NEXT_SERVER );
  303. }
  304. CDebugPrimRenderer2D::CDebugPrimRenderer2D()
  305. {
  306. m_debugLines.EnsureCapacity( 128 );
  307. }
  308. void CDebugPrimRenderer2D::Clear()
  309. {
  310. m_debugLines.SetCount( 0 );
  311. }
  312. void CDebugPrimRenderer2D::AddNormalizedLine2D( float sx, float sy, float ex, float ey, uint r, uint g, uint b )
  313. {
  314. int nIndex = m_debugLines.AddToTail();
  315. m_debugLines[nIndex].m_EndPoints[0].Init( sx, sy );
  316. m_debugLines[nIndex].m_EndPoints[1].Init( ex, ey );
  317. m_debugLines[nIndex].m_nColor[0] = r;
  318. m_debugLines[nIndex].m_nColor[1] = g;
  319. m_debugLines[nIndex].m_nColor[2] = b;
  320. m_debugLines[nIndex].m_nColor[3] = 255;
  321. }
  322. void CDebugPrimRenderer2D::AddScreenspaceLine2D( float sx, float sy, float ex, float ey, uint r, uint g, uint b )
  323. {
  324. int nBackBufWidth, nBackBufHeight;
  325. materials->GetBackBufferDimensions( nBackBufWidth, nBackBufHeight );
  326. float flInvBackBufWidth = 1.0f / nBackBufWidth, flInvBackBufHeight = 1.0f / nBackBufHeight;
  327. int nIndex = m_debugLines.AddToTail();
  328. m_debugLines[nIndex].m_EndPoints[0].Init( sx * flInvBackBufWidth, sy * flInvBackBufHeight );
  329. m_debugLines[nIndex].m_EndPoints[1].Init( ex * flInvBackBufWidth, ey * flInvBackBufHeight );
  330. m_debugLines[nIndex].m_nColor[0] = r;
  331. m_debugLines[nIndex].m_nColor[1] = g;
  332. m_debugLines[nIndex].m_nColor[2] = b;
  333. m_debugLines[nIndex].m_nColor[3] = 255;
  334. }
  335. void CDebugPrimRenderer2D::AddScreenspaceRect2D( float sx, float sy, float ex, float ey, uint r, uint g, uint b )
  336. {
  337. AddScreenspaceLine2D( sx, sy, ex, sy, r, g, b );
  338. AddScreenspaceLine2D( ex, sy, ex, ey, r, g, b );
  339. AddScreenspaceLine2D( ex, ey, sx, ey, r, g, b );
  340. AddScreenspaceLine2D( sx, ey, sx, sy, r, g, b );
  341. }
  342. void CDebugPrimRenderer2D::AddScreenspaceLineList2D( uint nCount, const Vector2D *pVerts, const VertexColor_t &color )
  343. {
  344. int nBackBufWidth, nBackBufHeight;
  345. materials->GetBackBufferDimensions( nBackBufWidth, nBackBufHeight );
  346. float flInvBackBufWidth = 1.0f / nBackBufWidth, flInvBackBufHeight = 1.0f / nBackBufHeight;
  347. for ( uint i = 0; i < nCount; ++i )
  348. {
  349. int nIndex = m_debugLines.AddToTail();
  350. m_debugLines[nIndex].m_EndPoints[0].Init( pVerts[0].x * flInvBackBufWidth, pVerts[0].y * flInvBackBufHeight );
  351. m_debugLines[nIndex].m_EndPoints[1].Init( pVerts[1].x * flInvBackBufWidth, pVerts[1].y * flInvBackBufHeight );
  352. m_debugLines[nIndex].m_nColor[0] = color.r;
  353. m_debugLines[nIndex].m_nColor[1] = color.g;
  354. m_debugLines[nIndex].m_nColor[2] = color.b;
  355. m_debugLines[nIndex].m_nColor[3] = 255;
  356. pVerts += 2;
  357. }
  358. }
  359. void CDebugPrimRenderer2D::RenderScreenspaceDepthTexture( float sx, float sy, float ex, float ey, float su, float sv, float eu, float ev, CTextureReference &depthTex, float zLo, float zHi )
  360. {
  361. int nBackBufWidth, nBackBufHeight;
  362. materials->GetBackBufferDimensions( nBackBufWidth, nBackBufHeight );
  363. float flInvBackBufWidth = 1.0f / nBackBufWidth, flInvBackBufHeight = 1.0f / nBackBufHeight;
  364. sx *= flInvBackBufWidth;
  365. sy *= flInvBackBufHeight;
  366. ex *= flInvBackBufWidth;
  367. ey *= flInvBackBufHeight;
  368. const float xl = -1.0f;
  369. const float yl = 1.0f;
  370. const float xh = 1.0f;
  371. const float yh = -1.0f;
  372. IMaterial *pMaterial = materials->FindMaterial( "debug/debugshadowbuffer", TEXTURE_GROUP_OTHER, true );
  373. if ( !pMaterial )
  374. return;
  375. float flInvZRange = 1.0f / ( zHi - zLo );
  376. IMaterialVar *c0_x = pMaterial->FindVar( "$c0_x", NULL, false );
  377. c0_x->SetFloatValue( flInvZRange );
  378. IMaterialVar *c0_y = pMaterial->FindVar( "$c0_y", NULL, false );
  379. c0_y->SetFloatValue( -zLo * flInvZRange );
  380. IMaterialVar *c0_z = pMaterial->FindVar( "$c0_z", NULL, false );
  381. c0_z->SetFloatValue( 0.0f );
  382. bool bFound = false;
  383. IMaterialVar *pMatVar = pMaterial->FindVar( "$basetexture", &bFound, false );
  384. if ( bFound && pMatVar )
  385. {
  386. if ( pMatVar->GetTextureValue() != depthTex )
  387. {
  388. pMatVar->SetTextureValue( depthTex );
  389. }
  390. }
  391. CMatRenderContextPtr pRenderContext( materials );
  392. pRenderContext->Bind( pMaterial );
  393. IMesh* pMesh = pRenderContext->GetDynamicMesh( true );
  394. CMeshBuilder meshBuilder;
  395. meshBuilder.Begin( pMesh, MATERIAL_QUADS, 1 );
  396. meshBuilder.Position3f( Lerp( sx, xl, xh ), Lerp( sy, yl, yh ), 0.0f );
  397. meshBuilder.TexCoord2f( 0, su, sv );
  398. meshBuilder.Color4ub( 255, 255, 255, 255);
  399. meshBuilder.AdvanceVertex();
  400. meshBuilder.Position3f( Lerp( ex, xl, xh ), Lerp( sy, yl, yh ), 0.0f );
  401. meshBuilder.TexCoord2f( 0, eu, sv );
  402. meshBuilder.Color4ub( 255, 255, 255, 255);
  403. meshBuilder.AdvanceVertex();
  404. meshBuilder.Position3f( Lerp( ex, xl, xh ), Lerp( ey, yl, yh ), 0.0f );
  405. meshBuilder.TexCoord2f( 0, eu, ev );
  406. meshBuilder.Color4ub( 255, 255, 255, 255);
  407. meshBuilder.AdvanceVertex();
  408. meshBuilder.Position3f( Lerp( sx, xl, xh ), Lerp( ey, yl, yh ), 0.0f );
  409. meshBuilder.TexCoord2f( 0, su, ev );
  410. meshBuilder.Color4ub( 255, 255, 255, 255);
  411. meshBuilder.AdvanceVertex();
  412. meshBuilder.End();
  413. pMesh->Draw();
  414. }
  415. void CDebugPrimRenderer2D::Render2D( )
  416. {
  417. if ( m_debugLines.Count() )
  418. {
  419. RenderDebugLines2D( m_debugLines.Count(), &m_debugLines[0] );
  420. }
  421. }
  422. void CDebugPrimRenderer2D::RenderDebugLines2D( uint nNumLines, const CDebugLine *pLines )
  423. {
  424. if ( !nNumLines )
  425. return;
  426. const float xl = -1.0f;
  427. const float yl = 1.0f;
  428. const float xh = 1.0f;
  429. const float yh = -1.0f;
  430. IMaterial *pMaterial = materials->FindMaterial( "debug/debugscreenspacewireframe", TEXTURE_GROUP_OTHER, true );
  431. if ( !pMaterial )
  432. return;
  433. IMaterialVar *c0_x = pMaterial->FindVar( "$c0_x", NULL, false );
  434. c0_x->SetFloatValue( 1.0f );
  435. IMaterialVar *c0_y = pMaterial->FindVar( "$c0_y", NULL, false );
  436. c0_y->SetFloatValue( 1.0f );
  437. IMaterialVar *c0_z = pMaterial->FindVar( "$c0_z", NULL, false );
  438. c0_z->SetFloatValue( 1.0f );
  439. CMatRenderContextPtr pRenderContext( materials );
  440. pRenderContext->Bind( pMaterial );
  441. IMesh* pMesh = pRenderContext->GetDynamicMesh( true );
  442. CMeshBuilder meshBuilder;
  443. meshBuilder.Begin( pMesh, MATERIAL_LINES, nNumLines );
  444. for ( uint i = 0; i < nNumLines; ++i )
  445. {
  446. const CDebugLine &debugLine = pLines[i];
  447. meshBuilder.Position3f( Lerp( debugLine.m_EndPoints[0].x, xl, xh ), Lerp( debugLine.m_EndPoints[0].y, yl, yh ), 0.0f );
  448. meshBuilder.Color4ub( debugLine.m_nColor[0], debugLine.m_nColor[1], debugLine.m_nColor[2], 255 );
  449. meshBuilder.AdvanceVertex();
  450. meshBuilder.Position3f( Lerp( debugLine.m_EndPoints[1].x, xl, xh ), Lerp( debugLine.m_EndPoints[1].y, yl, yh ), 0.0f );
  451. meshBuilder.Color4ub( debugLine.m_nColor[0], debugLine.m_nColor[1], debugLine.m_nColor[2], 255 );
  452. meshBuilder.AdvanceVertex();
  453. }
  454. meshBuilder.End();
  455. pMesh->Draw();
  456. }
  457. void CDebugPrimRenderer2D::AddScreenspaceWireframeFrustum2D( const VMatrix &xform, const VertexColor_t &color, bool bShowAxes )
  458. {
  459. Vector2D points[ CCSMFrustumDefinition::NUM_FRUSTUM_LINES * 2 ];
  460. Vector2D *pDstPoint = points;
  461. for ( uint i = 0; i < CCSMFrustumDefinition::NUM_FRUSTUM_LINES; ++i )
  462. {
  463. Vector4D s, e;
  464. xform.V4Mul( CCSMFrustumDefinition::g_vProjFrustumVerts[ CCSMFrustumDefinition::g_nFrustumLineVertIndices[ i * 2 + 0 ] ], s );
  465. xform.V4Mul( CCSMFrustumDefinition::g_vProjFrustumVerts[ CCSMFrustumDefinition::g_nFrustumLineVertIndices[ i * 2 + 1 ] ], e );
  466. s *= ( 1.0f / s.w );
  467. e *= ( 1.0f / e.w );
  468. pDstPoint[0].Init( s.x, s.y );
  469. pDstPoint[1].Init( e.x, e.y );
  470. pDstPoint += 2;
  471. }
  472. AddScreenspaceLineList2D( CCSMFrustumDefinition::NUM_FRUSTUM_LINES, points, color );
  473. if ( bShowAxes )
  474. {
  475. Vector4D s, e;
  476. xform.V4Mul( Vector4D( 0.0f, 0.0f, 0.0f, 1.0f ), s );
  477. xform.V4Mul( Vector4D( 0.0f, 0.0f, 0.95f, 1.0f ), e );
  478. s *= ( 1.0f / s.w );
  479. e *= ( 1.0f / e.w );
  480. points[0].Init( s.x, s.y );
  481. points[1].Init( e.x, e.y );
  482. AddScreenspaceLineList2D( 1, points, VertexColor_t( 20, 20, 255, 255 ) );
  483. xform.V4Mul( Vector4D( 0.0f, 0.0f, 0.0f, 1.0f ), s );
  484. xform.V4Mul( Vector4D( 0.0f, 15.0f, 0.0f, 1.0f ), e );
  485. s *= ( 1.0f / s.w );
  486. e *= ( 1.0f / e.w );
  487. points[0].Init( s.x, s.y );
  488. points[1].Init( e.x, e.y );
  489. AddScreenspaceLineList2D( 1, points, VertexColor_t( 20, 255, 20, 255 ) );
  490. xform.V4Mul( Vector4D( 0.0f, 0.0f, 0.0f, 1.0f ), s );
  491. xform.V4Mul( Vector4D( 15.0f, 0.0f, 0.0f, 1.0f ), e );
  492. s *= ( 1.0f / s.w );
  493. e *= ( 1.0f / e.w );
  494. points[0].Init( s.x, s.y );
  495. points[1].Init( e.x, e.y );
  496. AddScreenspaceLineList2D( 1, points, VertexColor_t( 255, 20, 20, 255 ) );
  497. }
  498. }
  499. // TODO: Break CCascadeLightManager out to a separate file?
  500. #if defined( _X360 )
  501. #define CSM_DEFAULT_DEPTH_TEXTURE_RESOLUTION 704*2
  502. #elif defined( _PS3 )
  503. #define CSM_DEFAULT_DEPTH_TEXTURE_RESOLUTION 640*2
  504. #else
  505. // Important note: On PC, this depth texture resolution (or the inverse of it) is effectively hardcoded into the filter kernels sample offsets. Don't change it unless you fix this dependency.
  506. #define CSM_DEFAULT_DEPTH_TEXTURE_RESOLUTION 1024*2
  507. #define CSM_FALLBACK_DEPTH_TEXTURE_RESOLUTION 768*2
  508. #define CSM_FALLBACK2_DEPTH_TEXTURE_RESOLUTION 640*2
  509. #endif
  510. CCascadeLightManager::CCascadeLightManager() :
  511. m_bRenderTargetsAllocated( false ),
  512. m_nDepthTextureResolution( CSM_DEFAULT_DEPTH_TEXTURE_RESOLUTION ),
  513. m_bCSMIsActive( false ),
  514. m_bStateIsValid( false ),
  515. m_nCurRenderTargetQualityMode( CSMQUALITY_HIGH )
  516. {
  517. V_memset( &m_flRotX, 0, sizeof( m_flRotX ) );
  518. V_memset( &m_flRotY, 0, sizeof( m_flRotY ) );
  519. m_curState.m_CSMParallelSplit.Init( m_nDepthTextureResolution / 2, MAX_SUN_LIGHT_SHADOW_CASCADE_SIZE );
  520. m_curViewModelState.m_CSMParallelSplit.Init( m_nDepthTextureResolution / 2, MAX_SUN_LIGHT_SHADOW_CASCADE_SIZE );
  521. }
  522. CCascadeLightManager::~CCascadeLightManager()
  523. {
  524. }
  525. #ifdef OSX
  526. static ConVar mat_osx_force_csm_enabled( "mat_osx_force_csm_enabled", "0", FCVAR_RELEASE );
  527. static bool OSX_HardwareGoodEnoughForCSMs()
  528. {
  529. if ( IsPlatformOSX() )
  530. {
  531. // Historically, CS:GO did not have CSMs or multicore rendering on Mac. Both features are
  532. // available on Mac post the Sep 2014 Linux port integration, but multicore is not enough
  533. // to absorb the perf hit of CSMs on low end Macs. This function identifies the Macs on
  534. // which we do not want to enable CSMs, those that satisfy the following properties:
  535. // 1. lowend GPU identified in CShaderDeviceMgrBase::ReadHardwareCaps by setting
  536. // the convar mat_osx_csm_enabled to false;
  537. // 2. CPU has four or less logical processors (and less than 2.6GHz recorded clock speed)
  538. if ( mat_osx_force_csm_enabled.GetBool() )
  539. {
  540. return true;
  541. }
  542. bool bGoodEnough = true;
  543. // Check GPU
  544. static ConVarRef mat_osx_csm_enabled( "mat_osx_csm_enabled" );
  545. if ( !mat_osx_csm_enabled.GetBool() )
  546. {
  547. // GPU not good enough
  548. //printf("CSM: GPU matched string \"%s\", not good enough\n");
  549. bGoodEnough = false;
  550. }
  551. // Check CPU
  552. CPUInformation const& cpuInfo = GetCPUInformation();
  553. //printf( "CSM: CPU has %d logical processors\n", cpuInfo.m_nLogicalProcessors );
  554. if ( cpuInfo.m_nLogicalProcessors <= 4 )
  555. {
  556. // allow if clock speed is >= 2.6GHz, observing the list of Mac CPU's since Jan '08, this will now enable CSM's
  557. // on most Mac Pro's and iMacs (those that have the ability for GPU's to pass the test above, but would have been excluded due to logical processor count).
  558. if ( ( (double)cpuInfo.m_Speed / 1000000000.0 ) < 2.6 )
  559. {
  560. //printf("CSM: CPU cores not enough\n");
  561. bGoodEnough = false;
  562. }
  563. }
  564. return bGoodEnough;
  565. }
  566. else
  567. {
  568. // Platform other than OSX
  569. Assert( 0 );
  570. return true;
  571. }
  572. }
  573. #endif
  574. bool CCascadeLightManager::InitRenderTargets()
  575. {
  576. VPROF_BUDGET( "CCascadeLightManager::InitRenderTargets", VPROF_BUDGETGROUP_SHADOW_DEPTH_TEXTURING );
  577. CsmDbgMsg( "C_CascadeLight::InitRenderTargets\n" );
  578. if (
  579. #ifdef OSX
  580. !OSX_HardwareGoodEnoughForCSMs() ||
  581. #endif
  582. !cl_csm_enabled.GetBool() ||
  583. !g_pMaterialSystemHardwareConfig->SupportsCascadedShadowMapping() ||
  584. !g_pMaterialSystemHardwareConfig->SupportsShadowDepthTextures()
  585. )
  586. {
  587. DeinitRenderTargets();
  588. cl_csm_enabled.SetValue( 0 );
  589. return false;
  590. }
  591. if ( m_bRenderTargetsAllocated )
  592. return true;
  593. m_bRenderTargetsAllocated = true;
  594. ImageFormat dstFormat = g_pMaterialSystemHardwareConfig->GetShadowDepthTextureFormat(); // Vendor-dependent depth texture format
  595. #ifndef _X360
  596. ImageFormat nullFormat = g_pMaterialSystemHardwareConfig->GetNullTextureFormat(); // Vendor-dependent null texture format (takes as little memory as possible)
  597. #endif
  598. RenderTargetSizeMode_t sizeMode = RT_SIZE_OFFSCREEN;
  599. // Don't allow the shadow buffer render target's to get resized to always be <= the size of the backbuffer on the PC.
  600. // This allows us to use 1024x1024 or larger shadow depth buffers when 1024x768 backbuffers, for example.
  601. sizeMode = RT_SIZE_NO_CHANGE;
  602. m_nCurRenderTargetQualityMode = GetCSMQualityMode();
  603. if( !( IsGameConsole() ) )
  604. {
  605. m_nDepthTextureResolution = CSM_DEFAULT_DEPTH_TEXTURE_RESOLUTION;
  606. if ( GetCSMQualityMode() == CSMQUALITY_VERY_LOW )
  607. {
  608. m_nDepthTextureResolution = CSM_FALLBACK2_DEPTH_TEXTURE_RESOLUTION;
  609. }
  610. else if ( GetCSMQualityMode() == CSMQUALITY_LOW )
  611. {
  612. m_nDepthTextureResolution = CSM_FALLBACK_DEPTH_TEXTURE_RESOLUTION;
  613. }
  614. }
  615. m_curState.m_CSMParallelSplit.Init( m_nDepthTextureResolution / 2, MAX_SUN_LIGHT_SHADOW_CASCADE_SIZE );
  616. m_curViewModelState.m_CSMParallelSplit.Init( m_nDepthTextureResolution / 2, MAX_SUN_LIGHT_SHADOW_CASCADE_SIZE );
  617. materials->BeginRenderTargetAllocation();
  618. #if defined(_PS3)
  619. m_DummyColorTexture.InitRenderTarget( 8, 8, sizeMode, nullFormat,
  620. MATERIAL_RT_DEPTH_NONE, false, "_rt_CSMDummy" );
  621. m_ShadowDepthTexture.InitRenderTarget( m_nDepthTextureResolution, m_nDepthTextureResolution, sizeMode, dstFormat,
  622. MATERIAL_RT_DEPTH_NONE, false, "_rt_CSMShadowDepth" );
  623. #elif defined(_X360)
  624. // For the 360, we'll be rendering depth directly into the dummy depth and Resolve()ing to the depth texture.
  625. // only need the dummy surface, don't care about color results
  626. m_DummyColorTexture.InitRenderTargetTexture( m_nDepthTextureResolution/2, m_nDepthTextureResolution/2, RT_SIZE_OFFSCREEN, IMAGE_FORMAT_BGR565, //IMAGE_FORMAT_BGRA8888,
  627. MATERIAL_RT_DEPTH_SHARED, false, "_rt_CSMShadowDummy", CREATERENDERTARGETFLAGS_ALIASCOLORANDDEPTHSURFACES );
  628. m_DummyColorTexture.InitRenderTargetSurface( m_nDepthTextureResolution/2, m_nDepthTextureResolution/2, IMAGE_FORMAT_BGR565, false );
  629. m_ShadowDepthTexture.InitRenderTargetTexture( m_nDepthTextureResolution, m_nDepthTextureResolution, RT_SIZE_OFFSCREEN,
  630. dstFormat, MATERIAL_RT_DEPTH_NONE, false, "_rt_CSMShadowDepth" );
  631. m_ShadowDepthTexture.InitRenderTargetSurface( 1, 1, dstFormat, false );
  632. #else
  633. m_DummyColorTexture.InitRenderTarget( m_nDepthTextureResolution, m_nDepthTextureResolution, sizeMode, nullFormat,
  634. MATERIAL_RT_DEPTH_NONE, false, "_rt_CSMShadowDummy" );
  635. m_ShadowDepthTexture.InitRenderTarget( m_nDepthTextureResolution, m_nDepthTextureResolution, sizeMode, dstFormat,
  636. MATERIAL_RT_DEPTH_NONE, false, "_rt_CSMShadowDepth" );
  637. #endif
  638. materials->EndRenderTargetAllocation();
  639. if ( ( !m_DummyColorTexture.IsValid() ) && ( !m_ShadowDepthTexture.IsValid() ) )
  640. {
  641. DeinitRenderTargets();
  642. cl_csm_enabled.SetValue(0);
  643. return false;
  644. }
  645. V_memset( &m_flRotX, 0, sizeof( m_flRotX ) );
  646. V_memset( &m_flRotY, 0, sizeof( m_flRotY ) );
  647. return true;
  648. }
  649. void CCascadeLightManager::ShutdownRenderTargets()
  650. {
  651. // This purposely does NOT actually destroy the render targets here, to clone the (strange, but well tested?) behavior of the clientshadowmgr.cpp.
  652. // Not destroying the shadow buffers when baseclientrendertargets.cpp calls this method is beneficial when loading HDR maps, which triggers a recreation of the well known
  653. // render targets during level load.
  654. CsmDbgMsg( "C_CascadeLight::ShutdownRenderTargets\n" );
  655. }
  656. void CCascadeLightManager::LevelInitPreEntity()
  657. {
  658. CsmDbgMsg( "C_CascadeLight::LevelInitPreEntity\n" );
  659. }
  660. void CCascadeLightManager::LevelInitPostEntity()
  661. {
  662. CsmDbgMsg( "C_CascadeLight::LevelInitPostEntity\n" );
  663. }
  664. void CCascadeLightManager::LevelShutdownPreEntity()
  665. {
  666. CsmDbgMsg( "C_CascadeLight::LevelShutdownPreEntity\n" );
  667. }
  668. void CCascadeLightManager::LevelShutdownPostEntity()
  669. {
  670. CsmDbgMsg( "C_CascadeLight::LevelShutdownPostEntity\n" );
  671. }
  672. void CCascadeLightManager::Shutdown()
  673. {
  674. CsmDbgMsg( "C_CascadeLight::Shutdown\n" );
  675. DeinitRenderTargets();
  676. }
  677. void CCascadeLightManager::DeinitRenderTargets()
  678. {
  679. CsmDbgMsg( "C_CascadeLight::DeinitRenderTargets\n" );
  680. UnlockAllShadowDepthTextures();
  681. if ( m_bRenderTargetsAllocated )
  682. {
  683. m_DummyColorTexture.Shutdown();
  684. m_ShadowDepthTexture.Shutdown();
  685. m_bRenderTargetsAllocated = false;
  686. }
  687. }
  688. bool CCascadeLightManager::IsEnabled() const
  689. {
  690. if ( !C_CascadeLight::Get() || !C_CascadeLight::Get()->IsEnabled() || !cl_csm_enabled.GetBool() || !m_bRenderTargetsAllocated )
  691. return false;
  692. return true;
  693. }
  694. bool CCascadeLightManager::IsEnabledAndActive() const
  695. {
  696. return IsEnabled() && ( C_CascadeLight::Get() != NULL );
  697. }
  698. void CCascadeLightManager::Draw3DDebugInfo()
  699. {
  700. if ( !IsEnabled() )
  701. return;
  702. CFullCSMState &state = m_capturedState.m_CSMParallelSplit.IsValid() ? m_capturedState : m_curState;
  703. if ( !state.m_CSMParallelSplit.IsValid() )
  704. return;
  705. const bool zTest = cl_csm_debug_render_ztest.GetBool();
  706. const SunLightState_t &lightState = state.m_CSMParallelSplit.GetLightState();
  707. const CFrustum *pCascadeFrustums = lightState.m_CascadeFrustums; pCascadeFrustums;
  708. const ShadowFrustaDebugInfo_t *pDebugInfo = lightState.m_DebugInfo; pDebugInfo;
  709. //const SunLightShaderParamsCB_t &shadowParams = lightState.m_SunLightShaderParams;
  710. const VMatrix *pCascadeProjToTexMatrices = lightState.m_CascadeProjToTexMatrices; pCascadeProjToTexMatrices;
  711. const CFrustum &sceneFrustum = state.m_sceneFrustum;
  712. const VMatrix sceneWorldToView( sceneFrustum.GetView() );
  713. const VMatrix &sceneViewToProj = sceneFrustum.GetProj();
  714. const VMatrix sceneWorldToProj( sceneViewToProj * sceneWorldToView );
  715. VMatrix sceneProjToWorld;
  716. sceneWorldToProj.InverseGeneral( sceneProjToWorld );
  717. const Vector &vEye = sceneFrustum.GetCameraPosition();
  718. const Vector &vForward = sceneFrustum.CameraForward();
  719. const Vector &vLeft = sceneFrustum.CameraLeft();
  720. const Vector &vUp = sceneFrustum.CameraUp();
  721. const Vector vDirToLight( -state.m_shadowDir );
  722. COMPILE_TIME_ASSERT( 4 == MAX_SUN_LIGHT_SHADOW_CASCADE_SIZE );
  723. if ( cl_csm_debug_culling.GetBool() )
  724. {
  725. int s = 0, e = lightState.m_nShadowCascadeSize;
  726. if ( cl_csm_debug_culling_cascade.GetInt() >= 0 )
  727. {
  728. s = clamp<int, int, int>( cl_csm_debug_culling_cascade.GetInt(), 0, lightState.m_nShadowCascadeSize - 1 );
  729. e = s + 1;
  730. }
  731. for ( int i = s; i < e; ++i )
  732. {
  733. if ( lightState.m_CascadeVolumeCullers[i].HasBaseFrustum() )
  734. {
  735. VPlane basePlanes[CVolumeCuller::cNumBaseFrustumPlanes];
  736. lightState.m_CascadeVolumeCullers[i].GetBaseFrustumPlanes( basePlanes );
  737. int nPlaneCount = lightState.m_CascadeVolumeCullers[i].GetNumBaseFrustumPlanes();
  738. DebugRenderConvexPolyhedron( (Vector4D*)basePlanes, nPlaneCount, Vector( 1.0f, 1.0f, .2f ), true );
  739. }
  740. if ( lightState.m_CascadeVolumeCullers[i].HasInclusionVolume() )
  741. DebugRenderConvexPolyhedron( (Vector4D*)lightState.m_CascadeVolumeCullers[i].GetInclusionVolumePlanes(), lightState.m_CascadeVolumeCullers[i].GetNumInclusionVolumePlanes(), Vector( .3f, 1.0f, .3f ), true );
  742. if ( lightState.m_CascadeVolumeCullers[i].HasExclusionFrustum() )
  743. DebugRenderConvexPolyhedron( (Vector4D *)lightState.m_CascadeVolumeCullers[i].GetExclusionFrustumPlanes(), lightState.m_CascadeVolumeCullers[i].GetNumExclusionFrustumPlanes(), Vector( 1, .25f, .25f ), true );
  744. }
  745. return;
  746. }
  747. for ( uint nCascadeIndex = 0; nCascadeIndex < lightState.m_nShadowCascadeSize; ++nCascadeIndex )
  748. {
  749. const CFrustum &shadowFrustum = lightState.m_CascadeFrustums[ nCascadeIndex ];
  750. //const VMatrix &shadowWorldToView = shadowFrustum.GetView();
  751. //const VMatrix &shadowViewToProj = shadowFrustum.GetProj();
  752. VMatrix projToWorld( shadowFrustum.GetInvViewProj() );
  753. DebugRenderWireframeFrustum3D( projToWorld, g_vCascadeFrustumColors[nCascadeIndex], zTest );
  754. }
  755. Add3DLineOverlay( sceneFrustum.GetCameraPosition(), sceneFrustum.GetCameraPosition() + vDirToLight * 250.0f, Vector( 1, 1, 1 ), zTest );
  756. for ( uint nCascadeIndex = 0; nCascadeIndex <= lightState.m_nShadowCascadeSize; ++nCascadeIndex )
  757. {
  758. const VMatrix sceneWorldToView( sceneFrustum.GetView() );
  759. const VMatrix &sceneViewToProj = sceneFrustum.GetProj();
  760. VMatrix sceneProjToView;
  761. sceneViewToProj.InverseGeneral( sceneProjToView );
  762. VMatrix sceneViewToWorld;
  763. sceneWorldToView.InverseGeneral( sceneViewToWorld );
  764. Vector v[8];
  765. for ( uint z = 0; z < 2; ++z )
  766. {
  767. const float flZ = z ? 1.0f : 0.0f;
  768. for ( uint i = 0; i < 4; ++i )
  769. {
  770. Vector vViewspacePoint;
  771. sceneProjToView.V3Mul( Vector( CCSMFrustumDefinition::g_vProjFrustumVerts[i].x, CCSMFrustumDefinition::g_vProjFrustumVerts[i].y, flZ ), vViewspacePoint );
  772. // Scale the vector so its Z is -1.0f (negative viewspace Z is inside the frustum due to RH proj matrices)
  773. if ( ( z ) && ( nCascadeIndex < lightState.m_nShadowCascadeSize ) )
  774. {
  775. float flOneOverZ = 1.0f / vViewspacePoint.z;
  776. vViewspacePoint *= flOneOverZ;
  777. vViewspacePoint.z *= -1.0f;
  778. vViewspacePoint *= lightState.m_DebugInfo[nCascadeIndex].m_flSplitPlaneDistance;
  779. }
  780. else if ( ( !z ) && ( nCascadeIndex ) )
  781. {
  782. float flOneOverZ = 1.0f / vViewspacePoint.z;
  783. vViewspacePoint *= flOneOverZ;
  784. vViewspacePoint.z *= -1.0f;
  785. vViewspacePoint *= lightState.m_DebugInfo[nCascadeIndex - 1].m_flSplitPlaneDistance;
  786. }
  787. else
  788. {
  789. // flip xy to be consistent with the other cases
  790. vViewspacePoint.x *= -1.0f;
  791. vViewspacePoint.y *= -1.0f;
  792. }
  793. sceneViewToWorld.V3Mul( vViewspacePoint, v[i + z * 4] );
  794. }
  795. }
  796. if ( !nCascadeIndex )
  797. {
  798. Add3DLineOverlay( v[0], v[1], g_vCascadeFrustumColors[nCascadeIndex], zTest );
  799. Add3DLineOverlay( v[1], v[2], g_vCascadeFrustumColors[nCascadeIndex], zTest );
  800. Add3DLineOverlay( v[2], v[3], g_vCascadeFrustumColors[nCascadeIndex], zTest );
  801. Add3DLineOverlay( v[3], v[0], g_vCascadeFrustumColors[nCascadeIndex], zTest );
  802. }
  803. Add3DLineOverlay( v[4], v[5], g_vCascadeFrustumColors[nCascadeIndex], zTest );
  804. Add3DLineOverlay( v[5], v[6], g_vCascadeFrustumColors[nCascadeIndex], zTest );
  805. Add3DLineOverlay( v[6], v[7], g_vCascadeFrustumColors[nCascadeIndex], zTest );
  806. Add3DLineOverlay( v[7], v[4], g_vCascadeFrustumColors[nCascadeIndex], zTest );
  807. Add3DLineOverlay( v[0], v[4], g_vCascadeFrustumColors[nCascadeIndex], zTest );
  808. Add3DLineOverlay( v[1], v[5], g_vCascadeFrustumColors[nCascadeIndex], zTest );
  809. Add3DLineOverlay( v[2], v[6], g_vCascadeFrustumColors[nCascadeIndex], zTest );
  810. Add3DLineOverlay( v[3], v[7], g_vCascadeFrustumColors[nCascadeIndex], zTest );
  811. }
  812. Vector vFadeStart( vEye + vForward * lightState.m_flZLerpStartDist );
  813. Vector vFadeEnd( vEye + vForward * lightState.m_flZLerpEndDist );
  814. for ( uint y = 0; y < 8; y++ )
  815. {
  816. Add3DLineOverlay(
  817. vFadeStart + vLeft * -300.0f + vUp * Lerp( y / 7.0f, -1.0f, 1.0f ) * 300.0f,
  818. vFadeStart + vLeft * 300.0f + vUp * Lerp( y / 7.0f, -1.0f, 1.0f ) * 300.0f,
  819. Vector( .1f, 0.0f, 1.0f ), true );
  820. }
  821. for ( uint y = 0; y < 8; y++ )
  822. {
  823. Add3DLineOverlay(
  824. vFadeStart + vUp * -300.0f + vLeft * Lerp( y / 7.0f, -1.0f, 1.0f ) * 300.0f,
  825. vFadeStart + vUp * 300.0f + vLeft * Lerp( y / 7.0f, -1.0f, 1.0f ) * 300.0f,
  826. Vector( .1f, 0.0f, 1.0f ), true );
  827. }
  828. for ( uint y = 0; y < 8; y++ )
  829. {
  830. Add3DLineOverlay(
  831. vFadeEnd + vLeft * -300.0f + vUp * Lerp( y / 7.0f, -1.0f, 1.0f ) * 300.0f,
  832. vFadeEnd + vLeft * 300.0f + vUp * Lerp( y / 7.0f, -1.0f, 1.0f ) * 300.0f,
  833. Vector( .1f, 0.5f, 1.0f ), true );
  834. }
  835. for ( uint y = 0; y < 8; y++ )
  836. {
  837. Add3DLineOverlay(
  838. vFadeEnd + vUp * -300.0f + vLeft * Lerp( y / 7.0f, -1.0f, 1.0f ) * 300.0f,
  839. vFadeEnd + vUp * 300.0f + vLeft * Lerp( y / 7.0f, -1.0f, 1.0f ) * 300.0f,
  840. Vector( .1f, 0.5f, 1.0f ), true );
  841. }
  842. //DebugRenderWireframeFrustum3D( sceneFrustum.GetInvViewProj(), Vector( .4f, .4f, .8f ), zTest );
  843. }
  844. void CCascadeLightManager::Draw2DDebugInfo()
  845. {
  846. if ( !IsEnabled() )
  847. return;
  848. CFullCSMState &state = m_capturedState.m_CSMParallelSplit.IsValid() ? m_capturedState : m_curState;
  849. if ( !state.m_CSMParallelSplit.IsValid() )
  850. return;
  851. const SunLightState_t &lightState = state.m_CSMParallelSplit.GetLightState();
  852. const CFrustum *pCascadeFrustums = lightState.m_CascadeFrustums;
  853. const ShadowFrustaDebugInfo_t *pDebugInfo = lightState.m_DebugInfo;
  854. //const SunLightShaderParamsCB_t &shadowParams = lightState.m_SunLightShaderParams;
  855. const VMatrix *pCascadeProjToTexMatrices = lightState.m_CascadeProjToTexMatrices;
  856. const CFrustum &sceneFrustum = state.m_sceneFrustum;
  857. const VMatrix sceneWorldToView( sceneFrustum.GetView() );
  858. const VMatrix &sceneViewToProj = sceneFrustum.GetProj();
  859. const VMatrix sceneWorldToProj( sceneViewToProj * sceneWorldToView );
  860. VMatrix sceneProjToWorld;
  861. sceneWorldToProj.InverseGeneral( sceneProjToWorld );
  862. m_debugPrimRenderer.Clear();
  863. int nFirstCascadeIndex = 0;
  864. int nLastCascadeIndex = (int)lightState.m_nShadowCascadeSize - 1;
  865. #if defined( _GAMECONSOLE )
  866. const int nShadowBufferDebugVisWidth = 256;
  867. const int nShadowBufferDebugVisHeight = 256;
  868. #else
  869. const int nShadowBufferDebugVisWidth = 512;
  870. const int nShadowBufferDebugVisHeight = 512;
  871. #endif
  872. for ( int nCascadeIndex = nFirstCascadeIndex; nCascadeIndex <= nLastCascadeIndex; ++nCascadeIndex )
  873. {
  874. const Rect_t &cascadeViewport = lightState.m_CascadeViewports[nCascadeIndex];
  875. int nPlacementX = nCascadeIndex & 1;
  876. int nPlacementY = nCascadeIndex >> 1;
  877. Rect_t destRect;
  878. #if defined( _GAMECONSOLE )
  879. destRect.x = 64 + ( nShadowBufferDebugVisWidth + 75 ) * nPlacementX;
  880. destRect.y = 64 + ( nShadowBufferDebugVisHeight + 75 ) * nPlacementY;
  881. #else
  882. destRect.x = 16 + ( nShadowBufferDebugVisWidth + 75 ) * nPlacementX;
  883. destRect.y = 16 + ( nShadowBufferDebugVisHeight + 75 ) * nPlacementY;
  884. #endif
  885. destRect.width = nShadowBufferDebugVisWidth;
  886. destRect.height = nShadowBufferDebugVisHeight;
  887. VertexColor_t color( g_vCascadeFrustumColors[nCascadeIndex].x * 255, g_vCascadeFrustumColors[nCascadeIndex].y * 255, g_vCascadeFrustumColors[nCascadeIndex].z * 255, 255 );
  888. m_debugPrimRenderer.AddScreenspaceRect2D( destRect.x, destRect.y, destRect.x + destRect.width, destRect.y + destRect.height, color.r, color.g, color.b );
  889. m_debugPrimRenderer.RenderScreenspaceDepthTexture(
  890. destRect.x, destRect.y, destRect.x + destRect.width, destRect.y + destRect.height,
  891. (float)cascadeViewport.x / m_nDepthTextureResolution,
  892. (float)cascadeViewport.y / m_nDepthTextureResolution,
  893. (float)( cascadeViewport.x + cascadeViewport.width ) / m_nDepthTextureResolution,
  894. (float)( cascadeViewport.y + cascadeViewport.height ) / m_nDepthTextureResolution,
  895. m_ShadowDepthTexture, cl_csm_debug_vis_lo_range.GetFloat(), cl_csm_debug_vis_hi_range.GetFloat() );
  896. const CFrustum &shadowFrustum = pCascadeFrustums[ nCascadeIndex ];
  897. const VMatrix shadowWorldToView( shadowFrustum.GetView() );
  898. const VMatrix &shadowViewToProj = shadowFrustum.GetProj();
  899. const VMatrix shadowWorldToProj( shadowViewToProj * shadowWorldToView );
  900. const VMatrix shadowProjToTex( pCascadeProjToTexMatrices[nCascadeIndex] );
  901. const VMatrix sceneProjToTex( shadowProjToTex * ( shadowWorldToProj * sceneProjToWorld ) );
  902. VMatrix shadowTexToRect(
  903. destRect.width, 0.0f, 0.0f, destRect.x,
  904. 0.0f, destRect.height, 0.0f, destRect.y,
  905. 0.0f, 0.0f, 0.0f, .5f,
  906. 0.0f, 0.0f, 0.0f, 1.0f );
  907. const VMatrix sceneProjToRect( shadowTexToRect * sceneProjToTex );
  908. m_debugPrimRenderer.AddScreenspaceWireframeFrustum2D( sceneProjToRect, color, true );
  909. if ( m_capturedState.m_CSMParallelSplit.IsValid() )
  910. {
  911. CFullCSMState &actualState = m_curState;
  912. const CFrustum &actualSceneFrustum = actualState.m_sceneFrustum;
  913. const VMatrix actualSceneWorldToView( actualSceneFrustum.GetView() );
  914. const VMatrix &actualSceneViewToProj = actualSceneFrustum.GetProj();
  915. const VMatrix actualSceneWorldToProj( actualSceneViewToProj * actualSceneWorldToView );
  916. VMatrix actualSceneProjToWorld;
  917. actualSceneWorldToProj.InverseGeneral( actualSceneProjToWorld );
  918. const VMatrix actualSceneProjToTex( shadowProjToTex * ( shadowWorldToProj * actualSceneProjToWorld ) );
  919. const VMatrix actualSceneProjToRect( shadowTexToRect * actualSceneProjToTex );
  920. VertexColor_t actualFrustumColor( 0, 255, 0, 255 );
  921. m_debugPrimRenderer.AddScreenspaceWireframeFrustum2D( actualSceneProjToRect, actualFrustumColor, true );
  922. }
  923. VMatrix shadowWorldToRect( shadowTexToRect * ( shadowProjToTex * shadowWorldToProj ) );
  924. for ( uint i = 0; i < pDebugInfo[nCascadeIndex].m_nNumWorldFocusVerts; ++i )
  925. {
  926. const Vector &v = pDebugInfo[nCascadeIndex].m_WorldFocusVerts[i];
  927. Vector4D worldVert( v.x, v.y, v.z, 1.0f );
  928. Vector4D rectVert;
  929. shadowWorldToRect.V4Mul( worldVert, rectVert );
  930. rectVert *= ( 1.0f / rectVert.w );
  931. Vector2D points[4];
  932. points[0].Init( rectVert.x - 5, rectVert.y );
  933. points[1].Init( rectVert.x + 5, rectVert.y );
  934. points[2].Init( rectVert.x, rectVert.y - 5 );
  935. points[3].Init( rectVert.x, rectVert.y + 5);
  936. m_debugPrimRenderer.AddScreenspaceLineList2D( 2, points, VertexColor_t( 20, 255, 20, 255 ) );
  937. }
  938. for ( int nPrevSplitIndex = 0; nPrevSplitIndex < nCascadeIndex; ++nPrevSplitIndex )
  939. {
  940. const CFrustum &prevShadowFrustum = pCascadeFrustums[ nPrevSplitIndex ];
  941. const VMatrix prevShadowWorldToView( prevShadowFrustum.GetView() );
  942. const VMatrix &prevShadowViewToProj = prevShadowFrustum.GetProj();
  943. const VMatrix prevShadowWorldToProj( prevShadowViewToProj * prevShadowWorldToView );
  944. VMatrix prevShadowProjToWorld;
  945. prevShadowWorldToProj.InverseGeneral( prevShadowProjToWorld );
  946. const VMatrix prevShadowProjToShadowRect( shadowTexToRect * ( shadowProjToTex * ( shadowWorldToProj * prevShadowProjToWorld ) ) );
  947. VertexColor_t prevSplitColor( g_vCascadeFrustumColors[nPrevSplitIndex].x * 255, g_vCascadeFrustumColors[nPrevSplitIndex].y * 255, g_vCascadeFrustumColors[nPrevSplitIndex].z * 255, 255 );
  948. m_debugPrimRenderer.AddScreenspaceWireframeFrustum2D( prevShadowProjToShadowRect, prevSplitColor, false );
  949. }
  950. }
  951. m_debugPrimRenderer.Render2D();
  952. }
  953. void CCascadeLightManager::DrawTextDebugInfo()
  954. {
  955. CFullCSMState &curState = GetActiveState();
  956. uint cur_y = 105;
  957. ScreenText( 5, cur_y, 255, 95, 95, 255, "Active State: %s Pos:(%3.3f, %3.3f, %3.3f), Forward:(%3.3f, %3.3f, %3.3f), Left:(%3.3f, %3.3f, %3.3f), Up:(%3.3f, %3.3f, %3.3f)",
  958. m_capturedState.m_CSMParallelSplit.IsValid() ? "CAP" : "CUR",
  959. curState.m_sceneFrustum.GetCameraPosition().x, curState.m_sceneFrustum.GetCameraPosition().y, curState.m_sceneFrustum.GetCameraPosition().z,
  960. curState.m_sceneFrustum.CameraForward().x, curState.m_sceneFrustum.CameraForward().y, curState.m_sceneFrustum.CameraForward().z,
  961. curState.m_sceneFrustum.CameraLeft().x, curState.m_sceneFrustum.CameraLeft().y, curState.m_sceneFrustum.CameraLeft().z,
  962. curState.m_sceneFrustum.CameraUp().x, curState.m_sceneFrustum.CameraUp().y, curState.m_sceneFrustum.CameraUp().z );
  963. cur_y += 2;
  964. if ( GetClientWorldEntity() )
  965. {
  966. const Vector &worldMins = GetClientWorldEntity()->m_WorldMins;
  967. const Vector &worldMaxs = GetClientWorldEntity()->m_WorldMaxs;
  968. ScreenText( 5, cur_y, 255, 95, 95, 255, "World Bounds: (%f,%f,%f) - (%f,%f,%f)",
  969. worldMins.x, worldMins.y, worldMins.z,
  970. worldMaxs.x, worldMaxs.y, worldMaxs.z );
  971. cur_y += 2;
  972. }
  973. uint m_nTotalAABB = 0;
  974. uint m_nTotalAABBPassed = 0;
  975. uint m_nTotalCenterHalfDiagonal = 0;
  976. uint m_nTotalCenterHalfDiagonalPassed = 0;
  977. uint i;
  978. for ( i = 0; i < 4; i++ )
  979. {
  980. CVolumeCuller &cascadeVolumeCuller = (i == 3) ? m_curViewModelState.m_CSMParallelSplit.GetLightState().m_CascadeVolumeCullers[0] : curState.m_CSMParallelSplit.GetLightState().m_CascadeVolumeCullers[i];
  981. CVolumeCuller::CullCheckStats_t &cullStats = cascadeVolumeCuller.GetStats();
  982. ScreenText( 5, cur_y, 255, 95, 95, 255, "Cascade %u: Total AABB Cull Checks: %u, Passed: %u, Total World AABB Cull Checks: %u, Passed: %u",
  983. i,
  984. cullStats.m_nTotalAABB, cullStats.m_nTotalAABBPassed,
  985. cullStats.m_nTotalCenterHalfDiagonal, cullStats.m_nTotalCenterHalfDiagonalPassed );
  986. cur_y += 2;
  987. m_nTotalAABB += cullStats.m_nTotalAABB;
  988. m_nTotalAABBPassed += cullStats.m_nTotalAABBPassed;
  989. m_nTotalCenterHalfDiagonal += cullStats.m_nTotalCenterHalfDiagonal;
  990. m_nTotalCenterHalfDiagonalPassed += cullStats.m_nTotalCenterHalfDiagonalPassed;
  991. cascadeVolumeCuller.ClearCullCheckStats();
  992. }
  993. ScreenText( 5, cur_y, 255, 95, 95, 255, "All Cascades: Total AABB Cull Checks: %u, Passed: %u, Total World AABB Cull Checks: %u, Passed: %u",
  994. m_nTotalAABB, m_nTotalAABBPassed,
  995. m_nTotalCenterHalfDiagonal, m_nTotalCenterHalfDiagonalPassed );
  996. cur_y += 2;
  997. }
  998. void CCascadeLightManager::CFullCSMState::Update( const CViewSetup &viewSetup, const Vector &shadowDir, color32 lightColor, int lightColorScale, float flMaxShadowDist, float flMaxVisibleDist, uint nMaxCascadeSize, uint nAtlasFirstCascadeIndex, int nCSMQualityLevel, bool bSetAllCascadesToFirst )
  999. {
  1000. m_shadowDir = shadowDir;
  1001. m_flMaxShadowDist = flMaxShadowDist;
  1002. m_flMaxVisibleDist = flMaxVisibleDist;
  1003. m_nMaxCascadeSize = nMaxCascadeSize;
  1004. m_flSceneAspectRatio = viewSetup.ComputeViewMatrices( &m_sceneWorldToView, &m_sceneViewToProj, &m_sceneWorldToProj );
  1005. m_sceneFrustum.BuildFrustumFromParameters( viewSetup.origin, viewSetup.angles, viewSetup.zNear, viewSetup.zFar, viewSetup.fov, m_flSceneAspectRatio, m_sceneWorldToView, m_sceneViewToProj );
  1006. SunLightViewState_t sunLightViewState;
  1007. sunLightViewState.m_Direction = shadowDir;
  1008. sunLightViewState.m_LightColor = lightColor;
  1009. sunLightViewState.m_LightColorScale = lightColorScale;
  1010. sunLightViewState.m_flMaxShadowDist = flMaxShadowDist;
  1011. sunLightViewState.m_flMaxVisibleDist = flMaxVisibleDist;
  1012. sunLightViewState.m_frustum = m_sceneFrustum;
  1013. sunLightViewState.m_nMaxCascadeSize = nMaxCascadeSize;
  1014. sunLightViewState.m_nAtlasFirstCascadeIndex = nAtlasFirstCascadeIndex;
  1015. sunLightViewState.m_nCSMQualityLevel = nCSMQualityLevel;
  1016. sunLightViewState.m_bSetAllCascadesToFirst = bSetAllCascadesToFirst;
  1017. m_CSMParallelSplit.Update( sunLightViewState );
  1018. m_bValid = ( m_CSMParallelSplit.GetLightState().m_nShadowCascadeSize != 0 );
  1019. }
  1020. void CCascadeLightManager::RenderViews( CCascadeLightManager::CFullCSMState &state, bool bIncludeViewModels )
  1021. {
  1022. SunLightState_t &lightState = state.m_CSMParallelSplit.GetLightState();
  1023. #if 0
  1024. VMatrix computedWorldToView;
  1025. VMatrix computedViewToProj;
  1026. VMatrix computedWorldToProj;
  1027. #endif
  1028. uint nCascadeIndex = 0;
  1029. if( IsGameConsole() )
  1030. {
  1031. // don't use cascade 0 for console. TODO - at some point we should make better use of texture space, right now we waste 25%
  1032. nCascadeIndex = bIncludeViewModels ? 0 : 1;
  1033. }
  1034. else
  1035. {
  1036. if ( ( !bIncludeViewModels ) && ( GetCSMQualityMode() <= CSMQUALITY_LOW ) )
  1037. nCascadeIndex = 1;
  1038. }
  1039. CMatRenderContextPtr pRenderContext( materials );
  1040. for ( ; nCascadeIndex < lightState.m_nShadowCascadeSize; ++nCascadeIndex )
  1041. {
  1042. CViewSetup shadowView;
  1043. shadowView.m_flAspectRatio = 1.0f;
  1044. shadowView.x = lightState.m_CascadeViewports[nCascadeIndex].x;
  1045. shadowView.y = lightState.m_CascadeViewports[nCascadeIndex].y;
  1046. shadowView.width = lightState.m_CascadeViewports[nCascadeIndex].width;
  1047. shadowView.height = lightState.m_CascadeViewports[nCascadeIndex].height;
  1048. shadowView.m_bRenderToSubrectOfLargerScreen = true;
  1049. #if defined(_X360)
  1050. // render into top left viewport
  1051. // resolve to appropriate quadrant of final texture
  1052. shadowView.xCsmDstOffset = shadowView.x;
  1053. shadowView.yCsmDstOffset = shadowView.y;
  1054. shadowView.x = 0;
  1055. shadowView.y = 0;
  1056. #endif
  1057. const CFrustum &cascadeFrustum = lightState.m_CascadeFrustums[nCascadeIndex];
  1058. // Force custom matrices, to avoid FP precision issues causing shadow continuity problems. (We need precise control over the matrices used for rendering.)
  1059. if ( cl_csm_use_forced_view_matrices.GetBool() )
  1060. {
  1061. shadowView.m_bCustomViewMatrix = true;
  1062. // Argh - m_matCustomViewMatrix is actually a custom world->camera matrix, not world->view!
  1063. // The view->camera matrix only has 0,-1,1 values so it shouldn't affect precision.
  1064. shadowView.m_matCustomViewMatrix = ( g_matViewToCameraMatrix * VMatrix( cascadeFrustum.GetView() ) ).As3x4();
  1065. shadowView.m_bCustomProjMatrix = true;
  1066. shadowView.m_matCustomProjMatrix = cascadeFrustum.GetProj();
  1067. }
  1068. cascadeFrustum.GetClipSpaceBounds( shadowView.m_OrthoLeft, shadowView.m_OrthoBottom, shadowView.m_OrthoRight, shadowView.m_OrthoTop );
  1069. shadowView.origin = cascadeFrustum.GetCameraPosition();
  1070. shadowView.angles = cascadeFrustum.GetCameraAngles();
  1071. shadowView.zNear = shadowView.zNearViewmodel = cascadeFrustum.GetCameraNearPlane();
  1072. shadowView.zFar = shadowView.zFarViewmodel = cascadeFrustum.GetCameraFarPlane();
  1073. if ( cl_csm_debug_2d.GetBool() && cl_csm_use_forced_view_matrices.GetBool() && cl_csm_hack_proj_matrices_for_cull_debugging.GetBool() )
  1074. {
  1075. MatrixBuildOrtho(
  1076. shadowView.m_matCustomProjMatrix,
  1077. Lerp( -2.0f, shadowView.m_OrthoLeft, shadowView.m_OrthoRight ),
  1078. Lerp( -2.0f, shadowView.m_OrthoTop, shadowView.m_OrthoBottom ),
  1079. Lerp( -2.0f, shadowView.m_OrthoRight, shadowView.m_OrthoLeft ),
  1080. Lerp( -2.0f, shadowView.m_OrthoBottom, shadowView.m_OrthoTop ),
  1081. shadowView.zNear,
  1082. shadowView.zFar );
  1083. }
  1084. shadowView.m_bDoBloomAndToneMapping = false;
  1085. shadowView.m_nMotionBlurMode = MOTION_BLUR_DISABLE;
  1086. // Set depth bias factors specific to this cascade
  1087. #if 0
  1088. float flShadowSlopeScaleDepthBias = g_pMaterialSystemHardwareConfig->GetShadowSlopeScaleDepthBias();
  1089. float flShadowDepthBias = g_pMaterialSystemHardwareConfig->GetShadowDepthBias();
  1090. #else
  1091. static ConVar *s_csm_slopescales[4] = { &cl_csm_slopescaledepthbias_c0, &cl_csm_slopescaledepthbias_c1, &cl_csm_slopescaledepthbias_c2, &cl_csm_slopescaledepthbias_c3 };
  1092. static ConVar *s_csm_depthbias[4] = { &cl_csm_depthbias_c0, &cl_csm_depthbias_c1, &cl_csm_depthbias_c2, &cl_csm_depthbias_c3 };
  1093. float flShadowSlopeScaleDepthBias = s_csm_slopescales[nCascadeIndex]->GetFloat();
  1094. float flShadowDepthBias = s_csm_depthbias[nCascadeIndex]->GetFloat();
  1095. if ( bIncludeViewModels )
  1096. {
  1097. flShadowSlopeScaleDepthBias = cl_csm_viewmodel_slopescaledepthbias.GetFloat();
  1098. flShadowDepthBias = cl_csm_viewmodel_depthbias.GetFloat();
  1099. }
  1100. #endif
  1101. pRenderContext->PerpareForCascadeDraw( nCascadeIndex, flShadowSlopeScaleDepthBias, flShadowDepthBias );
  1102. pRenderContext->SetShadowDepthBiasFactors( flShadowSlopeScaleDepthBias, flShadowDepthBias );
  1103. pRenderContext->CullMode( MATERIAL_CULLMODE_NONE );
  1104. shadowView.m_bOrtho = true;
  1105. shadowView.m_bCSMView = true;
  1106. CVolumeCuller &volumeCuller = lightState.m_CascadeVolumeCullers[nCascadeIndex];
  1107. if ( ( nCascadeIndex == ( lightState.m_nShadowCascadeSize - 1 ) ) && ( GetCSMQualityMode() <= CSMQUALITY_LOW ) )
  1108. {
  1109. volumeCuller.SetCullSmallObjects( true, cl_csm_cull_small_prop_threshold_volume.GetFloat() );
  1110. }
  1111. else
  1112. {
  1113. volumeCuller.SetCullSmallObjects( false, 1e+10f );
  1114. }
  1115. shadowView.m_pCSMVolumeCuller = &volumeCuller;
  1116. #if 0
  1117. // Purely for debugging.
  1118. shadowView.m_bCustomViewMatrix = false;
  1119. shadowView.m_bCustomProjMatrix = false;
  1120. shadowView.ComputeViewMatrices( &computedWorldToView, &computedViewToProj, &computedWorldToProj );
  1121. if ( cl_csm_use_forced_view_matrices.GetBool() )
  1122. {
  1123. shadowView.m_bCustomViewMatrix = true;
  1124. shadowView.m_bCustomProjMatrix = true;
  1125. }
  1126. Vector currentViewForward, currentViewRight, currentViewUp;
  1127. AngleVectors( shadowView.angles, &currentViewForward, &currentViewRight, &currentViewUp );
  1128. // Now compute the culling planes the same way as CRender::OrthoExtractFrustumPlanes() does, so they can be manually
  1129. // compared against the planes the CSM manager computed. The game makes several assumptions about view and ortho projection space.
  1130. VPlane frustumPlanes[6];
  1131. float orgOffset = DotProduct(shadowView.origin, currentViewForward);
  1132. frustumPlanes[FRUSTUM_FARZ].m_Normal = -currentViewForward;
  1133. frustumPlanes[FRUSTUM_FARZ].m_Dist = -shadowView.zFar - orgOffset;
  1134. frustumPlanes[FRUSTUM_NEARZ].m_Normal = currentViewForward;
  1135. frustumPlanes[FRUSTUM_NEARZ].m_Dist = shadowView.zNear + orgOffset;
  1136. orgOffset = DotProduct(shadowView.origin, currentViewRight);
  1137. frustumPlanes[FRUSTUM_LEFT].m_Normal = currentViewRight;
  1138. frustumPlanes[FRUSTUM_LEFT].m_Dist = shadowView.m_OrthoLeft + orgOffset;
  1139. frustumPlanes[FRUSTUM_RIGHT].m_Normal = -currentViewRight;
  1140. frustumPlanes[FRUSTUM_RIGHT].m_Dist = -shadowView.m_OrthoRight - orgOffset;
  1141. orgOffset = DotProduct(shadowView.origin, currentViewUp);
  1142. frustumPlanes[FRUSTUM_TOP].m_Normal = currentViewUp;
  1143. frustumPlanes[FRUSTUM_TOP].m_Dist = shadowView.m_OrthoTop + orgOffset;
  1144. frustumPlanes[FRUSTUM_BOTTOM].m_Normal = -currentViewUp;
  1145. frustumPlanes[FRUSTUM_BOTTOM].m_Dist = -shadowView.m_OrthoBottom - orgOffset;
  1146. #endif
  1147. // Render to the shadow depth texture with appropriate view
  1148. view->UpdateShadowDepthTexture( m_DummyColorTexture, m_ShadowDepthTexture, shadowView, true, bIncludeViewModels );
  1149. }
  1150. pRenderContext->CullMode( MATERIAL_CULLMODE_CCW );
  1151. }
  1152. void CCascadeLightManager::PreRender()
  1153. {
  1154. }
  1155. Vector CCascadeLightManager::GetShadowDirection()
  1156. {
  1157. Vector vShadowDir( C_CascadeLight::Get()->GetShadowDirection() );
  1158. if ( ( cl_csm_use_env_light_direction.GetBool() ) && ( C_CascadeLight::Get()->UseLightEnvAngles() ) && ( C_CascadeLight::Get()->GetEnvLightShadowDirection().Length() > .5f ) )
  1159. {
  1160. vShadowDir = C_CascadeLight::Get()->GetEnvLightShadowDirection();
  1161. }
  1162. if ( cl_csm_rot_override.GetBool() )
  1163. {
  1164. const float flRotDegPerSec = 20.0f;
  1165. float flRotX = cl_csm_rot_x.GetFloat(), flRotY = cl_csm_rot_y.GetFloat();
  1166. if ( m_flRotX[0] || m_flRotX[1] )
  1167. {
  1168. flRotX += m_flRotX[0] * gpGlobals->frametime * flRotDegPerSec;
  1169. flRotX += m_flRotX[1] * gpGlobals->frametime * flRotDegPerSec;
  1170. if ( flRotX > 360.0f )
  1171. flRotX -= 360.0f;
  1172. else if ( flRotX < 0.0f )
  1173. flRotX += 360.0f;
  1174. cl_csm_rot_x.SetValue( flRotX );
  1175. }
  1176. if ( m_flRotY[0] || m_flRotY[1] )
  1177. {
  1178. flRotY += m_flRotY[0] * gpGlobals->frametime * flRotDegPerSec;
  1179. flRotY += m_flRotY[1] * gpGlobals->frametime * flRotDegPerSec;
  1180. if ( flRotY > 360.0f )
  1181. flRotY -= 360.0f;
  1182. else if ( flRotY < 0.0f )
  1183. flRotY += 360.0f;
  1184. cl_csm_rot_y.SetValue( flRotY );
  1185. }
  1186. QAngle angles;
  1187. angles.Init( flRotX, flRotY, cl_csm_rot_z.GetFloat() );
  1188. AngleVectors( angles, &vShadowDir );
  1189. }
  1190. return vShadowDir.Normalized();
  1191. }
  1192. // bSetup only used on PS3 right now - to support 2 pass Build/Draw rendering
  1193. // bSetup indicates whether to execute once per frame setup code, do this in the buildlist (1st pass) pass only
  1194. // Needed since this will get called twice on PS3 if 2 pass drawing is on
  1195. // bSetup = true otherwise
  1196. void CCascadeLightManager::ComputeShadowDepthTextures( const CViewSetup &viewSetup, bool bSetup )
  1197. {
  1198. m_bStateIsValid = false;
  1199. m_bCSMIsActive = false;
  1200. if (
  1201. #ifdef OSX
  1202. !OSX_HardwareGoodEnoughForCSMs() ||
  1203. #endif
  1204. !cl_csm_enabled.GetBool() ||
  1205. !g_pMaterialSystemHardwareConfig->SupportsCascadedShadowMapping() ||
  1206. !g_pMaterialSystemHardwareConfig->SupportsShadowDepthTextures()
  1207. )
  1208. {
  1209. cl_csm_enabled.SetValue( 0 );
  1210. if ( m_bRenderTargetsAllocated )
  1211. {
  1212. // This code path will only execute if CSM initializes successfully at startup, but is then disabled either from the console or a config/device change.
  1213. materials->ReEnableRenderTargetAllocation_IRealizeIfICallThisAllTexturesWillBeUnloadedAndLoadTimeWillSufferHorribly();
  1214. DeinitRenderTargets();
  1215. materials->FinishRenderTargetAllocation();
  1216. }
  1217. return;
  1218. }
  1219. if ( !m_bRenderTargetsAllocated )
  1220. {
  1221. // If shadow depth texture is now needed but wasn't allocated, allocate it.
  1222. // (This is not a normal code path - it's only taken if the user turns on CSM from the console.)
  1223. materials->ReEnableRenderTargetAllocation_IRealizeIfICallThisAllTexturesWillBeUnloadedAndLoadTimeWillSufferHorribly();
  1224. InitRenderTargets();
  1225. materials->FinishRenderTargetAllocation();
  1226. }
  1227. else if ( m_nCurRenderTargetQualityMode != GetCSMQualityMode() )
  1228. {
  1229. DeinitRenderTargets();
  1230. // Quality level has changed - recreate render targets as they may change size.
  1231. materials->ReEnableRenderTargetAllocation_IRealizeIfICallThisAllTexturesWillBeUnloadedAndLoadTimeWillSufferHorribly();
  1232. InitRenderTargets();
  1233. materials->FinishRenderTargetAllocation();
  1234. }
  1235. CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
  1236. if ( !m_bRenderTargetsAllocated || !C_CascadeLight::Get() )
  1237. {
  1238. m_curState.Reset();
  1239. m_curViewModelState.Reset();
  1240. }
  1241. else
  1242. {
  1243. Vector vShadowDir( GetShadowDirection() );
  1244. color32 lightColor = C_CascadeLight::Get()->GetColor();
  1245. int lightColorScale = C_CascadeLight::Get()->GetColorScale();
  1246. float flMaxShadowDist = cl_csm_max_shadow_dist.GetFloat();
  1247. if ( flMaxShadowDist <= 0.0f )
  1248. {
  1249. flMaxShadowDist = C_CascadeLight::Get()->GetMaxShadowDist();
  1250. #ifdef OSX
  1251. if ( GetCSMQualityMode() == CSMQUALITY_HIGH )
  1252. {
  1253. // At the highest CSM quality level boost the max shadow distance (match Windows on high end Macs)
  1254. // This seems OK from a CS fairness perspective (it can be argued either way whether this gives a player an advantage, or disadvantage).
  1255. flMaxShadowDist *= 1.4f;
  1256. }
  1257. else if ( GetCSMQualityMode() == CSMQUALITY_LOW )
  1258. {
  1259. // match PS3 distance for lowest performing Macs
  1260. flMaxShadowDist *= 0.8f;
  1261. }
  1262. else if ( GetCSMQualityMode() == CSMQUALITY_VERY_LOW )
  1263. {
  1264. // match PS3 distance for lowest performing Macs
  1265. flMaxShadowDist *= 0.6f;
  1266. }
  1267. #else
  1268. if ( ( !IsGameConsole() ) &&
  1269. ( GetCSMQualityMode() == CSMQUALITY_HIGH ) )
  1270. {
  1271. // At the highest CSM quality level boost the max shadow distance.
  1272. // This seems OK from a CS fairness perspective (it can be argued either way whether this gives a player an advantage, or disadvantage).
  1273. flMaxShadowDist *= 1.4f;
  1274. }
  1275. #endif
  1276. }
  1277. if ( flMaxShadowDist <= 0.0f )
  1278. flMaxShadowDist = 400.0f;
  1279. flMaxShadowDist = clamp<float>( flMaxShadowDist, 1.0f, 10000.0f );
  1280. m_curState.Update( viewSetup, vShadowDir, lightColor, lightColorScale, flMaxShadowDist, cl_csm_max_visible_dist.GetFloat(), MAX_CSM_CASCADES, 0, GetCSMQualityMode(), false );
  1281. CViewSetup viewModelViewSetup( viewSetup );
  1282. viewModelViewSetup.zNear = .5f;
  1283. viewModelViewSetup.zFar = cl_csm_viewmodel_farz.GetFloat();
  1284. m_curViewModelState.Update( viewModelViewSetup, vShadowDir, lightColor, lightColorScale, cl_csm_viewmodel_max_shadow_dist.GetFloat(), cl_csm_viewmodel_max_visible_dist.GetFloat(), 1, 3, GetCSMQualityMode(), true );
  1285. if ( cl_csm_capture_state.GetInt() )
  1286. {
  1287. cl_csm_capture_state.SetValue( 0 );
  1288. m_capturedState = m_curState;
  1289. }
  1290. if ( cl_csm_clear_captured_state.GetInt() )
  1291. {
  1292. cl_csm_clear_captured_state.SetValue( 0 );
  1293. m_capturedState.Clear();
  1294. }
  1295. // The CSM sampling shader can only handle MAX_CSM_CASCADES cascades to reduce the number of dynamic combos.
  1296. if ( GetActiveState().IsValid() && ( GetActiveState().m_CSMParallelSplit.GetLightState().m_nShadowCascadeSize == MAX_CSM_CASCADES ) )
  1297. {
  1298. pRenderContext->BeginGeneratingCSMs();
  1299. RenderViews( GetActiveState(), false );
  1300. bool bRenderViewModelCascade = cl_csm_viewmodel_shadows.GetBool();
  1301. if ( ( !IsGameConsole() ) &&
  1302. ( GetCSMQualityMode() == CSMQUALITY_VERY_LOW ) )
  1303. {
  1304. bRenderViewModelCascade = false;
  1305. }
  1306. if ( bRenderViewModelCascade )
  1307. {
  1308. RenderViews( m_curViewModelState, true );
  1309. }
  1310. pRenderContext->EndGeneratingCSMs();
  1311. m_bCSMIsActive = true;
  1312. }
  1313. }
  1314. pRenderContext->SetCascadedShadowMapping( m_bCSMIsActive );
  1315. if ( m_bCSMIsActive )
  1316. {
  1317. pRenderContext->SetCascadedShadowMappingState( GetActiveState().m_CSMParallelSplit.GetLightState().m_SunLightShaderParams, m_ShadowDepthTexture );
  1318. if ( cl_csm_debug_2d.GetBool() )
  1319. {
  1320. // Draw the text here so it doesn't lag 1 frame behind the other debug info
  1321. DrawTextDebugInfo();
  1322. }
  1323. }
  1324. m_bStateIsValid = m_bCSMIsActive;
  1325. }
  1326. void CCascadeLightManager::UnlockAllShadowDepthTextures()
  1327. {
  1328. if ( m_bCSMIsActive )
  1329. {
  1330. CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
  1331. pRenderContext->SetCascadedShadowMapping( false );
  1332. m_bCSMIsActive = false;
  1333. }
  1334. }
  1335. void CCascadeLightManager::BeginViewModelRendering()
  1336. {
  1337. if ( !IsEnabledAndActive() || !m_bStateIsValid || !cl_csm_viewmodel_shadows.GetBool() )
  1338. return;
  1339. if ( ( !IsGameConsole() ) &&
  1340. ( GetCSMQualityMode() == CSMQUALITY_VERY_LOW ) )
  1341. return;
  1342. m_bCSMIsActive = true;
  1343. CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
  1344. pRenderContext->SetCascadedShadowMapping( true );
  1345. CascadedShadowMappingState_t &viewModelShaderParams = m_curViewModelState.m_CSMParallelSplit.GetLightState().m_SunLightShaderParams;
  1346. viewModelShaderParams.m_bIsRenderingViewModels = true;
  1347. pRenderContext->SetCascadedShadowMappingState( viewModelShaderParams, m_ShadowDepthTexture );
  1348. }
  1349. void CCascadeLightManager::EndViewModelRendering()
  1350. {
  1351. if ( !IsEnabledAndActive() || !m_bStateIsValid || !cl_csm_viewmodel_shadows.GetBool() )
  1352. return;
  1353. if ( ( !IsGameConsole() ) &&
  1354. ( GetCSMQualityMode() == CSMQUALITY_VERY_LOW ) )
  1355. return;
  1356. if ( m_bCSMIsActive )
  1357. {
  1358. CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
  1359. pRenderContext->SetCascadedShadowMapping( false );
  1360. m_bCSMIsActive = false;
  1361. // 7LS - poke is view model rendering, testing, should move to somewhere more sensible
  1362. m_curViewModelState.m_CSMParallelSplit.GetLightState().m_SunLightShaderParams.m_bIsRenderingViewModels = false;
  1363. }
  1364. }
  1365. void CCascadeLightManager::BeginReflectionView()
  1366. {
  1367. if ( !m_bCSMIsActive )
  1368. return;
  1369. if ( ( GetCSMQualityMode() > CSMQUALITY_LOW ) && !cl_csm_force_no_csm_in_reflections.GetBool() )
  1370. return;
  1371. CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
  1372. pRenderContext->SetCascadedShadowMapping( false );
  1373. }
  1374. void CCascadeLightManager::EndReflectionView()
  1375. {
  1376. if ( !m_bCSMIsActive )
  1377. return;
  1378. if ( ( GetCSMQualityMode() > CSMQUALITY_LOW ) && !cl_csm_force_no_csm_in_reflections.GetBool() )
  1379. return;
  1380. CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
  1381. pRenderContext->SetCascadedShadowMapping( true );
  1382. }
  1383. void CCascadeLightManager::DumpStatus()
  1384. {
  1385. Msg( "CSM enabled: %i\n", cl_csm_enabled.GetBool() );
  1386. Msg( "Render targets allocated: %i\n", m_bRenderTargetsAllocated );
  1387. Msg( "Depth texture resolution: %i\n", m_nDepthTextureResolution );
  1388. Msg( "Hardware config supportsCascadedShadowMapping: %i\n", g_pMaterialSystemHardwareConfig->SupportsCascadedShadowMapping() );
  1389. Msg( "Hardware config supportsShadowDepthTextures: %i\n", g_pMaterialSystemHardwareConfig->SupportsShadowDepthTextures() );
  1390. Msg( "Hardware config SupportsBilinearPCFSampling: %i\n", g_pMaterialSystemHardwareConfig->SupportsBilinearPCFSampling() );
  1391. Msg( "Current actual CSM quality level (%i=highest, will be forced to 0 if HW doesn't support bilinear PCF): %i\n", CSMQUALITY_TOTAL_MODES - 1, GetCSMQualityMode() );
  1392. Msg( "env_cascade_light entity exists: %i\n", C_CascadeLight::Get() != NULL );
  1393. if ( C_CascadeLight::Get() )
  1394. {
  1395. Msg( "env_cascade_light values:\n" );
  1396. Msg( "Shadow direction: %f %f %f\n", C_CascadeLight::Get()->GetShadowDirection().x, C_CascadeLight::Get()->GetShadowDirection().y, C_CascadeLight::Get()->GetShadowDirection().z );
  1397. Msg( "Light env shadow direction: %f %f %f\n", C_CascadeLight::Get()->GetEnvLightShadowDirection().x, C_CascadeLight::Get()->GetEnvLightShadowDirection().y, C_CascadeLight::Get()->GetEnvLightShadowDirection().z );
  1398. Msg( "Use light env shadow angles: %u\n", C_CascadeLight::Get()->UseLightEnvAngles() );
  1399. Msg( "Max shadow dist: %f\n", C_CascadeLight::Get()->GetMaxShadowDist() );
  1400. }
  1401. }
  1402. void CC_CSM_Status( const CCommand& args )
  1403. {
  1404. g_CascadeLightManager.DumpStatus();
  1405. }
  1406. CSMQualityMode_t CCascadeLightManager::GetCSMQualityMode()
  1407. {
  1408. if ( IsGameConsole() )
  1409. return CSMQUALITY_VERY_LOW;
  1410. if ( !g_pMaterialSystemHardwareConfig->SupportsBilinearPCFSampling() )
  1411. {
  1412. // DX9-class ATI cards: always using VERY_LOW, because the PCF sampling shader has hardcoded knowledge of the shadow depth texture's res
  1413. return CSMQUALITY_VERY_LOW;
  1414. }
  1415. return materials->GetCurrentConfigForVideoCard().GetCSMQualityMode();
  1416. }