Project

General

Profile

SO3Engine
SO3ShadowPSSM.cpp
Go to the documentation of this file.
1
11#include "SO3Renderer/SO3Root.h"
12
13namespace SO3
14{
16{
17#ifdef RPI
18 return false;
19#endif
20
21 //test if shaders are supported by the card
22 const Ogre::RenderSystemCapabilities* caps = SRoot::getSingleton().GetOgreRenderSystem()->getCapabilities();
23
24 bool isSupported = true;
25 Ogre::PixelFormat rttformat;
26
27 bool pfsupport = SRoot::getSingleton().GetRttPixelFormat(rttformat, false, true);
28
29 isSupported = pfsupport && caps && caps->hasCapability(Ogre::RSC_VERTEX_PROGRAM) &&
30 caps->hasCapability(Ogre::RSC_FRAGMENT_PROGRAM) &&
31 caps->hasCapability(Ogre::RSC_NON_POWER_OF_2_TEXTURES) &&
32 (caps->isShaderProfileSupported("ps_3_0") || caps->isShaderProfileSupported("ps_4_0") || (caps->isShaderProfileSupported("arbfp1")) || (caps->isShaderProfileSupported("glsles")) || (caps->isShaderProfileSupported("glsl300es")));
33
34 if (isSupported)
35 Ogre::LogManager::getSingleton().logMessage("[SShadowPSSM] is supported!");
36 else
37 Ogre::LogManager::getSingleton().logMessage("[SShadowPSSM] is not supported!");
38
39 return isSupported;
40}
41
42SShadowPSSM::SShadowPSSM() : SShadow(0, "", SShadowManager::SO3_SHADOWS_PSSM)
43{
44}
45
46SShadowPSSM::SShadowPSSM(SShadowManager* sManager) : SShadow(sManager, "PSSM", SShadowManager::SO3_SHADOWS_PSSM)
47{
48 ogreScene->setShadowTechnique(static_cast <Ogre::ShadowTechnique> (Ogre::SHADOWDETAILTYPE_TEXTURE | Ogre::SHADOWDETAILTYPE_INTEGRATED | shadowManager->GetLightingTechnique()));
49
50 unsigned short quality = sManager->GetShadowQuality();
51 unsigned int cascadeCount = (quality < SShadowManager::SO3_SHADOWS_QUALITY_HIGH) ? 2 : 3;
52 //shadowCameraSetup->setOptimalAdjustFactor(15);
53 ogreScene->setShadowTextureSelfShadow(false);
54 ogreScene->setShadowCasterRenderBackFaces(true);
55
56 // 3 textures per spotlight
57 ogreScene->setShadowTextureCountPerLightType(Ogre::Light::LT_SPOTLIGHT, cascadeCount);
58 ogreScene->setShadowTextureCountPerLightType(Ogre::Light::LT_POINT, cascadeCount);
59
60 // 3 textures per directional light
61 ogreScene->setShadowTextureCountPerLightType(Ogre::Light::LT_DIRECTIONAL, cascadeCount);
62 ogreScene->setShadowTextureCount(cascadeCount); // * 4
63
64 //get best format on device
66
67 ogreScene->setShadowTextureConfig(0, (unsigned short)(quality * 1.5f), (unsigned short)(quality * 1.5f), mRttFormat);
68 ogreScene->setShadowTextureConfig(1, quality, quality, mRttFormat);
69 if (cascadeCount > 2)
70 ogreScene->setShadowTextureConfig(2, (unsigned short)(quality * 0.75f), (unsigned short)(quality * 0.75f), mRttFormat);
71 /*for (unsigned int i = 0; i < 4; i++)
72 {
73 ogreScene->setShadowTextureConfig(0 + (i * cascadeCount) , (unsigned short)(quality * 1.5f), (unsigned short)(quality * 1.5f), mRttFormat);
74 ogreScene->setShadowTextureConfig(1 + (i * cascadeCount), quality, quality, mRttFormat);
75
76 if (cascadeCount > 2)
77 ogreScene->setShadowTextureConfig(2 + (i * cascadeCount), (unsigned short)(quality * 0.75f), (unsigned short)(quality * 0.75f), mRttFormat);
78 }*/
79
80 ogreScene->setShadowTextureFSAA(2);
81 ogreScene->setShadowDirLightTextureOffset(0.6f);
82 ogreScene->setShadowTextureFadeStart(mFadeStart);
83 ogreScene->setShadowTextureFadeEnd(mFadeEnd);
84
85 try
86 {
87 Ogre::MaterialPtr mcaster = Ogre::MaterialManager::getSingleton().getByName("SO3/PSSM/ShadowCaster");
88 Ogre::MaterialPtr emptyMat;
89 ogreScene->setShadowTextureCasterMaterial(mcaster);
90 ogreScene->setShadowTextureReceiverMaterial(emptyMat);
91 }
92 catch(Ogre::Exception &e)
93 {
94 //can fail here is a material texture is missing
95 MMechostr(MSKDEBUG, ">>> SShadowPSSM error : %s\n", e.what());
96 }
97
98 // shadow camera setup
99 Ogre::ShadowCameraSetupPtr shadowCameraSetup = StablePSSMShadowCameraSetup::create();
100 SetCameraSetup(shadowCameraSetup);
101
102 float farClip = ogreScene->getShadowFarDistance();
103 float lambda = 0.99f; // lower lamdba means more uniform, higher lambda means more logarithmic
104
105 Ogre::PSSMShadowCameraSetup* pssmSetup = static_cast<StablePSSMShadowCameraSetup*>(shadowCameraSetup.get());
106 //first split and padding should be the camera near clip
107 pssmSetup->calculateSplitPoints(cascadeCount, 1.0f, farClip, lambda);
108 pssmSetup->setSplitPadding(0.2f);
109 pssmSetup->setOptimalAdjustFactor(0, 10);
110 pssmSetup->setOptimalAdjustFactor(1, 1);
111
112 if (cascadeCount > 2)
113 pssmSetup->setOptimalAdjustFactor(2, 0);
114
115 //overide first split point
116 Ogre::PSSMShadowCameraSetup::SplitPointList splitPoints = pssmSetup->getSplitPoints();
117 splitPoints[0] = Ogre::Real(0.01);
118 pssmSetup->setSplitPoints(splitPoints);
119
120 CreateMaterialsPass();
121}
122
124{
125 //reset to default
126 Ogre::MaterialPtr emptyMat;
127 ogreScene->setShadowTextureCasterMaterial(emptyMat);
128 ogreScene->setShadowTextureReceiverMaterial(emptyMat);
129
130 CleanMaterials();
131
132 ogreScene->setShadowTextureCountPerLightType(Ogre::Light::LT_SPOTLIGHT, 1);
133 ogreScene->setShadowTextureCountPerLightType(Ogre::Light::LT_DIRECTIONAL, 1);
134 ogreScene->setShadowTextureCountPerLightType(Ogre::Light::LT_POINT, 1);
135 ogreScene->setShadowTextureCount(1);
136 ogreScene->setShadowTexturePixelFormat(Ogre::PF_X8R8G8B8);
137 ogreScene->setShadowCasterRenderBackFaces(false);
138 ogreScene->setShadowTextureSelfShadow(true);
139 ogreScene->setShadowTechnique(Ogre::SHADOWTYPE_NONE);
140}
141
143{
144 ogreScene->setShadowTechnique(static_cast <Ogre::ShadowTechnique> (Ogre::SHADOWDETAILTYPE_TEXTURE | Ogre::SHADOWDETAILTYPE_INTEGRATED | shadowManager->GetLightingTechnique()));
145}
146
148{
149 if (pass->getName() == "PSSM/PASS")
150 return true;
151
152 return false;
153}
154
155void SShadowPSSM::RemoveMaterialPass(Ogre::Technique* tech)
156{
157 if (!tech)
158 return;
159
160 //remove previous shadow pass
161 Ogre::Technique::Passes passes = tech->getPasses();
162 for (unsigned int i = 0; i < passes.size(); i++)
163 {
164 Ogre::Pass* pass = passes[i];
165 if (pass->getName() == "PSSM/PASS")
166 {
167 tech->removePass(i);
168 break;
169 }
170 }
171
172 tech->setShadowCasterMaterial("");
173 tech->setShadowReceiverMaterial("");
174}
175
176void SShadowPSSM::UpdateShadowMaterial(Ogre::Technique* tech)
177{
178 if (!tech || (tech->getParent()->getName() == "Ogre/Debug/LinesMat") /*|| ((tech->getSchemeName() != Ogre::MSN_SHADERGEN) &&
179 (tech->getSchemeName() != "Default") &&
180 (tech->getSchemeName() != "basic_mat"))*/)
181 return;
182
183 //remove previous pass
184 RemoveMaterialPass(tech);
185
186 // If the technique is transparent, then ignore for rendering
187 if (tech->hasColourWriteDisabled() || (!tech->getParent()->getReceiveShadows()) || (tech->getSchemeName() == "SO3/LIGHTSHAFT"))
188 return;
189
190 Ogre::Technique::Passes opasses = tech->getPasses();
191 Ogre::MaterialPtr baseMat;
192
193 //look to alpha rejection pass > 120
194 Ogre::TexturePtr alphaTex;
195 Ogre::Pass* alphaPass = 0;
196 Ogre::TextureUnitState* astate = 0;
197
198 //search for alpha texture
199 if (opasses.size() > 0)
200 {
201 Ogre::Pass* pass = opasses[0];
202 if (pass && Ogre::Real(pass->getAlphaRejectValue()) > 120.0f)
203 {
204 unsigned short nbTex = pass->getNumTextureUnitStates();
205 for (unsigned short t = 0; t < nbTex && !alphaTex; t++)
206 {
207 Ogre::TextureUnitState* ustate = pass->getTextureUnitState(t);
208 Ogre::TexturePtr texptr = ustate->_getTexturePtr();
209 if (texptr && texptr->hasAlpha() && (texptr->getTextureType() == Ogre::TEX_TYPE_2D))
210 {
211 alphaTex = texptr;
212 astate = ustate;
213 alphaPass = pass;
214 }
215 }
216 }
217 }
218
219 size_t nbshadow = ogreScene->getShadowTextureConfigList().size();// / 4;
220 if (alphaTex)
221 if (nbshadow <= 2)
222 baseMat = Ogre::MaterialManager::getSingleton().getByName("SO3/PSSM/ShadowReceiver2");
223 else
224 baseMat = Ogre::MaterialManager::getSingleton().getByName("SO3/PSSM/ShadowReceiver");
225 else
226 if (nbshadow <= 2)
227 baseMat = Ogre::MaterialManager::getSingleton().getByName("SO3/PSSM/ShadowReceiver2/basic");
228 else
229 baseMat = Ogre::MaterialManager::getSingleton().getByName("SO3/PSSM/ShadowReceiver/basic");
230
231 Ogre::Pass* basePass = baseMat->getTechnique(0)->getPass(0);
232
233 Ogre::Pass* nPass = tech->createPass();
234 *nPass = *basePass;
235 nPass->setName("PSSM/PASS");
236 nPass->setIlluminationStage(Ogre::IS_DECAL);
237 //if (GetShadowManager()->GetLightingTechnique() == SShadowManager::SO3_ADDITIVE_SHADOWS_LIGHTING)
238 // nPass->setSceneBlending(Ogre::SBT_TRANSPARENT_COLOUR);
239 //else
240 //nPass->setSceneBlending(Ogre::SBT_MODULATE);
241 nPass->setLightingEnabled(false);
242 nPass->setDepthBias(0.01f, 1.0f);
243
244 Ogre::Pass* oPass = 0;
245 if (alphaTex)
246 oPass = alphaPass;
247 else if (opasses.size() > 0)
248 oPass = opasses[0];
249
250 Ogre::Real pointSize = 1.0f;
251
252 if (oPass && !oPass->getPolygonModeOverrideable() && (oPass->getPolygonMode() == Ogre::PM_POINTS))
253 {
254 nPass->setPolygonMode(Ogre::PM_POINTS);
255 nPass->setPointSize(oPass->getPointSize());
256 }
257
258 nPass->setDiffuse(oPass->getDiffuse());
259 nPass->setAmbient(oPass->getAmbient());
260 nPass->setDepthWriteEnabled(false);
261 nPass->setAlphaRejectSettings(oPass->getAlphaRejectFunction(), oPass->getAlphaRejectValue(), oPass->isAlphaToCoverageEnabled());
262
263 // add the texture with alpha
264 if (alphaTex)
265 {
266 Ogre::TextureUnitState* nTunitState = nPass->getTextureUnitState((nbshadow <= 2) ? 2 : 3);
267 *nTunitState = *astate;
268 }
269
270 Ogre::MaterialPtr mcaster;
271 if (!oPass->getDepthWriteEnabled() || alphaTex)
272 {
273 if (!alphaTex)
274 {
275 try
276 {
277 mcaster = Ogre::MaterialManager::getSingleton().getByName("SO3/PSSM/ShadowCaster")->clone("SO3/PSSM/ShadowCaster" + tech->getParent()->getName(), tech->getParent()->getGroup());
278 }
279 catch (Ogre::Exception&)
280 {
281 mcaster = Ogre::MaterialManager::getSingleton().getByName("SO3/PSSM/ShadowCaster" + tech->getParent()->getName());
282 }
283 }
284 else
285 {
286 try
287 {
288 mcaster = Ogre::MaterialManager::getSingleton().getByName("SO3/PSSM/ShadowCaster/Alpha")->clone("SO3/PSSM/ShadowCaster/Alpha" + tech->getParent()->getName(), tech->getParent()->getGroup());
289 }
290 catch (Ogre::Exception&)
291 {
292 mcaster = Ogre::MaterialManager::getSingleton().getByName("SO3/PSSM/ShadowCaster/Alpha" + tech->getParent()->getName());
293 }
294 }
295
296 if (!mcaster.isNull() && mcaster->getTechnique(0) != 0)
297 {
298 mcaster->getTechnique(0)->getPass(0)->setDiffuse(oPass->getDiffuse());
299 mcaster->getTechnique(0)->getPass(0)->setAmbient(oPass->getAmbient());
300 if (alphaTex)
301 {
302 if (mcaster->getTechnique(0)->getPass(0)->getNumTextureUnitStates() > 0)
303 *(mcaster->getTechnique(0)->getPass(0)->getTextureUnitState(0)) = *astate;
304 else
305 *(mcaster->getTechnique(0)->getPass(0)->createTextureUnitState()) = *astate;
306 }
307 else if (mcaster->getTechnique(0)->getPass(0)->getNumTextureUnitStates() > 0)
308 mcaster->getTechnique(0)->getPass(0)->removeAllTextureUnitStates();
309 }
310 tech->setShadowCasterMaterial(mcaster);
311 }
312 else
313 {
314 tech->setShadowCasterMaterial(mcaster);
315 }
316
317 tech->getParent()->reload();
318
319 //set split points on material
320 const Ogre::PSSMShadowCameraSetup::SplitPointList& splitPointList = static_cast<Ogre::PSSMShadowCameraSetup*>(cameraSetup.get())->getSplitPoints();
321 Ogre::Vector4 splitPoints;
322 for (unsigned int i = 0; i < splitPointList.size() && i < 4; ++i)
323 {
324 splitPoints[i] = splitPointList[i];
325 }
326
327 // set fogging
328 Ogre::Real shadowEnd = ogreScene->getShadowFarDistance();
329 //nPass->setFog(true, Ogre::FOG_LINEAR, Ogre::ColourValue::White, 0, shadowEnd * mFadeStart, shadowEnd * mFadeEnd);
330 Ogre::Real dstart = shadowEnd * mFadeStart;
331 Ogre::Real dend = shadowEnd * mFadeEnd;
332 Ogre::GpuProgramParametersSharedPtr sparams = nPass->getFragmentProgramParameters();
333 if (sparams)
334 {
335 sparams->setNamedConstant("pssmSplitPoints", splitPoints);
336 sparams->setNamedConstant("fogParams", Ogre::Vector4(0.0f, dstart, dend, 1.0f / (dend - dstart)));
337
338 //float fardist = ogreScene->getShadowFarDistance();
339 //unsigned short quality = GetShadowManager()->GetShadowQuality();
340 //float bias = (quality <= SShadowManager::SO3_SHADOWS_QUALITY_LOW) ? 0.01f : (quality <= SShadowManager::SO3_SHADOWS_QUALITY_MEDIUM) ? 0.005f : (quality > SShadowManager::SO3_SHADOWS_QUALITY_HIGH) ? 0.0002f : 0.001f;
341 //sparams->setNamedConstant("shadowBias", bias / fardist);
342 }
343}
344
345void SShadowPSSM::CreateMaterialsPass()
346{
347 const SGroupMaterialMap groupmatmap = (*currentScene->GetMaterials());
348 SGroupMaterialMap::const_iterator iGroupMaterialList = groupmatmap.begin();
349 while (iGroupMaterialList != groupmatmap.end())
350 {
351 const SMaterialMap matmap = (*iGroupMaterialList->second);
352 SMaterialMap::const_iterator iMaterialList = matmap.begin();
353 while (iMaterialList != matmap.end())
354 {
355 Ogre::MaterialPtr material = iMaterialList->second->getOgreMaterialPointer();
356 Ogre::Material::Techniques techniques = material->getTechniques();
357 for (unsigned int t = 0; t < techniques.size(); t++)
358 {
359 UpdateShadowMaterial(techniques[t]);
360 }
361
362 iMaterialList++;
363 }
364 iGroupMaterialList++;
365 }
366}
367
368void SShadowPSSM::CleanMaterials()
369{
370 // avoid a removed texture to be referenced in the shadow caster
371 Ogre::MaterialPtr caster = Ogre::MaterialManager::getSingleton().getByName("SO3/PSSM/ShadowCaster");
372 if (caster && (caster->getNumTechniques() > 0) && (caster->getTechnique(0)->getNumPasses() > 0) && (caster->getTechnique(0)->getPass(0)->getNumTextureUnitStates() > 0))
373 {
374 caster->getTechnique(0)->getPass(0)->removeAllTextureUnitStates();
375 caster->getTechnique(0)->getPass(0)->createTextureUnitState();
376 }
377
378 const SGroupMaterialMap groupmatmap = (*currentScene->GetMaterials());
379 SGroupMaterialMap::const_iterator iGroupMaterialList = groupmatmap.begin();
380 while (iGroupMaterialList != groupmatmap.end())
381 {
382 const SMaterialMap matmap = (*iGroupMaterialList->second);
383 SMaterialMap::const_iterator iMaterialList = matmap.begin();
384 while (iMaterialList != matmap.end())
385 {
386 Ogre::MaterialPtr material = iMaterialList->second->getOgreMaterialPointer();
388
389 //remove the shadow passs
390 Ogre::Material::Techniques techniques = material->getTechniques();
391 for (unsigned int t = 0; t < techniques.size(); t++)
392 {
393 RemoveMaterialPass(techniques[t]);
394 material->reload();
395 }
396
397 iMaterialList++;
398 }
399 iGroupMaterialList++;
400 }
401}
402
404{
405 setCameraLightDirectionThreshold(Ogre::Degree(25.0f));
406}
407//---------------------------------------------------------------------
411//---------------------------------------------------------------------
412void StablePSSMShadowCameraSetup::getShadowCamera(const Ogre::SceneManager *sm, const Ogre::Camera *cam, const Ogre::Viewport *vp, const Ogre::Light *light, Ogre::Camera *texCam, size_t iteration) const
413{
414 // apply the right clip distance.
415 Ogre::PSSMShadowCameraSetup::SplitPointList splitPoints = getSplitPoints();
416 Ogre::uint splitCount = getSplitCount();
417 Ogre::Real splitPadding = getSplitPadding();
418
419 Ogre::Real nearDist = splitPoints[iteration];
420 Ogre::Real farDist = splitPoints[iteration + 1];
421
422 if (light->getType() != Ogre::Light::LT_DIRECTIONAL)
423 {
424 float range = light->getAttenuationRange();
425 farDist = std::min(farDist, range * range);
426 }
427
428 // Add a padding factor to internal distances so that the connecting split point will not have bad artifacts.
429 if (iteration > 0)
430 {
431 nearDist -= splitPadding;
432 }
433 if (iteration < splitCount - 1)
434 {
435 farDist += splitPadding;
436 }
437
438 // Ouch, I know this is hacky, but it's the easiest way to re-use LiSPSM / Focussed
439 // functionality right now without major changes
440 Ogre::Camera* _cam = const_cast<Ogre::Camera*>(cam);
441 Ogre::Real oldNear = _cam->getNearClipDistance();
442 Ogre::Real oldFar = _cam->getFarClipDistance();
443 Ogre::Radian oldFovY = _cam->getFOVy();
444 Ogre::Matrix4 oldMatrix = _cam->getProjectionMatrix();
445 bool iscustom = _cam->isCustomProjectionMatrixEnabled();
446
447 _cam->setNearClipDistance(nearDist);
448 _cam->setFarClipDistance(farDist);
449
450 //if (iscustom)
451 //{
452 Ogre::Matrix4 projmat = _cam->getProjectionMatrix();
453 Ogre::Radian nCamFov = Ogre::Radian(Ogre::Math::ATan(1.0f / projmat[1][1]) * 2.0f);
454 _cam->setCustomProjectionMatrix(false);
455 _cam->setFOVy(nCamFov);
456 //}
457
458 //force culling with new cam settings
459 auto cullCam = dynamic_cast<Ogre::Camera*>(texCam->getCullingFrustum());
460 Ogre::FocusedShadowCameraSetup::getShadowCamera(sm, cam, vp, light, cullCam, iteration);
461
462 Ogre::LiSPSMShadowCameraSetup::getShadowCamera(sm, cam, vp, light, texCam, iteration);
463
464 // restore near/far
465 _cam->setNearClipDistance(oldNear);
466 _cam->setFarClipDistance(oldFar);
467 _cam->setFOVy(oldFovY);
468 if (iscustom)
469 _cam->setCustomProjectionMatrix(true, oldMatrix);
470}
471
472}
MMechostr(MSKDEBUG, " > Start loading Plugin SO3Engine dll\n")
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)
Ogre::Real mFadeStart
Definition SO3Shadow.h:80
Ogre::Real mFadeEnd
Definition SO3Shadow.h:81
SShadowManager * shadowManager
Definition SO3Shadow.h:75
Ogre::ShadowCameraSetupPtr cameraSetup
Definition SO3Shadow.h:76
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()
virtual bool IsShadowMaterialPass(Ogre::Pass *pass)
virtual void UpdateShadowTechnique()
static bool CheckSystemCompatibility()
virtual void UpdateShadowMaterial(Ogre::Technique *tech)
virtual void RemoveMaterialPass(Ogre::Technique *tech)
StablePSSMShadowCameraSetup()
Constructor, defaults to 3 splits.
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 override
static Ogre::ShadowCameraSetupPtr create()
std::unordered_map< std::string, SMaterial * > SMaterialMap
std::unordered_map< std::string, SMaterialMap * > SGroupMaterialMap