csplugincommon/rendermanager/shadow_pssm.h
Go to the documentation of this file.00001 /* 00002 Copyright (C) 2008 by Frank Richter 00003 00004 This library is free software; you can redistribute it and/or 00005 modify it under the terms of the GNU Library General Public 00006 License as published by the Free Software Foundation; either 00007 version 2 of the License, or (at your option) any later version. 00008 00009 This library is distributed in the hope that it will be useful, 00010 but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00012 Library General Public License for more details. 00013 00014 You should have received a copy of the GNU Library General Public 00015 License along with this library; if not, write to the Free 00016 Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 00017 */ 00018 00019 #ifndef __CS_CSPLUGINCOMMON_RENDERMANAGER_SHADOW_PSSM_H__ 00020 #define __CS_CSPLUGINCOMMON_RENDERMANAGER_SHADOW_PSSM_H__ 00021 00026 #include "ivideo/shader/shader.h" 00027 00028 #include "csutil/cfgacc.h" 00029 00030 #include "cstool/meshfilter.h" 00031 00032 #include "csplugincommon/rendermanager/operations.h" 00033 #include "csplugincommon/rendermanager/rendertree.h" 00034 #include "csplugincommon/rendermanager/shadow_common.h" 00035 #include "csplugincommon/rendermanager/standardsorter.h" 00036 #include "csplugincommon/rendermanager/viscull.h" 00037 00038 #include "csgeom/matrix4.h" 00039 #include "csgeom/projections.h" 00040 00041 class csShaderVariable; 00042 00043 namespace CS 00044 { 00045 namespace RenderManager 00046 { 00047 00048 struct ShadowPSSMExtraMeshData 00049 { 00050 csRef<csShaderVariable> svMeshID; 00051 }; 00052 00067 template<typename RenderTree, typename LayerConfigType> 00068 class ShadowPSSM 00069 { 00070 public: 00071 struct PersistentData; 00072 00094 class ViewSetup 00095 { 00096 public: 00097 PersistentData& persist; 00098 00099 CS::RenderManager::RenderView* rview; 00100 int numParts; 00101 float* splitDists; 00102 float lx, rx, ty, by; 00103 bool doFixedCloseShadow; 00104 00105 SingleRenderLayer depthRenderLayer; 00106 uint lastMeshID; 00107 csHash<csRef<csShaderVariable>, csPtrKey<iShaderVariableContext> > meshIDs; 00108 00109 ViewSetup (PersistentData& persist, CS::RenderManager::RenderView* rview) 00110 : persist (persist), rview (rview), 00111 doFixedCloseShadow (persist.fixedCloseShadow > 0), 00112 depthRenderLayer (persist.settings.shadowShaderType, 00113 persist.settings.shadowDefaultShader), 00114 lastMeshID (0) 00115 { 00116 // PSSM: split layers 00117 00118 float _near = SMALL_Z; 00119 float _far = persist.farZ; 00120 00121 int firstPart = 0; 00122 numParts = persist.numSplits + 1; 00123 if (doFixedCloseShadow) 00124 { 00125 numParts++; 00126 } 00127 splitDists = new float[numParts+1]; 00128 if (doFixedCloseShadow) 00129 { 00130 firstPart = 1; 00131 splitDists[0] = _near; 00132 _near = persist.fixedCloseShadow; 00133 } 00134 00135 splitDists[firstPart] = _near; 00136 for (int i = firstPart; i <= numParts; i++) 00137 { 00138 const float n = _near, f = _far; 00139 const float iFrac = (float)(i-firstPart)/(float)(numParts-firstPart); 00140 splitDists[i] = (n * pow (f/n, iFrac) + n + (f-n)*iFrac)*0.5f; 00141 } 00142 // Get visible frustum in to lx/ty,rx/by 00143 { 00144 int frameWidth = rview->GetGraphics3D()->GetWidth (); 00145 int frameHeight = rview->GetGraphics3D()->GetHeight (); 00146 lx = 0; 00147 rx = frameWidth; 00148 ty = frameHeight; 00149 by = 0; 00150 } 00151 } 00152 00153 ~ViewSetup() { delete[] splitDists; } 00154 }; 00155 00156 struct CachedLightData : 00157 public CS::Memory::CustomAllocated 00158 { 00159 uint lastSetupFrame; 00160 bool lightProjectSetup; 00161 // Transform light space to post-project light space 00162 CS::Math::Matrix4 lightProject; 00163 struct SuperFrustum : public CS::Utility::FastRefCount<SuperFrustum> 00164 { 00165 int actualNumParts; 00166 // Transform world space to light space 00167 csReversibleTransform world2light_base; 00168 csReversibleTransform world2light_rotated; 00169 csMatrix3 frustumRotation; 00170 00171 csBox3 lightBBoxLS; 00172 /* @@@ TODO: Would be nice to get bbox of actual shadow casting 00173 * objects ... All meshes in the superFrustum would have to be 00174 * collected, and not just visible ones intersecting it */ 00175 csBox3 castingObjectsBBoxPP; 00176 csBox3 lightBBoxPP; 00177 00178 CS::Utility::MeshFilter meshFilter; 00179 00180 struct Frustum 00181 { 00182 bool draw; 00183 // Volume (in post-project light space) 00184 csBox3 volumePP; 00185 /* @@@ FIXME: res thinks: shouldn't be csRef<>s - pointers should 00186 suffice as cached Frustums are supposedly cleaned up between 00187 frames (and hence no SV pointers should dangle) */ 00188 csRef<csShaderVariable> shadowMapProjectSV; 00189 csRef<csShaderVariable> shadowMapUnscaleSV; 00190 csRef<csShaderVariable> shadowMapDimSV; 00191 csRef<csShaderVariable> shadowClipSV; 00192 csRef<csShaderVariable> textureSVs[rtaNumAttachments]; 00193 00194 // Object bboxes in post-project light space 00195 csBox3 receivingObjectsBBoxPP; 00196 00197 Frustum() : draw (true) {} 00198 }; 00199 Frustum* frustums; 00200 00201 ~SuperFrustum() { delete[] frustums; } 00202 }; 00203 typedef csRefArray<SuperFrustum> LightFrustumsArray; 00204 struct LightFrustums 00205 { 00206 uint frustumsSetupFrame; 00207 uint setupFrame; 00208 LightFrustumsArray frustums; 00209 00210 LightFrustums() : frustumsSetupFrame (~0), setupFrame (~0) {} 00211 }; 00212 csHash<LightFrustums, csRef<iCamera> > lightFrustumsHash; 00213 uint sublightNum; 00214 00215 CachedLightData() : lastSetupFrame (~0), lightProjectSetup (false), 00216 sublightNum (0) {} 00217 00218 uint GetSublightNum() const { return (uint)sublightNum; } 00219 00220 void SetupFrame (RenderTree& tree, ShadowPSSM& shadows, iLight* light) 00221 { 00222 if (light->GetFlags().Check (CS_LIGHT_NOSHADOWS)) return; 00223 00224 ViewSetup& viewSetup = shadows.viewSetup; 00225 uint currentFrame = viewSetup.rview->GetCurrentFrameNumber(); 00226 if (lastSetupFrame != currentFrame) 00227 { 00228 lightFrustumsHash.DeleteAll(); 00229 lastSetupFrame = currentFrame; 00230 } 00231 00232 csRef<iCamera> camera (viewSetup.rview->GetCamera()); 00233 00234 LightFrustums& lightFrustumsSettings = 00235 lightFrustumsHash.GetOrCreate ( 00236 camera, LightFrustums()); 00237 00238 if (lightFrustumsSettings.frustumsSetupFrame != currentFrame) 00239 { 00240 float lightCutoff = light->GetCutoffDistance(); 00241 if (!lightProjectSetup) 00242 { 00243 float lightNear = SMALL_Z; 00244 CS::Math::Matrix4 lightProject; 00245 csLightType ltype = light->GetType(); 00246 int numFrustums = 1; 00247 switch (ltype) 00248 { 00249 case CS_LIGHT_DIRECTIONAL: 00250 numFrustums = 1; 00251 { 00252 lightProject = CS::Math::Projections::Ortho ( 00253 lightCutoff, -lightCutoff, lightCutoff, -lightCutoff, 00254 -lightCutoff, -lightNear); 00255 } 00256 break; 00257 case CS_LIGHT_POINTLIGHT: 00258 case CS_LIGHT_SPOTLIGHT: 00259 if (ltype == CS_LIGHT_POINTLIGHT) 00260 numFrustums = 6; 00261 else 00262 numFrustums = 1; 00263 { 00264 CS::Math::Matrix4 flipZW ( 00265 1, 0, 0, 0, 00266 0, 1, 0, 0, 00267 0, 0, -1, 0, 00268 0, 0, 0, -1); 00269 //lightProject = flipZW * CS::Math::Projections::Frustum ( 00270 // -lightNear, lightNear, -lightNear, lightNear, // @@@ TODO: use spot angle 00271 // lightNear, lightCutoff, true); 00272 lightProject = flipZW * CS::Math::Projections::Frustum ( 00273 lightCutoff, -lightCutoff, lightCutoff, -lightCutoff, // @@@ TODO: use spot angle 00274 -lightCutoff, -lightNear); 00275 } 00276 break; 00277 } 00278 this->sublightNum = numFrustums; 00279 this->lightProject = lightProject; 00280 lightProjectSetup = true; 00281 } 00282 /*csPrintf ("lightProject = %s\n", lightProject.Description().GetData()); 00283 { 00284 csVector4 a (0, 0, -lightNear, 1); 00285 csVector4 b = lightProject * a; 00286 csPrintf ("%s -> %s ", a.Description().GetData(), b.Description().GetData()); 00287 } 00288 { 00289 csVector4 a (0, 0, lightNear, 1); 00290 csVector4 b = lightProject * a; 00291 csPrintf ("%s -> %s ", a.Description().GetData(), b.Description().GetData()); 00292 } 00293 { 00294 csVector4 a (0, 0, lightCutoff, 1); 00295 csVector4 b = lightProject * a; 00296 csPrintf ("%s -> %s ", a.Description().GetData(), b.Description().GetData()); 00297 } 00298 { 00299 csVector4 a (0, 0, -lightCutoff, 1); 00300 csVector4 b = lightProject * a; 00301 csPrintf ("%s -> %s ", a.Description().GetData(), b.Description().GetData()); 00302 } 00303 csPrintf ("\n");*/ 00304 const csReversibleTransform& world2light_base ( 00305 light->GetMovable()->GetFullTransform()); 00306 00307 const csBox3& lightBBox = light->GetLocalBBox(); 00308 if (tree.IsDebugFlagEnabled (shadows.persist.dbgLightBBox)) 00309 { 00310 tree.AddDebugBBox (lightBBox, 00311 world2light_base.GetInverse(), 00312 csColor (1, 1, 1)); 00313 } 00314 00315 static const csMatrix3 frustRotationMatrices[6] = 00316 { 00317 csMatrix3 (), // must be identity 00318 csMatrix3 (1, 0, 0, 0, 0, 1, 0, -1, 0), 00319 csMatrix3 (1, 0, 0, 0, 0, -1, 0, 1, 0), 00320 csMatrix3 (0, 0, -1, 0, 1, 0, 1, 0, 0), 00321 csMatrix3 (0, 0, 1, 0, 1, 0, -1, 0, 0), 00322 csMatrix3 (1, 0, 0, 0, -1, 0, 0, 0, -1) // last must be 180 deg into other direction 00323 }; 00324 csVector2 corner2D[4] = { 00325 csVector2 (viewSetup.lx, viewSetup.ty), 00326 csVector2 (viewSetup.lx, viewSetup.by), 00327 csVector2 (viewSetup.rx, viewSetup.ty), 00328 csVector2 (viewSetup.rx, viewSetup.by) 00329 }; 00330 00331 LightFrustumsArray& lightFrustums = 00332 lightFrustumsSettings.frustums; 00333 00334 LightingVariablesHelper lightVarsHelper (viewSetup.persist.lightVarsPersist); 00335 for (uint f = 0; f < sublightNum; f++) 00336 { 00337 /* Compute intersection of light frustum with view frustums: 00338 1. Compute corners of split frustums 00339 2. Translate corners to light space 00340 3. Compute bounding box from corners 00341 */ 00342 csRef<SuperFrustum> newFrust; 00343 newFrust.AttachNew (new SuperFrustum); 00344 SuperFrustum& superFrustum = *(lightFrustums[lightFrustums.Push ( 00345 newFrust)]); 00346 superFrustum.world2light_base = world2light_base; 00347 superFrustum.world2light_rotated = world2light_base; 00348 superFrustum.frustumRotation = frustRotationMatrices[f]; 00349 superFrustum.world2light_rotated.SetO2T ( 00350 superFrustum.world2light_rotated.GetO2T() 00351 * frustRotationMatrices[f]); 00352 if (shadows.persist.limitedShadow) 00353 superFrustum.meshFilter.SetFilterMode (CS::Utility::MESH_FILTER_INCLUDE); 00354 00355 00356 csBox3 frustBBox ( 00357 csVector3 (-FLT_MAX, -FLT_MAX, 0), 00358 csVector3 (FLT_MAX, FLT_MAX, FLT_MAX)); 00359 /*{ 00360 csTransform boxTF (frustRotationMatrices[f], csVector3 (0)); 00361 frustBBox = boxTF.Other2This (frustBBox); 00362 }*/ 00363 frustBBox *= lightBBox; // @@@ lightBBox should prolly be rotated 00364 /*tree.AddDebugBBox (frustBBox, 00365 superFrustum.world2light_rotated.GetInverse(), 00366 csColor (0.8, 0.8, 0.8));*/ 00367 superFrustum.lightBBoxLS = frustBBox; 00368 superFrustum.lightBBoxPP.StartBoundingBox(); 00369 for (int c = 0; c < 7; c++) 00370 { 00371 csVector3 cornerLight = frustBBox.GetCorner (c); 00372 csVector4 cornerUndiv = lightProject * csVector4 (cornerLight); 00373 csVector3 cornerDiv = 00374 csVector3 (cornerUndiv.x, cornerUndiv.y, cornerUndiv.z); 00375 //cornerDiv /= cornerUndiv.w; 00376 superFrustum.lightBBoxPP.AddBoundingVertex (cornerDiv); 00377 } 00378 00379 superFrustum.actualNumParts = 0; 00380 for (int i = 0; i < viewSetup.numParts; i++) 00381 { 00382 if (lightCutoff < viewSetup.splitDists[i]) break; 00383 superFrustum.actualNumParts++; 00384 } 00385 superFrustum.frustums = 00386 new typename SuperFrustum::Frustum[superFrustum.actualNumParts]; 00387 00388 for (int i = 0; i < superFrustum.actualNumParts; i++) 00389 { 00390 bool partFixed = viewSetup.doFixedCloseShadow && (i == 0); 00391 00392 typename SuperFrustum::Frustum& lightFrustum = 00393 superFrustum.frustums[i]; 00394 00395 // Frustum corner, camera space 00396 csVector3 cornerCam; 00397 // Frustum corner, world space 00398 csVector3 cornerWorld; 00399 // Frustum corner, light space 00400 csVector3 cornerLight; 00401 // Frustum slice bbox, light space 00402 csBox3 frustumLight; 00403 csBox3 frustumCam; 00404 frustumLight.StartBoundingBox(); 00405 frustumCam.StartBoundingBox(); 00406 for (int c = 0; c < 4; c++) 00407 { 00408 cornerCam = camera->InvPerspective ( 00409 corner2D[c], viewSetup.splitDists[i]); 00410 frustumCam.AddBoundingVertex (cornerCam); 00411 cornerWorld = camera->GetTransform().This2Other ( 00412 cornerCam); 00413 cornerLight = superFrustum.world2light_rotated.Other2This (cornerWorld); 00414 frustumLight.AddBoundingVertex (cornerLight); 00415 00416 cornerCam = camera->InvPerspective ( 00417 corner2D[c], viewSetup.splitDists[i+1]); 00418 frustumCam.AddBoundingVertex (cornerCam); 00419 cornerWorld = camera->GetTransform().This2Other ( 00420 cornerCam); 00421 cornerLight = superFrustum.world2light_rotated.Other2This (cornerWorld); 00422 frustumLight.AddBoundingVertex (cornerLight); 00423 } 00424 if (tree.IsDebugFlagEnabled (shadows.persist.dbgSplitFrustumCam)) 00425 { 00426 tree.AddDebugBBox (frustumCam, 00427 camera->GetTransform().GetInverse(), 00428 csColor (1, 0, 1)); 00429 } 00430 if (tree.IsDebugFlagEnabled (shadows.persist.dbgSplitFrustumLight)) 00431 { 00432 tree.AddDebugBBox (frustumLight, 00433 superFrustum.world2light_rotated.GetInverse(), 00434 csColor (0, 1, 0)); 00435 } 00436 if (!partFixed) frustumLight *= frustBBox; 00437 if (tree.IsDebugFlagEnabled (shadows.persist.dbgSplitFrustumLight)) 00438 { 00439 tree.AddDebugBBox (frustumLight, 00440 superFrustum.world2light_rotated.GetInverse(), 00441 csColor (0, 1, 1)); 00442 } 00443 00444 lightFrustum.shadowMapProjectSV = lightVarsHelper.CreateTempSV ( 00445 viewSetup.persist.svNames.GetLightSVId ( 00446 csLightShaderVarCache::lightShadowMapProjection)); 00447 lightFrustum.shadowMapProjectSV->SetArraySize (4); 00448 for (int j = 0; j < 4; j++) 00449 { 00450 csShaderVariable* item = lightVarsHelper.CreateTempSV ( 00451 CS::InvalidShaderVarStringID); 00452 lightFrustum.shadowMapProjectSV->SetArrayElement (j, item); 00453 } 00454 lightFrustum.shadowMapUnscaleSV = lightVarsHelper.CreateTempSV ( 00455 viewSetup.persist.unscaleSVName); 00456 lightFrustum.shadowMapDimSV = lightVarsHelper.CreateTempSV ( 00457 viewSetup.persist.svNames.GetLightSVId ( 00458 csLightShaderVarCache::lightShadowMapPixelSize)); 00459 00460 lightFrustum.shadowClipSV = lightVarsHelper.CreateTempSV ( 00461 viewSetup.persist.shadowClipSVName); 00462 lightFrustum.shadowClipSV->SetValue (csVector2 ( 00463 viewSetup.splitDists[i], 00464 (i+1 == superFrustum.actualNumParts) ? FLT_MAX : viewSetup.splitDists[i+1])); 00465 00466 size_t numTex = viewSetup.persist.settings.targets.GetSize(); 00467 for (size_t t = 0; t < numTex; t++) 00468 { 00469 const ShadowSettings::Target* target = 00470 viewSetup.persist.settings.targets[t]; 00471 lightFrustum.textureSVs[target->attachment] = 00472 lightVarsHelper.CreateTempSV (target->svName); 00473 } 00474 00475 if (frustumLight.Empty()) 00476 { 00477 lightFrustum.draw = false; 00478 continue; 00479 } 00480 00481 00482 // Frustum slice corner, light space before W divide 00483 csVector4 cornerUndiv; 00484 // Frustum slice corner, light space after W divide 00485 csVector3 cornerDiv; 00486 00487 lightFrustum.volumePP.StartBoundingBox(); 00488 for (int c = 0; c < 7; c++) 00489 { 00490 cornerLight = frustumLight.GetCorner (c); 00491 cornerUndiv = lightProject * csVector4 (cornerLight); 00492 cornerDiv = 00493 csVector3 (cornerUndiv.x, cornerUndiv.y, cornerUndiv.z); 00494 //cornerDiv /= cornerUndiv.w; 00495 lightFrustum.volumePP.AddBoundingVertex (cornerDiv); 00496 } 00497 //superFrustum.lightBBoxLS += frustumLight; 00498 } 00499 } 00500 00501 lightFrustumsSettings.frustumsSetupFrame = currentFrame; 00502 } 00503 } 00504 00505 void AddShadowMapTarget (typename RenderTree::MeshNode* meshNode, 00506 PersistentData& persist, const SingleRenderLayer& layerConfig, 00507 RenderTree& renderTree, iLight* light, ViewSetup& viewSetup) 00508 { 00509 if (light->GetFlags().Check (CS_LIGHT_NOSHADOWS)) return; 00510 00511 LightFrustums* lightFrustumsPtr = 00512 lightFrustumsHash.GetElementPointer ( 00513 viewSetup.rview->GetCamera()); 00514 if (lightFrustumsPtr == 0) 00515 return; // @@@ FIXME: when does that happen? 00516 00517 LightFrustums& lightFrustums = *lightFrustumsPtr; 00518 00519 uint currentFrame = viewSetup.rview->GetCurrentFrameNumber(); 00520 if (lightFrustums.setupFrame 00521 == currentFrame) 00522 return; 00523 lightFrustums.setupFrame = currentFrame; 00524 00525 csBox3 clipToView; 00526 clipToView = csBox3 (csVector3 (-1, -1, 0), 00527 csVector3 (1, 1, FLT_MAX)); 00528 00529 typename RenderTree::ContextNode& context = meshNode->GetOwner(); 00530 00531 CS_ALLOC_STACK_ARRAY(iTextureHandle*, texHandles, 00532 persist.settings.targets.GetSize()); 00533 for (size_t l = 0; l < lightFrustums.frustums.GetSize(); l++) 00534 { 00535 const SuperFrustum& superFrust = *(lightFrustums.frustums[l]); 00536 const csBox3& allCastersBoxPP = superFrust.castingObjectsBBoxPP; 00537 //superFrust.lightBBoxPP; 00538 csBox3 allVolumes; 00539 for (int frustNum = 0; frustNum < superFrust.actualNumParts; frustNum++) 00540 { 00541 const typename SuperFrustum::Frustum& lightFrust = superFrust.frustums[frustNum]; 00542 //if (lightFrust.containedObjectsPP.GetSize() == 0) continue; 00543 00544 bool partFixed = viewSetup.doFixedCloseShadow && (frustNum == 0); 00545 00546 allVolumes += lightFrust.volumePP; 00547 csBox3 castersBox = allCastersBoxPP; 00548 //castersBox *= allVolumes; // *** 00549 //csPrintf ("casters: %s\n", castersBox.Description().GetData()); 00550 /* Fit map to the bounding box of all shadowed(received) objects. 00551 - If the shadowed objects are smaller than the light frustum in some 00552 dimension makes sure the shadow map is used optimally. 00553 - Likewise, we only need to expend enough shadow map to cover 00554 all casters. */ 00555 csBox3 receiversBox; 00556 if (!partFixed) 00557 { 00558 receiversBox = lightFrust.receivingObjectsBBoxPP; 00559 // @@@ FIXME: causes light frustum clipping errors somewhere down below... 00560 //receiversBox *= lightFrust.volumePP; 00561 //receiversBox *= castersBox; 00562 } 00563 else 00564 { 00565 castersBox = receiversBox = lightFrust.volumePP; 00566 } 00567 receiversBox *= clipToView; // @@@ Redundant? 00568 //csPrintf ("receivers: %s\n", receiversBox.Description().GetData()); 00569 bool noCasters = (castersBox.Empty()); 00570 00571 CS::RenderManager::RenderView* rview = context.renderView; 00572 csRef<CS::RenderManager::RenderView> newRenderView; 00573 newRenderView = renderTree.GetPersistentData().renderViews.CreateRenderView (); 00574 newRenderView->SetOriginalCamera (rview->GetOriginalCamera ()); 00575 newRenderView->SetEngine (rview->GetEngine ()); 00576 newRenderView->SetThisSector (rview->GetThisSector ()); 00577 00578 /* The minimum Z over all parts is used to avoid clipping shadows of 00579 casters closer to the light than the split plane. 00580 Ideally, allObjsBoxPP.MinZ() would be mapped to depth -1, and depths 00581 below clamped */ 00582 // FIXME, again: should better be allCastersBoxPP.MinZ(); 00583 float n = superFrust.lightBBoxPP.MinZ(); 00584 float f = csMin (castersBox.MaxZ(), receiversBox.MaxZ()) + EPSILON; 00585 /* Sometimes n==f which would result in an invalid matrix w/o EPSILON */ 00586 00587 CS::Math::Matrix4 crop; 00588 if (!lightFrust.draw) 00589 { 00590 /* Case: a frustum slice does not intersect with the light 00591 frustum: Just make sure the frustum is clipped correctly, 00592 actual SM or SM transform doesn't matter much */ 00593 crop = CS::Math::Matrix4 ( 00594 0, 0, 0, 10, 00595 0, 0, 0, 10, 00596 0, 0, 1, 0, 00597 0, 0, 0, 1); 00598 00599 lightFrust.shadowMapUnscaleSV->SetValue (csVector4 ( 00600 0, 0, -10, -10)); 00601 } 00602 else if (noCasters) 00603 { 00604 /* Case: a frustum slice doesn't have any shadow casters. 00605 All shadow receivers are unshadowed (the empty SM is used 00606 for that), but also the frustum must be clipped correctly. */ 00607 crop = CS::Math::Matrix4 ( 00608 1, 0, 0, 0, 00609 0, 1, 0, 0, 00610 0, 0, 1, 0, 00611 0, 0, 0, 1); 00612 00613 lightFrust.shadowMapUnscaleSV->SetValue (csVector4 ( 00614 1, 1, 0, 0)); 00615 00616 f = 1.0f; 00617 n = f - EPSILON; 00618 } 00619 else 00620 { 00621 const float focusMinX = csMax (receiversBox.MinX(), castersBox.MinX()); 00622 const float focusMinY = csMax (receiversBox.MinY(), castersBox.MinY()); 00623 const float focusMaxX = csMin (receiversBox.MaxX(), castersBox.MaxX()); 00624 const float focusMaxY = csMin (receiversBox.MaxY(), castersBox.MaxY()); 00625 const float frustW = focusMaxX - focusMinX; 00626 const float frustH = focusMaxY - focusMinY; 00627 const float cropScaleX = 2.0f/frustW; 00628 const float cropScaleY = 2.0f/frustH; 00629 const float cropShiftX = 00630 (-1.0f * (focusMaxX + focusMinX))/frustW; 00631 const float cropShiftY = 00632 (-1.0f * (focusMaxY + focusMinY))/frustH; 00633 crop = CS::Math::Matrix4 ( 00634 cropScaleX, 0, 0, cropShiftX, 00635 0, cropScaleY, 0, cropShiftY, 00636 0, 0, 1, 0, 00637 0, 0, 0, 1); 00638 00639 const float uncropScaleX = 1.0f/cropScaleX; 00640 const float uncropScaleY = 1.0f/cropScaleY; 00641 const float uncropShiftX = -cropShiftX/cropScaleX; 00642 const float uncropShiftY = -cropShiftY/cropScaleY; 00643 lightFrust.shadowMapUnscaleSV->SetValue (csVector4 ( 00644 uncropScaleX, uncropScaleY, uncropShiftX, uncropShiftY)); 00645 } 00646 00647 CS::Math::Matrix4 Mortho = CS::Math::Projections::Ortho (-1, 1, 1, -1, 00648 f, n); 00649 CS::Math::Matrix4 matrix = ((Mortho * crop) * lightProject) 00650 * CS::Math::Matrix4 (superFrust.frustumRotation); 00651 00652 for (int i = 0; i < 4; i++) 00653 { 00654 csShaderVariable* item = lightFrust.shadowMapProjectSV->GetArrayElement (i); 00655 item->SetValue (matrix.Row (i)); 00656 } 00657 00658 int shadowMapSize; 00659 if (partFixed) 00660 shadowMapSize = persist.shadowMapResClose; 00661 else 00662 { 00663 switch (light->GetType()) 00664 { 00665 default: 00666 case CS_LIGHT_DIRECTIONAL: 00667 shadowMapSize = persist.shadowMapResD; 00668 break; 00669 case CS_LIGHT_POINTLIGHT: 00670 shadowMapSize = persist.shadowMapResP; 00671 break; 00672 case CS_LIGHT_SPOTLIGHT: 00673 shadowMapSize = persist.shadowMapResS; 00674 break; 00675 } 00676 } 00677 lightFrust.shadowMapDimSV->SetValue (csVector4 (1.0f/shadowMapSize, 00678 1.0f/shadowMapSize, shadowMapSize, shadowMapSize)); 00679 00680 if (!lightFrust.draw) 00681 { 00682 for (size_t t = 0; t < persist.settings.targets.GetSize(); t++) 00683 { 00684 // Should not be used anyway 00685 const ShadowSettings::Target* target = 00686 viewSetup.persist.settings.targets[t]; 00687 lightFrust.textureSVs[target->attachment]->SetValue (0); 00688 } 00689 continue; 00690 } 00691 else if (noCasters) 00692 { 00693 for (size_t t = 0; t < persist.settings.targets.GetSize(); t++) 00694 { 00695 // Can be 0 when using 1 light max 00696 const ShadowSettings::Target* target = 00697 viewSetup.persist.settings.targets[t]; 00698 lightFrust.textureSVs[target->attachment]->SetValue ( 00699 GetEmptyShadowMap (persist, t, context)); 00700 } 00701 continue; 00702 } 00703 00704 csReversibleTransform view = superFrust.world2light_base; 00705 00706 csRef<iCustomMatrixCamera> shadowViewCam = 00707 newRenderView->GetEngine()->CreateCustomMatrixCamera(); 00708 newRenderView->SetCamera (shadowViewCam->GetCamera()); 00709 shadowViewCam->SetProjectionMatrix (matrix); 00710 shadowViewCam->GetCamera()->SetTransform (view); 00711 00712 for (size_t t = 0; t < persist.settings.targets.GetSize(); t++) 00713 { 00714 ShadowSettings::Target* target = 00715 viewSetup.persist.settings.targets[t]; 00716 iTextureHandle* tex = target->texCache.QueryUnusedTexture ( 00717 shadowMapSize, shadowMapSize); 00718 lightFrust.textureSVs[target->attachment]->SetValue (tex); 00719 if (renderTree.IsDebugFlagEnabled (persist.dbgShadowTex)) 00720 renderTree.AddDebugTexture (tex); 00721 texHandles[target->attachment] = tex; 00722 } 00723 00724 newRenderView->SetViewDimensions (shadowMapSize, shadowMapSize); 00725 csBox2 clipBox (0, 0, shadowMapSize, shadowMapSize); 00726 csRef<iClipper2D> newView; 00727 newView.AttachNew (new csBoxClipper (clipBox)); 00728 newRenderView->SetClipper (newView); 00729 newRenderView->SetMeshFilter(superFrust.meshFilter); 00730 00731 // Create a new context for shadow map w/ computed view 00732 typename RenderTree::ContextNode* shadowMapCtx = 00733 renderTree.CreateContext (newRenderView); 00734 for (size_t t = 0; t < persist.settings.targets.GetSize(); t++) 00735 { 00736 shadowMapCtx->renderTargets[ 00737 persist.settings.targets[t]->attachment].texHandle = 00738 texHandles[t]; 00739 } 00740 shadowMapCtx->drawFlags = CSDRAW_CLEARSCREEN | CSDRAW_CLEARZBUFFER; 00741 shadowMapCtx->postEffects = persist.settings.postEffects; 00742 00743 /* @@@ FIXME: This will break as soon as the shadowmaps have 00744 different resolutions! 00745 Probably the post effects manager should be changed to handle 00746 changing resolutions well */ 00747 if (shadowMapCtx->postEffects.IsValid()) 00748 { 00749 CS::Math::Matrix4 perspectiveFixup; 00750 shadowMapCtx->postEffects->SetupView (shadowMapSize, shadowMapSize, 00751 perspectiveFixup); 00752 shadowMapCtx->perspectiveFixup = perspectiveFixup; 00753 } 00754 00755 // Setup the new context 00756 ShadowmapContextSetup contextFunction (layerConfig, 00757 persist.shaderManager, viewSetup, persist.settings.provideIDs); 00758 contextFunction (*shadowMapCtx); 00759 } 00760 } 00761 } 00762 00763 void ClearFrameData() 00764 { 00765 //frustumsSetup = false; 00766 //lightFrustums.Empty(); 00767 lightProjectSetup = false; 00768 } 00769 00770 iTextureHandle* GetEmptyShadowMap (PersistentData& persist, size_t target, 00771 typename RenderTree::ContextNode& context) 00772 { 00773 if (persist.emptySMs.GetSize() == 0) 00774 { 00775 CS::RenderManager::RenderView* rview = context.renderView; 00776 csRef<CS::RenderManager::RenderView> newRenderView; 00777 newRenderView = context.owner.GetPersistentData().renderViews.CreateRenderView (); 00778 newRenderView->SetEngine (rview->GetEngine ()); 00779 newRenderView->SetViewDimensions (1, 1); 00780 00781 csRef<iCustomMatrixCamera> shadowViewCam = 00782 newRenderView->GetEngine()->CreateCustomMatrixCamera(); 00783 newRenderView->SetCamera (shadowViewCam->GetCamera()); 00784 00785 csBox2 clipBox (0, 0, 1, 1); 00786 csRef<iClipper2D> newView; 00787 newView.AttachNew (new csBoxClipper (clipBox)); 00788 newRenderView->SetClipper (newView); 00789 00790 persist.emptySMs.SetSize (persist.settings.targets.GetSize()); 00791 00792 typename RenderTree::ContextNode* shadowMapCtx = 00793 context.owner.CreateContext (newRenderView); 00794 for (size_t t = 0; t < persist.settings.targets.GetSize(); t++) 00795 { 00796 csRef<iTextureHandle> tex = persist.g3d->GetTextureManager() 00797 ->CreateTexture (1, 1, csimg2D, 00798 persist.settings.targets[t]->texCache.GetFormat(), 00799 persist.settings.targets[t]->texCache.GetFlags ()); 00800 persist.emptySMs.Put (t, tex); 00801 shadowMapCtx->renderTargets[ 00802 persist.settings.targets[t]->attachment].texHandle = tex; 00803 } 00804 shadowMapCtx->drawFlags = CSDRAW_CLEARSCREEN | CSDRAW_CLEARZBUFFER; 00805 } 00806 return persist.emptySMs[target]; 00807 } 00808 }; 00809 private: 00810 class ShadowmapContextSetup 00811 { 00812 class MeshIDSVSetup 00813 { 00814 public: 00815 MeshIDSVSetup (SVArrayHolder& svArrays, ViewSetup& viewSetup) 00816 : svArrays (svArrays), viewSetup (viewSetup) 00817 { 00818 tempStack.Setup (svArrays.GetNumSVNames ()); 00819 } 00820 00821 void operator() (typename RenderTree::MeshNode* node) 00822 { 00823 for (size_t i = 0; i < node->meshes.GetSize (); ++i) 00824 { 00825 typename RenderTree::MeshNode::SingleMesh& mesh = node->meshes[i]; 00826 csShaderVariable* svMeshID = viewSetup.meshIDs.Get (mesh.meshObjSVs, 0); 00827 if (!svMeshID) continue; 00828 00829 tempStack[svMeshID->GetName()] = svMeshID; 00830 00831 for (size_t layer = 0; layer < svArrays.GetNumLayers(); ++layer) 00832 { 00833 // Back-merge it onto the real one 00834 csShaderVariableStack localStack; 00835 svArrays.SetupSVStack (localStack, layer, mesh.contextLocalId); 00836 localStack.MergeFront (tempStack); 00837 } 00838 } 00839 } 00840 00841 private: 00842 SVArrayHolder& svArrays; 00843 csShaderVariableStack tempStack; 00844 ViewSetup& viewSetup; 00845 }; 00846 public: 00847 ShadowmapContextSetup (const SingleRenderLayer& layerConfig, 00848 iShaderManager* shaderManager, ViewSetup& viewSetup, 00849 bool doIDTexture) 00850 : layerConfig (layerConfig), shaderManager (shaderManager), 00851 viewSetup (viewSetup), doIDTexture (doIDTexture) 00852 { 00853 00854 } 00855 00856 void operator() (typename RenderTree::ContextNode& context) 00857 { 00858 CS::RenderManager::RenderView* rview = context.renderView; 00859 iSector* sector = rview->GetThisSector (); 00860 00861 // @@@ This is somewhat "boilerplate" sector/rview setup. 00862 rview->SetThisSector (sector); 00863 sector->CallSectorCallbacks (rview); 00864 // Make sure the clip-planes are ok 00865 CS::RenderViewClipper::SetupClipPlanes (rview->GetRenderContext ()); 00866 00867 if (context.owner.IsDebugFlagEnabled ( 00868 viewSetup.persist.dbgSplitFrustumLight)) 00869 context.owner.AddDebugClipPlanes (rview); 00870 00871 // Do the culling 00872 iVisibilityCuller* culler = sector->GetVisibilityCuller (); 00873 Viscull<RenderTree> (context, rview, culler); 00874 00875 // TODO: portals 00876 00877 // Sort the mesh lists 00878 { 00879 StandardMeshSorter<RenderTree> mySorter (rview->GetEngine ()); 00880 mySorter.SetupCameraLocation (rview->GetCamera ()->GetTransform ().GetOrigin ()); 00881 ForEachMeshNode (context, mySorter); 00882 } 00883 00884 // After sorting, assign in-context per-mesh indices 00885 { 00886 SingleMeshContextNumbering<RenderTree> numbering; 00887 ForEachMeshNode (context, numbering); 00888 } 00889 00890 // Setup the SV arrays 00891 // Push the default stuff 00892 SetupStandardSVs (context, layerConfig, shaderManager, sector); 00893 00894 // Setup the material&mesh SVs 00895 { 00896 StandardSVSetup<RenderTree, SingleRenderLayer> svSetup ( 00897 context.svArrays, layerConfig); 00898 00899 ForEachMeshNode (context, svSetup); 00900 } 00901 // Set up mesh ID SVs 00902 if (doIDTexture) 00903 { 00904 MeshIDSVSetup svSetup (context.svArrays, viewSetup); 00905 00906 ForEachMeshNode (context, svSetup); 00907 } 00908 00909 SetupStandardShader (context, shaderManager, layerConfig); 00910 00911 // Setup shaders and tickets 00912 SetupStandardTicket (context, shaderManager, layerConfig); 00913 } 00914 00915 00916 private: 00917 const SingleRenderLayer& layerConfig; 00918 iShaderManager* shaderManager; 00919 ViewSetup& viewSetup; 00920 bool doIDTexture; 00921 }; 00922 public: 00923 00928 struct PersistentData 00929 { 00930 uint dbgSplitFrustumCam; 00931 uint dbgSplitFrustumLight; 00932 uint dbgLightBBox; 00933 uint dbgShadowTex; 00934 uint dbgFlagShadowClipPlanes; 00935 csLightShaderVarCache svNames; 00936 CS::ShaderVarStringID unscaleSVName; 00937 CS::ShaderVarStringID shadowClipSVName; 00938 LightingSorter::PersistentData lightSorterPersist; 00939 LightingVariablesHelper::PersistentData lightVarsPersist; 00940 iShaderManager* shaderManager; 00941 csRefArray<iTextureHandle> emptySMs; 00942 iGraphics3D* g3d; 00943 00944 csString configPrefix; 00945 ShadowSettings settings; 00946 00947 bool limitedShadow; 00948 int shadowMapResD, shadowMapResP, shadowMapResS; 00949 int shadowMapResClose; 00950 int numSplits; 00951 float farZ; 00952 float fixedCloseShadow; 00953 00954 PersistentData() : limitedShadow (false) 00955 { 00956 } 00957 00958 ~PersistentData() 00959 { 00960 } 00961 00963 void SetConfigPrefix (const char* configPrefix) 00964 { 00965 this->configPrefix = configPrefix; 00966 } 00967 00968 void Initialize (iObjectRegistry* objectReg, 00969 RenderTreeBase::DebugPersistent& dbgPersist) 00970 { 00971 csRef<iShaderManager> shaderManager = 00972 csQueryRegistry<iShaderManager> (objectReg); 00973 csRef<iGraphics3D> g3d = 00974 csQueryRegistry<iGraphics3D> (objectReg); 00975 00976 this->shaderManager = shaderManager; 00977 this->g3d = g3d; 00978 iShaderVarStringSet* strings = shaderManager->GetSVNameStringset(); 00979 svNames.SetStrings (strings); 00980 00981 csConfigAccess cfg (objectReg); 00982 if (configPrefix.IsEmpty()) 00983 { 00984 settings.ReadSettings (objectReg, "Depth"); 00985 } 00986 else 00987 { 00988 settings.ReadSettings (objectReg, 00989 cfg->GetStr ( 00990 csString().Format ("%s.ShadowsType", configPrefix.GetData()), "Depth")); 00991 limitedShadow = cfg->GetBool ( 00992 csString().Format ("%s.LimitedShadow", configPrefix.GetData()), false); 00993 numSplits = cfg->GetInt ( 00994 csString().Format ("%s.NumSplits", configPrefix.GetData()), 2); 00995 farZ = cfg->GetFloat ( 00996 csString().Format ("%s.FarZ", configPrefix.GetData()), 100); 00997 int shadowMapRes = cfg->GetInt ( 00998 csString().Format ("%s.ShadowMapResolution", configPrefix.GetData()), 512); 00999 shadowMapResD = cfg->GetInt ( 01000 csString().Format ("%s.ShadowMapResolution.Directional", configPrefix.GetData()), 01001 shadowMapRes); 01002 shadowMapResP = cfg->GetInt ( 01003 csString().Format ("%s.ShadowMapResolution.Point", configPrefix.GetData()), 01004 shadowMapRes/2); 01005 shadowMapResS = cfg->GetInt ( 01006 csString().Format ("%s.ShadowMapResolution.Spot", configPrefix.GetData()), 01007 shadowMapRes/2); 01008 shadowMapResClose = cfg->GetInt ( 01009 csString().Format ("%s.CloseShadowMapResolution", configPrefix.GetData()), 01010 shadowMapRes); 01011 fixedCloseShadow = cfg->GetFloat ( 01012 csString().Format ("%s.FixedCloseShadow", configPrefix.GetData()), 0); 01013 } 01014 01015 unscaleSVName = strings->Request ("light shadow map unscale"); 01016 shadowClipSVName = strings->Request ("light shadow clip"); 01017 01018 dbgSplitFrustumCam = dbgPersist.RegisterDebugFlag ("draw.pssm.split.frustum.cam"); 01019 dbgSplitFrustumLight = dbgPersist.RegisterDebugFlag ("draw.pssm.split.frustum.light"); 01020 dbgLightBBox = dbgPersist.RegisterDebugFlag ("draw.pssm.lightbbox"); 01021 dbgShadowTex = dbgPersist.RegisterDebugFlag ("textures.shadow"); 01022 dbgFlagShadowClipPlanes = 01023 dbgPersist.RegisterDebugFlag ("draw.clipplanes.shadow"); 01024 } 01025 void UpdateNewFrame () 01026 { 01027 csTicks time = csGetTicks (); 01028 settings.AdvanceFrame (time); 01029 lightVarsPersist.UpdateNewFrame(); 01030 } 01031 }; 01032 01033 typedef ViewSetup ShadowParameters; 01034 01035 ShadowPSSM (PersistentData& persist, 01036 const LayerConfigType& layerConfig, 01037 typename RenderTree::MeshNode* node, 01038 ViewSetup& viewSetup) 01039 : persist (persist), layerConfig (layerConfig), 01040 renderTree (node->GetOwner().owner), meshNode (node), 01041 viewSetup (viewSetup) 01042 { } 01043 01044 uint HandleOneLight (typename RenderTree::MeshNode::SingleMesh& singleMesh, 01045 iLight* light, CachedLightData& lightData, 01046 csShaderVariableStack* lightStacks, 01047 uint lightNum, uint subLightNum) 01048 { 01049 LightingVariablesHelper lightVarsHelper (viewSetup.persist.lightVarsPersist); 01050 01051 if (persist.settings.provideIDs && !singleMesh.svMeshID.IsValid()) 01052 { 01053 singleMesh.svMeshID = lightVarsHelper.CreateTempSV ( 01054 viewSetup.persist.settings.svMeshIDName); 01055 lightStacks[0][singleMesh.svMeshID->GetName()] = singleMesh.svMeshID; 01056 uint meshID = ++viewSetup.lastMeshID; 01057 singleMesh.svMeshID->SetValue ((int)meshID); 01058 viewSetup.meshIDs.Put (singleMesh.meshObjSVs, singleMesh.svMeshID); 01059 } 01060 01061 typename CachedLightData::LightFrustumsArray& lightFrustums = 01062 lightData.lightFrustumsHash.GetElementPointer ( 01063 viewSetup.rview->GetCamera())->frustums; 01064 typename CachedLightData::SuperFrustum& superFrust = 01065 *(lightFrustums[subLightNum]); 01066 01067 csBox3 meshBboxLS; 01068 csVector3 vLight; 01069 csBox3 meshBboxWorld (singleMesh.renderMesh->object2world.This2Other ( 01070 singleMesh.renderMesh->bbox)); 01071 vLight = superFrust.world2light_rotated.Other2This ( 01072 meshBboxWorld.GetCorner (0)); 01073 meshBboxLS.StartBoundingBox (csVector3 (vLight.x, 01074 vLight.y, vLight.z)); 01075 csBox3 meshBboxLightPP; 01076 csVector4 vLightPP; 01077 vLightPP = lightData.lightProject * csVector4 (vLight); 01078 //vLightPP /= vLightPP.w; 01079 meshBboxLightPP.StartBoundingBox (csVector3 (vLightPP.x, 01080 vLightPP.y, vLightPP.z)); 01081 for (int c = 1; c < 8; c++) 01082 { 01083 vLight = superFrust.world2light_rotated.Other2This ( 01084 meshBboxWorld.GetCorner (c)); 01085 meshBboxLS.AddBoundingVertexSmart (csVector3 (vLight.x, 01086 vLight.y, vLight.z)); 01087 vLightPP = lightData.lightProject * csVector4 (vLight); 01088 //vLightPP /= vLightPP.w; 01089 meshBboxLightPP.AddBoundingVertexSmart (csVector3 (vLightPP.x, 01090 vLightPP.y, vLightPP.z)); 01091 } 01092 /*csPrintf ("%s -> %s\n", 01093 singleMesh.meshWrapper->QueryObject()->GetName(), 01094 meshBboxLightPP.Description().GetData());*/ 01095 01096 if (!superFrust.lightBBoxLS.TestIntersect (meshBboxLS)) 01097 //if (!lightFrustum.volumePP.TestIntersect (meshBboxLightPP)) 01098 { 01099 return 0; 01100 } 01101 01102 if (persist.limitedShadow) 01103 { 01104 if (singleMesh.meshFlags.Check (CS_ENTITY_LIMITEDSHADOWCAST)) 01105 { 01106 superFrust.meshFilter.AddFilterMesh (singleMesh.meshWrapper); 01107 superFrust.castingObjectsBBoxPP += meshBboxLightPP; 01108 /* Here's a stupid bug: limited shadow casters which are outside 01109 the view won't cast shadows */ 01110 } 01111 } 01112 else 01113 { 01114 if (!singleMesh.meshFlags.Check (CS_ENTITY_NOSHADOWCAST)) 01115 { 01116 // Mesh casts shadow 01117 superFrust.castingObjectsBBoxPP += meshBboxLightPP; 01118 } 01119 else 01120 { 01121 // Mesh does not cast shadow 01122 superFrust.meshFilter.AddFilterMesh (singleMesh.meshWrapper); 01123 } 01124 } 01125 01126 01127 uint spreadFlags = 0; 01128 if (!singleMesh.meshFlags.Check (CS_ENTITY_NOSHADOWRECEIVE)) 01129 { 01130 csBox3 meshBBoxView = 01131 viewSetup.rview->GetCamera()->GetTransform().Other2This ( 01132 meshBboxWorld); 01133 int s = 0; 01134 for (int f = 0; f < superFrust.actualNumParts; f++) 01135 { 01136 typename CachedLightData::SuperFrustum::Frustum& lightFrustum = 01137 superFrust.frustums[f]; 01138 //if (lightFrustum.volumePP.Empty()) continue; 01139 // Clip mesh to view split ... 01140 if ((meshBBoxView.MaxZ() < viewSetup.splitDists[f]) 01141 || (meshBBoxView.MinZ() > viewSetup.splitDists[f+1])) 01142 continue; 01143 // ... and light frustum in view split (might be a bit smaller) 01144 if (!lightFrustum.volumePP.Overlap (meshBboxLightPP)) continue; 01145 01146 lightFrustum.receivingObjectsBBoxPP += meshBboxLightPP; 01147 01148 // Add shadow map SVs 01149 lightVarsHelper.MergeAsArrayItem (lightStacks[s], 01150 lightFrustum.shadowMapProjectSV, lightNum); 01151 lightVarsHelper.MergeAsArrayItem (lightStacks[s], 01152 lightFrustum.shadowMapUnscaleSV, lightNum); 01153 lightVarsHelper.MergeAsArrayItem (lightStacks[s], 01154 lightFrustum.shadowMapDimSV, lightNum); 01155 if (lightStacks[s].GetSize() > lightFrustum.shadowClipSV->GetName()) 01156 { 01157 lightStacks[s][lightFrustum.shadowClipSV->GetName()] = 01158 lightFrustum.shadowClipSV; 01159 } 01160 01161 for (size_t t = 0; t < persist.settings.targets.GetSize(); t++) 01162 { 01163 const ShadowSettings::Target* target = 01164 viewSetup.persist.settings.targets[t]; 01165 lightVarsHelper.MergeAsArrayItem (lightStacks[s], 01166 lightFrustum.textureSVs[target->attachment], lightNum); 01167 } 01168 spreadFlags |= (1 << s); 01169 s++; 01170 } 01171 } 01172 else 01173 spreadFlags = 1; 01174 return spreadFlags; 01175 } 01176 01177 static bool NeedFinalHandleLight() { return true; } 01178 void FinalHandleLight (iLight* light, CachedLightData& lightData) 01179 { 01180 lightData.AddShadowMapTarget (meshNode, persist, 01181 viewSetup.depthRenderLayer, renderTree, light, viewSetup); 01182 01183 lightData.ClearFrameData(); 01184 } 01185 01186 csFlags GetLightFlagsMask () const { return csFlags (0); } 01187 01188 size_t GetLightLayerSpread() const { return viewSetup.numParts; } 01189 protected: 01190 PersistentData& persist; 01191 const LayerConfigType& layerConfig; 01192 RenderTree& renderTree; 01193 typename RenderTree::MeshNode* meshNode; 01194 ViewSetup& viewSetup; 01195 }; 01196 01197 } 01198 } 01199 01200 #endif // __CS_CSPLUGINCOMMON_RENDERMANAGER_SHADOW_PSSM_H__
Generated for Crystal Space 2.1 by doxygen 1.6.1
