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->SetEngine (rview->GetEngine ()); 00575 newRenderView->SetThisSector (rview->GetThisSector ()); 00576 00577 /* The minimum Z over all parts is used to avoid clipping shadows of 00578 casters closer to the light than the split plane. 00579 Ideally, allObjsBoxPP.MinZ() would be mapped to depth -1, and depths 00580 below clamped */ 00581 // FIXME, again: should better be allCastersBoxPP.MinZ(); 00582 float n = superFrust.lightBBoxPP.MinZ(); 00583 float f = csMin (castersBox.MaxZ(), receiversBox.MaxZ()) + EPSILON; 00584 /* Sometimes n==f which would result in an invalid matrix w/o EPSILON */ 00585 00586 CS::Math::Matrix4 crop; 00587 if (!lightFrust.draw) 00588 { 00589 /* Case: a frustum slice does not intersect with the light 00590 frustum: Just make sure the frustum is clipped correctly, 00591 actual SM or SM transform doesn't matter much */ 00592 crop = CS::Math::Matrix4 ( 00593 0, 0, 0, 10, 00594 0, 0, 0, 10, 00595 0, 0, 1, 0, 00596 0, 0, 0, 1); 00597 00598 lightFrust.shadowMapUnscaleSV->SetValue (csVector4 ( 00599 0, 0, -10, -10)); 00600 } 00601 else if (noCasters) 00602 { 00603 /* Case: a frustum slice doesn't have any shadow casters. 00604 All shadow receivers are unshadowed (the empty SM is used 00605 for that), but also the frustum must be clipped correctly. */ 00606 crop = CS::Math::Matrix4 ( 00607 1, 0, 0, 0, 00608 0, 1, 0, 0, 00609 0, 0, 1, 0, 00610 0, 0, 0, 1); 00611 00612 lightFrust.shadowMapUnscaleSV->SetValue (csVector4 ( 00613 1, 1, 0, 0)); 00614 00615 f = 1.0f; 00616 n = f - EPSILON; 00617 } 00618 else 00619 { 00620 const float focusMinX = csMax (receiversBox.MinX(), castersBox.MinX()); 00621 const float focusMinY = csMax (receiversBox.MinY(), castersBox.MinY()); 00622 const float focusMaxX = csMin (receiversBox.MaxX(), castersBox.MaxX()); 00623 const float focusMaxY = csMin (receiversBox.MaxY(), castersBox.MaxY()); 00624 const float frustW = focusMaxX - focusMinX; 00625 const float frustH = focusMaxY - focusMinY; 00626 const float cropScaleX = 2.0f/frustW; 00627 const float cropScaleY = 2.0f/frustH; 00628 const float cropShiftX = 00629 (-1.0f * (focusMaxX + focusMinX))/frustW; 00630 const float cropShiftY = 00631 (-1.0f * (focusMaxY + focusMinY))/frustH; 00632 crop = CS::Math::Matrix4 ( 00633 cropScaleX, 0, 0, cropShiftX, 00634 0, cropScaleY, 0, cropShiftY, 00635 0, 0, 1, 0, 00636 0, 0, 0, 1); 00637 00638 const float uncropScaleX = 1.0f/cropScaleX; 00639 const float uncropScaleY = 1.0f/cropScaleY; 00640 const float uncropShiftX = -cropShiftX/cropScaleX; 00641 const float uncropShiftY = -cropShiftY/cropScaleY; 00642 lightFrust.shadowMapUnscaleSV->SetValue (csVector4 ( 00643 uncropScaleX, uncropScaleY, uncropShiftX, uncropShiftY)); 00644 } 00645 00646 CS::Math::Matrix4 Mortho = CS::Math::Projections::Ortho (-1, 1, 1, -1, 00647 f, n); 00648 CS::Math::Matrix4 matrix = ((Mortho * crop) * lightProject) 00649 * CS::Math::Matrix4 (superFrust.frustumRotation); 00650 00651 for (int i = 0; i < 4; i++) 00652 { 00653 csShaderVariable* item = lightFrust.shadowMapProjectSV->GetArrayElement (i); 00654 item->SetValue (matrix.Row (i)); 00655 } 00656 00657 int shadowMapSize; 00658 if (partFixed) 00659 shadowMapSize = persist.shadowMapResClose; 00660 else 00661 { 00662 switch (light->GetType()) 00663 { 00664 default: 00665 case CS_LIGHT_DIRECTIONAL: 00666 shadowMapSize = persist.shadowMapResD; 00667 break; 00668 case CS_LIGHT_POINTLIGHT: 00669 shadowMapSize = persist.shadowMapResP; 00670 break; 00671 case CS_LIGHT_SPOTLIGHT: 00672 shadowMapSize = persist.shadowMapResS; 00673 break; 00674 } 00675 } 00676 lightFrust.shadowMapDimSV->SetValue (csVector4 (1.0f/shadowMapSize, 00677 1.0f/shadowMapSize, shadowMapSize, shadowMapSize)); 00678 00679 if (!lightFrust.draw) 00680 { 00681 for (size_t t = 0; t < persist.settings.targets.GetSize(); t++) 00682 { 00683 // Should not be used anyway 00684 const ShadowSettings::Target* target = 00685 viewSetup.persist.settings.targets[t]; 00686 lightFrust.textureSVs[target->attachment]->SetValue (0); 00687 } 00688 continue; 00689 } 00690 else if (noCasters) 00691 { 00692 for (size_t t = 0; t < persist.settings.targets.GetSize(); t++) 00693 { 00694 // Can be 0 when using 1 light max 00695 const ShadowSettings::Target* target = 00696 viewSetup.persist.settings.targets[t]; 00697 lightFrust.textureSVs[target->attachment]->SetValue ( 00698 GetEmptyShadowMap (persist, t, context)); 00699 } 00700 continue; 00701 } 00702 00703 csReversibleTransform view = superFrust.world2light_base; 00704 00705 csRef<iCustomMatrixCamera> shadowViewCam = 00706 newRenderView->GetEngine()->CreateCustomMatrixCamera(); 00707 newRenderView->SetCamera (shadowViewCam->GetCamera()); 00708 shadowViewCam->SetProjectionMatrix (matrix); 00709 shadowViewCam->GetCamera()->SetTransform (view); 00710 00711 for (size_t t = 0; t < persist.settings.targets.GetSize(); t++) 00712 { 00713 ShadowSettings::Target* target = 00714 viewSetup.persist.settings.targets[t]; 00715 iTextureHandle* tex = target->texCache.QueryUnusedTexture ( 00716 shadowMapSize, shadowMapSize); 00717 lightFrust.textureSVs[target->attachment]->SetValue (tex); 00718 if (renderTree.IsDebugFlagEnabled (persist.dbgShadowTex)) 00719 renderTree.AddDebugTexture (tex); 00720 texHandles[target->attachment] = tex; 00721 } 00722 00723 newRenderView->SetViewDimensions (shadowMapSize, shadowMapSize); 00724 csBox2 clipBox (0, 0, shadowMapSize, shadowMapSize); 00725 csRef<iClipper2D> newView; 00726 newView.AttachNew (new csBoxClipper (clipBox)); 00727 newRenderView->SetClipper (newView); 00728 newRenderView->SetMeshFilter(superFrust.meshFilter); 00729 00730 // Create a new context for shadow map w/ computed view 00731 typename RenderTree::ContextNode* shadowMapCtx = 00732 renderTree.CreateContext (newRenderView); 00733 for (size_t t = 0; t < persist.settings.targets.GetSize(); t++) 00734 { 00735 shadowMapCtx->renderTargets[ 00736 persist.settings.targets[t]->attachment].texHandle = 00737 texHandles[t]; 00738 } 00739 shadowMapCtx->drawFlags = CSDRAW_CLEARSCREEN | CSDRAW_CLEARZBUFFER; 00740 shadowMapCtx->postEffects = persist.settings.postEffects; 00741 00742 /* @@@ FIXME: This will break as soon as the shadowmaps have 00743 different resolutions! 00744 Probably the post effects manager should be changed to handle 00745 changing resolutions well */ 00746 if (shadowMapCtx->postEffects.IsValid()) 00747 { 00748 CS::Math::Matrix4 perspectiveFixup; 00749 shadowMapCtx->postEffects->SetupView (shadowMapSize, shadowMapSize, 00750 perspectiveFixup); 00751 shadowMapCtx->perspectiveFixup = perspectiveFixup; 00752 } 00753 00754 // Setup the new context 00755 ShadowmapContextSetup contextFunction (layerConfig, 00756 persist.shaderManager, viewSetup, persist.settings.provideIDs); 00757 contextFunction (*shadowMapCtx); 00758 } 00759 } 00760 } 00761 00762 void ClearFrameData() 00763 { 00764 //frustumsSetup = false; 00765 //lightFrustums.Empty(); 00766 lightProjectSetup = false; 00767 } 00768 00769 iTextureHandle* GetEmptyShadowMap (PersistentData& persist, size_t target, 00770 typename RenderTree::ContextNode& context) 00771 { 00772 if (persist.emptySMs.GetSize() == 0) 00773 { 00774 CS::RenderManager::RenderView* rview = context.renderView; 00775 csRef<CS::RenderManager::RenderView> newRenderView; 00776 newRenderView = context.owner.GetPersistentData().renderViews.CreateRenderView (); 00777 newRenderView->SetEngine (rview->GetEngine ()); 00778 newRenderView->SetViewDimensions (1, 1); 00779 00780 csRef<iCustomMatrixCamera> shadowViewCam = 00781 newRenderView->GetEngine()->CreateCustomMatrixCamera(); 00782 newRenderView->SetCamera (shadowViewCam->GetCamera()); 00783 00784 csBox2 clipBox (0, 0, 1, 1); 00785 csRef<iClipper2D> newView; 00786 newView.AttachNew (new csBoxClipper (clipBox)); 00787 newRenderView->SetClipper (newView); 00788 00789 persist.emptySMs.SetSize (persist.settings.targets.GetSize()); 00790 00791 typename RenderTree::ContextNode* shadowMapCtx = 00792 context.owner.CreateContext (newRenderView); 00793 for (size_t t = 0; t < persist.settings.targets.GetSize(); t++) 00794 { 00795 csRef<iTextureHandle> tex = persist.g3d->GetTextureManager() 00796 ->CreateTexture (1, 1, csimg2D, 00797 persist.settings.targets[t]->texCache.GetFormat(), 00798 persist.settings.targets[t]->texCache.GetFlags ()); 00799 persist.emptySMs.Put (t, tex); 00800 shadowMapCtx->renderTargets[ 00801 persist.settings.targets[t]->attachment].texHandle = tex; 00802 } 00803 shadowMapCtx->drawFlags = CSDRAW_CLEARSCREEN | CSDRAW_CLEARZBUFFER; 00804 } 00805 return persist.emptySMs[target]; 00806 } 00807 }; 00808 private: 00809 class ShadowmapContextSetup 00810 { 00811 class MeshIDSVSetup 00812 { 00813 public: 00814 MeshIDSVSetup (SVArrayHolder& svArrays, ViewSetup& viewSetup) 00815 : svArrays (svArrays), viewSetup (viewSetup) 00816 { 00817 tempStack.Setup (svArrays.GetNumSVNames ()); 00818 } 00819 00820 void operator() (typename RenderTree::MeshNode* node) 00821 { 00822 for (size_t i = 0; i < node->meshes.GetSize (); ++i) 00823 { 00824 typename RenderTree::MeshNode::SingleMesh& mesh = node->meshes[i]; 00825 csShaderVariable* svMeshID = viewSetup.meshIDs.Get (mesh.meshObjSVs, 0); 00826 if (!svMeshID) continue; 00827 00828 tempStack[svMeshID->GetName()] = svMeshID; 00829 00830 for (size_t layer = 0; layer < svArrays.GetNumLayers(); ++layer) 00831 { 00832 // Back-merge it onto the real one 00833 csShaderVariableStack localStack; 00834 svArrays.SetupSVStack (localStack, layer, mesh.contextLocalId); 00835 localStack.MergeFront (tempStack); 00836 } 00837 } 00838 } 00839 00840 private: 00841 SVArrayHolder& svArrays; 00842 csShaderVariableStack tempStack; 00843 ViewSetup& viewSetup; 00844 }; 00845 public: 00846 ShadowmapContextSetup (const SingleRenderLayer& layerConfig, 00847 iShaderManager* shaderManager, ViewSetup& viewSetup, 00848 bool doIDTexture) 00849 : layerConfig (layerConfig), shaderManager (shaderManager), 00850 viewSetup (viewSetup), doIDTexture (doIDTexture) 00851 { 00852 00853 } 00854 00855 void operator() (typename RenderTree::ContextNode& context) 00856 { 00857 CS::RenderManager::RenderView* rview = context.renderView; 00858 iSector* sector = rview->GetThisSector (); 00859 00860 // @@@ This is somewhat "boilerplate" sector/rview setup. 00861 rview->SetThisSector (sector); 00862 sector->CallSectorCallbacks (rview); 00863 // Make sure the clip-planes are ok 00864 CS::RenderViewClipper::SetupClipPlanes (rview->GetRenderContext ()); 00865 00866 if (context.owner.IsDebugFlagEnabled ( 00867 viewSetup.persist.dbgSplitFrustumLight)) 00868 context.owner.AddDebugClipPlanes (rview); 00869 00870 // Do the culling 00871 iVisibilityCuller* culler = sector->GetVisibilityCuller (); 00872 Viscull<RenderTree> (context, rview, culler); 00873 00874 // TODO: portals 00875 00876 // Sort the mesh lists 00877 { 00878 StandardMeshSorter<RenderTree> mySorter (rview->GetEngine ()); 00879 mySorter.SetupCameraLocation (rview->GetCamera ()->GetTransform ().GetOrigin ()); 00880 ForEachMeshNode (context, mySorter); 00881 } 00882 00883 // After sorting, assign in-context per-mesh indices 00884 { 00885 SingleMeshContextNumbering<RenderTree> numbering; 00886 ForEachMeshNode (context, numbering); 00887 } 00888 00889 // Setup the SV arrays 00890 // Push the default stuff 00891 SetupStandardSVs (context, layerConfig, shaderManager, sector); 00892 00893 // Setup the material&mesh SVs 00894 { 00895 StandardSVSetup<RenderTree, SingleRenderLayer> svSetup ( 00896 context.svArrays, layerConfig); 00897 00898 ForEachMeshNode (context, svSetup); 00899 } 00900 // Set up mesh ID SVs 00901 if (doIDTexture) 00902 { 00903 MeshIDSVSetup svSetup (context.svArrays, viewSetup); 00904 00905 ForEachMeshNode (context, svSetup); 00906 } 00907 00908 SetupStandardShader (context, shaderManager, layerConfig); 00909 00910 // Setup shaders and tickets 00911 SetupStandardTicket (context, shaderManager, layerConfig); 00912 } 00913 00914 00915 private: 00916 const SingleRenderLayer& layerConfig; 00917 iShaderManager* shaderManager; 00918 ViewSetup& viewSetup; 00919 bool doIDTexture; 00920 }; 00921 public: 00922 00927 struct PersistentData 00928 { 00929 uint dbgSplitFrustumCam; 00930 uint dbgSplitFrustumLight; 00931 uint dbgLightBBox; 00932 uint dbgShadowTex; 00933 uint dbgFlagShadowClipPlanes; 00934 csLightShaderVarCache svNames; 00935 CS::ShaderVarStringID unscaleSVName; 00936 CS::ShaderVarStringID shadowClipSVName; 00937 LightingSorter::PersistentData lightSorterPersist; 00938 LightingVariablesHelper::PersistentData lightVarsPersist; 00939 iShaderManager* shaderManager; 00940 csRefArray<iTextureHandle> emptySMs; 00941 iGraphics3D* g3d; 00942 00943 csString configPrefix; 00944 ShadowSettings settings; 00945 00946 bool limitedShadow; 00947 int shadowMapResD, shadowMapResP, shadowMapResS; 00948 int shadowMapResClose; 00949 int numSplits; 00950 float farZ; 00951 float fixedCloseShadow; 00952 00953 PersistentData() : limitedShadow (false) 00954 { 00955 } 00956 00957 ~PersistentData() 00958 { 00959 } 00960 00962 void SetConfigPrefix (const char* configPrefix) 00963 { 00964 this->configPrefix = configPrefix; 00965 } 00966 00967 void Initialize (iObjectRegistry* objectReg, 00968 RenderTreeBase::DebugPersistent& dbgPersist) 00969 { 00970 csRef<iShaderManager> shaderManager = 00971 csQueryRegistry<iShaderManager> (objectReg); 00972 csRef<iGraphics3D> g3d = 00973 csQueryRegistry<iGraphics3D> (objectReg); 00974 00975 this->shaderManager = shaderManager; 00976 this->g3d = g3d; 00977 iShaderVarStringSet* strings = shaderManager->GetSVNameStringset(); 00978 svNames.SetStrings (strings); 00979 00980 csConfigAccess cfg (objectReg); 00981 if (configPrefix.IsEmpty()) 00982 { 00983 settings.ReadSettings (objectReg, "Depth"); 00984 } 00985 else 00986 { 00987 settings.ReadSettings (objectReg, 00988 cfg->GetStr ( 00989 csString().Format ("%s.ShadowsType", configPrefix.GetData()), "Depth")); 00990 limitedShadow = cfg->GetBool ( 00991 csString().Format ("%s.LimitedShadow", configPrefix.GetData()), false); 00992 numSplits = cfg->GetInt ( 00993 csString().Format ("%s.NumSplits", configPrefix.GetData()), 2); 00994 farZ = cfg->GetFloat ( 00995 csString().Format ("%s.FarZ", configPrefix.GetData()), 100); 00996 int shadowMapRes = cfg->GetInt ( 00997 csString().Format ("%s.ShadowMapResolution", configPrefix.GetData()), 512); 00998 shadowMapResD = cfg->GetInt ( 00999 csString().Format ("%s.ShadowMapResolution.Directional", configPrefix.GetData()), 01000 shadowMapRes); 01001 shadowMapResP = cfg->GetInt ( 01002 csString().Format ("%s.ShadowMapResolution.Point", configPrefix.GetData()), 01003 shadowMapRes/2); 01004 shadowMapResS = cfg->GetInt ( 01005 csString().Format ("%s.ShadowMapResolution.Spot", configPrefix.GetData()), 01006 shadowMapRes/2); 01007 shadowMapResClose = cfg->GetInt ( 01008 csString().Format ("%s.CloseShadowMapResolution", configPrefix.GetData()), 01009 shadowMapRes); 01010 fixedCloseShadow = cfg->GetFloat ( 01011 csString().Format ("%s.FixedCloseShadow", configPrefix.GetData()), 0); 01012 } 01013 01014 unscaleSVName = strings->Request ("light shadow map unscale"); 01015 shadowClipSVName = strings->Request ("light shadow clip"); 01016 01017 dbgSplitFrustumCam = dbgPersist.RegisterDebugFlag ("draw.pssm.split.frustum.cam"); 01018 dbgSplitFrustumLight = dbgPersist.RegisterDebugFlag ("draw.pssm.split.frustum.light"); 01019 dbgLightBBox = dbgPersist.RegisterDebugFlag ("draw.pssm.lightbbox"); 01020 dbgShadowTex = dbgPersist.RegisterDebugFlag ("textures.shadow"); 01021 dbgFlagShadowClipPlanes = 01022 dbgPersist.RegisterDebugFlag ("draw.clipplanes.shadow"); 01023 } 01024 void UpdateNewFrame () 01025 { 01026 csTicks time = csGetTicks (); 01027 settings.AdvanceFrame (time); 01028 lightVarsPersist.UpdateNewFrame(); 01029 } 01030 }; 01031 01032 typedef ViewSetup ShadowParameters; 01033 01034 ShadowPSSM (PersistentData& persist, 01035 const LayerConfigType& layerConfig, 01036 typename RenderTree::MeshNode* node, 01037 ViewSetup& viewSetup) 01038 : persist (persist), layerConfig (layerConfig), 01039 renderTree (node->GetOwner().owner), meshNode (node), 01040 viewSetup (viewSetup) 01041 { } 01042 01043 uint HandleOneLight (typename RenderTree::MeshNode::SingleMesh& singleMesh, 01044 iLight* light, CachedLightData& lightData, 01045 csShaderVariableStack* lightStacks, 01046 uint lightNum, uint subLightNum) 01047 { 01048 LightingVariablesHelper lightVarsHelper (viewSetup.persist.lightVarsPersist); 01049 01050 if (persist.settings.provideIDs && !singleMesh.svMeshID.IsValid()) 01051 { 01052 singleMesh.svMeshID = lightVarsHelper.CreateTempSV ( 01053 viewSetup.persist.settings.svMeshIDName); 01054 lightStacks[0][singleMesh.svMeshID->GetName()] = singleMesh.svMeshID; 01055 uint meshID = ++viewSetup.lastMeshID; 01056 singleMesh.svMeshID->SetValue ((int)meshID); 01057 viewSetup.meshIDs.Put (singleMesh.meshObjSVs, singleMesh.svMeshID); 01058 } 01059 01060 typename CachedLightData::LightFrustumsArray& lightFrustums = 01061 lightData.lightFrustumsHash.GetElementPointer ( 01062 viewSetup.rview->GetCamera())->frustums; 01063 typename CachedLightData::SuperFrustum& superFrust = 01064 *(lightFrustums[subLightNum]); 01065 01066 csBox3 meshBboxLS; 01067 csVector3 vLight; 01068 csBox3 meshBboxWorld (singleMesh.renderMesh->object2world.This2Other ( 01069 singleMesh.renderMesh->bbox)); 01070 vLight = superFrust.world2light_rotated.Other2This ( 01071 meshBboxWorld.GetCorner (0)); 01072 meshBboxLS.StartBoundingBox (csVector3 (vLight.x, 01073 vLight.y, vLight.z)); 01074 csBox3 meshBboxLightPP; 01075 csVector4 vLightPP; 01076 vLightPP = lightData.lightProject * csVector4 (vLight); 01077 //vLightPP /= vLightPP.w; 01078 meshBboxLightPP.StartBoundingBox (csVector3 (vLightPP.x, 01079 vLightPP.y, vLightPP.z)); 01080 for (int c = 1; c < 8; c++) 01081 { 01082 vLight = superFrust.world2light_rotated.Other2This ( 01083 meshBboxWorld.GetCorner (c)); 01084 meshBboxLS.AddBoundingVertexSmart (csVector3 (vLight.x, 01085 vLight.y, vLight.z)); 01086 vLightPP = lightData.lightProject * csVector4 (vLight); 01087 //vLightPP /= vLightPP.w; 01088 meshBboxLightPP.AddBoundingVertexSmart (csVector3 (vLightPP.x, 01089 vLightPP.y, vLightPP.z)); 01090 } 01091 /*csPrintf ("%s -> %s\n", 01092 singleMesh.meshWrapper->QueryObject()->GetName(), 01093 meshBboxLightPP.Description().GetData());*/ 01094 01095 if (!superFrust.lightBBoxLS.TestIntersect (meshBboxLS)) 01096 //if (!lightFrustum.volumePP.TestIntersect (meshBboxLightPP)) 01097 { 01098 return 0; 01099 } 01100 01101 if (persist.limitedShadow) 01102 { 01103 if (singleMesh.meshFlags.Check (CS_ENTITY_LIMITEDSHADOWCAST)) 01104 { 01105 superFrust.meshFilter.AddFilterMesh (singleMesh.meshWrapper); 01106 superFrust.castingObjectsBBoxPP += meshBboxLightPP; 01107 /* Here's a stupid bug: limited shadow casters which are outside 01108 the view won't cast shadows */ 01109 } 01110 } 01111 else 01112 { 01113 if (!singleMesh.meshFlags.Check (CS_ENTITY_NOSHADOWCAST)) 01114 { 01115 // Mesh casts shadow 01116 superFrust.castingObjectsBBoxPP += meshBboxLightPP; 01117 } 01118 else 01119 { 01120 // Mesh does not cast shadow 01121 superFrust.meshFilter.AddFilterMesh (singleMesh.meshWrapper); 01122 } 01123 } 01124 01125 01126 uint spreadFlags = 0; 01127 if (!singleMesh.meshFlags.Check (CS_ENTITY_NOSHADOWRECEIVE)) 01128 { 01129 csBox3 meshBBoxView = 01130 viewSetup.rview->GetCamera()->GetTransform().Other2This ( 01131 meshBboxWorld); 01132 int s = 0; 01133 for (int f = 0; f < superFrust.actualNumParts; f++) 01134 { 01135 typename CachedLightData::SuperFrustum::Frustum& lightFrustum = 01136 superFrust.frustums[f]; 01137 //if (lightFrustum.volumePP.Empty()) continue; 01138 // Clip mesh to view split ... 01139 if ((meshBBoxView.MaxZ() < viewSetup.splitDists[f]) 01140 || (meshBBoxView.MinZ() > viewSetup.splitDists[f+1])) 01141 continue; 01142 // ... and light frustum in view split (might be a bit smaller) 01143 if (!lightFrustum.volumePP.Overlap (meshBboxLightPP)) continue; 01144 01145 lightFrustum.receivingObjectsBBoxPP += meshBboxLightPP; 01146 01147 // Add shadow map SVs 01148 lightVarsHelper.MergeAsArrayItem (lightStacks[s], 01149 lightFrustum.shadowMapProjectSV, lightNum); 01150 lightVarsHelper.MergeAsArrayItem (lightStacks[s], 01151 lightFrustum.shadowMapUnscaleSV, lightNum); 01152 lightVarsHelper.MergeAsArrayItem (lightStacks[s], 01153 lightFrustum.shadowMapDimSV, lightNum); 01154 if (lightStacks[s].GetSize() > lightFrustum.shadowClipSV->GetName()) 01155 { 01156 lightStacks[s][lightFrustum.shadowClipSV->GetName()] = 01157 lightFrustum.shadowClipSV; 01158 } 01159 01160 for (size_t t = 0; t < persist.settings.targets.GetSize(); t++) 01161 { 01162 const ShadowSettings::Target* target = 01163 viewSetup.persist.settings.targets[t]; 01164 lightVarsHelper.MergeAsArrayItem (lightStacks[s], 01165 lightFrustum.textureSVs[target->attachment], lightNum); 01166 } 01167 spreadFlags |= (1 << s); 01168 s++; 01169 } 01170 } 01171 else 01172 spreadFlags = 1; 01173 return spreadFlags; 01174 } 01175 01176 static bool NeedFinalHandleLight() { return true; } 01177 void FinalHandleLight (iLight* light, CachedLightData& lightData) 01178 { 01179 lightData.AddShadowMapTarget (meshNode, persist, 01180 viewSetup.depthRenderLayer, renderTree, light, viewSetup); 01181 01182 lightData.ClearFrameData(); 01183 } 01184 01185 csFlags GetLightFlagsMask () const { return csFlags (0); } 01186 01187 size_t GetLightLayerSpread() const { return viewSetup.numParts; } 01188 protected: 01189 PersistentData& persist; 01190 const LayerConfigType& layerConfig; 01191 RenderTree& renderTree; 01192 typename RenderTree::MeshNode* meshNode; 01193 ViewSetup& viewSetup; 01194 }; 01195 01196 } 01197 } 01198 01199 #endif // __CS_CSPLUGINCOMMON_RENDERMANAGER_SHADOW_PSSM_H__
Generated for Crystal Space 2.0 by doxygen 1.6.1