Project

General

Profile

SO3Engine
SO3ShadowCSM.cpp
Go to the documentation of this file.
1
11#include "SO3Renderer/SO3Root.h"
12
13 // GPU constants
14namespace Ogre
15{
16 //Singleton instance
17 template<> SO3::CSMGpuConstants* Ogre::Singleton<SO3::CSMGpuConstants>::msSingleton = 0;
18}
19
20namespace SO3
21{
23 {
24#ifdef RPI
25 return false;
26#endif
27
28 //test if shaders are supported by the card
29 const Ogre::RenderSystemCapabilities* caps = SRoot::getSingleton().GetOgreRenderSystem()->getCapabilities();
30
31 bool isSupported = true;
32 Ogre::PixelFormat rttformat;
33
34 bool pfsupport = SRoot::getSingleton().GetRttPixelFormat(rttformat, false, true);
35
36 isSupported = pfsupport && caps && caps->hasCapability(Ogre::RSC_VERTEX_PROGRAM) &&
37 caps->hasCapability(Ogre::RSC_FRAGMENT_PROGRAM) &&
38 caps->hasCapability(Ogre::RSC_NON_POWER_OF_2_TEXTURES) &&
39 (caps->isShaderProfileSupported("ps_3_0") || caps->isShaderProfileSupported("ps_4_0") || (caps->isShaderProfileSupported("arbfp1")) || (caps->isShaderProfileSupported("glsles")) || (caps->isShaderProfileSupported("glsl300es")));
40
41 if (isSupported)
42 Ogre::LogManager::getSingleton().logMessage("[SShadowCSM] is supported!");
43 else
44 Ogre::LogManager::getSingleton().logMessage("[SShadowCSM] is not supported!");
45
46 return isSupported;
47 }
48
49 SShadowCSM::SShadowCSM() : SShadow(0, "", SShadowManager::SO3_SHADOWS_CSM)
50 {
51 }
52
53 SShadowCSM::SShadowCSM(SShadowManager* sManager) : SShadow(sManager, "CSM", SShadowManager::SO3_SHADOWS_CSM)
54 {
55 //clear shadow textures
56 ogreScene->setShadowTechnique(static_cast <Ogre::ShadowTechnique> (Ogre::SHADOWDETAILTYPE_TEXTURE | Ogre::SHADOWDETAILTYPE_INTEGRATED | shadowManager->GetLightingTechnique()));
57
58 unsigned short quality = sManager->GetShadowQuality();
59 unsigned int textureCount = (quality <= SShadowManager::SO3_SHADOWS_QUALITY_MEDIUM) ? 2 : (quality == SShadowManager::SO3_SHADOWS_QUALITY_HIGH) ? 3 : 4;
60 ogreScene->setShadowCasterRenderBackFaces(true);
61 ogreScene->setShadowTextureSelfShadow(false);
62 ogreScene->setShadowTextureCount(textureCount);
63 ogreScene->setShadowDirLightTextureOffset(0.1f);
64 ogreScene->setShadowTextureFadeStart(mFadeStart);
65 ogreScene->setShadowTextureFadeEnd(mFadeEnd);
66
67 try
68 {
69 Ogre::MaterialPtr mcaster = Ogre::MaterialManager::getSingleton().getByName("SO3/CSM/ShadowCaster");
70 Ogre::MaterialPtr emptyMat;
71 ogreScene->setShadowTextureCasterMaterial(mcaster);
72 ogreScene->setShadowTextureReceiverMaterial(emptyMat);
73 }
74 catch (Ogre::Exception &e)
75 {
76 //can fail here is a material texture is missing
77 std::string error = e.what();
78 }
79
80 ogreScene->setShadowTextureCountPerLightType(Ogre::Light::LT_DIRECTIONAL, textureCount);
81 ogreScene->setShadowTextureCountPerLightType(Ogre::Light::LT_SPOTLIGHT, 0);
82 ogreScene->setShadowTextureCountPerLightType(Ogre::Light::LT_POINT, 0);
83
84 //get best format on device
86
87 ogreScene->setShadowTextureConfig(0, quality, quality, mRttFormat);
88 ogreScene->setShadowTextureConfig(1, quality, quality, mRttFormat);
89
90 if (textureCount >= 3)
91 ogreScene->setShadowTextureConfig(2, (unsigned short)(quality * 0.75f), (unsigned short)(quality * 0.75f), mRttFormat);
92 if (textureCount == 4)
93 ogreScene->setShadowTextureConfig(3, quality / 2, quality / 2, mRttFormat);
94
95 // camera setup
97
98 float farClip = (ogreScene->getShadowFarDistance() + 1.0f);
99 float lambda = 0.9999f; // lower lamdba means more uniform, higher lambda means more logarithmic
100 shadowCameraSetup->calculateSplitPoints(textureCount, 1.01f, farClip, lambda);
102
103 // Apply settings
104 shadowCameraSetup->setSplitPoints(points);
105 shadowCameraSetup->setSplitPadding(0.5f);
106
107 SetCameraSetup(Ogre::ShadowCameraSetupPtr(shadowCameraSetup));
108 CreateMaterialsPass();
109 }
110
112 {
113 //reset to default
114 Ogre::MaterialPtr emptyMat;
115 ogreScene->setShadowTextureCasterMaterial(emptyMat);
116 ogreScene->setShadowTextureReceiverMaterial(emptyMat);
117
118 // before we clean the shadows textures
119 CleanMaterials();
120
121 ogreScene->setShadowTextureCount(1);
122 ogreScene->setShadowTextureCountPerLightType(Ogre::Light::LT_SPOTLIGHT, 1);
123 ogreScene->setShadowTextureCountPerLightType(Ogre::Light::LT_DIRECTIONAL, 1);
124 ogreScene->setShadowTextureCountPerLightType(Ogre::Light::LT_POINT, 1);
125 ogreScene->setShadowTexturePixelFormat(Ogre::PF_X8R8G8B8);
126 ogreScene->setShadowCasterRenderBackFaces(false);
127 ogreScene->setShadowTextureSelfShadow(true);
128 ogreScene->setShadowTechnique(Ogre::SHADOWTYPE_NONE);
129 }
130
132 {
133 ogreScene->setShadowTechnique(static_cast <Ogre::ShadowTechnique> (Ogre::SHADOWDETAILTYPE_TEXTURE | Ogre::SHADOWDETAILTYPE_INTEGRATED | shadowManager->GetLightingTechnique()));
134 }
135
136 bool SShadowCSM::IsShadowMaterialPass(Ogre::Pass* pass)
137 {
138 if (pass->getName() == "CSM/PASS")
139 return true;
140
141 return false;
142 }
143
144 void SShadowCSM::RemoveMaterialPass(Ogre::Technique* tech)
145 {
146 if (!tech)
147 return;
148
149 //remove previous shadow pass
150 Ogre::Technique::Passes passes = tech->getPasses();
151 for (unsigned int i = 0; i < passes.size(); i++)
152 {
153 Ogre::Pass* pass = passes[i];
154 if (pass->getName() == "CSM/PASS")
155 {
156 tech->removePass(i);
157 break;
158 }
159 }
160
161 tech->setShadowCasterMaterial("");
162 tech->setShadowReceiverMaterial("");
163 }
164
165 void SShadowCSM::UpdateShadowMaterial(Ogre::Technique* tech)
166 {
167 if (!tech || (tech->getParent()->getName() == "Ogre/Debug/LinesMat") /*|| ((tech->getSchemeName() != Ogre::MSN_SHADERGEN) &&
168 (tech->getSchemeName() != "Default") &&
169 (tech->getSchemeName() != "basic_mat")) */)
170 return;
171
172 //remove previous pass
173 RemoveMaterialPass(tech);
174
175 // If the technique is transparent, then ignore for rendering
176 if (tech->hasColourWriteDisabled() || (!tech->getParent()->getReceiveShadows()) || (tech->getSchemeName() == "SO3/LIGHTSHAFT"))
177 return;
178
179 Ogre::Technique::Passes opasses = tech->getPasses();
180 Ogre::MaterialPtr baseMat;
181
182 //look to alpha rejection pass > 120
183 Ogre::TexturePtr alphaTex;
184 Ogre::Pass* alphaPass = 0;
185 Ogre::TextureUnitState* astate = 0;
186
187 //search for alpha texture
188 if (opasses.size() > 0)
189 {
190 Ogre::Pass* pass = opasses[0];
191 if (pass && Ogre::Real(pass->getAlphaRejectValue()) > 120.0f)
192 {
193 unsigned short nbTex = pass->getNumTextureUnitStates();
194 for (unsigned short t = 0; t < nbTex && !alphaTex; t++)
195 {
196 Ogre::TextureUnitState* ustate = pass->getTextureUnitState(t);
197 Ogre::TexturePtr texptr = ustate->_getTexturePtr();
198 if (texptr && texptr->hasAlpha() && (texptr->getTextureType() == Ogre::TEX_TYPE_2D))
199 {
200 alphaTex = texptr;
201 astate = ustate;
202 alphaPass = pass;
203 }
204 }
205 }
206 }
207
208 size_t nbshadow = ogreScene->getShadowTextureConfigList().size();
209 if (alphaTex)
210 if (nbshadow <= 2)
211 baseMat = Ogre::MaterialManager::getSingleton().getByName("SO3/CSM/ShadowReceiver2");
212 else if (nbshadow == 3)
213 baseMat = Ogre::MaterialManager::getSingleton().getByName("SO3/CSM/ShadowReceiver3");
214 else
215 baseMat = Ogre::MaterialManager::getSingleton().getByName("SO3/CSM/ShadowReceiver");
216 else
217 if (nbshadow <= 2)
218 baseMat = Ogre::MaterialManager::getSingleton().getByName("SO3/CSM/ShadowReceiver2/basic");
219 else if (nbshadow == 3)
220 baseMat = Ogre::MaterialManager::getSingleton().getByName("SO3/CSM/ShadowReceiver3/basic");
221 else
222 baseMat = Ogre::MaterialManager::getSingleton().getByName("SO3/CSM/ShadowReceiver/basic");
223
224 Ogre::Pass* basePass = baseMat->getTechnique(0)->getPass(0);
225
226 Ogre::Pass* nPass = tech->createPass();
227 *nPass = *basePass;
228 nPass->setName("CSM/PASS");
229 nPass->setIlluminationStage(Ogre::IS_DECAL);
230 //nPass->setSceneBlending(Ogre::SBT_MODULATE);
231 nPass->setLightingEnabled(false);
232 nPass->setDepthBias(0.01f, 1.0f);
233
234 Ogre::Pass* oPass = 0;
235 if (alphaTex)
236 oPass = alphaPass;
237 else if (opasses.size() > 0)
238 oPass = opasses[0];
239
240 if (oPass && !oPass->getPolygonModeOverrideable() && (oPass->getPolygonMode() == Ogre::PM_POINTS))
241 {
242 nPass->setPolygonMode(Ogre::PM_POINTS);
243 nPass->setPointSize(oPass->getPointSize());
244 }
245
246 nPass->setDiffuse(oPass->getDiffuse());
247 nPass->setAmbient(oPass->getAmbient());
248 nPass->setDepthWriteEnabled(false);
249 nPass->setAlphaRejectSettings(oPass->getAlphaRejectFunction(), oPass->getAlphaRejectValue(), oPass->isAlphaToCoverageEnabled());
250
251 if (!basePass->getTextureUnitState(nbshadow)->isLoaded())
252 basePass->getTextureUnitState(nbshadow)->_load();
253
254 // add the texture with alpha
255 if (alphaTex)
256 {
257 Ogre::TextureUnitState* nTunitState = nPass->getTextureUnitState((nbshadow <= 2) ? 3 : (nbshadow == 3) ? 4 : 5);
258 *nTunitState = *astate;
259 }
260
261 Ogre::MaterialPtr mcaster;
262 if (!oPass->getDepthWriteEnabled() || alphaTex)
263 {
264 if (!alphaTex)
265 {
266 try
267 {
268 mcaster = Ogre::MaterialManager::getSingleton().getByName("SO3/CSM/ShadowCaster")->clone("SO3/CSM/ShadowCaster" + tech->getParent()->getName(), tech->getParent()->getGroup());
269 }
270 catch (Ogre::Exception&)
271 {
272 mcaster = Ogre::MaterialManager::getSingleton().getByName("SO3/CSM/ShadowCaster" + tech->getParent()->getName());
273 }
274 }
275 else
276 {
277 try
278 {
279 mcaster = Ogre::MaterialManager::getSingleton().getByName("SO3/CSM/ShadowCaster/Alpha")->clone("SO3/CSM/ShadowCaster/Alpha" + tech->getParent()->getName(), tech->getParent()->getGroup());
280 }
281 catch (Ogre::Exception&)
282 {
283 mcaster = Ogre::MaterialManager::getSingleton().getByName("SO3/CSM/ShadowCaster/Alpha" + tech->getParent()->getName());
284 }
285 }
286
287 if (!mcaster.isNull() && mcaster->getTechnique(0) != 0)
288 {
289 mcaster->getTechnique(0)->getPass(0)->setDiffuse(oPass->getDiffuse());
290 mcaster->getTechnique(0)->getPass(0)->setAmbient(oPass->getAmbient());
291 if (alphaTex)
292 {
293 if (mcaster->getTechnique(0)->getPass(0)->getNumTextureUnitStates() > 0)
294 *(mcaster->getTechnique(0)->getPass(0)->getTextureUnitState(0)) = *astate;
295 else
296 *(mcaster->getTechnique(0)->getPass(0)->createTextureUnitState()) = *astate;
297 }
298 else if (mcaster->getTechnique(0)->getPass(0)->getNumTextureUnitStates() > 0)
299 mcaster->getTechnique(0)->getPass(0)->removeAllTextureUnitStates();
300 }
301 tech->setShadowCasterMaterial(mcaster);
302 }
303 else
304 {
305 tech->setShadowCasterMaterial(mcaster);
306 }
307
308 tech->getParent()->reload();
309
310 // set fogging
311 Ogre::Real shadowEnd = ogreScene->getShadowFarDistance();
312 //nPass->setFog(true, Ogre::FOG_LINEAR, Ogre::ColourValue::White, 0, shadowEnd * mFadeStart, shadowEnd * mFadeEnd);
313 Ogre::Real dstart = shadowEnd * mFadeStart;
314 Ogre::Real dend = shadowEnd * mFadeEnd;
315 Ogre::GpuProgramParametersSharedPtr sparams = nPass->getFragmentProgramParameters();
316 if (sparams)
317 {
318 sparams->setNamedConstant("fogParams", Ogre::Vector4(0.0f, dstart, dend, 1.0f / (dend - dstart)));
319 //float fardist = ogreScene->getShadowFarDistance();
320 //unsigned short quality = GetShadowManager()->GetShadowQuality();
321 //float bias = (quality <= SShadowManager::SO3_SHADOWS_QUALITY_LOW) ? 0.1f : (quality <= SShadowManager::SO3_SHADOWS_QUALITY_MEDIUM) ? 0.05f : (quality > SShadowManager::SO3_SHADOWS_QUALITY_HIGH) ? 0.002f : 0.01f;
322 //sparams->setNamedConstant("fixedDepthBias", Ogre::Vector4(bias / fardist, (bias * 1.5f) / fardist, (bias * 1.8f) / fardist, (bias * 2.0f) / fardist));
323 }
324 }
325
326 void SShadowCSM::CreateMaterialsPass()
327 {
328 const SGroupMaterialMap groupmatmap = (*currentScene->GetMaterials());
329 SGroupMaterialMap::const_iterator iGroupMaterialList = groupmatmap.begin();
330 while (iGroupMaterialList != groupmatmap.end())
331 {
332 const SMaterialMap matmap = (*iGroupMaterialList->second);
333 SMaterialMap::const_iterator iMaterialList = matmap.begin();
334 while (iMaterialList != matmap.end())
335 {
336 Ogre::MaterialPtr material = iMaterialList->second->getOgreMaterialPointer();
337 Ogre::Material::Techniques techniques = material->getTechniques();
338 for (unsigned int t = 0; t < techniques.size(); t++)
339 {
340 UpdateShadowMaterial(techniques[t]);
341 }
342
343 iMaterialList++;
344 }
345 iGroupMaterialList++;
346 }
347 }
348
349 void SShadowCSM::CleanMaterials()
350 {
351 // avoid a removed texture to be referenced in the shadow caster
352 Ogre::MaterialPtr caster = Ogre::MaterialManager::getSingleton().getByName("SO3/CSM/ShadowCaster");
353 if (caster && (caster->getNumTechniques() > 0) && (caster->getTechnique(0)->getNumPasses() > 0) && (caster->getTechnique(0)->getPass(0)->getNumTextureUnitStates() > 0))
354 {
355 caster->getTechnique(0)->getPass(0)->removeAllTextureUnitStates();
356 caster->getTechnique(0)->getPass(0)->createTextureUnitState();
357 }
358
359 const SGroupMaterialMap groupmatmap = (*currentScene->GetMaterials());
360 SGroupMaterialMap::const_iterator iGroupMaterialList = groupmatmap.begin();
361 while (iGroupMaterialList != groupmatmap.end())
362 {
363 const SMaterialMap matmap = (*iGroupMaterialList->second);
364 SMaterialMap::const_iterator iMaterialList = matmap.begin();
365 while (iMaterialList != matmap.end())
366 {
367 Ogre::MaterialPtr material = iMaterialList->second->getOgreMaterialPointer();
369
370 Ogre::Material::Techniques techniques = material->getTechniques();
371 for (unsigned int t = 0; t < techniques.size(); t++)
372 {
373 RemoveMaterialPass(techniques[t]);
374 material->reload();
375 }
376
377 iMaterialList++;
378 }
379 iGroupMaterialList++;
380 }
381 }
382
383 /* CSM Camera Setup from Matthew Paul Reid sample code
384 https://bitbucket.org/ScaleRender/ogrecascadedshadows/downloads
385 */
387 mSplitPadding(1.0f),
388 mGpuConstants(constants)
389 {
390 calculateSplitPoints(3, 5.0f, ogreScene->getShadowFarDistance());
391 }
392 //---------------------------------------------------------------------
396 //---------------------------------------------------------------------
397 void StableCSMShadowCameraSetup::calculateSplitPoints(size_t cascadeCount, Ogre::Real firstSplitDist, Ogre::Real farDist, Ogre::Real lambda)
398 {
399 if (cascadeCount < 2)
400 OGRE_EXCEPT(Ogre::Exception::ERR_INVALIDPARAMS, "Cannot specify less than 2 cascades", "StableCSMShadowCameraSetup::calculateSplitPoints");
401
402 mSplitPoints.resize(cascadeCount + 1);
403 mCascadeCount = cascadeCount;
404
405 mSplitPoints[0] = 0.0f;
406 firstSplitDist = std::max(1.0f, firstSplitDist);
407 farDist = (farDist * 2.0f) / (mCascadeCount + 1);
408 for (size_t i = 1; i < mCascadeCount; i++)
409 {
410 Ogre::Real fraction = (Ogre::Real)i / (Ogre::Real)mCascadeCount;
411 Ogre::Real splitPoint = firstSplitDist + lambda * Ogre::Math::Pow(farDist / firstSplitDist, fraction) +
412 (1.0f - lambda) * (fraction * (farDist - firstSplitDist));
413
414 mSplitPoints[i] = splitPoint;
415 }
416 mSplitPoints[mCascadeCount] = farDist;
417 }
418 //---------------------------------------------------------------------
420 {
421 if (newSplitPoints.size() < 3) // 3, not 2 since splits + 1 points
422 OGRE_EXCEPT(Ogre::Exception::ERR_INVALIDPARAMS, "Cannot specify less than 2 splits", "StableCSMShadowCameraSetup::setSplitPoints");
423 mCascadeCount = newSplitPoints.size() - 1;
424 mSplitPoints = newSplitPoints;
425 }
426
427 //---------------------------------------------------------------------
428 void StableCSMShadowCameraSetup::getShadowCamera(const Ogre::SceneManager *sm, const Ogre::Camera *cam,
429 const Ogre::Viewport *vp, const Ogre::Light *light, Ogre::Camera *texCam, size_t iteration) const
430 {
431 texCam->setLodBias(0.25);
432
433 // apply the right clip distance.
434 Ogre::Real nearDist = mSplitPoints[iteration];
435 Ogre::Real farDist = mSplitPoints[iteration + 1];
436
437 // Add a padding factor to internal distances so that the connecting split point will not have bad artifacts.
438 if (iteration > 0)
439 {
440 nearDist -= mSplitPadding;
441 }
442 if (iteration < mCascadeCount - 1)
443 {
444 farDist += mSplitPadding;
445 }
446
447 mCurrentIteration = iteration;
448
449 getShadowCameraForCascade(sm, cam, vp, light, texCam, iteration, nearDist, farDist);
450 }
451
452 void StableCSMShadowCameraSetup::getShadowCameraForCascade(const Ogre::SceneManager *sm, const Ogre::Camera *cam,
453 const Ogre::Viewport *vp, const Ogre::Light *light, Ogre::Camera *texCam, size_t iteration,
454 Ogre::Real nearSplit, Ogre::Real farSplit) const
455 {
456 Ogre::Vector3 pos, dir;
457 Ogre::Matrix3 rot;
458
459 bool iscustom = cam->isCustomProjectionMatrixEnabled();
460 Ogre::Radian nCamFov = cam->getFOVy();
461 if (iscustom)
462 {
463 Ogre::Matrix4 projmat = cam->getProjectionMatrix();
464 nCamFov = Ogre::Radian(Ogre::Math::ATan(1.0f / projmat[1][1]) * 2.0f);
465 }
466
467 // reset custom view / projection matrix in case already set
468 texCam->setCustomViewMatrix(false);
469 texCam->setCustomProjectionMatrix(false);
470
471 // Directional lights
472 if (light->getType() == Ogre::Light::LT_DIRECTIONAL)
473 {
474 // set up the shadow texture
475 // Set ortho projection
476 texCam->setProjectionType(Ogre::PT_ORTHOGRAPHIC);
477 // set easy FOV and near dist so that texture covers far dist
478 texCam->setFOVy(Ogre::Degree(90));
479
480 float nearClip = light->getShadowNearClipDistance();
481 if (nearClip <= 0.0f)
482 nearClip = cam->getNearClipDistance();
483
484 float farClip = light->getShadowFarClipDistance();
485 if (farClip <= 0.0f)
486 farClip = cam->getFarClipDistance();
487
488 texCam->setNearClipDistance(nearClip);
489 texCam->setFarClipDistance(farClip);
490
491 // Calculate texCam direction, which same as directional light direction
492 dir = -light->getDerivedDirection();
493 dir.normalise();
494
495 //get light orientation
496 Ogre::Vector3 up = Ogre::Vector3::UNIT_Y;
497 // Check it's not coincident with dir
498 if (Ogre::Math::Abs(up.dotProduct(dir)) >= 1.0f)
499 {
500 // Use camera up
501 up = Ogre::Vector3::UNIT_Z;
502 }
503 rot = Ogre::Math::lookRotation(dir, up);
504
505 // Find minimum enclosing sphere for view frustum
506 // We do this in local space so that we don't have slight precision variation between frames
507 float vertical = Ogre::Math::Tan(nCamFov * 0.5f);
508 float horizontal = Ogre::Math::Tan(nCamFov * 0.5f);
509
510 if (!iscustom)
511 horizontal = horizontal * cam->getAspectRatio();
512
513 Ogre::Vector3 topLeftFar;
514 topLeftFar.x = horizontal * farSplit;
515 topLeftFar.y = vertical * farSplit;
516 topLeftFar.z = farSplit;
517
518 Ogre::Vector3 bottomRightNear;
519 bottomRightNear.z = nearSplit;
520 bottomRightNear.x = horizontal * bottomRightNear.z;
521 bottomRightNear.y = vertical * bottomRightNear.z;
522
523 float dist = (topLeftFar.squaredLength() - bottomRightNear.squaredLength()) / (2 * (topLeftFar.z - bottomRightNear.z));
524
525 if (dist > farSplit)
526 dist = farSplit;
527
528 Ogre::Vector3 localPos(0, 0, -dist); // we have now found the point along frustum center which is equi-distant to the opposing corner positions
529
530 Ogre::Real diameter = topLeftFar.distance(-localPos) * 2.0f;
531 pos = cam->getDerivedPosition() + cam->getDerivedOrientation() * localPos;
532
533 diameter *= (Ogre::Real)1.01; // allow some boundary pixels for filtering etc. TODO - make this a user constant
534 pos += dir * 0.5 * (farClip - nearClip); // pull light back so we can see the scene
535
536 //calculate window size
537 texCam->setOrthoWindowWidth(diameter);
538
539 // Round local x/y position based on a world-space texel; this helps to reduce
540 // jittering caused by the projection moving with the camera
541 Ogre::Real worldTexelSize = texCam->getOrthoWindowWidth() / texCam->getViewport()->getActualWidth();
542
543 //convert world space camera position into light space
544 Ogre::Vector3 lightSpacePos = rot.transpose() * pos;
545
546 //snap to nearest texel
547 lightSpacePos.x -= fmod(lightSpacePos.x, worldTexelSize);
548 lightSpacePos.y -= fmod(lightSpacePos.y, worldTexelSize);
549
550 //convert back to world space
551 pos = rot * lightSpacePos;
552
553 // Finally set position
554 texCam->getParentNode()->setPosition(pos);
555 texCam->getParentNode()->setOrientation(rot);
556 }
557 /*
558 else
559 {
560 float nearClip = nearSplit;
561 float farClip = farSplit;
562
563 if (nearClip <= 0.0f)
564 nearClip = cam->getNearClipDistance();
565
566 if (farClip <= 0.0f)
567 farClip = cam->getFarClipDistance();
568
569 texCam->setNearClipDistance(nearClip);
570 texCam->setFarClipDistance(farClip);
571
572 FocusedShadowCameraSetup::getShadowCamera(sm, cam, vp, light, texCam, iteration);
573 }*/
574
575 // set some GPU shader parameters
576 mGpuConstants->updateCascade(*texCam, iteration);
577 }
578
579
580
581 // GPU constants
583 {
584 if (!msSingleton)
585 msSingleton = new CSMGpuConstants();
586
587 return msSingleton;
588 }
589
591 {
592 if (!msSingleton)
593 msSingleton = new CSMGpuConstants();
594
595 return (*msSingleton);
596 }
597
599 {
600 mCascadeCount = 4;
601 mParamsScaleBias = Ogre::GpuProgramManager::getSingletonPtr()->createSharedParameters("params_shadowMatrixScaleBias");
602
603 for (size_t i = 1; i < mCascadeCount; i++)
604 {
605 mParamsScaleBias->addConstantDefinition("texMatrixScaleBias" + Ogre::StringConverter::toString(i), Ogre::GCT_FLOAT4);
606 }
607 }
608
609
611 {
612 try
613 {
614 mParamsScaleBias = Ogre::GpuProgramManager::getSingletonPtr()->getSharedParameters("params_shadowMatrixScaleBias");
615 }
616 catch (Ogre::Exception&)
617 {
618 }
619
620 if (mParamsScaleBias)
621 mParamsScaleBias->removeAllConstantDefinitions();
622 }
623
624
625 void CSMGpuConstants::updateCascade(const Ogre::Camera &texCam, size_t index)
626 {
627 if (index == 0)
628 {
629 mFirstCascadeViewMatrix = texCam.getViewMatrix();
630 mFirstCascadeCamWidth = texCam.getOrthoWindowWidth();
631 mViewRange = texCam.getFarClipDistance() - texCam.getNearClipDistance();
632 }
633 else
634 {
635 Ogre::Matrix4 mat0 = mFirstCascadeViewMatrix;
636 Ogre::Matrix4 mat1 = texCam.getViewMatrix();
637
638 Ogre::Real offsetX = mat1[0][3] - mat0[0][3];
639 Ogre::Real offsetY = mat1[1][3] - mat0[1][3];
640 Ogre::Real offsetZ = mat1[2][3] - mat0[2][3];
641
642 Ogre::Real width0 = mFirstCascadeCamWidth;
643 Ogre::Real width1 = texCam.getOrthoWindowWidth();
644
645 Ogre::Real oneOnWidth = 1.0f / width0;
646 Ogre::Real offCenter = width1 / (2.0f * width0) - 0.5f;
647
648 Ogre::RenderSystem* rs = Ogre::Root::getSingletonPtr()->getRenderSystem();
649 float depthRange = Ogre::Math::Abs(rs->getMinimumDepthInputValue() - rs->getMaximumDepthInputValue());
650
651 Ogre::Vector4 result;
652 result.x = offsetX * oneOnWidth + offCenter;
653 result.y = -offsetY * oneOnWidth + offCenter;
654 result.z = -depthRange * offsetZ / mViewRange;
655 result.w = width0 / width1;
656
657 mParamsScaleBias->setNamedConstant("texMatrixScaleBias" + Ogre::StringConverter::toString(index), result);
658 }
659 }
660
661}
static CSMGpuConstants & getSingleton()
static CSMGpuConstants * getSingletonPtr()
void updateCascade(const Ogre::Camera &texCam, size_t index)
bool GetRttPixelFormat(Ogre::PixelFormat &format, bool alpha=false, bool floattex=false)
Definition SO3Root.cpp:650
Ogre::RenderSystem * GetOgreRenderSystem()
Definition SO3Root.cpp:865
void RemoveGeneratedMaterial(Ogre::Material *mat)
Definition SO3Root.cpp:2343
static SRoot & getSingleton()
Definition SO3Root.cpp:116
static SRoot * getSingletonPtr()
Definition SO3Root.cpp:111
const SMaterialMap * GetMaterials(const std::string &groupName)
virtual void RemoveMaterialPass(Ogre::Technique *tech)
static bool CheckSystemCompatibility()
virtual bool IsShadowMaterialPass(Ogre::Pass *pass)
virtual void UpdateShadowMaterial(Ogre::Technique *tech)
virtual void UpdateShadowTechnique()
Ogre::Real mFadeStart
Definition SO3Shadow.h:80
Ogre::Real mFadeEnd
Definition SO3Shadow.h:81
SShadowManager * shadowManager
Definition SO3Shadow.h:75
Ogre::SceneManager * ogreScene
Definition SO3Shadow.h:74
void SetCameraSetup(Ogre::ShadowCameraSetupPtr shadowCameraSetup)
Definition SO3Shadow.cpp:57
Ogre::PixelFormat mRttFormat
Definition SO3Shadow.h:77
SScene * currentScene
Definition SO3Shadow.h:73
ShadowLightingType GetLightingTechnique()
ShadowQuality GetShadowQuality()
void calculateSplitPoints(size_t cascadeCount, Ogre::Real firstSplitDist, Ogre::Real farDist, Ogre::Real lambda=0.95)
virtual void getShadowCamera(const Ogre::SceneManager *sm, const Ogre::Camera *cam, const Ogre::Viewport *vp, const Ogre::Light *light, Ogre::Camera *texCam, size_t iteration) const
Returns a stable CSM shadow camera for the given iteration.
void setSplitPadding(Ogre::Real pad)
void setSplitPoints(const SplitPointList &newSplitPoints)
void getShadowCameraForCascade(const Ogre::SceneManager *sm, const Ogre::Camera *cam, const Ogre::Viewport *vp, const Ogre::Light *light, Ogre::Camera *texCam, size_t iteration, Ogre::Real nearSplit, Ogre::Real farSplit) const
StableCSMShadowCameraSetup(Ogre::SceneManager *ogreScene, CSMGpuConstants *constants)
const SplitPointList & getSplitPoints() const
Returns the calculated split points.
std::vector< Ogre::Real > SplitPointList
std::unordered_map< std::string, SMaterial * > SMaterialMap
std::unordered_map< std::string, SMaterialMap * > SGroupMaterialMap