SO3Engine
SO3DeferredShadowManager.cpp
Go to the documentation of this file.
1/*
2-----------------------------------------------------------------------------
3This source file is part of OpenSpace3D
4For the latest info, see http://www.openspace3d.com
5
6Copyright (c) 2012 I-maginer
7
8This program is free software; you can redistribute it and/or modify it under
9the terms of the GNU Lesser General Public License as published by the Free Software
10Foundation; either version 2 of the License, or (at your option) any later
11version.
12
13This program is distributed in the hope that it will be useful, but WITHOUT
14ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
15FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
16
17You should have received a copy of the GNU Lesser General Public License along with
18this program; if not, write to the Free Software Foundation, Inc., 59 Temple
19Place - Suite 330, Boston, MA 02111-1307, USA, or go to
20http://www.gnu.org/copyleft/lesser.txt
21
22-----------------------------------------------------------------------------
23*/
24#include <boost/lexical_cast.hpp>
27
28
29template<> SO3::SDeferredShadowManager* Ogre::Singleton<SO3::SDeferredShadowManager>::msSingleton = 0;
30
31namespace SO3
32{
33
35{
36 // Init textures ptr to zero
37 shadowStandardTexture.reset();
38 shadowCubicTexture.reset();
39
40 // Init materials ptr to zero
41 shadowStandardMaterial.reset();
42 shadowCubicMaterial.reset();
43
44 // Useful matrix for shadow texture projection
45 PROJECTIONCLIPSPACE2DTOIMAGESPACE_PERSPECTIVE = Ogre::Matrix4(0.5, 0, 0, 0.5,
46 0, -0.5, 0, 0.5,
47 0, 0, 1, 0,
48 0, 0, 0, 1);
49
50 // Setting up shadow textures to medium quality values
51 standardTextureSize = 1024;
52 standardTexturePixelFormat = Ogre::PF_FLOAT16_R;
53 standardTextureFsaa = 0;
54 standardTextureNeedRebuild = true;
55 cubicTextureSize = 512;
56 cubicTexturePixelFormat = Ogre::PF_FLOAT16_R;
57 cubicTextureFsaa = 0;
58 cubicTextureNeedRebuild = true;
59
60 // Setting up names
61 deferredShadowStandardTextureName = std::string(SO3_DEFERRED_SHADOWS_SCHEME_NAME) + std::string(SO3_DEFERRED_SHADOWS_STANDARD_BASE_NAME) + std::string(SO3_DEFERRED_SHADOWS_TEXTURE_NAME);
62 deferredShadowStandardCameraName = std::string(SO3_DEFERRED_SHADOWS_SCHEME_NAME) + std::string(SO3_DEFERRED_SHADOWS_STANDARD_BASE_NAME) + std::string(SO3_DEFERRED_SHADOWS_CAMERA_NAME);
63 deferredShadowStandardMaterialName = std::string(SO3_DEFERRED_SHADOWS_SCHEME_NAME) + std::string(SO3_DEFERRED_SHADOWS_STANDARD_BASE_NAME) + std::string(SO3_DEFERRED_SHADOWS_MATERIAL_NAME);
64 deferredShadowCubicTextureName = std::string(SO3_DEFERRED_SHADOWS_SCHEME_NAME) + std::string(SO3_DEFERRED_SHADOWS_CUBIC_BASE_NAME) + std::string(SO3_DEFERRED_SHADOWS_TEXTURE_NAME);
65 deferredShadowCubicCameraName = std::string(SO3_DEFERRED_SHADOWS_SCHEME_NAME) + std::string(SO3_DEFERRED_SHADOWS_CUBIC_BASE_NAME) + std::string(SO3_DEFERRED_SHADOWS_CAMERA_NAME);
66 deferredShadowCubicMaterialName = std::string(SO3_DEFERRED_SHADOWS_SCHEME_NAME) + std::string(SO3_DEFERRED_SHADOWS_CUBIC_BASE_NAME) + std::string(SO3_DEFERRED_SHADOWS_MATERIAL_NAME);
67
68 // Define some camera setup
69 spotShadowCameraSetup = new Ogre::DefaultShadowCameraSetup();
70 pointShadowCameraSetup = new Ogre::DefaultShadowCameraSetup();
71 directionalShadowCameraSetup = new Ogre::DefaultShadowCameraSetup();
72 /*directionalShadowCameraSetup = new Ogre::LiSPSMShadowCameraSetup();
73
74 // Further configuration for non-default camera setup.
75 static_cast<Ogre::LiSPSMShadowCameraSetup*>(directionalShadowCameraSetup)->setOptimalAdjustFactor(5);*/
76
77 // Hook up the shadow handlers.
78 Ogre::MaterialManager::getSingleton().addListener(this, SO3_DEFERRED_SHADOWS_SCHEME_NAME);
79}
80
82{
83 Ogre::MaterialManager::getSingleton().removeListener(this, SO3_DEFERRED_SHADOWS_SCHEME_NAME);
84 DestroyShadowStandardTexture();
85 DestroyShadowCubicTexture();
86
87 // Remove camera setup
88 SO3_SAFE_DELETE(spotShadowCameraSetup);
89 SO3_SAFE_DELETE(pointShadowCameraSetup);
90 SO3_SAFE_DELETE(directionalShadowCameraSetup);
91}
92
97
99{
100 assert(msSingleton);
101 return (*msSingleton);
102}
103
104void SDeferredShadowManager::RegisterSceneManager(Ogre::SceneManager* targetScene)
105{
106 OgreSceneManagerList::iterator ogreSceneManagerSearched = ogreSceneManagerList.find(targetScene);
107 if (ogreSceneManagerSearched != ogreSceneManagerList.end())
108 SO3_EXCEPT(SExceptionItemIdentity, "Trying to register an already registered scene manager!", "SDeferredShadowManager::RegisterSceneManager", true);
109 else
110 {
111 // TODO Store the original shadow parameters, for restoring while unregistering
112 // Configure deferred shadows
113 targetScene->setShadowTechnique(Ogre::SHADOWTYPE_NONE);
114
115 // Create shadow standard texture camera. Camera names are handled by each scene, so no worries about duplicate items
116 Ogre::Camera* ogreStandardShadowCamera = targetScene->createCamera(deferredShadowStandardCameraName);
117 ogreStandardShadowCamera->setAspectRatio(1);
118 standardTextureCameraByScene.insert(StandardTextureCameraByScene::value_type(targetScene, ogreStandardShadowCamera));
119
120 // Create shadow cubic texture cameras.
121 std::vector<Ogre::Camera*> ogreCubicCameras;
122 for(int cpt = 0; cpt < 6; cpt++)
123 {
124 Ogre::Camera* ogreCubicShadowCamera = targetScene->createCamera(deferredShadowCubicCameraName + boost::lexical_cast<std::string, int>(cpt));
125 // Store a reference to the camera for fast access.
126 ogreCubicCameras.push_back(ogreCubicShadowCamera);
127 }
128 cubicTextureCamerasByScene.insert(CubicTextureCamerasByScene::value_type(targetScene, ogreCubicCameras));
129
130 // Add target scenemanager to our list
131 ogreSceneManagerList.insert(targetScene);
132 }
133}
134
135void SDeferredShadowManager::UnregisterSceneManager(Ogre::SceneManager* existingScene)
136{
137 OgreSceneManagerList::iterator ogreSceneManagerSearched = ogreSceneManagerList.find(existingScene);
138 if (ogreSceneManagerSearched == ogreSceneManagerList.end())
139 SO3_EXCEPT(SExceptionItemNotFound, "Trying to unregister a scene manager that is not registered!", "SDeferredShadowManager::UnregisterSceneManager", true);
140 else
141 {
142 // Destroy shadow standard texture camera.
143 StandardTextureCameraByScene::iterator iCamera = standardTextureCameraByScene.find(existingScene);
144 Ogre::Camera* ogreStandardShadowCamera = iCamera->second;
145 standardTextureCameraByScene.erase(iCamera);
146 existingScene->destroyCamera(ogreStandardShadowCamera);
147
148 // TODO Destroy shadow cubic texture cameras.
149 CubicTextureCamerasByScene::iterator iCameras = cubicTextureCamerasByScene.find(existingScene);
150 for(int cpt = 0; cpt < 6; cpt++)
151 {
152 Ogre::Camera* ogreCubicShadowCamera = iCameras->second.at(cpt);
153 existingScene->destroyCamera(ogreCubicShadowCamera);
154 }
155 iCameras->second.clear();
156 cubicTextureCamerasByScene.erase(iCameras);
157
158 // TODO Restore shadow parameters
159 // Remove from our list
160 ogreSceneManagerList.erase(ogreSceneManagerSearched);
161 }
162}
163
169
175
181
183{
184 if(standardTextureSize != size)
185 standardTextureNeedRebuild = true;
186
187 standardTextureSize = size;
188}
189
191{
192 if(standardTexturePixelFormat != fmt)
193 standardTextureNeedRebuild = true;
194
195 standardTexturePixelFormat = fmt;
196}
197
199{
200 if(standardTextureFsaa != fsaa)
201 standardTextureNeedRebuild = true;
202
203 standardTextureFsaa = fsaa;
204}
205
207{
208 if(cubicTextureSize != size)
209 cubicTextureNeedRebuild = true;
210
211 cubicTextureSize = size;
212}
213
215{
216 if(cubicTexturePixelFormat != fmt)
217 cubicTextureNeedRebuild = true;
218
219 cubicTexturePixelFormat = fmt;
220}
221
223{
224 if(cubicTextureFsaa != fsaa)
225 cubicTextureNeedRebuild = true;
226
227 cubicTextureFsaa = fsaa;
228}
229
230void SDeferredShadowManager::CreateShadowStandardTexture()
231{
232 // Delete existing texture if needed
233 DestroyShadowStandardTexture();
234
235 // Create the RTT texture
236 shadowStandardTexture = Ogre::TextureManager::getSingleton().createManual(deferredShadowStandardTextureName,
237 Ogre::ResourceGroupManager::INTERNAL_RESOURCE_GROUP_NAME,
238 Ogre::TEX_TYPE_2D,
239 standardTextureSize,
240 standardTextureSize,
241 0,
242 standardTexturePixelFormat,
243 Ogre::TU_RENDERTARGET,
244 0,
245 false,
246 standardTextureFsaa);
247 // Ensure texture loaded
248 shadowStandardTexture->load();
249
250 // Create Material used for rendering this shadow
251 shadowStandardMaterial = Ogre::MaterialManager::getSingleton().create(deferredShadowStandardMaterialName, Ogre::ResourceGroupManager::INTERNAL_RESOURCE_GROUP_NAME);
252
253 // Configure the material
254 Ogre::Pass* ogreShadowPass = shadowStandardMaterial->getTechnique(0)->getPass(0);
255 ogreShadowPass->removeAllTextureUnitStates();
256 Ogre::TextureUnitState* texUnit = ogreShadowPass->createTextureUnitState(deferredShadowStandardTextureName);
257 texUnit->setTextureAddressingMode(Ogre::TextureUnitState::TAM_BORDER);
258 texUnit->setTextureBorderColour(Ogre::ColourValue::White);
259 shadowStandardMaterial->touch();
260
261 // All done
262 standardTextureNeedRebuild = false;
263}
264
265void SDeferredShadowManager::CreateShadowCubicTexture()
266{
267 // Delete existing texture if needed
268 DestroyShadowCubicTexture();
269
270 // Create the RTT cubic texture
271 shadowCubicTexture = Ogre::TextureManager::getSingleton().createManual(deferredShadowCubicTextureName,
272 Ogre::ResourceGroupManager::INTERNAL_RESOURCE_GROUP_NAME,
273 Ogre::TEX_TYPE_CUBE_MAP,
274 cubicTextureSize,
275 cubicTextureSize,
276 0,
277 cubicTexturePixelFormat,
278 Ogre::TU_RENDERTARGET,
279 0,
280 false,
281 cubicTextureFsaa);
282 // Ensure texture loaded
283 shadowCubicTexture->load();
284
285 // Create Material used for rendering this shadow
286 shadowCubicMaterial = Ogre::MaterialManager::getSingleton().create(deferredShadowCubicMaterialName, Ogre::ResourceGroupManager::INTERNAL_RESOURCE_GROUP_NAME);
287
288 // Configure the material
289 Ogre::Pass* ogreShadowPass = shadowCubicMaterial->getTechnique(0)->getPass(0);
290 ogreShadowPass->removeAllTextureUnitStates();
291 Ogre::TextureUnitState* texUnit = ogreShadowPass->createTextureUnitState(deferredShadowCubicTextureName);
292// texUnit->setCubicTexture(&shadowCubicTexture, true);
293 texUnit->setCubicTextureName(shadowCubicTexture->getName(), true);
294 texUnit->setTextureAddressingMode(Ogre::TextureUnitState::TAM_BORDER);
295 texUnit->setTextureBorderColour(Ogre::ColourValue::White);
296 shadowCubicMaterial->touch();
297
298 // All done
299 cubicTextureNeedRebuild = false;
300}
301
302void SDeferredShadowManager::DestroyShadowStandardTexture()
303{
304 // Check if there's an existing texture for this scene manager
305 if(shadowStandardTexture)
306 {
307 // Delete the viewport
308 Ogre::RenderTarget* ogreShadowRenderTarget = shadowStandardTexture->getBuffer()->getRenderTarget();
309 Ogre::Viewport* ogreShadowViewport = ogreShadowRenderTarget->getViewport(0);
310 if(ogreShadowViewport->getCamera() != 0)
311 ogreShadowViewport->setCamera(0);
312 ogreShadowRenderTarget->removeViewport(0);
313 // ogreShadowRenderTarget->setDepthBufferPool(1);
314
315 // Delete the material
316 Ogre::MaterialManager::getSingleton().remove(shadowStandardMaterial->getHandle());
317 shadowStandardMaterial.reset();
318
319 // Finally release the texture
320 Ogre::TextureManager::getSingleton().remove(shadowStandardTexture->getHandle());
321 shadowStandardTexture.reset();
322 standardTextureNeedRebuild = true;
323 }
324}
325
326void SDeferredShadowManager::DestroyShadowCubicTexture()
327{
328 // Check if there's an existing texture for this scene manager
329 if(shadowCubicTexture)
330 {
331 // Delete the viewports
332 for(int cpt = 0; cpt < 6; cpt++)
333 {
334 Ogre::RenderTarget* ogreShadowRenderTarget = shadowCubicTexture->getBuffer(cpt)->getRenderTarget();
335 Ogre::Viewport* ogreShadowViewport = ogreShadowRenderTarget->getViewport(0);
336 if(ogreShadowViewport->getCamera() != 0)
337 ogreShadowViewport->setCamera(0);
338 ogreShadowRenderTarget->removeViewport(0);
339 // ogreShadowRenderTarget->setDepthBufferPool(1);
340 }
341
342 // Delete the material
343 Ogre::MaterialManager::getSingleton().remove(shadowCubicMaterial->getHandle());
344 shadowCubicMaterial.reset();
345
346 // Finally release the texture
347 Ogre::TextureManager::getSingleton().remove(shadowCubicTexture->getHandle());
348 shadowCubicTexture.reset();
349 cubicTextureNeedRebuild = true;
350 }
351}
352
353Ogre::TexturePtr& SDeferredShadowManager::PrepareShadowTexture(Ogre::Camera* ogreCamera, Ogre::Viewport* ogreViewport, const Ogre::Light* light, Ogre::Pass* ogrePass)
354{
355 // You must have verify that light casts shadows before calling this function!
356 Ogre::SceneManager* ogreTargetScene = ogreCamera->getSceneManager();
357 OgreSceneManagerList::iterator ogreSceneManagerSearched = ogreSceneManagerList.find(ogreTargetScene);
358 if (ogreSceneManagerSearched == ogreSceneManagerList.end())
359 SO3_EXCEPT(SExceptionItemNotFound, "Can not prepare shadow texture for the scenemanager \""+ ogreTargetScene->getName() +"\", as it seems that it does not use deferred rendering!", "SDeferredShadowManager::PrepareShadowTexture", true);
360
361 // Pause current rendering
362 Ogre::SceneManager::RenderContext* context = ogreTargetScene->_pauseRendering();
363
364 // Prepare 2D texture or Cubic texture?
365 if(light->getType() == Ogre::Light::LT_POINT)
366 PrepareShadowCubicTextureImpl(ogreTargetScene, ogreCamera, ogreViewport, light);
367 else
368 PrepareShadowTextureImpl(ogreTargetScene, ogreCamera, ogreViewport, light);
369
370 // Resume rendering
371 ogreTargetScene->_resumeRendering(context);
372
373 // VERY IMPORTANT!
374 // Set auto_param ACT_TEXTURE_VIEWPROJ_MATRIX, it's not bounded correctly when we do not use Ogre's internal shadows.
375 // As a drawback, this parameter must not be bounded as a auto_param in the program!
376 Ogre::Camera* ogreShadowCamera = 0;
377 if(light->getType() == Ogre::Light::LT_POINT)
378 ogreShadowCamera = cubicTextureCamerasByScene.find(ogreTargetScene)->second.front();
379 else
380 ogreShadowCamera = standardTextureCameraByScene.find(ogreTargetScene)->second;
381
382 assert(ogreShadowCamera != 0);
383 Ogre::GpuProgramParametersSharedPtr params = ogrePass->getFragmentProgramParameters();
384 Ogre::Matrix4 textureProjectionMatrix = PROJECTIONCLIPSPACE2DTOIMAGESPACE_PERSPECTIVE * ogreShadowCamera->getProjectionMatrixWithRSDepth() * ogreShadowCamera->getViewMatrix();
385 if (params->_findNamedConstantDefinition("shadowViewProjMat"))
386 params->setNamedConstant("shadowViewProjMat", textureProjectionMatrix);
387
388 // Return the prepared texture
389 if(light->getType() == Ogre::Light::LT_POINT)
390 return shadowCubicTexture;
391 else
392 return shadowStandardTexture;
393}
394
395void SDeferredShadowManager::PrepareShadowTextureImpl(Ogre::SceneManager* ogreTargetScene, Ogre::Camera* ogreCamera, Ogre::Viewport* ogreViewport, const Ogre::Light* ogreLight)
396{
397 // First, check if we need to create the texture
398 if(standardTextureNeedRebuild)
399 CreateShadowStandardTexture();
400
401 // Get the scene shadow standard texture camera
402 StandardTextureCameraByScene::iterator iCamera = standardTextureCameraByScene.find(ogreTargetScene);
403 Ogre::Camera* ogreShadowCamera = iCamera->second;
404
405 // Check rtt viewport
406 Ogre::RenderTarget* ogreShadowRTT = shadowStandardTexture->getBuffer()->getRenderTarget();
407 Ogre::Viewport* ogreShadowViewport = 0;
408 if(ogreShadowRTT->getNumViewports() == 0)
409 {
410 ogreShadowViewport = ogreShadowRTT->addViewport(ogreShadowCamera);
411 ogreShadowViewport->setClearEveryFrame(true);
412 ogreShadowViewport->setOverlaysEnabled(false);
413 ogreShadowViewport->setMaterialScheme(SO3_DEFERRED_SHADOWS_SCHEME_NAME);
414 ogreShadowRTT->setAutoUpdated(false);
415 }
416 else
417 ogreShadowViewport = ogreShadowRTT->getViewport(0);
418
419 // Be sure that the viewport is bind to the correct camera
420 assert(ogreShadowViewport != 0);
421 ogreShadowViewport->setCamera(ogreShadowCamera);
422
423 // Associate main view camera as LOD camera
424 ogreShadowCamera->setLodCamera(ogreCamera);
425 ogreShadowCamera->setDirection(ogreLight->getDerivedDirection());
426 if (ogreLight->getType() == Ogre::Light::LT_SPOTLIGHT)
427 {
428 ogreShadowCamera->setPosition(ogreLight->getDerivedPosition());
429 spotShadowCameraSetup->getShadowCamera(ogreTargetScene, ogreCamera, ogreViewport, ogreLight, ogreShadowCamera, 0);
430 }
431 else
432 {
433 directionalShadowCameraSetup->getShadowCamera(ogreTargetScene, ogreCamera, ogreViewport, ogreLight, ogreShadowCamera, 0);
434 }
435
436 // Further config on the material
437 shadowStandardMaterial->getTechnique(0)->getPass(0)->getTextureUnitState(0)->setProjectiveTexturing(true, ogreShadowCamera);
438
439 // Setup background colour
440 ogreShadowViewport->setBackgroundColour(Ogre::ColourValue::White);
441
442 // Update target
443 ogreShadowRTT->update();
444}
445
446void SDeferredShadowManager::PrepareShadowCubicTextureImpl(Ogre::SceneManager* ogreTargetScene, Ogre::Camera* ogreCamera, Ogre::Viewport* ogreViewport, const Ogre::Light* ogreLight)
447{
448 // First, check if we need to create the texture
449 if(cubicTextureNeedRebuild)
450 CreateShadowCubicTexture();
451
452 // Get the list of all the cubic camera for this scene
453 std::vector<Ogre::Camera*> ogreCubicCameras = cubicTextureCamerasByScene.find(ogreTargetScene)->second;
454
455 // Iterate Rtts
456 for(int cpt = 0; cpt < 6; cpt++)
457 {
458 // Get the scene shadow cubic texture camera
459 Ogre::Camera* ogreShadowCamera = ogreCubicCameras.at(cpt);
460
461 // Check rtt viewport
462 Ogre::RenderTarget* ogreShadowRTT = shadowCubicTexture->getBuffer(cpt)->getRenderTarget();
463 Ogre::Viewport* ogreShadowViewport = 0;
464 if(ogreShadowRTT->getNumViewports() == 0)
465 {
466 ogreShadowViewport = ogreShadowRTT->addViewport(ogreShadowCamera);
467 ogreShadowViewport->setClearEveryFrame(true);
468 ogreShadowViewport->setOverlaysEnabled(false);
469 ogreShadowViewport->setMaterialScheme(SO3_DEFERRED_SHADOWS_SCHEME_NAME);
470 ogreShadowRTT->setAutoUpdated(false);
471 }
472 else
473 ogreShadowViewport = ogreShadowRTT->getViewport(0);
474
475 // Be sure that the viewport is bind to the correct camera
476 assert(ogreShadowViewport != 0);
477 ogreShadowViewport->setCamera(ogreShadowCamera);
478
479 // Get the shadow camera setup
480 pointShadowCameraSetup->getShadowCamera(ogreTargetScene, ogreCamera, ogreViewport, ogreLight, ogreShadowCamera, 0);
481
482 // Override some stuff of the camera setup
483 ogreShadowCamera->setProjectionType(Ogre::PT_PERSPECTIVE);
484 ogreShadowCamera->setAspectRatio(1);
485 ogreShadowCamera->setFOVy(Ogre::Degree(90));
486
487 // Associate main view camera as LOD camera
488 ogreShadowCamera->setLodCamera(ogreCamera);
489
490 // Set position (after getShadowCameraSetup()!)
491 ogreShadowCamera->setPosition(ogreLight->getDerivedPosition());
492
493 // Set orientation (after getShadowCameraSetup()!), face the good cube face
494 ogreShadowCamera->setOrientation(Ogre::Quaternion::IDENTITY);
495 switch(cpt)
496 {
497 case 0:
498 ogreShadowCamera->yaw(Ogre::Degree(-90));
499 break;
500 case 1:
501 ogreShadowCamera->yaw(Ogre::Degree(90));
502 break;
503 case 2:
504 ogreShadowCamera->pitch(Ogre::Degree(90));
505 break;
506 case 3:
507 ogreShadowCamera->pitch(Ogre::Degree(-90));
508 break;
509 case 5:
510 ogreShadowCamera->yaw(Ogre::Degree(180));
511 break;
512 }
513
514 // Further config on the material
515 shadowCubicMaterial->getTechnique(0)->getPass(0)->getTextureUnitState(0)->setProjectiveTexturing(true, ogreShadowCamera);
516
517 // Setup background colour
518 ogreShadowViewport->setBackgroundColour(Ogre::ColourValue::White);
519
520 // Update target
521 ogreShadowRTT->update();
522 }
523}
524
525Ogre::Technique* SDeferredShadowManager::handleSchemeNotFound(unsigned short schemeIndex, const Ogre::String& schemeName, Ogre::Material* originalMaterial, unsigned short lodIndex, const Ogre::Renderable* rend)
526{
527 Ogre::Material::TechniqueIterator schemeTechniqueIt = originalMaterial->getTechniqueIterator();
528 while(schemeTechniqueIt.hasMoreElements())
529 {
530 Ogre::Technique* schemeTechnique = schemeTechniqueIt.getNext();
531 if(schemeTechnique->getSchemeName() == schemeName)
532 return schemeTechnique;
533 }
534
535 Ogre::Technique* shadowTechnique = 0;
536 if(schemeName == SO3_DEFERRED_SHADOWS_SCHEME_NAME)
537 {
538 // Get a reference to the original technique
539 Ogre::MaterialManager& ogreMaterialManager = Ogre::MaterialManager::getSingleton();
540 ogreMaterialManager.setActiveScheme(Ogre::MaterialManager::DEFAULT_SCHEME_NAME);
541 Ogre::Technique* originalTechnique = originalMaterial->getBestTechnique(lodIndex, rend);
542
543 // Get a reference to the template shadow caster material
544 Ogre::MaterialPtr shadowCasterMaterial = Ogre::MaterialManager::getSingleton().getByName(SO3_DEFERRED_SHADOW_CASTER_NAME);
545 if (!shadowCasterMaterial)
546 SO3_EXCEPT(SExceptionItemNotFound, "Cannot locate the shadow caster material named \"" + std::string(SO3_DEFERRED_SHADOW_CASTER_NAME) + "'", "SDeferredShadowManager::handleSchemeNotFound", true);
547
548 // Make sure it's loaded
549 if(!shadowCasterMaterial->isLoaded())
550 shadowCasterMaterial->load();
551
552 // Store a reference to the shadow caster technique used by the default scheme
553 Ogre::Technique* shadowCasterTechnique = shadowCasterMaterial->getBestTechnique();
554
555 // Now, get back to the deferred shadow scheme
556 ogreMaterialManager.setActiveScheme(SO3_DEFERRED_SHADOWS_SCHEME_NAME);
557
558 // Create a new empty gbuffer technique on the existing material.
559 shadowTechnique = originalMaterial->createTechnique();
560 shadowTechnique->removeAllPasses();
561 shadowTechnique->setSchemeName(SO3_DEFERRED_SHADOWS_SCHEME_NAME);
562
563 // Iterate throught the original material passes.
564 for (unsigned short i=0; i<originalTechnique->getNumPasses(); i++)
565 {
566 Ogre::Pass* originalPass = originalTechnique->getPass(i);
567 Ogre::Pass* shadowPass = shadowTechnique->createPass();
568
569 // Special case alpha-blended passes
570 if((originalPass->getSourceBlendFactor() == Ogre::SBF_SOURCE_ALPHA)
571 &&(originalPass->getDestBlendFactor() == Ogre::SBF_ONE_MINUS_SOURCE_ALPHA)
572 ||(originalPass->getAlphaRejectFunction() != Ogre::CMPF_ALWAYS_PASS))
573 {
574 // Code from Ogre::SceneManager::deriveShadowCasterPass
575 // Alpha blended passes must retain their transparency
576 shadowPass->setAlphaRejectSettings(originalPass->getAlphaRejectFunction(), originalPass->getAlphaRejectValue());
577 shadowPass->setSceneBlending(originalPass->getSourceBlendFactor(), originalPass->getDestBlendFactor());
578 shadowPass->getParent()->getParent()->setTransparencyCastsShadows(true);
579
580 // So we allow the texture units, but override the colour functions
581 // Copy texture state, shift up one since 0 is shadow texture
582 unsigned short origPassTUCount = originalPass->getNumTextureUnitStates();
583 for (unsigned short t = 0; t < origPassTUCount; ++t)
584 {
585 // copy base state
586 Ogre::TextureUnitState* shadowTextureUnit = originalPass->createTextureUnitState();
587 (*shadowTextureUnit) = *(originalPass->getTextureUnitState(t));
588
589 // override colour function. I use additive shadows, so set it to black. With non-additive shadow technique it should be the shadow colour.
590 shadowTextureUnit->setColourOperationEx(Ogre::LBX_SOURCE1, Ogre::LBS_MANUAL, Ogre::LBS_CURRENT, Ogre::ColourValue::Black);
591 }
592 }
593 else
594 {
595 // reset
596 shadowPass->setSceneBlending(Ogre::SBT_REPLACE);
597 shadowPass->setAlphaRejectFunction(Ogre::CMPF_ALWAYS_PASS);
598 }
599
600 // Propagate culling modes
601 shadowPass->setCullingMode(originalPass->getCullingMode());
602 shadowPass->setManualCullingMode(originalPass->getManualCullingMode());
603
604 // Set our shadow caster programs
605 Ogre::Pass* shadowCasterDefaultPass = shadowCasterTechnique->getPass(0);
606
607 // Start with vertex program
608 if(shadowCasterDefaultPass->hasVertexProgram())
609 {
610 shadowPass->setVertexProgram(shadowCasterDefaultPass->getVertexProgramName(), false);
611 const Ogre::GpuProgramPtr& shadowPassVertexProgram = shadowPass->getVertexProgram();
612 if (!shadowPassVertexProgram->isLoaded())
613 shadowPassVertexProgram->load();
614
615 // Copy params
616 shadowPass->setVertexProgramParameters(shadowCasterDefaultPass->getVertexProgramParameters());
617 }
618
619 // Continue with fragment program
620 if(shadowCasterDefaultPass->hasFragmentProgram())
621 {
622 shadowPass->setFragmentProgram(shadowCasterDefaultPass->getFragmentProgramName(), false);
623 const Ogre::GpuProgramPtr& shadowPassFragmentProgram = shadowPass->getVertexProgram();
624 if (!shadowPassFragmentProgram->isLoaded())
625 shadowPassFragmentProgram->load();
626
627 // Copy params
628 shadowPass->setFragmentProgramParameters(shadowCasterDefaultPass->getFragmentProgramParameters());
629 }
630
631 // handle the case where there is no fixed pipeline support
632 shadowPass->getParent()->getParent()->compile();
633 shadowPass = shadowPass->getParent()->getParent()->getBestTechnique()->getPass(0);
634
635 // All done, process the next pass.
636 }
637 }
638 return shadowTechnique;
639}
640
641}
void RegisterSceneManager(Ogre::SceneManager *targetScene)
static SDeferredShadowManager * getSingletonPtr()
void SetShadowStandardTextureFSAA(unsigned short fsaa)
void SetShadowStandardTextureSize(unsigned short size)
void SetShadowCubicTextureSize(unsigned short size)
static SDeferredShadowManager & getSingleton()
void UnregisterSceneManager(Ogre::SceneManager *existingScene)
void SetShadowStandardTexturePixelFormat(Ogre::PixelFormat fmt)
Ogre::TexturePtr & PrepareShadowTexture(Ogre::Camera *ogreCamera, Ogre::Viewport *ogreViewport, const Ogre::Light *light, Ogre::Pass *ogrePass)
void SetShadowTextureFSAA(unsigned short fsaa)
void SetShadowTextureSize(unsigned short size)
void SetShadowTexturePixelFormat(Ogre::PixelFormat fmt)
void SetShadowCubicTexturePixelFormat(Ogre::PixelFormat fmt)
void SetShadowCubicTextureFSAA(unsigned short fsaa)
virtual Ogre::Technique * handleSchemeNotFound(unsigned short schemeIndex, const Ogre::String &schemeName, Ogre::Material *originalMaterial, unsigned short lodIndex, const Ogre::Renderable *rend)
SException indicating that an attempt to create a new item with a given identifier fails cause anothe...
SException indicating that an attempt to get an item fails, cause there's no item with the given iden...