00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
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
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
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
00162 CS::Math::Matrix4 lightProject;
00163 struct SuperFrustum : public CS::Utility::FastRefCount<SuperFrustum>
00164 {
00165 int actualNumParts;
00166
00167 csReversibleTransform world2light_base;
00168 csReversibleTransform world2light_rotated;
00169 csMatrix3 frustumRotation;
00170
00171 csBox3 lightBBoxLS;
00172
00173
00174
00175 csBox3 castingObjectsBBoxPP;
00176 csBox3 lightBBoxPP;
00177
00178 CS::Utility::MeshFilter meshFilter;
00179
00180 struct Frustum
00181 {
00182 bool draw;
00183
00184 csBox3 volumePP;
00185
00186
00187
00188 csRef<csShaderVariable> shadowMapProjectSV;
00189 csRef<csShaderVariable> shadowMapUnscaleSV;
00190 csRef<csShaderVariable> shadowMapDimSV;
00191 csRef<csShaderVariable> shadowClipSV;
00192 csRef<csShaderVariable> textureSVs[rtaNumAttachments];
00193
00194
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
00270
00271
00272 lightProject = flipZW * CS::Math::Projections::Frustum (
00273 lightCutoff, -lightCutoff, lightCutoff, -lightCutoff,
00274 -lightCutoff, -lightNear);
00275 }
00276 break;
00277 }
00278 this->sublightNum = numFrustums;
00279 this->lightProject = lightProject;
00280 lightProjectSetup = true;
00281 }
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302
00303
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 (),
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)
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
00338
00339
00340
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
00361
00362
00363 frustBBox *= lightBBox;
00364
00365
00366
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
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
00396 csVector3 cornerCam;
00397
00398 csVector3 cornerWorld;
00399
00400 csVector3 cornerLight;
00401
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
00483 csVector4 cornerUndiv;
00484
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
00495 lightFrustum.volumePP.AddBoundingVertex (cornerDiv);
00496 }
00497
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;
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
00538 csBox3 allVolumes;
00539 for (int frustNum = 0; frustNum < superFrust.actualNumParts; frustNum++)
00540 {
00541 const typename SuperFrustum::Frustum& lightFrust = superFrust.frustums[frustNum];
00542
00543
00544 bool partFixed = viewSetup.doFixedCloseShadow && (frustNum == 0);
00545
00546 allVolumes += lightFrust.volumePP;
00547 csBox3 castersBox = allCastersBoxPP;
00548
00549
00550
00551
00552
00553
00554
00555 csBox3 receiversBox;
00556 if (!partFixed)
00557 {
00558 receiversBox = lightFrust.receivingObjectsBBoxPP;
00559
00560
00561
00562 }
00563 else
00564 {
00565 castersBox = receiversBox = lightFrust.volumePP;
00566 }
00567 receiversBox *= clipToView;
00568
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
00578
00579
00580
00581
00582 float n = superFrust.lightBBoxPP.MinZ();
00583 float f = csMin (castersBox.MaxZ(), receiversBox.MaxZ()) + EPSILON;
00584
00585
00586 CS::Math::Matrix4 crop;
00587 if (!lightFrust.draw)
00588 {
00589
00590
00591
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
00604
00605
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
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
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
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
00743
00744
00745
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
00755 ShadowmapContextSetup contextFunction (layerConfig,
00756 persist.shaderManager, viewSetup, persist.settings.provideIDs);
00757 contextFunction (*shadowMapCtx);
00758 }
00759 }
00760 }
00761
00762 void ClearFrameData()
00763 {
00764
00765
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
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
00861 rview->SetThisSector (sector);
00862 sector->CallSectorCallbacks (rview);
00863
00864 CS::RenderViewClipper::SetupClipPlanes (rview->GetRenderContext ());
00865
00866 if (context.owner.IsDebugFlagEnabled (
00867 viewSetup.persist.dbgSplitFrustumLight))
00868 context.owner.AddDebugClipPlanes (rview);
00869
00870
00871 iVisibilityCuller* culler = sector->GetVisibilityCuller ();
00872 Viscull<RenderTree> (context, rview, culler);
00873
00874
00875
00876
00877 {
00878 StandardMeshSorter<RenderTree> mySorter (rview->GetEngine ());
00879 mySorter.SetupCameraLocation (rview->GetCamera ()->GetTransform ().GetOrigin ());
00880 ForEachMeshNode (context, mySorter);
00881 }
00882
00883
00884 {
00885 SingleMeshContextNumbering<RenderTree> numbering;
00886 ForEachMeshNode (context, numbering);
00887 }
00888
00889
00890
00891 SetupStandardSVs (context, layerConfig, shaderManager, sector);
00892
00893
00894 {
00895 StandardSVSetup<RenderTree, SingleRenderLayer> svSetup (
00896 context.svArrays, layerConfig);
00897
00898 ForEachMeshNode (context, svSetup);
00899 }
00900
00901 if (doIDTexture)
00902 {
00903 MeshIDSVSetup svSetup (context.svArrays, viewSetup);
00904
00905 ForEachMeshNode (context, svSetup);
00906 }
00907
00908 SetupStandardShader (context, shaderManager, layerConfig);
00909
00910
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
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
01088 meshBboxLightPP.AddBoundingVertexSmart (csVector3 (vLightPP.x,
01089 vLightPP.y, vLightPP.z));
01090 }
01091
01092
01093
01094
01095 if (!superFrust.lightBBoxLS.TestIntersect (meshBboxLS))
01096
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
01108
01109 }
01110 }
01111 else
01112 {
01113 if (!singleMesh.meshFlags.Check (CS_ENTITY_NOSHADOWCAST))
01114 {
01115
01116 superFrust.castingObjectsBBoxPP += meshBboxLightPP;
01117 }
01118 else
01119 {
01120
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
01138
01139 if ((meshBBoxView.MaxZ() < viewSetup.splitDists[f])
01140 || (meshBBoxView.MinZ() > viewSetup.splitDists[f+1]))
01141 continue;
01142
01143 if (!lightFrustum.volumePP.Overlap (meshBboxLightPP)) continue;
01144
01145 lightFrustum.receivingObjectsBBoxPP += meshBboxLightPP;
01146
01147
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__