00001 /* 00002 ----------------------------------------------------------------------------- 00003 This source file is part of OGRE 00004 (Object-oriented Graphics Rendering Engine) 00005 For the latest info, see http://ogre.sourceforge.net/ 00006 00007 Copyright © 2000-2002 The OGRE Team 00008 Also see acknowledgements in Readme.html 00009 00010 This program is free software; you can redistribute it and/or modify it under 00011 the terms of the GNU Lesser General Public License as published by the Free Software 00012 Foundation; either version 2 of the License, or (at your option) any later 00013 version. 00014 00015 This program is distributed in the hope that it will be useful, but WITHOUT 00016 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 00017 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. 00018 00019 You should have received a copy of the GNU Lesser General Public License along with 00020 this program; if not, write to the Free Software Foundation, Inc., 59 Temple 00021 Place - Suite 330, Boston, MA 02111-1307, USA, or go to 00022 http://www.gnu.org/copyleft/lesser.txt. 00023 ----------------------------------------------------------------------------- 00024 */ 00025 #include "OgreStableHeaders.h" 00026 00027 #include "OgreSceneManager.h" 00028 00029 #include "OgreCamera.h" 00030 #include "OgreRenderSystem.h" 00031 #include "OgreMeshManager.h" 00032 #include "OgreMesh.h" 00033 #include "OgreSubMesh.h" 00034 #include "OgreEntity.h" 00035 #include "OgreSubEntity.h" 00036 #include "OgreLight.h" 00037 #include "OgreMath.h" 00038 #include "OgreControllerManager.h" 00039 #include "OgreMaterialManager.h" 00040 #include "OgreAnimation.h" 00041 #include "OgreAnimationTrack.h" 00042 #include "OgreRenderQueueSortingGrouping.h" 00043 #include "OgreOverlay.h" 00044 #include "OgreOverlayManager.h" 00045 #include "OgreStringConverter.h" 00046 #include "OgreRenderQueueListener.h" 00047 #include "OgreBillboardSet.h" 00048 #include "OgrePass.h" 00049 #include "OgreTechnique.h" 00050 #include "OgreTextureUnitState.h" 00051 #include "OgreException.h" 00052 #include "OgreLogManager.h" 00053 #include "OgreHardwareBufferManager.h" 00054 #include "OgreRoot.h" 00055 #include "OgreSpotShadowFadePng.h" 00056 #include "OgreGpuProgramManager.h" 00057 #include "OgreGpuProgram.h" 00058 #include "OgreShadowVolumeExtrudeProgram.h" 00059 00060 // This class implements the most basic scene manager 00061 00062 #include <cstdio> 00063 00064 namespace Ogre { 00065 00066 SceneManager::SceneManager() 00067 { 00068 // Root scene node 00069 mSceneRoot = new SceneNode(this, "root node"); 00070 mRenderQueue = 0; 00071 00072 // No sky by default 00073 mSkyPlaneEnabled = false; 00074 mSkyBoxEnabled = false; 00075 mSkyDomeEnabled = false; 00076 00077 // init sky 00078 mSkyPlaneEntity = 0; 00079 size_t i; 00080 for (i = 0; i < 6; ++i) 00081 { 00082 mSkyBoxEntity[i] = 0; 00083 } 00084 for (i = 0; i < 5; ++i) 00085 { 00086 mSkyDomeEntity[i] = 0; 00087 } 00088 mSkyPlaneNode = 0; 00089 mSkyDomeNode = 0; 00090 mSkyBoxNode = 0; 00091 00092 00093 // No fog 00094 mFogMode = FOG_NONE; 00095 00096 mDisplayNodes = false; 00097 00098 mShowBoundingBoxes = false; 00099 mShadowTechnique = SHADOWTYPE_NONE; 00100 mDebugShadows = false; 00101 mShadowDebugPass = 0; 00102 mShadowStencilPass = 0; 00103 mShadowModulativePass = 0; 00104 mShadowCasterPlainBlackPass = 0; 00105 mShadowReceiverPass = 0; 00106 mFullScreenQuad = 0; 00107 mShadowCasterSphereQuery = 0; 00108 mShadowCasterAABBQuery = 0; 00109 mShadowDirLightExtrudeDist = 10000; 00110 mIlluminationStage = IRS_NONE; 00111 mShadowFarDist = 0; 00112 mShadowFarDistSquared = 0; 00113 mShadowIndexBufferSize = 51200; 00114 mShadowTextureSize = 512; 00115 mShadowTextureCount = 1; 00116 mShadowColour = ColourValue(0.25, 0.25, 0.25); 00117 mShadowTextureOffset = 0.6; 00118 mShadowTextureFadeStart = 0.7; 00119 mShadowTextureFadeEnd = 0.9; 00120 mShadowUseInfiniteFarPlane = true; 00121 00122 00123 } 00124 00125 SceneManager::~SceneManager() 00126 { 00127 clearScene(); 00128 removeAllCameras(); 00129 delete mSceneRoot; 00130 delete mFullScreenQuad; 00131 delete mShadowCasterSphereQuery; 00132 delete mShadowCasterAABBQuery; 00133 delete mRenderQueue; 00134 } 00135 //----------------------------------------------------------------------- 00136 RenderQueue* SceneManager::getRenderQueue(void) 00137 { 00138 if (!mRenderQueue) 00139 { 00140 initRenderQueue(); 00141 } 00142 return mRenderQueue; 00143 } 00144 //----------------------------------------------------------------------- 00145 void SceneManager::initRenderQueue(void) 00146 { 00147 mRenderQueue = new RenderQueue(); 00148 // init render queues that do not need shadows 00149 mRenderQueue->getQueueGroup(RENDER_QUEUE_BACKGROUND)->setShadowsEnabled(false); 00150 mRenderQueue->getQueueGroup(RENDER_QUEUE_OVERLAY)->setShadowsEnabled(false); 00151 mRenderQueue->getQueueGroup(RENDER_QUEUE_SKIES_EARLY)->setShadowsEnabled(false); 00152 mRenderQueue->getQueueGroup(RENDER_QUEUE_SKIES_LATE)->setShadowsEnabled(false); 00153 } 00154 //----------------------------------------------------------------------- 00155 Camera* SceneManager::createCamera(const String& name) 00156 { 00157 Camera *c = new Camera(name, this); 00158 mCameras.insert(CameraList::value_type(name, c)); 00159 00160 00161 return c; 00162 } 00163 00164 //----------------------------------------------------------------------- 00165 Camera* SceneManager::getCamera(const String& name) 00166 { 00167 CameraList::iterator i = mCameras.find(name); 00168 if (i == mCameras.end()) 00169 { 00170 return 0; 00171 } 00172 else 00173 { 00174 return i->second; 00175 } 00176 } 00177 00178 //----------------------------------------------------------------------- 00179 void SceneManager::removeCamera(Camera *cam) 00180 { 00181 // Find in list 00182 CameraList::iterator i = mCameras.begin(); 00183 for (; i != mCameras.end(); ++i) 00184 { 00185 if (i->second == cam) 00186 { 00187 mCameras.erase(i); 00188 // notify render targets 00189 mDestRenderSystem->_notifyCameraRemoved(cam); 00190 delete cam; 00191 break; 00192 } 00193 } 00194 00195 } 00196 00197 //----------------------------------------------------------------------- 00198 void SceneManager::removeCamera(const String& name) 00199 { 00200 // Find in list 00201 CameraList::iterator i = mCameras.find(name); 00202 if (i != mCameras.end()) 00203 { 00204 // Notify render system 00205 mDestRenderSystem->_notifyCameraRemoved(i->second); 00206 delete i->second; 00207 mCameras.erase(i); 00208 } 00209 00210 } 00211 00212 //----------------------------------------------------------------------- 00213 void SceneManager::removeAllCameras(void) 00214 { 00215 00216 CameraList::iterator i = mCameras.begin(); 00217 for (; i != mCameras.end(); ++i) 00218 { 00219 // Notify render system 00220 mDestRenderSystem->_notifyCameraRemoved(i->second); 00221 delete i->second; 00222 } 00223 mCameras.clear(); 00224 } 00225 00226 //----------------------------------------------------------------------- 00227 Light* SceneManager::createLight(const String& name) 00228 { 00229 Light *l = new Light(name); 00230 mLights.insert(SceneLightList::value_type(name, l)); 00231 return l; 00232 } 00233 00234 //----------------------------------------------------------------------- 00235 Light* SceneManager::getLight(const String& name) 00236 { 00237 SceneLightList::iterator i = mLights.find(name); 00238 if (i == mLights.end()) 00239 { 00240 return 0; 00241 } 00242 else 00243 { 00244 return i->second; 00245 } 00246 } 00247 00248 //----------------------------------------------------------------------- 00249 void SceneManager::removeLight(Light *l) 00250 { 00251 // Find in list 00252 SceneLightList::iterator i = mLights.begin(); 00253 for (; i != mLights.end(); ++i) 00254 { 00255 if (i->second == l) 00256 { 00257 mLights.erase(i); 00258 delete l; 00259 break; 00260 } 00261 } 00262 00263 } 00264 00265 //----------------------------------------------------------------------- 00266 void SceneManager::removeLight(const String& name) 00267 { 00268 // Find in list 00269 SceneLightList::iterator i = mLights.find(name); 00270 if (i != mLights.end()) 00271 { 00272 delete i->second; 00273 mLights.erase(i); 00274 } 00275 00276 } 00277 00278 //----------------------------------------------------------------------- 00279 void SceneManager::removeAllLights(void) 00280 { 00281 00282 SceneLightList::iterator i = mLights.begin(); 00283 for (; i != mLights.end(); ++i) 00284 { 00285 delete i->second; 00286 } 00287 mLights.clear(); 00288 } 00289 //----------------------------------------------------------------------- 00290 bool SceneManager::lightLess::operator()(const Light* a, const Light* b) const 00291 { 00292 return a->tempSquareDist < b->tempSquareDist; 00293 } 00294 //----------------------------------------------------------------------- 00295 void SceneManager::_populateLightList(const Vector3& position, LightList& destList) 00296 { 00297 // Really basic trawl of the lights, then sort 00298 destList.clear(); 00299 00300 SceneLightList::iterator i, iend; 00301 iend = mLights.end(); 00302 for (i = mLights.begin(); i != iend; ++i) 00303 { 00304 Light* lt = i->second; 00305 if (lt->isVisible()) 00306 { 00307 if (lt->getType() == Light::LT_DIRECTIONAL) 00308 { 00309 // No distance 00310 lt->tempSquareDist = 0.0f; 00311 destList.push_back(lt); 00312 } 00313 else 00314 { 00315 // Calc squared distance 00316 lt->tempSquareDist = (lt->getDerivedPosition() - position).squaredLength(); 00317 // only add in-range lights 00318 Real range = lt->getAttenuationRange(); 00319 if (lt->tempSquareDist <= (range * range)) 00320 { 00321 destList.push_back(lt); 00322 } 00323 } 00324 } 00325 } 00326 00327 // Sort 00328 std::sort(destList.begin(), destList.end(), lightLess()); 00329 00330 00331 } 00332 //----------------------------------------------------------------------- 00333 Entity* SceneManager::createEntity(const String& entityName, PrefabType ptype) 00334 { 00335 switch (ptype) 00336 { 00337 case PT_PLANE: 00338 return createEntity(entityName, "Prefab_Plane"); 00339 00340 break; 00341 } 00342 00343 return 0; 00344 } 00345 00346 //----------------------------------------------------------------------- 00347 Entity* SceneManager::createEntity( 00348 const String& entityName, 00349 const String& meshName ) 00350 { 00351 // Check name not used 00352 EntityList::iterator it = mEntities.find( entityName ); 00353 if( it != mEntities.end() ) 00354 { 00355 Except( 00356 Exception::ERR_DUPLICATE_ITEM, 00357 "An entity with the name " + entityName + " already exists", 00358 "SceneManager::createEntity" ); 00359 } 00360 00361 // Get mesh (load if required) 00362 Mesh* pMesh = MeshManager::getSingleton().load( meshName ); 00363 00364 // Create entity 00365 Entity* e = new Entity( entityName, pMesh, this ); 00366 00367 // Add to internal list 00368 mEntities[entityName] = e; //.insert(EntityList::value_type(entityName, e)); 00369 00370 return e; 00371 } 00372 00373 //----------------------------------------------------------------------- 00374 Entity* SceneManager::getEntity(const String& name) 00375 { 00376 EntityList::iterator i = mEntities.find(name); 00377 if (i == mEntities.end()) 00378 { 00379 return 0; 00380 } 00381 else 00382 { 00383 return i->second; 00384 } 00385 } 00386 00387 //----------------------------------------------------------------------- 00388 void SceneManager::removeEntity(Entity *cam) 00389 { 00390 // Find in list 00391 EntityList::iterator i = mEntities.begin(); 00392 for (; i != mEntities.end(); ++i) 00393 { 00394 if (i->second == cam) 00395 { 00396 mEntities.erase(i); 00397 delete cam; 00398 break; 00399 } 00400 } 00401 00402 } 00403 00404 //----------------------------------------------------------------------- 00405 void SceneManager::removeEntity(const String& name) 00406 { 00407 // Find in list 00408 EntityList::iterator i = mEntities.find(name); 00409 if (i != mEntities.end()) 00410 { 00411 delete i->second; 00412 mEntities.erase(i); 00413 } 00414 00415 } 00416 00417 //----------------------------------------------------------------------- 00418 void SceneManager::removeAllEntities(void) 00419 { 00420 00421 EntityList::iterator i = mEntities.begin(); 00422 for (; i != mEntities.end(); ++i) 00423 { 00424 delete i->second; 00425 } 00426 mEntities.clear(); 00427 } 00428 00429 //----------------------------------------------------------------------- 00430 void SceneManager::removeAllBillboardSets(void) 00431 { 00432 // Delete all BillboardSets 00433 for (BillboardSetList::iterator bi = mBillboardSets.begin(); 00434 bi != mBillboardSets.end(); ++bi) 00435 { 00436 delete bi->second; 00437 } 00438 mBillboardSets.clear(); 00439 } 00440 //----------------------------------------------------------------------- 00441 void SceneManager::clearScene(void) 00442 { 00443 // Delete all SceneNodes, except root that is 00444 for (SceneNodeList::iterator i = mSceneNodes.begin(); 00445 i != mSceneNodes.end(); ++i) 00446 { 00447 delete i->second; 00448 } 00449 mSceneNodes.clear(); 00450 mAutoTrackingSceneNodes.clear(); 00451 00452 // Clear root node of all children 00453 mSceneRoot->removeAllChildren(); 00454 mSceneRoot->detachAllObjects(); 00455 00456 removeAllEntities(); 00457 removeAllBillboardSets(); 00458 removeAllLights(); 00459 00460 // Clear animations 00461 destroyAllAnimations(); 00462 00463 // Remove sky nodes since they've been deleted 00464 mSkyBoxNode = mSkyPlaneNode = mSkyDomeNode = 0; 00465 mSkyBoxEnabled = mSkyPlaneEnabled = mSkyDomeEnabled = false; 00466 00467 } 00468 00469 //----------------------------------------------------------------------- 00470 Material* SceneManager::createMaterial(const String& name) 00471 { 00472 // Create using MaterialManager 00473 Material* m = (Material*)MaterialManager::getSingleton().create(name); 00474 00475 00476 return m; 00477 } 00478 //----------------------------------------------------------------------- 00479 Material* SceneManager::getDefaultMaterialSettings(void) 00480 { 00481 return Material::mDefaultSettings; 00482 } 00483 //----------------------------------------------------------------------- 00484 Material* SceneManager::getMaterial(const String& name) 00485 { 00486 return (Material*)MaterialManager::getSingleton().getByName(name); 00487 } 00488 00489 //----------------------------------------------------------------------- 00490 Material* SceneManager::getMaterial(int handle) 00491 { 00492 return static_cast<Material*>( 00493 MaterialManager::getSingleton().getByHandle(handle)); 00494 } 00495 //----------------------------------------------------------------------- 00496 SceneNode* SceneManager::createSceneNode(void) 00497 { 00498 SceneNode* sn = new SceneNode(this); 00499 mSceneNodes[sn->getName()] = sn; 00500 return sn; 00501 } 00502 //----------------------------------------------------------------------- 00503 SceneNode* SceneManager::createSceneNode(const String& name) 00504 { 00505 SceneNode* sn = new SceneNode(this, name); 00506 mSceneNodes[sn->getName()] = sn; 00507 return sn; 00508 } 00509 //----------------------------------------------------------------------- 00510 void SceneManager::destroySceneNode(const String& name) 00511 { 00512 SceneNodeList::iterator i = mSceneNodes.find(name); 00513 00514 if (i == mSceneNodes.end()) 00515 { 00516 Except(Exception::ERR_ITEM_NOT_FOUND, "SceneNode '" + name + "' not found.", 00517 "SceneManager::destroySceneNode"); 00518 } 00519 00520 // Find any scene nodes which are tracking this node, and turn them off 00521 AutoTrackingSceneNodes::iterator ai, aiend; 00522 aiend = mAutoTrackingSceneNodes.end(); 00523 for (ai = mAutoTrackingSceneNodes.begin(); ai != aiend; ++ai) 00524 { 00525 SceneNode* n = *ai; 00526 // Tracking this node 00527 if (n->getAutoTrackTarget() == i->second) 00528 { 00529 // turn off, this will notify SceneManager to remove 00530 n->setAutoTracking(false); 00531 // no need to reset iterator since set erase does not invalidate 00532 } 00533 // node is itself a tracker 00534 else if (n == i->second) 00535 { 00536 mAutoTrackingSceneNodes.erase(ai); 00537 } 00538 } 00539 00540 delete i->second; 00541 mSceneNodes.erase(i); 00542 } 00543 //----------------------------------------------------------------------- 00544 SceneNode* SceneManager::getRootSceneNode(void) const 00545 { 00546 return mSceneRoot; 00547 } 00548 //----------------------------------------------------------------------- 00549 SceneNode* SceneManager::getSceneNode(const String& name) const 00550 { 00551 SceneNodeList::const_iterator i = mSceneNodes.find(name); 00552 00553 if (i == mSceneNodes.end()) 00554 { 00555 Except(Exception::ERR_ITEM_NOT_FOUND, "SceneNode '" + name + "' not found.", 00556 "SceneManager::getSceneNode"); 00557 } 00558 00559 return i->second; 00560 00561 } 00562 //----------------------------------------------------------------------- 00563 Pass* SceneManager::setPass(Pass* pass) 00564 { 00565 static bool lastUsedVertexProgram = false; 00566 static bool lastUsedFragmentProgram = false; 00567 00568 if (mIlluminationStage == IRS_RENDER_TO_TEXTURE) 00569 { 00570 // Derive a special shadow caster pass from this one 00571 pass = deriveShadowCasterPass(pass); 00572 } 00573 else if (mIlluminationStage == IRS_RENDER_MODULATIVE_PASS) 00574 { 00575 pass = deriveShadowReceiverPass(pass); 00576 } 00577 00578 // TEST 00579 /* 00580 LogManager::getSingleton().logMessage("BEGIN PASS " + StringConverter::toString(pass->getIndex()) + 00581 " of " + pass->getParent()->getParent()->getName()); 00582 */ 00583 00584 if (pass->hasVertexProgram()) 00585 { 00586 mDestRenderSystem->bindGpuProgram(pass->getVertexProgram()->_getBindingDelegate()); 00587 // bind parameters later since they can be per-object 00588 lastUsedVertexProgram = true; 00589 } 00590 else 00591 { 00592 // Unbind program? 00593 if (lastUsedVertexProgram) 00594 { 00595 mDestRenderSystem->unbindGpuProgram(GPT_VERTEX_PROGRAM); 00596 lastUsedVertexProgram = false; 00597 } 00598 // Set fixed-function vertex parameters 00599 00600 // Set surface reflectance properties, only valid if lighting is enabled 00601 if (pass->getLightingEnabled()) 00602 { 00603 mDestRenderSystem->_setSurfaceParams( 00604 pass->getAmbient(), 00605 pass->getDiffuse(), 00606 pass->getSpecular(), 00607 pass->getSelfIllumination(), 00608 pass->getShininess() ); 00609 } 00610 00611 // Dynamic lighting enabled? 00612 mDestRenderSystem->setLightingEnabled(pass->getLightingEnabled()); 00613 } 00614 00615 // Using a fragment program? 00616 if (pass->hasFragmentProgram()) 00617 { 00618 mDestRenderSystem->bindGpuProgram( 00619 pass->getFragmentProgram()->_getBindingDelegate()); 00620 // bind parameters later since they can be per-object 00621 lastUsedFragmentProgram = true; 00622 } 00623 else 00624 { 00625 // Unbind program? 00626 if (lastUsedFragmentProgram) 00627 { 00628 mDestRenderSystem->unbindGpuProgram(GPT_FRAGMENT_PROGRAM); 00629 lastUsedFragmentProgram = false; 00630 } 00631 00632 // Set fixed-function fragment settings 00633 00634 // Fog (assumes we want pixel fog which is the usual) 00635 // New fog params can either be from scene or from material 00636 FogMode newFogMode; 00637 ColourValue newFogColour; 00638 Real newFogStart, newFogEnd, newFogDensity; 00639 if (pass->getFogOverride()) 00640 { 00641 // New fog params from material 00642 newFogMode = pass->getFogMode(); 00643 newFogColour = pass->getFogColour(); 00644 newFogStart = pass->getFogStart(); 00645 newFogEnd = pass->getFogEnd(); 00646 newFogDensity = pass->getFogDensity(); 00647 } 00648 else 00649 { 00650 // New fog params from scene 00651 newFogMode = mFogMode; 00652 newFogColour = mFogColour; 00653 newFogStart = mFogStart; 00654 newFogEnd = mFogEnd; 00655 newFogDensity = mFogDensity; 00656 } 00657 mDestRenderSystem->_setFog( 00658 newFogMode, newFogColour, newFogDensity, newFogStart, newFogEnd); 00659 00660 } 00661 00662 // The rest of the settings are the same no matter whether we use programs or not 00663 00664 // Set scene blending 00665 mDestRenderSystem->_setSceneBlending( 00666 pass->getSourceBlendFactor(), pass->getDestBlendFactor()); 00667 00668 00669 // Texture unit settings 00670 00671 Pass::TextureUnitStateIterator texIter = pass->getTextureUnitStateIterator(); 00672 size_t unit = 0; 00673 while(texIter.hasMoreElements()) 00674 { 00675 TextureUnitState* pTex = texIter.getNext(); 00676 mDestRenderSystem->_setTextureUnitSettings(unit, *pTex); 00677 ++unit; 00678 } 00679 // Disable remaining texture units 00680 mDestRenderSystem->_disableTextureUnitsFrom(pass->getNumTextureUnitStates()); 00681 00682 // Set up non-texture related material settings 00683 // Depth buffer settings 00684 mDestRenderSystem->_setDepthBufferFunction(pass->getDepthFunction()); 00685 mDestRenderSystem->_setDepthBufferCheckEnabled(pass->getDepthCheckEnabled()); 00686 mDestRenderSystem->_setDepthBufferWriteEnabled(pass->getDepthWriteEnabled()); 00687 mDestRenderSystem->_setDepthBias(pass->getDepthBias()); 00688 // Set colour write mode 00689 // Right now we only use on/off, not per-channel 00690 bool colWrite = pass->getColourWriteEnabled(); 00691 mDestRenderSystem->_setColourBufferWriteEnabled(colWrite, colWrite, colWrite, colWrite); 00692 // Culling mode 00693 mDestRenderSystem->_setCullingMode(pass->getCullingMode()); 00694 // Shading 00695 mDestRenderSystem->setShadingType(pass->getShadingMode()); 00696 00697 return pass; 00698 } 00699 //----------------------------------------------------------------------- 00700 void SceneManager::_renderScene(Camera* camera, Viewport* vp, bool includeOverlays) 00701 { 00702 Root::getSingleton()._setCurrentSceneManager(this); 00703 // Prep Pass for use in debug shadows 00704 initShadowVolumeMaterials(); 00705 // Perform a quick pre-check to see whether we should override far distance 00706 // When using stencil volumes we have to use infinite far distance 00707 // to prevent dark caps getting clipped 00708 if ((mShadowTechnique == SHADOWTYPE_STENCIL_ADDITIVE || 00709 mShadowTechnique == SHADOWTYPE_STENCIL_MODULATIVE) && 00710 camera->getFarClipDistance() != 0 && 00711 mDestRenderSystem->getCapabilities()->hasCapability(RSC_INFINITE_FAR_PLANE) && 00712 mShadowUseInfiniteFarPlane) 00713 { 00714 // infinite far distance 00715 camera->setFarClipDistance(0); 00716 } 00717 00718 mCameraInProgress = camera; 00719 mCamChanged = true; 00720 00721 00722 // Update the scene, only do this once per frame 00723 static unsigned long lastFrameNumber = 0; 00724 unsigned long thisFrameNumber = Root::getSingleton().getCurrentFrameNumber(); 00725 if (thisFrameNumber != lastFrameNumber) 00726 { 00727 // Update animations 00728 _applySceneAnimations(); 00729 // Update controllers 00730 ControllerManager::getSingleton().updateAllControllers(); 00731 lastFrameNumber = thisFrameNumber; 00732 } 00733 00734 // Update scene graph for this camera (can happen multiple times per frame) 00735 _updateSceneGraph(camera); 00736 00737 // Auto-track nodes 00738 AutoTrackingSceneNodes::iterator atsni, atsniend; 00739 atsniend = mAutoTrackingSceneNodes.end(); 00740 for (atsni = mAutoTrackingSceneNodes.begin(); atsni != atsniend; ++atsni) 00741 { 00742 (*atsni)->_autoTrack(); 00743 } 00744 // Auto-track camera if required 00745 camera->_autoTrack(); 00746 00747 00748 // Are we using any shadows at all? 00749 if (mShadowTechnique != SHADOWTYPE_NONE && 00750 mIlluminationStage != IRS_RENDER_TO_TEXTURE) 00751 { 00752 // Locate any lights which could be affecting the frustum 00753 findLightsAffectingFrustum(camera); 00754 if (mShadowTechnique == SHADOWTYPE_TEXTURE_MODULATIVE 00755 /* || mShadowTechnique == SHADOWTYPE_TEXTURE_SHADOWMAP */) 00756 { 00757 // ******* 00758 // WARNING 00759 // ******* 00760 // This call will result in re-entrant calls to this method 00761 // therefore anything which comes before this is NOT 00762 // guaranteed persistent. Make sure that anything which 00763 // MUST be specific to this camera / target is done 00764 // AFTER THIS POINT 00765 prepareShadowTextures(camera, vp); 00766 // reset the cameras because of the re-entrant call 00767 mCameraInProgress = camera; 00768 mCamChanged = true; 00769 } 00770 } 00771 00772 // Invert vertex winding? 00773 if (camera->isReflected()) 00774 { 00775 mDestRenderSystem->setInvertVertexWinding(true); 00776 } 00777 else 00778 { 00779 mDestRenderSystem->setInvertVertexWinding(false); 00780 } 00781 00782 // Set the viewport 00783 setViewport(vp); 00784 00785 // Tell params about camera 00786 mAutoParamDataSource.setCurrentCamera(camera); 00787 // Set autoparams for finite dir light extrusion 00788 mAutoParamDataSource.setShadowDirLightExtrusionDistance(mShadowDirLightExtrudeDist); 00789 00790 // Tell params about current ambient light 00791 mAutoParamDataSource.setAmbientLightColour(mAmbientLight); 00792 00793 // Tell params about render target 00794 mAutoParamDataSource.setCurrentRenderTarget(vp->getTarget()); 00795 00796 00797 // Set camera window clipping planes (if any) 00798 if (mDestRenderSystem->getCapabilities()->hasCapability(RSC_USER_CLIP_PLANES)) 00799 { 00800 if (camera->isWindowSet()) 00801 { 00802 const std::vector<Plane>& planeList = 00803 camera->getWindowPlanes(); 00804 for (ushort i = 0; i < 4; ++i) 00805 { 00806 mDestRenderSystem->enableClipPlane(i, true); 00807 mDestRenderSystem->setClipPlane(i, planeList[i]); 00808 } 00809 } 00810 else 00811 { 00812 for (ushort i = 0; i < 4; ++i) 00813 { 00814 mDestRenderSystem->enableClipPlane(i, false); 00815 } 00816 } 00817 } 00818 00819 // Clear the render queue 00820 getRenderQueue()->clear(); 00821 00822 // Parse the scene and tag visibles 00823 _findVisibleObjects(camera, 00824 mIlluminationStage == IRS_RENDER_TO_TEXTURE? true : false); 00825 // Add overlays, if viewport deems it 00826 if (vp->getOverlaysEnabled()) 00827 { 00828 OverlayManager::getSingleton()._queueOverlaysForRendering(camera, getRenderQueue(), vp); 00829 } 00830 // Queue skies 00831 _queueSkiesForRendering(camera); 00832 00833 00834 // Don't do view / proj here anymore 00835 // Checked per renderable now, although only changed when required 00836 //mDestRenderSystem->_setViewMatrix(camera->getViewMatrix()); 00837 //mDestRenderSystem->_setProjectionMatrix(camera->getProjectionMatrix()); 00838 00839 mDestRenderSystem->_beginGeometryCount(); 00840 // Begin the frame 00841 mDestRenderSystem->_beginFrame(); 00842 00843 // Set rasterisation mode 00844 mDestRenderSystem->_setRasterisationMode(camera->getDetailLevel()); 00845 00846 // Render scene content 00847 _renderVisibleObjects(); 00848 00849 // End frame 00850 mDestRenderSystem->_endFrame(); 00851 00852 // Notify camera or vis faces 00853 camera->_notifyRenderedFaces(mDestRenderSystem->_getFaceCount()); 00854 00855 00856 00857 } 00858 00859 00860 //----------------------------------------------------------------------- 00861 void SceneManager::_setDestinationRenderSystem(RenderSystem* sys) 00862 { 00863 mDestRenderSystem = sys; 00864 00865 } 00866 00867 00868 //----------------------------------------------------------------------- 00869 void SceneManager::setWorldGeometry(const String& filename) 00870 { 00871 // This default implementation cannot handle world geometry 00872 Except(Exception::ERR_INVALIDPARAMS, 00873 "World geometry is not supported by the generic SceneManager.", 00874 "SceneManager::setWorldGeometry"); 00875 } 00876 00877 //----------------------------------------------------------------------- 00878 bool SceneManager::materialLess::operator() (const Material* x, const Material* y) const 00879 { 00880 // If x transparent and y not, x > y (since x has to overlap y) 00881 if (x->isTransparent() && !y->isTransparent()) 00882 { 00883 return false; 00884 } 00885 // If y is transparent and x not, x < y 00886 else if (!x->isTransparent() && y->isTransparent()) 00887 { 00888 return true; 00889 } 00890 else 00891 { 00892 // Otherwise don't care (both transparent or both solid) 00893 // Just arbitrarily use pointer 00894 return x < y; 00895 } 00896 00897 } 00898 00899 //----------------------------------------------------------------------- 00900 void SceneManager::setSkyPlane( 00901 bool enable, 00902 const Plane& plane, 00903 const String& materialName, 00904 Real gscale, 00905 Real tiling, 00906 bool drawFirst, 00907 Real bow) 00908 { 00909 mSkyPlaneEnabled = enable; 00910 if (enable) 00911 { 00912 String meshName = "SkyPlane"; 00913 mSkyPlane = plane; 00914 00915 Material* m = getMaterial(materialName); 00916 if (!m) 00917 { 00918 Except(Exception::ERR_INVALIDPARAMS, 00919 "Sky plane material '" + materialName + "' not found.", 00920 "SceneManager::setSkyPlane"); 00921 } 00922 // Make sure the material doesn't update the depth buffer 00923 m->setDepthWriteEnabled(false); 00924 // Ensure loaded 00925 m->load(); 00926 00927 mSkyPlaneDrawFirst = drawFirst; 00928 00929 // Set up the plane 00930 Mesh* planeMesh = (Mesh*)MeshManager::getSingleton().getByName(meshName); 00931 if (planeMesh) 00932 { 00933 // Destroy the old one 00934 MeshManager::getSingleton().unload(planeMesh); 00935 delete planeMesh; 00936 } 00937 00938 // Create up vector 00939 Vector3 up = plane.normal.crossProduct(Vector3::UNIT_X); 00940 if (up == Vector3::ZERO) 00941 up = plane.normal.crossProduct(-Vector3::UNIT_Z); 00942 00943 // Create skyplane 00944 if( bow > 0 ) 00945 { 00946 // Build a curved skyplane 00947 planeMesh = MeshManager::getSingleton().createCurvedPlane(meshName, plane, gscale * 100, gscale * 100, gscale * bow * 100, 6, 6, false, 1, tiling, tiling, up); 00948 } 00949 else 00950 { 00951 planeMesh = MeshManager::getSingleton().createPlane(meshName, plane, gscale * 100, gscale * 100, 1, 1, false, 1, tiling, tiling, up); 00952 } 00953 00954 // Create entity 00955 if (mSkyPlaneEntity) 00956 { 00957 // destroy old one, do it by name for speed 00958 removeEntity(meshName); 00959 } 00960 // Create, use the same name for mesh and entity 00961 mSkyPlaneEntity = createEntity(meshName, meshName); 00962 mSkyPlaneEntity->setMaterialName(materialName); 00963 mSkyPlaneEntity->setCastShadows(false); 00964 00965 // Create node and attach 00966 if (!mSkyPlaneNode) 00967 { 00968 mSkyPlaneNode = createSceneNode(meshName + "Node"); 00969 } 00970 else 00971 { 00972 mSkyPlaneNode->detachAllObjects(); 00973 } 00974 mSkyPlaneNode->attachObject(mSkyPlaneEntity); 00975 00976 } 00977 } 00978 //----------------------------------------------------------------------- 00979 void SceneManager::setSkyBox( 00980 bool enable, 00981 const String& materialName, 00982 Real distance, 00983 bool drawFirst, 00984 const Quaternion& orientation ) 00985 { 00986 mSkyBoxEnabled = enable; 00987 if (enable) 00988 { 00989 Material* m = getMaterial(materialName); 00990 if (!m) 00991 { 00992 Except(Exception::ERR_INVALIDPARAMS, 00993 "Sky box material '" + materialName + " not found.", 00994 "SceneManager::setSkyBox"); 00995 } 00996 // Make sure the material doesn't update the depth buffer 00997 m->setDepthWriteEnabled(false); 00998 // Ensure loaded 00999 m->load(); 01000 // Also clamp texture, don't wrap (otherwise edges can get filtered) 01001 m->getBestTechnique()->getPass(0)->getTextureUnitState(0)->setTextureAddressingMode(TextureUnitState::TAM_CLAMP); 01002 01003 01004 mSkyBoxDrawFirst = drawFirst; 01005 01006 // Create node 01007 if (!mSkyBoxNode) 01008 { 01009 mSkyBoxNode = createSceneNode("SkyBoxNode"); 01010 } 01011 else 01012 { 01013 mSkyBoxNode->detachAllObjects(); 01014 } 01015 01016 MaterialManager& matMgr = MaterialManager::getSingleton(); 01017 // Set up the box (6 planes) 01018 for (int i = 0; i < 6; ++i) 01019 { 01020 Mesh* planeMesh = createSkyboxPlane((BoxPlane)i, distance, orientation); 01021 String entName = "SkyBoxPlane" + StringConverter::toString(i); 01022 01023 // Create entity 01024 if (mSkyBoxEntity[i]) 01025 { 01026 // destroy old one, do it by name for speed 01027 removeEntity(entName); 01028 } 01029 mSkyBoxEntity[i] = createEntity(entName, planeMesh->getName()); 01030 mSkyBoxEntity[i]->setCastShadows(false); 01031 // Have to create 6 materials, one for each frame 01032 // Used to use combined material but now we're using queue we can't split to change frame 01033 // This doesn't use much memory because textures aren't duplicated 01034 Material* boxMat = (Material*)matMgr.getByName(entName); 01035 if (!boxMat) 01036 { 01037 // Create new by clone 01038 boxMat = m->clone(entName); 01039 boxMat->load(); 01040 } 01041 else 01042 { 01043 // Copy over existing 01044 m->copyDetailsTo(boxMat); 01045 boxMat->load(); 01046 } 01047 // Set active frame 01048 boxMat->getBestTechnique()->getPass(0)->getTextureUnitState(0) 01049 ->setCurrentFrame(i); 01050 01051 mSkyBoxEntity[i]->setMaterialName(boxMat->getName()); 01052 01053 // Attach to node 01054 mSkyBoxNode->attachObject(mSkyBoxEntity[i]); 01055 } // for each plane 01056 01057 } 01058 01059 } 01060 //----------------------------------------------------------------------- 01061 void SceneManager::setSkyDome( 01062 bool enable, 01063 const String& materialName, 01064 Real curvature, 01065 Real tiling, 01066 Real distance, 01067 bool drawFirst, 01068 const Quaternion& orientation ) 01069 { 01070 mSkyDomeEnabled = enable; 01071 if (enable) 01072 { 01073 Material* m = getMaterial(materialName); 01074 if (!m) 01075 { 01076 Except(Exception::ERR_INVALIDPARAMS, 01077 "Sky dome material '" + materialName + " not found.", 01078 "SceneManager::setSkyDome"); 01079 } 01080 // Make sure the material doesn't update the depth buffer 01081 m->setDepthWriteEnabled(false); 01082 // Ensure loaded 01083 m->load(); 01084 01085 mSkyDomeDrawFirst = drawFirst; 01086 01087 // Create node 01088 if (!mSkyDomeNode) 01089 { 01090 mSkyDomeNode = createSceneNode("SkyDomeNode"); 01091 } 01092 else 01093 { 01094 mSkyDomeNode->detachAllObjects(); 01095 } 01096 01097 // Set up the dome (5 planes) 01098 for (int i = 0; i < 5; ++i) 01099 { 01100 Mesh* planeMesh = createSkydomePlane((BoxPlane)i, curvature, tiling, distance, orientation); 01101 01102 String entName = "SkyDomePlane" + StringConverter::toString(i); 01103 01104 // Create entity 01105 if (mSkyDomeEntity[i]) 01106 { 01107 // destroy old one, do it by name for speed 01108 removeEntity(entName); 01109 } 01110 mSkyDomeEntity[i] = createEntity(entName, planeMesh->getName()); 01111 mSkyDomeEntity[i]->setMaterialName(m->getName()); 01112 mSkyDomeEntity[i]->setCastShadows(false); 01113 01114 // Attach to node 01115 mSkyDomeNode->attachObject(mSkyDomeEntity[i]); 01116 } // for each plane 01117 01118 } 01119 } 01120 //----------------------------------------------------------------------- 01121 Mesh* SceneManager::createSkyboxPlane( 01122 BoxPlane bp, 01123 Real distance, 01124 const Quaternion& orientation ) 01125 { 01126 Plane plane; 01127 String meshName; 01128 Vector3 up; 01129 01130 meshName = "SkyBoxPlane_"; 01131 // Set up plane equation 01132 plane.d = distance; 01133 switch(bp) 01134 { 01135 case BP_FRONT: 01136 plane.normal = Vector3::UNIT_Z; 01137 up = Vector3::UNIT_Y; 01138 meshName += "Front"; 01139 break; 01140 case BP_BACK: 01141 plane.normal = -Vector3::UNIT_Z; 01142 up = Vector3::UNIT_Y; 01143 meshName += "Back"; 01144 break; 01145 case BP_LEFT: 01146 plane.normal = Vector3::UNIT_X; 01147 up = Vector3::UNIT_Y; 01148 meshName += "Left"; 01149 break; 01150 case BP_RIGHT: 01151 plane.normal = -Vector3::UNIT_X; 01152 up = Vector3::UNIT_Y; 01153 meshName += "Right"; 01154 break; 01155 case BP_UP: 01156 plane.normal = -Vector3::UNIT_Y; 01157 up = Vector3::UNIT_Z; 01158 meshName += "Up"; 01159 break; 01160 case BP_DOWN: 01161 plane.normal = Vector3::UNIT_Y; 01162 up = -Vector3::UNIT_Z; 01163 meshName += "Down"; 01164 break; 01165 } 01166 // Modify by orientation 01167 plane.normal = orientation * plane.normal; 01168 up = orientation * up; 01169 01170 01171 // Check to see if existing plane 01172 MeshManager& mm = MeshManager::getSingleton(); 01173 Mesh* planeMesh = (Mesh*)mm.getByName(meshName); 01174 if(planeMesh) 01175 { 01176 // destroy existing 01177 mm.unload(planeMesh); 01178 delete planeMesh; 01179 } 01180 // Create new 01181 Real planeSize = distance * 2; 01182 const int BOX_SEGMENTS = 1; 01183 planeMesh = mm.createPlane(meshName, plane, planeSize, planeSize, BOX_SEGMENTS, BOX_SEGMENTS, false, 1, 1, 1, up); 01184 01185 //planeMesh->_dumpContents(meshName); 01186 01187 return planeMesh; 01188 01189 } 01190 //----------------------------------------------------------------------- 01191 Mesh* SceneManager::createSkydomePlane( 01192 BoxPlane bp, 01193 Real curvature, 01194 Real tiling, 01195 Real distance, 01196 const Quaternion& orientation ) 01197 { 01198 01199 Plane plane; 01200 String meshName; 01201 Vector3 up; 01202 01203 meshName = "SkyDomePlane_"; 01204 // Set up plane equation 01205 plane.d = distance; 01206 switch(bp) 01207 { 01208 case BP_FRONT: 01209 plane.normal = Vector3::UNIT_Z; 01210 up = Vector3::UNIT_Y; 01211 meshName += "Front"; 01212 break; 01213 case BP_BACK: 01214 plane.normal = -Vector3::UNIT_Z; 01215 up = Vector3::UNIT_Y; 01216 meshName += "Back"; 01217 break; 01218 case BP_LEFT: 01219 plane.normal = Vector3::UNIT_X; 01220 up = Vector3::UNIT_Y; 01221 meshName += "Left"; 01222 break; 01223 case BP_RIGHT: 01224 plane.normal = -Vector3::UNIT_X; 01225 up = Vector3::UNIT_Y; 01226 meshName += "Right"; 01227 break; 01228 case BP_UP: 01229 plane.normal = -Vector3::UNIT_Y; 01230 up = Vector3::UNIT_Z; 01231 meshName += "Up"; 01232 break; 01233 case BP_DOWN: 01234 // no down 01235 return 0; 01236 } 01237 // Modify by orientation 01238 plane.normal = orientation * plane.normal; 01239 up = orientation * up; 01240 01241 // Check to see if existing plane 01242 MeshManager& mm = MeshManager::getSingleton(); 01243 Mesh* planeMesh = (Mesh*)mm.getByName(meshName); 01244 if(planeMesh) 01245 { 01246 // destroy existing 01247 mm.unload(planeMesh); 01248 delete planeMesh; 01249 } 01250 // Create new 01251 Real planeSize = distance * 2; 01252 const int BOX_SEGMENTS = 16; 01253 planeMesh = mm.createCurvedIllusionPlane(meshName, plane, planeSize, planeSize, curvature, 01254 BOX_SEGMENTS, BOX_SEGMENTS, false, 1, tiling, tiling, up, orientation, HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY, HardwareBuffer::HBU_STATIC_WRITE_ONLY, 01255 false, false); 01256 01257 //planeMesh->_dumpContents(meshName); 01258 01259 return planeMesh; 01260 01261 } 01262 01263 01264 //----------------------------------------------------------------------- 01265 void SceneManager::_updateSceneGraph(Camera* cam) 01266 { 01267 // Cascade down the graph updating transforms & world bounds 01268 // In this implementation, just update from the root 01269 // Smarter SceneManager subclasses may choose to update only 01270 // certain scene graph branches 01271 mSceneRoot->_update(true, false); 01272 01273 01274 } 01275 //----------------------------------------------------------------------- 01276 void SceneManager::_findVisibleObjects(Camera* cam, bool onlyShadowCasters) 01277 { 01278 // Tell nodes to find, cascade down all nodes 01279 mSceneRoot->_findVisibleObjects(cam, getRenderQueue(), true, 01280 mDisplayNodes, onlyShadowCasters); 01281 01282 } 01283 //----------------------------------------------------------------------- 01284 void SceneManager::_renderVisibleObjects(void) 01285 { 01286 // Render each separate queue 01287 RenderQueue::QueueGroupIterator queueIt = getRenderQueue()->_getQueueGroupIterator(); 01288 01289 // NB only queues which have been created are rendered, no time is wasted 01290 // parsing through non-existent queues (even though there are 10 available) 01291 01292 while (queueIt.hasMoreElements()) 01293 { 01294 // Get queue group id 01295 RenderQueueGroupID qId = queueIt.peekNextKey(); 01296 RenderQueueGroup* pGroup = queueIt.getNext(); 01297 01298 01299 bool repeatQueue = false; 01300 do // for repeating queues 01301 { 01302 // Fire queue started event 01303 if (fireRenderQueueStarted(qId)) 01304 { 01305 // Someone requested we skip this queue 01306 continue; 01307 } 01308 01309 renderQueueGroupObjects(pGroup); 01310 01311 // Fire queue ended event 01312 if (fireRenderQueueEnded(qId)) 01313 { 01314 // Someone requested we repeat this queue 01315 repeatQueue = true; 01316 } 01317 else 01318 { 01319 repeatQueue = false; 01320 } 01321 } while (repeatQueue); 01322 01323 } // for each queue group 01324 01325 } 01326 //----------------------------------------------------------------------- 01327 void SceneManager::renderAdditiveStencilShadowedQueueGroupObjects(RenderQueueGroup* pGroup) 01328 { 01329 RenderQueueGroup::PriorityMapIterator groupIt = pGroup->getIterator(); 01330 LightList lightList; 01331 01332 while (groupIt.hasMoreElements()) 01333 { 01334 RenderPriorityGroup* pPriorityGrp = groupIt.getNext(); 01335 01336 // Sort the queue first 01337 pPriorityGrp->sort(mCameraInProgress); 01338 01339 // Clear light list 01340 lightList.clear(); 01341 01342 // Render all the ambient passes first, no light iteration, no lights 01343 mIlluminationStage = IRS_AMBIENT; 01344 renderObjects(pPriorityGrp->_getSolidPasses(), false, &lightList); 01345 // Also render any objects which have receive shadows disabled 01346 renderObjects(pPriorityGrp->_getSolidPassesNoShadow(), true); 01347 01348 01349 // Now iterate per light 01350 mIlluminationStage = IRS_PER_LIGHT; 01351 01352 // Iterate over lights, render all volumes to stencil 01353 LightList::const_iterator li, liend; 01354 liend = mLightsAffectingFrustum.end(); 01355 01356 for (li = mLightsAffectingFrustum.begin(); li != liend; ++li) 01357 { 01358 Light* l = *li; 01359 // Set light state 01360 01361 if (l->getCastShadows()) 01362 { 01363 // Clear stencil 01364 mDestRenderSystem->clearFrameBuffer(FBT_STENCIL); 01365 renderShadowVolumesToStencil(l, mCameraInProgress); 01366 // turn stencil check on 01367 mDestRenderSystem->setStencilCheckEnabled(true); 01368 // NB we render where the stencil is equal to zero to render lit areas 01369 mDestRenderSystem->setStencilBufferParams(CMPF_EQUAL, 0); 01370 } 01371 01372 // render lighting passes for this light 01373 if (lightList.empty()) 01374 lightList.push_back(l); 01375 else 01376 lightList[0] = l; 01377 renderObjects(pPriorityGrp->_getSolidPassesDiffuseSpecular(), false, &lightList); 01378 01379 // Reset stencil params 01380 mDestRenderSystem->setStencilBufferParams(); 01381 mDestRenderSystem->setStencilCheckEnabled(false); 01382 mDestRenderSystem->_setDepthBufferParams(); 01383 01384 }// for each light 01385 01386 01387 // Now render decal passes, no need to set lights as lighting will be disabled 01388 mIlluminationStage = IRS_DECAL; 01389 renderObjects(pPriorityGrp->_getSolidPassesDecal(), false); 01390 01391 01392 }// for each priority 01393 01394 // reset lighting stage 01395 mIlluminationStage = IRS_NONE; 01396 01397 // Iterate again - variable name changed to appease gcc. 01398 RenderQueueGroup::PriorityMapIterator groupIt2 = pGroup->getIterator(); 01399 while (groupIt2.hasMoreElements()) 01400 { 01401 RenderPriorityGroup* pPriorityGrp = groupIt2.getNext(); 01402 01403 // Do transparents 01404 renderObjects(pPriorityGrp->_getTransparentPasses(), true); 01405 01406 }// for each priority 01407 01408 01409 } 01410 //----------------------------------------------------------------------- 01411 void SceneManager::renderModulativeStencilShadowedQueueGroupObjects(RenderQueueGroup* pGroup) 01412 { 01413 /* For each light, we need to render all the solids from each group, 01414 then do the modulative shadows, then render the transparents from 01415 each group. 01416 Now, this means we are going to reorder things more, but that it required 01417 if the shadows are to look correct. The overall order is preserved anyway, 01418 it's just that all the transparents are at the end instead of them being 01419 interleaved as in the normal rendering loop. 01420 */ 01421 // Iterate through priorities 01422 RenderQueueGroup::PriorityMapIterator groupIt = pGroup->getIterator(); 01423 01424 while (groupIt.hasMoreElements()) 01425 { 01426 RenderPriorityGroup* pPriorityGrp = groupIt.getNext(); 01427 01428 // Sort the queue first 01429 pPriorityGrp->sort(mCameraInProgress); 01430 01431 // Do (shadowable) solids 01432 renderObjects(pPriorityGrp->_getSolidPasses(), true); 01433 } 01434 01435 01436 // Iterate over lights, render all volumes to stencil 01437 LightList::const_iterator li, liend; 01438 liend = mLightsAffectingFrustum.end(); 01439 01440 for (li = mLightsAffectingFrustum.begin(); li != liend; ++li) 01441 { 01442 Light* l = *li; 01443 if (l->getCastShadows()) 01444 { 01445 // Clear stencil 01446 mDestRenderSystem->clearFrameBuffer(FBT_STENCIL); 01447 renderShadowVolumesToStencil(l, mCameraInProgress); 01448 // render full-screen shadow modulator for all lights 01449 setPass(mShadowModulativePass); 01450 // turn stencil check on 01451 mDestRenderSystem->setStencilCheckEnabled(true); 01452 // NB we render where the stencil is not equal to zero to render shadows, not lit areas 01453 mDestRenderSystem->setStencilBufferParams(CMPF_NOT_EQUAL, 0); 01454 renderSingleObject(mFullScreenQuad, mShadowModulativePass, false); 01455 // Reset stencil params 01456 mDestRenderSystem->setStencilBufferParams(); 01457 mDestRenderSystem->setStencilCheckEnabled(false); 01458 mDestRenderSystem->_setDepthBufferParams(); 01459 } 01460 01461 }// for each light 01462 01463 // Iterate again - variable name changed to appease gcc. 01464 RenderQueueGroup::PriorityMapIterator groupIt2 = pGroup->getIterator(); 01465 while (groupIt2.hasMoreElements()) 01466 { 01467 RenderPriorityGroup* pPriorityGrp = groupIt2.getNext(); 01468 01469 // Do non-shadowable solids 01470 renderObjects(pPriorityGrp->_getSolidPassesNoShadow(), true); 01471 01472 }// for each priority 01473 01474 01475 // Iterate again - variable name changed to appease gcc. 01476 RenderQueueGroup::PriorityMapIterator groupIt3 = pGroup->getIterator(); 01477 while (groupIt3.hasMoreElements()) 01478 { 01479 RenderPriorityGroup* pPriorityGrp = groupIt3.getNext(); 01480 01481 // Do transparents 01482 renderObjects(pPriorityGrp->_getTransparentPasses(), true); 01483 01484 }// for each priority 01485 01486 } 01487 //----------------------------------------------------------------------- 01488 void SceneManager::renderTextureShadowCasterQueueGroupObjects(RenderQueueGroup* pGroup) 01489 { 01490 static LightList nullLightList; 01491 // This is like the basic group render, except we skip all transparents 01492 // and we also render any non-shadowed objects 01493 // Note that non-shadow casters will have already been eliminated during 01494 // _findVisibleObjects 01495 01496 // Iterate through priorities 01497 RenderQueueGroup::PriorityMapIterator groupIt = pGroup->getIterator(); 01498 01499 // Override auto param ambient to force vertex programs and fixed function to 01500 // use shadow colour 01501 mAutoParamDataSource.setAmbientLightColour(mShadowColour); 01502 mDestRenderSystem->setAmbientLight(mShadowColour.r, mShadowColour.g, mShadowColour.b); 01503 01504 while (groupIt.hasMoreElements()) 01505 { 01506 RenderPriorityGroup* pPriorityGrp = groupIt.getNext(); 01507 01508 // Sort the queue first 01509 pPriorityGrp->sort(mCameraInProgress); 01510 01511 // Do solids, override light list incase any vertex programs use them 01512 renderObjects(pPriorityGrp->_getSolidPasses(), false, &nullLightList); 01513 renderObjects(pPriorityGrp->_getSolidPassesNoShadow(), false, &nullLightList); 01514 01515 }// for each priority 01516 01517 // reset ambient light 01518 mAutoParamDataSource.setAmbientLightColour(mAmbientLight); 01519 mDestRenderSystem->setAmbientLight(mAmbientLight.r, mAmbientLight.g, mAmbientLight.b); 01520 } 01521 //----------------------------------------------------------------------- 01522 void SceneManager::renderModulativeTextureShadowedQueueGroupObjects(RenderQueueGroup* pGroup) 01523 { 01524 /* For each light, we need to render all the solids from each group, 01525 then do the modulative shadows, then render the transparents from 01526 each group. 01527 Now, this means we are going to reorder things more, but that it required 01528 if the shadows are to look correct. The overall order is preserved anyway, 01529 it's just that all the transparents are at the end instead of them being 01530 interleaved as in the normal rendering loop. 01531 */ 01532 // Iterate through priorities 01533 RenderQueueGroup::PriorityMapIterator groupIt = pGroup->getIterator(); 01534 01535 while (groupIt.hasMoreElements()) 01536 { 01537 RenderPriorityGroup* pPriorityGrp = groupIt.getNext(); 01538 01539 // Sort the queue first 01540 pPriorityGrp->sort(mCameraInProgress); 01541 01542 // Do solids 01543 renderObjects(pPriorityGrp->_getSolidPasses(), true); 01544 renderObjects(pPriorityGrp->_getSolidPassesNoShadow(), true); 01545 } 01546 01547 01548 // Iterate over lights, render received shadows 01549 // only perform this if we're in the 'normal' render stage, to avoid 01550 // doing it during the render to texture 01551 if (mIlluminationStage == IRS_NONE) 01552 { 01553 mIlluminationStage = IRS_RENDER_MODULATIVE_PASS; 01554 01555 LightList::iterator i, iend; 01556 ShadowTextureList::iterator si, siend; 01557 iend = mLightsAffectingFrustum.end(); 01558 siend = mShadowTextures.end(); 01559 for (i = mLightsAffectingFrustum.begin(), si = mShadowTextures.begin(); 01560 i != iend && si != siend; ++i) 01561 { 01562 Light* l = *i; 01563 01564 if (!l->getCastShadows()) 01565 continue; 01566 01567 mCurrentShadowTexture = *si; 01568 // Hook up receiver texture 01569 mShadowReceiverPass->getTextureUnitState(0)->setTextureName( 01570 mCurrentShadowTexture->getName()); 01571 // Hook up projection frustum 01572 mShadowReceiverPass->getTextureUnitState(0)->setProjectiveTexturing( 01573 true, mCurrentShadowTexture->getViewport(0)->getCamera()); 01574 mAutoParamDataSource.setTextureProjector( 01575 mCurrentShadowTexture->getViewport(0)->getCamera()); 01576 // if this light is a spotlight, we need to add the spot fader layer 01577 if (l->getType() == Light::LT_SPOTLIGHT) 01578 { 01579 // Add spot fader if not present already 01580 if (mShadowReceiverPass->getNumTextureUnitStates() == 1) 01581 { 01582 TextureUnitState* t = 01583 mShadowReceiverPass->createTextureUnitState("spot_shadow_fade.png"); 01584 t->setProjectiveTexturing( 01585 true, mCurrentShadowTexture->getViewport(0)->getCamera()); 01586 t->setColourOperation(LBO_ADD); 01587 t->setTextureAddressingMode(TextureUnitState::TAM_CLAMP); 01588 } 01589 else 01590 { 01591 // Just set projector 01592 TextureUnitState* t = 01593 mShadowReceiverPass->getTextureUnitState(1); 01594 t->setProjectiveTexturing( 01595 true, mCurrentShadowTexture->getViewport(0)->getCamera()); 01596 } 01597 } 01598 else if (mShadowReceiverPass->getNumTextureUnitStates() > 1) 01599 { 01600 // remove spot fader layer 01601 mShadowReceiverPass->removeTextureUnitState(1); 01602 01603 } 01604 mShadowReceiverPass->_load(); 01605 01606 if (l->getCastShadows() && pGroup->getShadowsEnabled()) 01607 { 01608 renderTextureShadowReceiverQueueGroupObjects(pGroup); 01609 } 01610 01611 ++si; 01612 01613 }// for each light 01614 01615 mIlluminationStage = IRS_NONE; 01616 01617 } 01618 01619 // Iterate again - variable name changed to appease gcc. 01620 RenderQueueGroup::PriorityMapIterator groupIt3 = pGroup->getIterator(); 01621 while (groupIt3.hasMoreElements()) 01622 { 01623 RenderPriorityGroup* pPriorityGrp = groupIt3.getNext(); 01624 01625 // Do transparents 01626 renderObjects(pPriorityGrp->_getTransparentPasses(), true); 01627 01628 }// for each priority 01629 01630 } 01631 //----------------------------------------------------------------------- 01632 void SceneManager::renderTextureShadowReceiverQueueGroupObjects(RenderQueueGroup* pGroup) 01633 { 01634 static LightList nullLightList; 01635 01636 // Iterate through priorities 01637 RenderQueueGroup::PriorityMapIterator groupIt = pGroup->getIterator(); 01638 01639 // Override auto param ambient to force vertex programs to go full-bright 01640 mAutoParamDataSource.setAmbientLightColour(ColourValue::White); 01641 mDestRenderSystem->setAmbientLight(1, 1, 1); 01642 01643 while (groupIt.hasMoreElements()) 01644 { 01645 RenderPriorityGroup* pPriorityGrp = groupIt.getNext(); 01646 01647 // Do solids, override light list incase any vertex programs use them 01648 renderObjects(pPriorityGrp->_getSolidPasses(), false, &nullLightList); 01649 01650 // Don't render transparents or passes which have shadow receipt disabled 01651 01652 }// for each priority 01653 01654 // reset ambient 01655 mAutoParamDataSource.setAmbientLightColour(mAmbientLight); 01656 mDestRenderSystem->setAmbientLight(mAmbientLight.r, mAmbientLight.g, mAmbientLight.b); 01657 01658 } 01659 //----------------------------------------------------------------------- 01660 bool SceneManager::validatePassForRendering(Pass* pass) 01661 { 01662 // Bypass if we're doing a texture shadow render and 01663 // this pass is after the first (only 1 pass needed for shadow texture) 01664 if ((mIlluminationStage == IRS_RENDER_TO_TEXTURE || 01665 mIlluminationStage == IRS_RENDER_MODULATIVE_PASS) && 01666 pass->getIndex() > 0) 01667 { 01668 return false; 01669 } 01670 01671 return true; 01672 } 01673 //----------------------------------------------------------------------- 01674 bool SceneManager::validateRenderableForRendering(Pass* pass, Renderable* rend) 01675 { 01676 // Skip this renderable if we're doing texture shadows, it casts shadows 01677 // and we're doing the render receivers pass 01678 if (mShadowTechnique == SHADOWTYPE_TEXTURE_MODULATIVE && 01679 mIlluminationStage == IRS_RENDER_MODULATIVE_PASS && 01680 rend->getCastsShadows()) 01681 { 01682 return false; 01683 } 01684 01685 return true; 01686 01687 } 01688 //----------------------------------------------------------------------- 01689 void SceneManager::renderObjects( 01690 const RenderPriorityGroup::SolidRenderablePassMap& objs, bool doLightIteration, 01691 const LightList* manualLightList) 01692 { 01693 // ----- SOLIDS LOOP ----- 01694 RenderPriorityGroup::SolidRenderablePassMap::const_iterator ipass, ipassend; 01695 ipassend = objs.end(); 01696 for (ipass = objs.begin(); ipass != ipassend; ++ipass) 01697 { 01698 // Fast bypass if this group is now empty 01699 if (ipass->second->empty()) continue; 01700 01701 // Give SM a chance to eliminate this pass 01702 if (!validatePassForRendering(ipass->first)) 01703 continue; 01704 01705 // For solids, we try to do each pass in turn 01706 Pass* usedPass = setPass(ipass->first); 01707 RenderPriorityGroup::RenderableList* rendList = ipass->second; 01708 RenderPriorityGroup::RenderableList::const_iterator irend, irendend; 01709 irendend = rendList->end(); 01710 for (irend = rendList->begin(); irend != irendend; ++irend) 01711 { 01712 // Give SM a chance to eliminate 01713 if (!validateRenderableForRendering(ipass->first, *irend)) 01714 continue; 01715 // Render a single object, this will set up auto params if required 01716 renderSingleObject(*irend, usedPass, doLightIteration, manualLightList); 01717 } 01718 } 01719 } 01720 //----------------------------------------------------------------------- 01721 void SceneManager::renderObjects( 01722 const RenderPriorityGroup::TransparentRenderablePassList& objs, bool doLightIteration, 01723 const LightList* manualLightList) 01724 { 01725 // ----- TRANSPARENT LOOP ----- 01726 // This time we render by Z, not by pass 01727 // The mTransparentObjects set needs to be ordered first 01728 // Render each non-transparent entity in turn, grouped by material 01729 RenderPriorityGroup::TransparentRenderablePassList::const_iterator itrans, itransend; 01730 01731 itransend = objs.end(); 01732 for (itrans = objs.begin(); 01733 itrans != itransend; ++itrans) 01734 { 01735 // For transparents, we have to accept that we can't sort entirely by pass 01736 setPass(itrans->pass); 01737 renderSingleObject(itrans->renderable, itrans->pass, doLightIteration, 01738 manualLightList); 01739 } 01740 01741 } 01742 //----------------------------------------------------------------------- 01743 void SceneManager::renderQueueGroupObjects(RenderQueueGroup* pGroup) 01744 { 01745 if (pGroup->getShadowsEnabled() && 01746 mShadowTechnique == SHADOWTYPE_STENCIL_ADDITIVE) 01747 { 01748 // Additive stencil shadows in use 01749 renderAdditiveStencilShadowedQueueGroupObjects(pGroup); 01750 } 01751 else if (pGroup->getShadowsEnabled() && 01752 mShadowTechnique == SHADOWTYPE_STENCIL_MODULATIVE) 01753 { 01754 // Modulative stencil shadows in use 01755 renderModulativeStencilShadowedQueueGroupObjects(pGroup); 01756 } 01757 else if (mShadowTechnique == SHADOWTYPE_TEXTURE_MODULATIVE) 01758 { 01759 // Modulative texture shadows in use 01760 if (mIlluminationStage == IRS_RENDER_TO_TEXTURE) 01761 { 01762 // Shadow caster pass 01763 if (pGroup->getShadowsEnabled()) 01764 renderTextureShadowCasterQueueGroupObjects(pGroup); 01765 } 01766 else 01767 { 01768 // Ordinary pass 01769 renderModulativeTextureShadowedQueueGroupObjects(pGroup); 01770 } 01771 } 01772 else 01773 { 01774 // No shadows, ordinary pass 01775 renderBasicQueueGroupObjects(pGroup); 01776 } 01777 01778 01779 } 01780 //----------------------------------------------------------------------- 01781 void SceneManager::renderBasicQueueGroupObjects(RenderQueueGroup* pGroup) 01782 { 01783 // Basic render loop 01784 // Iterate through priorities 01785 RenderQueueGroup::PriorityMapIterator groupIt = pGroup->getIterator(); 01786 01787 while (groupIt.hasMoreElements()) 01788 { 01789 RenderPriorityGroup* pPriorityGrp = groupIt.getNext(); 01790 01791 // Sort the queue first 01792 pPriorityGrp->sort(mCameraInProgress); 01793 01794 // Do solids 01795 renderObjects(pPriorityGrp->_getSolidPasses(), true); 01796 // Do transparents 01797 renderObjects(pPriorityGrp->_getTransparentPasses(), true); 01798 01799 01800 }// for each priority 01801 } 01802 //----------------------------------------------------------------------- 01803 void SceneManager::renderSingleObject(Renderable* rend, Pass* pass, 01804 bool doLightIteration, const LightList* manualLightList) 01805 { 01806 static Matrix4 xform[256]; 01807 unsigned short numMatrices; 01808 static bool normalisedNormals = false; 01809 static SceneDetailLevel camDetailLevel = mCameraInProgress->getDetailLevel(); 01810 static SceneDetailLevel lastDetailLevel = camDetailLevel; 01811 static RenderOperation ro; 01812 static LightList localLightList; 01813 01814 if (pass->isProgrammable()) 01815 { 01816 // Tell auto params object about the renderable change 01817 mAutoParamDataSource.setCurrentRenderable(rend); 01818 pass->_updateAutoParamsNoLights(mAutoParamDataSource); 01819 } 01820 01821 // Set world transformation 01822 rend->getWorldTransforms(xform); 01823 numMatrices = rend->getNumWorldTransforms(); 01824 if (numMatrices > 1) 01825 { 01826 mDestRenderSystem->_setWorldMatrices(xform, numMatrices); 01827 } 01828 else 01829 { 01830 mDestRenderSystem->_setWorldMatrix(*xform); 01831 } 01832 01833 // Issue view / projection changes if any 01834 useRenderableViewProjMode(rend); 01835 01836 // Reissue any texture gen settings which are dependent on view matrix 01837 Pass::TextureUnitStateIterator texIter = pass->getTextureUnitStateIterator(); 01838 size_t unit = 0; 01839 while(texIter.hasMoreElements()) 01840 { 01841 TextureUnitState* pTex = texIter.getNext(); 01842 if (pTex->hasViewRelativeTextureCoordinateGeneration()) 01843 { 01844 mDestRenderSystem->_setTextureUnitSettings(unit, *pTex); 01845 } 01846 ++unit; 01847 } 01848 01849 01850 // Sort out normalisation 01851 bool thisNormalise = rend->getNormaliseNormals(); 01852 if (thisNormalise != normalisedNormals) 01853 { 01854 mDestRenderSystem->setNormaliseNormals(thisNormalise); 01855 normalisedNormals = thisNormalise; 01856 } 01857 01858 // Set up the solid / wireframe override 01859 SceneDetailLevel reqDetail = rend->getRenderDetail(); 01860 if (reqDetail != lastDetailLevel || reqDetail != camDetailLevel) 01861 { 01862 if (reqDetail > camDetailLevel) 01863 { 01864 // only downgrade detail; if cam says wireframe we don't go up to solid 01865 reqDetail = camDetailLevel; 01866 } 01867 mDestRenderSystem->_setRasterisationMode(reqDetail); 01868 lastDetailLevel = reqDetail; 01869 01870 } 01871 01872 mDestRenderSystem->setClipPlanes(rend->getClipPlanes()); 01873 01874 // Set up rendering operation 01875 rend->getRenderOperation(ro); 01876 ro.srcRenderable = rend; 01877 01878 if (doLightIteration) 01879 { 01880 // Here's where we issue the rendering operation to the render system 01881 // Note that we may do this once per light, therefore it's in a loop 01882 // and the light parameters are updated once per traversal through the 01883 // loop 01884 const LightList& rendLightList = rend->getLights(); 01885 bool iteratePerLight = pass->getRunOncePerLight(); 01886 size_t numIterations = iteratePerLight ? rendLightList.size() : 1; 01887 const LightList* pLightListToUse; 01888 for (size_t i = 0; i < numIterations; ++i) 01889 { 01890 // Determine light list to use 01891 if (iteratePerLight) 01892 { 01893 // Change the only element of local light list to be 01894 // the light at index i 01895 localLightList.clear(); 01896 // Check whether we need to filter this one out 01897 if (pass->getRunOnlyForOneLightType() && 01898 pass->getOnlyLightType() != rendLightList[i]->getType()) 01899 { 01900 // Skip 01901 continue; 01902 } 01903 01904 localLightList.push_back(rendLightList[i]); 01905 pLightListToUse = &localLightList; 01906 } 01907 else 01908 { 01909 // Use complete light list 01910 pLightListToUse = &rendLightList; 01911 } 01912 01913 // Do we need to update GPU program parameters? 01914 if (pass->isProgrammable()) 01915 { 01916 // Update any automatic gpu params for lights 01917 // Other bits of information will have to be looked up 01918 mAutoParamDataSource.setCurrentLightList(pLightListToUse); 01919 pass->_updateAutoParamsLightsOnly(mAutoParamDataSource); 01920 // NOTE: We MUST bind parameters AFTER updating the autos 01921 // TEST 01922 if (pass->hasVertexProgram()) 01923 { 01924 mDestRenderSystem->bindGpuProgramParameters(GPT_VERTEX_PROGRAM, 01925 pass->getVertexProgramParameters()); 01926 } 01927 if (pass->hasFragmentProgram()) 01928 { 01929 mDestRenderSystem->bindGpuProgramParameters(GPT_FRAGMENT_PROGRAM, 01930 pass->getFragmentProgramParameters()); 01931 } 01932 } 01933 // Do we need to update light states? 01934 // Only do this if fixed-function vertex lighting applies 01935 if (pass->getLightingEnabled() && !pass->hasVertexProgram()) 01936 { 01937 mDestRenderSystem->_useLights(*pLightListToUse, pass->getMaxSimultaneousLights()); 01938 } 01939 // issue the render op 01940 mDestRenderSystem->_render(ro); 01941 } // possibly iterate per light 01942 } 01943 else // no automatic light processing 01944 { 01945 // Do we need to update GPU program parameters? 01946 if (pass->isProgrammable()) 01947 { 01948 // Do we have a manual light list? 01949 if (manualLightList) 01950 { 01951 // Update any automatic gpu params for lights 01952 mAutoParamDataSource.setCurrentLightList(manualLightList); 01953 pass->_updateAutoParamsLightsOnly(mAutoParamDataSource); 01954 } 01955 01956 if (pass->hasVertexProgram()) 01957 { 01958 mDestRenderSystem->bindGpuProgramParameters(GPT_VERTEX_PROGRAM, 01959 pass->getVertexProgramParameters()); 01960 } 01961 if (pass->hasFragmentProgram()) 01962 { 01963 mDestRenderSystem->bindGpuProgramParameters(GPT_FRAGMENT_PROGRAM, 01964 pass->getFragmentProgramParameters()); 01965 } 01966 } 01967 01968 // Use manual lights if present, and not using vertex programs 01969 if (manualLightList && 01970 pass->getLightingEnabled() && !pass->hasVertexProgram()) 01971 { 01972 mDestRenderSystem->_useLights(*manualLightList, pass->getMaxSimultaneousLights()); 01973 } 01974 // issue the render op 01975 mDestRenderSystem->_render(ro); 01976 } 01977 } 01978 //----------------------------------------------------------------------- 01979 void SceneManager::setAmbientLight(const ColourValue& colour) 01980 { 01981 mAmbientLight = colour; 01982 mDestRenderSystem->setAmbientLight(colour.r, colour.g, colour.b); 01983 } 01984 //----------------------------------------------------------------------- 01985 const ColourValue& SceneManager::getAmbientLight(void) const 01986 { 01987 return mAmbientLight; 01988 } 01989 //----------------------------------------------------------------------- 01990 ViewPoint SceneManager::getSuggestedViewpoint(bool random) 01991 { 01992 // By default return the origin 01993 ViewPoint vp; 01994 vp.position = Vector3::ZERO; 01995 vp.orientation = Quaternion::IDENTITY; 01996 return vp; 01997 } 01998 //----------------------------------------------------------------------- 01999 void SceneManager::setFog(FogMode mode, const ColourValue& colour, Real density, Real start, Real end) 02000 { 02001 mFogMode = mode; 02002 mFogColour = colour; 02003 mFogStart = start; 02004 mFogEnd = end; 02005 mFogDensity = density; 02006 } 02007 //----------------------------------------------------------------------- 02008 FogMode SceneManager::getFogMode(void) const 02009 { 02010 return mFogMode; 02011 } 02012 //----------------------------------------------------------------------- 02013 const ColourValue& SceneManager::getFogColour(void) const 02014 { 02015 return mFogColour; 02016 } 02017 //----------------------------------------------------------------------- 02018 Real SceneManager::getFogStart(void) const 02019 { 02020 return mFogStart; 02021 } 02022 //----------------------------------------------------------------------- 02023 Real SceneManager::getFogEnd(void) const 02024 { 02025 return mFogEnd; 02026 } 02027 //----------------------------------------------------------------------- 02028 Real SceneManager::getFogDensity(void) const 02029 { 02030 return mFogDensity; 02031 } 02032 //----------------------------------------------------------------------- 02033 BillboardSet* SceneManager::createBillboardSet(const String& name, unsigned int poolSize) 02034 { 02035 BillboardSet* set = new BillboardSet( name, poolSize ); 02036 mBillboardSets[name] = set;//.insert(BillboardSetList::value_type(name, set)); 02037 02038 return set; 02039 } 02040 //----------------------------------------------------------------------- 02041 BillboardSet* SceneManager::getBillboardSet(const String& name) 02042 { 02043 BillboardSetList::iterator i = mBillboardSets.find(name); 02044 if (i == mBillboardSets.end()) 02045 { 02046 return 0; 02047 } 02048 else 02049 { 02050 return i->second; 02051 } 02052 } 02053 //----------------------------------------------------------------------- 02054 void SceneManager::removeBillboardSet(BillboardSet* set) 02055 { 02056 // Find in list 02057 BillboardSetList::iterator i = mBillboardSets.begin(); 02058 for (; i != mBillboardSets.end(); ++i) 02059 { 02060 if (i->second == set) 02061 { 02062 mBillboardSets.erase(i); 02063 delete set; 02064 break; 02065 } 02066 } 02067 02068 } 02069 //----------------------------------------------------------------------- 02070 void SceneManager::removeBillboardSet(const String& name) 02071 { 02072 // Find in list 02073 BillboardSetList::iterator i = mBillboardSets.find(name); 02074 if (i != mBillboardSets.end()) 02075 { 02076 delete i->second; 02077 mBillboardSets.erase(i); 02078 } 02079 } 02080 //----------------------------------------------------------------------- 02081 void SceneManager::setDisplaySceneNodes(bool display) 02082 { 02083 mDisplayNodes = display; 02084 } 02085 //----------------------------------------------------------------------- 02086 Animation* SceneManager::createAnimation(const String& name, Real length) 02087 { 02088 Animation* pAnim = new Animation(name, length); 02089 mAnimationsList[name] = pAnim; 02090 return pAnim; 02091 } 02092 //----------------------------------------------------------------------- 02093 Animation* SceneManager::getAnimation(const String& name) const 02094 { 02095 AnimationList::const_iterator i = mAnimationsList.find(name); 02096 if (i == mAnimationsList.end()) 02097 { 02098 Except(Exception::ERR_ITEM_NOT_FOUND, 02099 "Cannot find animation with name " + name, 02100 "SceneManager::getAnimation"); 02101 } 02102 return i->second; 02103 } 02104 //----------------------------------------------------------------------- 02105 void SceneManager::destroyAnimation(const String& name) 02106 { 02107 // Also destroy any animation states referencing this animation 02108 AnimationStateSet::iterator si, siend; 02109 siend = mAnimationStates.end(); 02110 for (si = mAnimationStates.begin(); si != siend; ) 02111 { 02112 if (si->second.getAnimationName() == name) 02113 { 02114 // erase, post increment to avoid the invalidated iterator 02115 mAnimationStates.erase(si++); 02116 } 02117 else 02118 { 02119 ++si; 02120 } 02121 } 02122 02123 AnimationList::iterator i = mAnimationsList.find(name); 02124 if (i == mAnimationsList.end()) 02125 { 02126 Except(Exception::ERR_ITEM_NOT_FOUND, 02127 "Cannot find animation with name " + name, 02128 "SceneManager::getAnimation"); 02129 } 02130 02131 // Free memory 02132 delete i->second; 02133 02134 mAnimationsList.erase(i); 02135 02136 02137 } 02138 //----------------------------------------------------------------------- 02139 void SceneManager::destroyAllAnimations(void) 02140 { 02141 // Destroy all states too, since they cannot reference destroyed animations 02142 destroyAllAnimationStates(); 02143 02144 AnimationList::iterator i; 02145 for (i = mAnimationsList.begin(); i != mAnimationsList.end(); ++i) 02146 { 02147 // destroy 02148 delete i->second; 02149 } 02150 mAnimationsList.clear(); 02151 } 02152 //----------------------------------------------------------------------- 02153 AnimationState* SceneManager::createAnimationState(const String& animName) 02154 { 02155 if (mAnimationStates.find(animName) != mAnimationStates.end()) 02156 { 02157 Except(Exception::ERR_DUPLICATE_ITEM, 02158 "Cannot create, AnimationState already exists: "+animName, 02159 "SceneManager::createAnimationState"); 02160 } 02161 02162 // Get animation, this will throw an exception if not found 02163 Animation* anim = getAnimation(animName); 02164 02165 // Create new state 02166 AnimationState newState(animName, 0, anim->getLength()); 02167 02168 // Record it 02169 std::pair<AnimationStateSet::iterator, bool> retPair = 02170 mAnimationStates.insert(AnimationStateSet::value_type(animName, newState)); 02171 02172 // Check boolean return 02173 if (retPair.second) 02174 { 02175 // insert was OK 02176 // Get pointer from iterator in pair 02177 return &(retPair.first->second); 02178 } 02179 else 02180 { 02181 // Problem 02182 // Not because of duplicate item, that's checked for above 02183 Except(Exception::ERR_INTERNAL_ERROR, "Unexpected error creating new animation state.", 02184 "SceneManager::createAnimationState"); 02185 } 02186 02187 02188 } 02189 //----------------------------------------------------------------------- 02190 AnimationState* SceneManager::getAnimationState(const String& animName) 02191 { 02192 AnimationStateSet::iterator i = mAnimationStates.find(animName); 02193 02194 if (i == mAnimationStates.end()) 02195 { 02196 Except(Exception::ERR_ITEM_NOT_FOUND, 02197 "Cannot locate animation state for animation " + animName, 02198 "SceneManager::getAnimationState"); 02199 } 02200 02201 return &(i->second); 02202 02203 } 02204 //----------------------------------------------------------------------- 02205 void SceneManager::destroyAnimationState(const String& name) 02206 { 02207 AnimationStateSet::iterator i = mAnimationStates.find(name); 02208 02209 if (i == mAnimationStates.end()) 02210 { 02211 Except(Exception::ERR_ITEM_NOT_FOUND, 02212 "Cannot locate animation state for animation " + name, 02213 "SceneManager::destroyAnimationState"); 02214 } 02215 02216 mAnimationStates.erase(i); 02217 02218 02219 } 02220 //----------------------------------------------------------------------- 02221 void SceneManager::destroyAllAnimationStates(void) 02222 { 02223 mAnimationStates.clear(); 02224 } 02225 //----------------------------------------------------------------------- 02226 void SceneManager::_applySceneAnimations(void) 02227 { 02228 AnimationStateSet::const_iterator i, iend; 02229 02230 i = mAnimationStates.begin(); 02231 iend = mAnimationStates.end(); 02232 02233 for (;i != iend; ++i) 02234 { 02235 if (i->second.getEnabled()) 02236 { 02237 Animation* anim = getAnimation(i->second.getAnimationName()); 02238 02239 // Reset any nodes involved 02240 // NB this excludes blended animations 02241 const Animation::TrackList& trackList = anim->_getTrackList(); 02242 Animation::TrackList::const_iterator ti, tend; 02243 ti = trackList.begin(); 02244 tend = trackList.end(); 02245 for (;ti != tend; ++ti) 02246 { 02247 Node* nd = ti->second->getAssociatedNode(); 02248 nd->resetToInitialState(); 02249 } 02250 02251 02252 // Apply the animation 02253 anim->apply(i->second.getTimePosition(), i->second.getWeight()); 02254 } 02255 } 02256 02257 02258 } 02259 //--------------------------------------------------------------------- 02260 void SceneManager::manualRender(RenderOperation* rend, 02261 Pass* pass, Viewport* vp, const Matrix4& worldMatrix, 02262 const Matrix4& viewMatrix, const Matrix4& projMatrix, 02263 bool doBeginEndFrame) 02264 { 02265 mDestRenderSystem->_setViewport(vp); 02266 mDestRenderSystem->_setWorldMatrix(worldMatrix); 02267 mDestRenderSystem->_setViewMatrix(viewMatrix); 02268 mDestRenderSystem->_setProjectionMatrix(projMatrix); 02269 02270 if (doBeginEndFrame) 02271 mDestRenderSystem->_beginFrame(); 02272 02273 setPass(pass); 02274 mDestRenderSystem->_render(*rend); 02275 02276 if (doBeginEndFrame) 02277 mDestRenderSystem->_endFrame(); 02278 02279 } 02280 //--------------------------------------------------------------------- 02281 Overlay* SceneManager::createOverlay(const String& name, ushort zorder) 02282 { 02283 /* 02284 // check not existing 02285 OverlayList::iterator i = mOverlays.find(name); 02286 if (i != mOverlays.end()) 02287 { 02288 Except(Exception::ERR_DUPLICATE_ITEM, 02289 "An overlay named " + name + " already exists.", 02290 "SceneManager::createOverlay"); 02291 } 02292 Overlay *newOverlay = new Overlay(name, zorder); 02293 02294 mOverlays.insert(OverlayList::value_type(name, newOverlay)); 02295 return newOverlay; 02296 */ 02297 02298 Overlay* newOverlay = (Overlay*)OverlayManager::getSingleton().create(name); 02299 newOverlay->setZOrder(zorder); 02300 return newOverlay; 02301 02302 02303 02304 } 02305 //--------------------------------------------------------------------- 02306 Overlay* SceneManager::getOverlay(const String& name) 02307 { 02308 /* 02309 OverlayList::iterator i = mOverlays.find(name); 02310 if (i == mOverlays.end()) 02311 { 02312 Except(Exception::ERR_ITEM_NOT_FOUND, 02313 "An overlay named " + name + " cannot be found.", 02314 "SceneManager::getOverlay"); 02315 } 02316 02317 return i->second; 02318 */ 02319 Overlay* ret = (Overlay*)OverlayManager::getSingleton().getByName(name); 02320 if (!ret) 02321 { 02322 Except(Exception::ERR_ITEM_NOT_FOUND, 02323 "An overlay named " + name + " cannot be found.", 02324 "SceneManager::getOverlay"); 02325 } 02326 02327 return ret; 02328 02329 } 02330 //--------------------------------------------------------------------- 02331 void SceneManager::destroyOverlay(const String& name) 02332 { 02333 /* 02334 OverlayList::iterator i = mOverlays.find(name); 02335 if (i == mOverlays.end()) 02336 { 02337 Except(Exception::ERR_ITEM_NOT_FOUND, 02338 "An overlay named " + name + " cannot be found.", 02339 "SceneManager::destroyOverlay"); 02340 } 02341 02342 delete i->second; 02343 mOverlays.erase(i); 02344 */ 02345 Overlay* pOver = (Overlay*)OverlayManager::getSingleton().getByName(name); 02346 if (!pOver) 02347 { 02348 Except(Exception::ERR_ITEM_NOT_FOUND, 02349 "An overlay named " + name + " cannot be found.", 02350 "SceneManager::destroyOverlay"); 02351 } 02352 OverlayManager::getSingleton().unload(pOver); 02353 delete pOver; 02354 02355 } 02356 //--------------------------------------------------------------------- 02357 void SceneManager::destroyAllOverlays(void) 02358 { 02359 /* 02360 OverlayList::iterator i, iend; 02361 iend = mOverlays.end(); 02362 for (i = mOverlays.begin(); i != iend; ++i) 02363 { 02364 delete i->second; 02365 } 02366 mOverlays.clear(); 02367 */ 02368 OverlayManager::getSingleton().unloadAndDestroyAll(); 02369 02370 02371 } 02372 //--------------------------------------------------------------------- 02373 void SceneManager::useRenderableViewProjMode(Renderable* pRend) 02374 { 02375 // Check view matrix 02376 static bool lastViewWasIdentity = false; 02377 bool useIdentityView = pRend->useIdentityView(); 02378 if (useIdentityView && (mCamChanged || !lastViewWasIdentity)) 02379 { 02380 // Using identity view now, change it 02381 mDestRenderSystem->_setViewMatrix(Matrix4::IDENTITY); 02382 lastViewWasIdentity = true; 02383 } 02384 else if (!useIdentityView && (mCamChanged || lastViewWasIdentity)) 02385 { 02386 // Coming back to normal from identity view 02387 mDestRenderSystem->_setViewMatrix(mCameraInProgress->getViewMatrix()); 02388 lastViewWasIdentity = false; 02389 } 02390 02391 static bool lastProjWasIdentity = false; 02392 bool useIdentityProj = pRend->useIdentityProjection(); 02393 02394 if (useIdentityProj && (mCamChanged || !lastProjWasIdentity)) 02395 { 02396 mDestRenderSystem->_setProjectionMatrix(Matrix4::IDENTITY); 02397 02398 lastProjWasIdentity = true; 02399 } 02400 else if (!useIdentityProj && (mCamChanged || lastProjWasIdentity)) 02401 { 02402 // Coming back from flat projection 02403 mDestRenderSystem->_setProjectionMatrix(mCameraInProgress->getProjectionMatrix()); 02404 lastProjWasIdentity = false; 02405 } 02406 02407 mCamChanged = false; 02408 02409 } 02410 02411 //--------------------------------------------------------------------- 02412 void SceneManager::_queueSkiesForRendering(Camera* cam) 02413 { 02414 // Update nodes 02415 // Translate the box by the camera position (constant distance) 02416 if (mSkyPlaneNode) 02417 { 02418 // The plane position relative to the camera has already been set up 02419 mSkyPlaneNode->setPosition(cam->getDerivedPosition()); 02420 } 02421 02422 if (mSkyBoxNode) 02423 { 02424 mSkyBoxNode->setPosition(cam->getDerivedPosition()); 02425 } 02426 02427 if (mSkyDomeNode) 02428 { 02429 mSkyDomeNode->setPosition(cam->getDerivedPosition()); 02430 } 02431 02432 RenderQueueGroupID qid; 02433 if (mSkyPlaneEnabled) 02434 { 02435 qid = mSkyPlaneDrawFirst? 02436 RENDER_QUEUE_SKIES_EARLY : RENDER_QUEUE_SKIES_LATE; 02437 getRenderQueue()->addRenderable(mSkyPlaneEntity->getSubEntity(0), qid, RENDERABLE_DEFAULT_PRIORITY); 02438 } 02439 02440 uint plane; 02441 if (mSkyBoxEnabled) 02442 { 02443 qid = mSkyBoxDrawFirst? 02444 RENDER_QUEUE_SKIES_EARLY : RENDER_QUEUE_SKIES_LATE; 02445 02446 for (plane = 0; plane < 6; ++plane) 02447 { 02448 getRenderQueue()->addRenderable( 02449 mSkyBoxEntity[plane]->getSubEntity(0), qid, RENDERABLE_DEFAULT_PRIORITY); 02450 } 02451 } 02452 02453 if (mSkyDomeEnabled) 02454 { 02455 qid = mSkyDomeDrawFirst? 02456 RENDER_QUEUE_SKIES_EARLY : RENDER_QUEUE_SKIES_LATE; 02457 02458 for (plane = 0; plane < 5; ++plane) 02459 { 02460 getRenderQueue()->addRenderable( 02461 mSkyDomeEntity[plane]->getSubEntity(0), qid, RENDERABLE_DEFAULT_PRIORITY); 02462 } 02463 } 02464 } 02465 //--------------------------------------------------------------------- 02466 void SceneManager::addRenderQueueListener(RenderQueueListener* newListener) 02467 { 02468 mRenderQueueListeners.push_back(newListener); 02469 } 02470 //--------------------------------------------------------------------- 02471 void SceneManager::removeRenderQueueListener(RenderQueueListener* delListener) 02472 { 02473 RenderQueueListenerList::iterator i, iend; 02474 iend = mRenderQueueListeners.end(); 02475 for (i = mRenderQueueListeners.begin(); i != iend; ++i) 02476 { 02477 if (*i == delListener) 02478 { 02479 mRenderQueueListeners.erase(i); 02480 break; 02481 } 02482 } 02483 02484 } 02485 //--------------------------------------------------------------------- 02486 bool SceneManager::fireRenderQueueStarted(RenderQueueGroupID id) 02487 { 02488 RenderQueueListenerList::iterator i, iend; 02489 bool skip = false; 02490 02491 iend = mRenderQueueListeners.end(); 02492 for (i = mRenderQueueListeners.begin(); i != iend; ++i) 02493 { 02494 (*i)->renderQueueStarted(id, skip); 02495 } 02496 return skip; 02497 } 02498 //--------------------------------------------------------------------- 02499 bool SceneManager::fireRenderQueueEnded(RenderQueueGroupID id) 02500 { 02501 RenderQueueListenerList::iterator i, iend; 02502 bool repeat = false; 02503 02504 iend = mRenderQueueListeners.end(); 02505 for (i = mRenderQueueListeners.begin(); i != iend; ++i) 02506 { 02507 (*i)->renderQueueEnded(id, repeat); 02508 } 02509 return repeat; 02510 } 02511 //--------------------------------------------------------------------- 02512 void SceneManager::setViewport(Viewport* vp) 02513 { 02514 mCurrentViewport = vp; 02515 // Set viewport in render system 02516 mDestRenderSystem->_setViewport(vp); 02517 } 02518 //--------------------------------------------------------------------- 02519 void SceneManager::showBoundingBoxes(bool bShow) 02520 { 02521 mShowBoundingBoxes = bShow; 02522 } 02523 //--------------------------------------------------------------------- 02524 bool SceneManager::getShowBoundingBoxes() const 02525 { 02526 return mShowBoundingBoxes; 02527 } 02528 //--------------------------------------------------------------------- 02529 void SceneManager::_notifyAutotrackingSceneNode(SceneNode* node, bool autoTrack) 02530 { 02531 if (autoTrack) 02532 { 02533 mAutoTrackingSceneNodes.insert(node); 02534 } 02535 else 02536 { 02537 mAutoTrackingSceneNodes.erase(node); 02538 } 02539 } 02540 //--------------------------------------------------------------------- 02541 void SceneManager::setShadowTechnique(ShadowTechnique technique) 02542 { 02543 mShadowTechnique = technique; 02544 if (technique == SHADOWTYPE_STENCIL_ADDITIVE || 02545 technique == SHADOWTYPE_STENCIL_MODULATIVE) 02546 { 02547 // Firstly check that we have a stencil 02548 // Otherwise forget it 02549 if (!mDestRenderSystem->getCapabilities()->hasCapability(RSC_HWSTENCIL)) 02550 { 02551 LogManager::getSingleton().logMessage( 02552 "WARNING: Stencil shadows were requested, but this device does not " 02553 "have a hardware stencil. Shadows disabled."); 02554 mShadowTechnique = SHADOWTYPE_NONE; 02555 } 02556 else if (mShadowIndexBuffer.isNull()) 02557 { 02558 // Create an estimated sized shadow index buffer 02559 mShadowIndexBuffer = HardwareBufferManager::getSingleton(). 02560 createIndexBuffer(HardwareIndexBuffer::IT_16BIT, 02561 mShadowIndexBufferSize, 02562 HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY, 02563 false); 02564 // tell all meshes to prepare shadow volumes 02565 MeshManager::getSingleton().setPrepareAllMeshesForShadowVolumes(true); 02566 } 02567 } 02568 02569 if (mShadowTechnique == SHADOWTYPE_STENCIL_ADDITIVE) 02570 { 02571 // Additive stencil, we need to split everything by illumination stage 02572 getRenderQueue()->setSplitPassesByLightingType(true); 02573 } 02574 else 02575 { 02576 getRenderQueue()->setSplitPassesByLightingType(false); 02577 } 02578 02579 if (mShadowTechnique != SHADOWTYPE_NONE) 02580 { 02581 // Tell render queue to split off non-shadowable materials 02582 getRenderQueue()->setSplitNoShadowPasses(true); 02583 } 02584 else 02585 { 02586 getRenderQueue()->setSplitNoShadowPasses(false); 02587 } 02588 02589 if (mShadowTechnique == SHADOWTYPE_TEXTURE_MODULATIVE 02590 /* || mShadowTechnique == SHADOWTYPE_TEXTURE_SHADOWMAP */) 02591 { 02592 createShadowTextures(mShadowTextureSize, mShadowTextureCount); 02593 } 02594 02595 } 02596 //--------------------------------------------------------------------- 02597 void SceneManager::findLightsAffectingFrustum(const Camera* camera) 02598 { 02599 // Basic iteration for this SM 02600 mLightsAffectingFrustum.clear(); 02601 SceneLightList::iterator i, iend; 02602 iend = mLights.end(); 02603 Sphere sphere; 02604 for (i = mLights.begin(); i != iend; ++i) 02605 { 02606 Light* l = i->second; 02607 if (l->getType() == Light::LT_DIRECTIONAL) 02608 { 02609 // Always visible 02610 mLightsAffectingFrustum.push_back(l); 02611 } 02612 else 02613 { 02614 // NB treating spotlight as point for simplicity 02615 // Just see if the lights attenuation range is within the frustum 02616 sphere.setCenter(l->getDerivedPosition()); 02617 sphere.setRadius(l->getAttenuationRange()); 02618 if (camera->isVisible(sphere)) 02619 { 02620 mLightsAffectingFrustum.push_back(l); 02621 } 02622 02623 } 02624 } 02625 02626 } 02627 //--------------------------------------------------------------------- 02628 bool SceneManager::ShadowCasterSceneQueryListener::queryResult( 02629 MovableObject* object) 02630 { 02631 if (object->getCastShadows() && object->isVisible()) 02632 { 02633 if (mFarDistSquared) 02634 { 02635 // Check object is within the shadow far distance 02636 Vector3 toObj = object->getParentNode()->_getDerivedPosition() 02637 - mCamera->getDerivedPosition(); 02638 Real radius = object->getWorldBoundingSphere().getRadius(); 02639 Real dist = toObj.squaredLength(); 02640 if (dist - (radius * radius) > mFarDistSquared) 02641 { 02642 // skip, beyond max range 02643 return true; 02644 } 02645 } 02646 02647 // If the object is in the frustum, we can always see the shadow 02648 if (mCamera->isVisible(object->getWorldBoundingBox())) 02649 { 02650 mCasterList->push_back(object); 02651 return true; 02652 } 02653 02654 // Otherwise, object can only be casting a shadow into our view if 02655 // the light is outside the frustum (or it's a directional light, 02656 // which are always outside), and the object is intersecting 02657 // on of the volumes formed between the edges of the frustum and the 02658 // light 02659 if (!mIsLightInFrustum || mLight->getType() == Light::LT_DIRECTIONAL) 02660 { 02661 // Iterate over volumes 02662 PlaneBoundedVolumeList::const_iterator i, iend; 02663 iend = mLightClipVolumeList->end(); 02664 for (i = mLightClipVolumeList->begin(); i != iend; ++i) 02665 { 02666 if (i->intersects(object->getWorldBoundingBox())) 02667 { 02668 mCasterList->push_back(object); 02669 return true; 02670 } 02671 02672 } 02673 02674 } 02675 } 02676 return true; 02677 } 02678 //--------------------------------------------------------------------- 02679 bool SceneManager::ShadowCasterSceneQueryListener::queryResult( 02680 SceneQuery::WorldFragment* fragment) 02681 { 02682 // don't deal with world geometry 02683 return true; 02684 } 02685 //--------------------------------------------------------------------- 02686 const SceneManager::ShadowCasterList& SceneManager::findShadowCastersForLight( 02687 const Light* light, const Camera* camera) 02688 { 02689 mShadowCasterList.clear(); 02690 02691 if (light->getType() == Light::LT_DIRECTIONAL) 02692 { 02693 // Basic AABB query encompassing the frustum and the extrusion of it 02694 AxisAlignedBox aabb; 02695 const Vector3* corners = camera->getWorldSpaceCorners(); 02696 Vector3 min, max; 02697 Vector3 extrude = light->getDirection() * -mShadowDirLightExtrudeDist; 02698 // do first corner 02699 min = max = corners[0]; 02700 min.makeFloor(corners[0] + extrude); 02701 max.makeCeil(corners[0] + extrude); 02702 for (size_t c = 1; c < 8; ++c) 02703 { 02704 min.makeFloor(corners[c]); 02705 max.makeCeil(corners[c]); 02706 min.makeFloor(corners[c] + extrude); 02707 max.makeCeil(corners[c] + extrude); 02708 } 02709 aabb.setExtents(min, max); 02710 02711 if (!mShadowCasterAABBQuery) 02712 mShadowCasterAABBQuery = createAABBQuery(aabb); 02713 else 02714 mShadowCasterAABBQuery->setBox(aabb); 02715 // Execute, use callback 02716 mShadowCasterQueryListener.prepare(false, 02717 &(light->_getFrustumClipVolumes(camera)), 02718 light, camera, &mShadowCasterList, mShadowFarDistSquared); 02719 mShadowCasterAABBQuery->execute(&mShadowCasterQueryListener); 02720 02721 02722 } 02723 else 02724 { 02725 Sphere s(light->getPosition(), light->getAttenuationRange()); 02726 // eliminate early if camera cannot see light sphere 02727 if (camera->isVisible(s)) 02728 { 02729 if (!mShadowCasterSphereQuery) 02730 mShadowCasterSphereQuery = createSphereQuery(s); 02731 else 02732 mShadowCasterSphereQuery->setSphere(s); 02733 02734 // Determine if light is inside or outside the frustum 02735 bool lightInFrustum = camera->isVisible(light->getDerivedPosition()); 02736 const PlaneBoundedVolumeList* volList = 0; 02737 if (!lightInFrustum) 02738 { 02739 // Only worth building an external volume list if 02740 // light is outside the frustum 02741 volList = &(light->_getFrustumClipVolumes(camera)); 02742 } 02743 02744 // Execute, use callback 02745 mShadowCasterQueryListener.prepare(lightInFrustum, 02746 volList, light, camera, &mShadowCasterList, mShadowFarDistSquared); 02747 mShadowCasterSphereQuery->execute(&mShadowCasterQueryListener); 02748 02749 } 02750 02751 } 02752 02753 02754 return mShadowCasterList; 02755 } 02756 //--------------------------------------------------------------------- 02757 void SceneManager::initShadowVolumeMaterials(void) 02758 { 02759 bool compileStencilDebugPass = false; 02760 bool compileStencilPass = false; 02761 02762 Material* matDebug = static_cast<Material*>( 02763 MaterialManager::getSingleton().getByName("Ogre/Debug/ShadowVolumes")); 02764 if (!matDebug) 02765 { 02766 // Create 02767 matDebug = static_cast<Material*>( 02768 MaterialManager::getSingleton().create("Ogre/Debug/ShadowVolumes")); 02769 mShadowDebugPass = matDebug->getTechnique(0)->getPass(0); 02770 mShadowDebugPass->setSceneBlending(SBT_ADD); 02771 mShadowDebugPass->setLightingEnabled(false); 02772 mShadowDebugPass->setDepthWriteEnabled(false); 02773 TextureUnitState* t = mShadowDebugPass->createTextureUnitState(); 02774 t->setColourOperationEx(LBX_MODULATE, LBS_MANUAL, LBS_CURRENT, 02775 ColourValue(0.7, 0.0, 0.2)); 02776 mShadowDebugPass->setCullingMode(CULL_NONE); 02777 compileStencilDebugPass = true; 02778 02779 } 02780 02781 Material* matStencil = static_cast<Material*>( 02782 MaterialManager::getSingleton().getByName("Ogre/StencilShadowVolumes")); 02783 if (!matStencil) 02784 { 02785 // Init 02786 matStencil = static_cast<Material*>( 02787 MaterialManager::getSingleton().create("Ogre/StencilShadowVolumes")); 02788 mShadowStencilPass = matStencil->getTechnique(0)->getPass(0); 02789 compileStencilPass = true; 02790 // Nothing else, we don't use this like a 'real' pass anyway, 02791 // it's more of a placeholder 02792 } 02793 02794 02795 02796 if (mDestRenderSystem->getCapabilities()->hasCapability(RSC_VERTEX_PROGRAM)) 02797 { 02798 ShadowVolumeExtrudeProgram::initialise(); 02799 02800 02801 // Enable the (infinite) point light extruder for now, just to get some params 02802 mShadowDebugPass->setVertexProgram( 02803 ShadowVolumeExtrudeProgram::programNames[ShadowVolumeExtrudeProgram::POINT_LIGHT]); 02804 mInfiniteExtrusionParams = 02805 mShadowDebugPass->getVertexProgramParameters(); 02806 mInfiniteExtrusionParams->setAutoConstant(0, 02807 GpuProgramParameters::ACT_WORLDVIEWPROJ_MATRIX); 02808 mInfiniteExtrusionParams->setAutoConstant(4, 02809 GpuProgramParameters::ACT_LIGHT_POSITION_OBJECT_SPACE); 02810 02811 // Enable the finite point light extruder for now, just to get some params 02812 mShadowStencilPass->setVertexProgram( 02813 ShadowVolumeExtrudeProgram::programNames[ShadowVolumeExtrudeProgram::POINT_LIGHT_FINITE]); 02814 mFiniteExtrusionParams = 02815 mShadowStencilPass->getVertexProgramParameters(); 02816 mFiniteExtrusionParams->setAutoConstant(0, 02817 GpuProgramParameters::ACT_WORLDVIEWPROJ_MATRIX); 02818 mFiniteExtrusionParams->setAutoConstant(4, 02819 GpuProgramParameters::ACT_LIGHT_POSITION_OBJECT_SPACE); 02820 // Note extra parameter 02821 mFiniteExtrusionParams->setAutoConstant(5, 02822 GpuProgramParameters::ACT_SHADOW_EXTRUSION_DISTANCE); 02823 02824 } 02825 02826 02827 if (compileStencilDebugPass) 02828 { 02829 matDebug->compile(); 02830 } 02831 02832 if (compileStencilPass) 02833 { 02834 matStencil->compile(); 02835 } 02836 02837 02838 02839 Material* matModStencil = static_cast<Material*>( 02840 MaterialManager::getSingleton().getByName("Ogre/StencilShadowModulationPass")); 02841 if (!matModStencil) 02842 { 02843 // Init 02844 matModStencil = static_cast<Material*>( 02845 MaterialManager::getSingleton().create("Ogre/StencilShadowModulationPass")); 02846 mShadowModulativePass = matModStencil->getTechnique(0)->getPass(0); 02847 mShadowModulativePass->setSceneBlending(SBF_DEST_COLOUR, SBF_ZERO); 02848 mShadowModulativePass->setLightingEnabled(false); 02849 mShadowModulativePass->setDepthWriteEnabled(false); 02850 mShadowModulativePass->setDepthCheckEnabled(false); 02851 TextureUnitState* t = mShadowModulativePass->createTextureUnitState(); 02852 t->setColourOperationEx(LBX_MODULATE, LBS_MANUAL, LBS_CURRENT, 02853 mShadowColour); 02854 02855 } 02856 02857 // Also init full screen quad while we're at it 02858 if (!mFullScreenQuad) 02859 { 02860 mFullScreenQuad = new Rectangle2D(); 02861 mFullScreenQuad->setCorners(-1,1,1,-1); 02862 } 02863 02864 // Also init shadow caster material for texture shadows 02865 Material* matPlainBlack = static_cast<Material*>( 02866 MaterialManager::getSingleton().getByName("Ogre/TextureShadowCaster")); 02867 if (!matPlainBlack) 02868 { 02869 matPlainBlack = static_cast<Material*>( 02870 MaterialManager::getSingleton().create("Ogre/TextureShadowCaster")); 02871 mShadowCasterPlainBlackPass = matPlainBlack->getTechnique(0)->getPass(0); 02872 // Lighting has to be on, because we need shadow coloured objects 02873 // Note that because we can't predict vertex programs, we'll have to 02874 // bind light values to those, and so we bind White to ambient 02875 // reflectance, and we'll set the ambient colour to the shadow colour 02876 mShadowCasterPlainBlackPass->setAmbient(ColourValue::White); 02877 mShadowCasterPlainBlackPass->setDiffuse(ColourValue::Black); 02878 mShadowCasterPlainBlackPass->setSelfIllumination(ColourValue::Black); 02879 mShadowCasterPlainBlackPass->setSpecular(ColourValue::Black); 02880 // no textures or anything else, we will bind vertex programs 02881 // every so often though 02882 } 02883 02884 Material* matShadRec = static_cast<Material*>( 02885 MaterialManager::getSingleton().getByName("Ogre/TextureShadowReceiver")); 02886 if (!matShadRec) 02887 { 02888 matShadRec = static_cast<Material*>( 02889 MaterialManager::getSingleton().create("Ogre/TextureShadowReceiver")); 02890 mShadowReceiverPass = matShadRec->getTechnique(0)->getPass(0); 02891 mShadowReceiverPass->setSceneBlending(SBF_DEST_COLOUR, SBF_ZERO); 02892 // No lighting, one texture unit 02893 // everything else will be bound as needed during the receiver pass 02894 mShadowReceiverPass->setLightingEnabled(false); 02895 TextureUnitState* t = mShadowReceiverPass->createTextureUnitState(); 02896 t->setTextureAddressingMode(TextureUnitState::TAM_CLAMP); 02897 } 02898 02899 // Set up spot shadow fade texture (loaded from code data block) 02900 Texture* spotShadowFadeTex = (Texture*) 02901 TextureManager::getSingleton().getByName("spot_shadow_fade.png"); 02902 if (!spotShadowFadeTex) 02903 { 02904 // Load the manual buffer into an image 02905 DataChunk chunk(SPOT_SHADOW_FADE_PNG, SPOT_SHADOW_FADE_PNG_SIZE); 02906 Image img; 02907 img.load(chunk, "png"); 02908 spotShadowFadeTex = 02909 TextureManager::getSingleton().loadImage("spot_shadow_fade.png", img, TEX_TYPE_2D); 02910 } 02911 02912 02913 02914 02915 } 02916 //--------------------------------------------------------------------- 02917 Pass* SceneManager::deriveShadowCasterPass(Pass* pass) 02918 { 02919 switch (mShadowTechnique) 02920 { 02921 case SHADOWTYPE_TEXTURE_MODULATIVE: 02922 if (pass->hasVertexProgram()) 02923 { 02924 // Have to merge the shadow caster vertex program in 02925 // This may in fact be blank, in which case it falls back on 02926 // fixed function 02927 mShadowCasterPlainBlackPass->setVertexProgram( 02928 pass->getShadowCasterVertexProgramName()); 02929 // Did this result in a new vertex program? 02930 if (mShadowCasterPlainBlackPass->hasVertexProgram()) 02931 { 02932 GpuProgram* prg = mShadowCasterPlainBlackPass->getVertexProgram(); 02933 // Load this program if not done already 02934 if (!prg->isLoaded()) 02935 prg->load(); 02936 // Copy params 02937 mShadowCasterPlainBlackPass->setVertexProgramParameters( 02938 pass->getShadowCasterVertexProgramParameters()); 02939 } 02940 // Also have to hack the light autoparams, that is done later 02941 } 02942 else if (mShadowCasterPlainBlackPass->hasVertexProgram()) 02943 { 02944 // reset 02945 mShadowCasterPlainBlackPass->setVertexProgram(""); 02946 } 02947 return mShadowCasterPlainBlackPass; 02948 /* 02949 case SHADOWTYPE_TEXTURE_SHADOWMAP: 02950 // todo 02951 return pass; 02952 */ 02953 default: 02954 return pass; 02955 }; 02956 02957 } 02958 //--------------------------------------------------------------------- 02959 Pass* SceneManager::deriveShadowReceiverPass(Pass* pass) 02960 { 02961 02962 switch (mShadowTechnique) 02963 { 02964 case SHADOWTYPE_TEXTURE_MODULATIVE: 02965 if (pass->hasVertexProgram()) 02966 { 02967 // Have to merge the receiver vertex program in 02968 // This may return "" which means fixed function will be used 02969 mShadowReceiverPass->setVertexProgram( 02970 pass->getShadowReceiverVertexProgramName()); 02971 // Did this result in a new vertex program? 02972 if (mShadowReceiverPass->hasVertexProgram()) 02973 { 02974 GpuProgram* prg = mShadowReceiverPass->getVertexProgram(); 02975 // Load this program if required 02976 if (!prg->isLoaded()) 02977 prg->load(); 02978 // Copy params 02979 mShadowReceiverPass->setVertexProgramParameters( 02980 pass->getShadowReceiverVertexProgramParameters()); 02981 } 02982 // Also have to hack the light autoparams, that is done later 02983 } 02984 else if (mShadowReceiverPass->hasVertexProgram()) 02985 { 02986 // reset 02987 mShadowReceiverPass->setVertexProgram(""); 02988 02989 } 02990 02991 return mShadowReceiverPass; 02992 /* 02993 case SHADOWTYPE_TEXTURE_SHADOWMAP: 02994 // todo 02995 return pass; 02996 */ 02997 default: 02998 return pass; 02999 }; 03000 03001 } 03002 //--------------------------------------------------------------------- 03003 void SceneManager::renderShadowVolumesToStencil(const Light* light, const Camera* camera) 03004 { 03005 03006 // Set up scissor test (point & spot lights only) 03007 bool scissored = false; 03008 if (light->getType() != Light::LT_DIRECTIONAL && 03009 mDestRenderSystem->getCapabilities()->hasCapability(RSC_SCISSOR_TEST)) 03010 { 03011 // Project the sphere onto the camera 03012 Real left, right, top, bottom; 03013 Sphere sphere(light->getDerivedPosition(), light->getAttenuationRange()); 03014 if (camera->projectSphere(sphere, &left, &top, &right, &bottom)) 03015 { 03016 scissored = true; 03017 // Turn normalised device coordinates into pixels 03018 int iLeft, iTop, iWidth, iHeight; 03019 mCurrentViewport->getActualDimensions(iLeft, iTop, iWidth, iHeight); 03020 size_t szLeft, szRight, szTop, szBottom; 03021 03022 szLeft = iLeft + ((left + 1) * 0.5 * iWidth); 03023 szRight = iLeft + ((right + 1) * 0.5 * iWidth); 03024 szTop = iTop + ((-top + 1) * 0.5 * iHeight); 03025 szBottom = iTop + ((-bottom + 1) * 0.5 * iHeight); 03026 03027 mDestRenderSystem->setScissorTest(true, szLeft, szTop, szRight, szBottom); 03028 03029 } 03030 03031 } 03032 03033 03034 03035 mDestRenderSystem->unbindGpuProgram(GPT_FRAGMENT_PROGRAM); 03036 03037 // Can we do a 2-sided stencil? 03038 bool stencil2sided = false; 03039 if (mDestRenderSystem->getCapabilities()->hasCapability(RSC_TWO_SIDED_STENCIL) && 03040 mDestRenderSystem->getCapabilities()->hasCapability(RSC_STENCIL_WRAP)) 03041 { 03042 // enable 03043 stencil2sided = true; 03044 } 03045 03046 // Do we have access to vertex programs? 03047 bool extrudeInSoftware = true; 03048 bool finiteExtrude = !mShadowUseInfiniteFarPlane || 03049 !mDestRenderSystem->getCapabilities()->hasCapability(RSC_INFINITE_FAR_PLANE); 03050 if (mDestRenderSystem->getCapabilities()->hasCapability(RSC_VERTEX_PROGRAM)) 03051 { 03052 extrudeInSoftware = false; 03053 // attach the appropriate extrusion vertex program 03054 // Note we never unset it because support for vertex programs is constant 03055 mShadowStencilPass->setVertexProgram( 03056 ShadowVolumeExtrudeProgram::getProgramName(light->getType(), finiteExtrude, false) 03057 , false); 03058 // Set params 03059 if (finiteExtrude) 03060 { 03061 mShadowStencilPass->setVertexProgramParameters(mFiniteExtrusionParams); 03062 } 03063 else 03064 { 03065 mShadowStencilPass->setVertexProgramParameters(mInfiniteExtrusionParams); 03066 } 03067 if (mDebugShadows) 03068 { 03069 mShadowDebugPass->setVertexProgram( 03070 ShadowVolumeExtrudeProgram::getProgramName(light->getType(), finiteExtrude, true) 03071 , false); 03072 // Set params 03073 if (finiteExtrude) 03074 { 03075 mShadowDebugPass->setVertexProgramParameters(mFiniteExtrusionParams); 03076 } 03077 else 03078 { 03079 mShadowDebugPass->setVertexProgramParameters(mInfiniteExtrusionParams); 03080 } 03081 } 03082 03083 mDestRenderSystem->bindGpuProgram(mShadowStencilPass->getVertexProgram()->_getBindingDelegate()); 03084 03085 } 03086 else 03087 { 03088 mDestRenderSystem->unbindGpuProgram(GPT_VERTEX_PROGRAM); 03089 } 03090 03091 // Add light to internal list for use in render call 03092 LightList lightList; 03093 // const_cast is forgiveable here since we pass this const 03094 lightList.push_back(const_cast<Light*>(light)); 03095 03096 // Turn off colour writing and depth writing 03097 mDestRenderSystem->_setColourBufferWriteEnabled(false, false, false, false); 03098 mDestRenderSystem->_setDepthBufferWriteEnabled(false); 03099 mDestRenderSystem->setStencilCheckEnabled(true); 03100 mDestRenderSystem->_setDepthBufferFunction(CMPF_LESS); 03101 03102 // Calculate extrusion distance 03103 Real extrudeDist; 03104 if (light->getType() == Light::LT_DIRECTIONAL) 03105 { 03106 extrudeDist = mShadowDirLightExtrudeDist; 03107 } 03108 03109 // Figure out the near clip volume 03110 const PlaneBoundedVolume& nearClipVol = 03111 light->_getNearClipVolume(camera); 03112 03113 // Get the shadow caster list 03114 const ShadowCasterList& casters = findShadowCastersForLight(light, camera); 03115 ShadowCasterList::const_iterator si, siend; 03116 siend = casters.end(); 03117 03118 // Determine whether zfail is required 03119 // We need to use zfail for ALL objects if we find a single object which 03120 // requires it 03121 bool zfailAlgo = false; 03122 unsigned long flags = 0; 03123 03124 for (si = casters.begin(); si != siend; ++si) 03125 { 03126 ShadowCaster* caster = *si; 03127 03128 if (nearClipVol.intersects(caster->getWorldBoundingBox())) 03129 { 03130 // We have a zfail case, we must use zfail for all objects 03131 zfailAlgo = true; 03132 break; 03133 } 03134 } 03135 03136 // Now iterate over the casters and render 03137 for (si = casters.begin(); si != siend; ++si) 03138 { 03139 ShadowCaster* caster = *si; 03140 flags = 0; 03141 03142 if (light->getType() != Light::LT_DIRECTIONAL) 03143 { 03144 extrudeDist = caster->getPointExtrusionDistance(light); 03145 } 03146 03147 if (!extrudeInSoftware && !finiteExtrude) 03148 { 03149 // hardware extrusion, to infinity (and beyond!) 03150 flags |= SRF_EXTRUDE_TO_INFINITY; 03151 } 03152 03153 if (zfailAlgo) 03154 { 03155 // We need to include the light and / or dark cap 03156 // But only if they will be visible 03157 if(camera->isVisible(caster->getLightCapBounds())) 03158 { 03159 flags |= SRF_INCLUDE_LIGHT_CAP; 03160 } 03161 } 03162 // Dark cap (no dark cap for directional lights using 03163 // hardware extrusion to infinity) 03164 if(!((flags & SRF_EXTRUDE_TO_INFINITY) && 03165 light->getType() == Light::LT_DIRECTIONAL) && 03166 camera->isVisible(caster->getDarkCapBounds(*light, extrudeDist))) 03167 { 03168 flags |= SRF_INCLUDE_DARK_CAP; 03169 } 03170 03171 // Get shadow renderables 03172 ShadowCaster::ShadowRenderableListIterator iShadowRenderables = 03173 caster->getShadowVolumeRenderableIterator(mShadowTechnique, 03174 light, &mShadowIndexBuffer, extrudeInSoftware, 03175 extrudeDist, flags); 03176 03177 while (iShadowRenderables.hasMoreElements()) 03178 { 03179 ShadowRenderable* sr = iShadowRenderables.getNext(); 03180 // omit hidden renderables 03181 if (sr->isVisible()) 03182 { 03183 // render volume, including dark and (maybe) light caps 03184 renderSingleShadowVolumeToStencil(sr, zfailAlgo, stencil2sided, &lightList); 03185 03186 // optionally render separate light cap 03187 if (sr->isLightCapSeparate() && 03188 (flags & SRF_INCLUDE_LIGHT_CAP)) 03189 { 03190 // must always fail depth check 03191 mDestRenderSystem->_setDepthBufferFunction(CMPF_ALWAYS_FAIL); 03192 assert(sr->getLightCapRenderable() && "Shadow renderable is " 03193 "missing a separate light cap renderable!"); 03194 renderSingleShadowVolumeToStencil(sr->getLightCapRenderable(), 03195 zfailAlgo, stencil2sided, &lightList); 03196 // reset depth function 03197 mDestRenderSystem->_setDepthBufferFunction(CMPF_LESS); 03198 } 03199 } 03200 } 03201 } 03202 // revert colour write state 03203 mDestRenderSystem->_setColourBufferWriteEnabled(true, true, true, true); 03204 // revert depth state 03205 mDestRenderSystem->_setDepthBufferParams(); 03206 03207 mDestRenderSystem->setStencilCheckEnabled(false); 03208 03209 mDestRenderSystem->unbindGpuProgram(GPT_VERTEX_PROGRAM); 03210 03211 if (scissored) 03212 { 03213 // disable scissor test 03214 mDestRenderSystem->setScissorTest(false); 03215 } 03216 03217 } 03218 //--------------------------------------------------------------------- 03219 void SceneManager::renderSingleShadowVolumeToStencil(ShadowRenderable* sr, 03220 bool zfailAlgo, bool stencil2sided, const LightList *manualLightList) 03221 { 03222 // Render a shadow volume here 03223 // - if we have 2-sided stencil, one render with no culling 03224 // - otherwise, 2 renders, one with each culling method and invert the ops 03225 setShadowVolumeStencilState(false, zfailAlgo, stencil2sided); 03226 renderSingleObject(sr, mShadowStencilPass, false, manualLightList); 03227 03228 if (!stencil2sided) 03229 { 03230 // Second pass 03231 setShadowVolumeStencilState(true, zfailAlgo, false); 03232 renderSingleObject(sr, mShadowStencilPass, false); 03233 } 03234 03235 // Do we need to render a debug shadow marker? 03236 if (mDebugShadows) 03237 { 03238 // reset stencil & colour ops 03239 mDestRenderSystem->setStencilBufferParams(); 03240 setPass(mShadowDebugPass); 03241 renderSingleObject(sr, mShadowDebugPass, false, manualLightList); 03242 mDestRenderSystem->_setColourBufferWriteEnabled(false, false, false, false); 03243 } 03244 } 03245 //--------------------------------------------------------------------- 03246 void SceneManager::setShadowVolumeStencilState(bool secondpass, bool zfail, bool twosided) 03247 { 03248 // First pass, do front faces if zpass 03249 // Second pass, do back faces if zpass 03250 // Invert if zfail 03251 // this is to ensure we always increment before decrement 03252 if ( (secondpass || zfail) && 03253 !(secondpass && zfail) ) 03254 { 03255 mDestRenderSystem->_setCullingMode( 03256 twosided? CULL_NONE : CULL_ANTICLOCKWISE); 03257 mDestRenderSystem->setStencilBufferParams( 03258 CMPF_ALWAYS_PASS, // always pass stencil check 03259 0, // no ref value (no compare) 03260 0xFFFFFFFF, // no mask 03261 SOP_KEEP, // stencil test will never fail 03262 zfail? (twosided? SOP_INCREMENT_WRAP : SOP_INCREMENT) : SOP_KEEP, // back face depth fail 03263 zfail? SOP_KEEP : (twosided? SOP_DECREMENT_WRAP : SOP_DECREMENT), // back face pass 03264 twosided 03265 ); 03266 } 03267 else 03268 { 03269 mDestRenderSystem->_setCullingMode( 03270 twosided? CULL_NONE : CULL_CLOCKWISE); 03271 mDestRenderSystem->setStencilBufferParams( 03272 CMPF_ALWAYS_PASS, // always pass stencil check 03273 0, // no ref value (no compare) 03274 0xFFFFFFFF, // no mask 03275 SOP_KEEP, // stencil test will never fail 03276 zfail? (twosided? SOP_DECREMENT_WRAP : SOP_DECREMENT) : SOP_KEEP, // front face depth fail 03277 zfail? SOP_KEEP : (twosided? SOP_INCREMENT_WRAP : SOP_INCREMENT), // front face pass 03278 twosided 03279 ); 03280 } 03281 } 03282 //--------------------------------------------------------------------- 03283 void SceneManager::setShadowColour(const ColourValue& colour) 03284 { 03285 mShadowColour = colour; 03286 03287 if (!mShadowModulativePass && !mShadowCasterPlainBlackPass) 03288 initShadowVolumeMaterials(); 03289 03290 mShadowModulativePass->getTextureUnitState(0)->setColourOperationEx( 03291 LBX_MODULATE, LBS_MANUAL, LBS_CURRENT, colour); 03292 } 03293 //--------------------------------------------------------------------- 03294 const ColourValue& SceneManager::getShadowColour(void) const 03295 { 03296 return mShadowColour; 03297 } 03298 //--------------------------------------------------------------------- 03299 void SceneManager::setShadowFarDistance(Real distance) 03300 { 03301 mShadowFarDist = distance; 03302 mShadowFarDistSquared = distance * distance; 03303 } 03304 //--------------------------------------------------------------------- 03305 void SceneManager::setShadowDirectionalLightExtrusionDistance(Real dist) 03306 { 03307 mShadowDirLightExtrudeDist = dist; 03308 } 03309 //--------------------------------------------------------------------- 03310 Real SceneManager::getShadowDirectionalLightExtrusionDistance(void) const 03311 { 03312 return mShadowDirLightExtrudeDist; 03313 } 03314 //--------------------------------------------------------------------- 03315 void SceneManager::setShadowIndexBufferSize(size_t size) 03316 { 03317 if (!mShadowIndexBuffer.isNull() && size != mShadowIndexBufferSize) 03318 { 03319 // re-create shadow buffer with new size 03320 mShadowIndexBuffer = HardwareBufferManager::getSingleton(). 03321 createIndexBuffer(HardwareIndexBuffer::IT_16BIT, 03322 mShadowIndexBufferSize, 03323 HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY, 03324 false); 03325 } 03326 mShadowIndexBufferSize = size; 03327 } 03328 //--------------------------------------------------------------------- 03329 void SceneManager::setShadowTextureSize(unsigned short size) 03330 { 03331 // possibly recreate 03332 createShadowTextures(size, mShadowTextureCount); 03333 mShadowTextureSize = size; 03334 } 03335 //--------------------------------------------------------------------- 03336 void SceneManager::setShadowTextureCount(unsigned short count) 03337 { 03338 // possibly recreate 03339 createShadowTextures(mShadowTextureSize, count); 03340 mShadowTextureCount = count; 03341 } 03342 //--------------------------------------------------------------------- 03343 void SceneManager::setShadowTextureSettings(unsigned short size, unsigned short count) 03344 { 03345 if (!mShadowTextures.empty() && 03346 (count != mShadowTextureCount || 03347 size != mShadowTextureSize)) 03348 { 03349 // recreate 03350 createShadowTextures(size, count); 03351 } 03352 mShadowTextureCount = count; 03353 mShadowTextureSize = size; 03354 } 03355 //--------------------------------------------------------------------- 03356 void SceneManager::createShadowTextures(unsigned short size, unsigned short count) 03357 { 03358 static const String baseName = "Ogre/ShadowTexture"; 03359 03360 if ((mShadowTechnique != SHADOWTYPE_TEXTURE_MODULATIVE 03361 /*&& mShadowTechnique != SHADOWTYPE_TEXTURE_SHADOWMAP */) || 03362 !mShadowTextures.empty() && 03363 count == mShadowTextureCount && 03364 size == mShadowTextureSize) 03365 { 03366 // no change 03367 return; 03368 } 03369 03370 03371 // destroy existing 03372 ShadowTextureList::iterator i, iend; 03373 iend = mShadowTextures.end(); 03374 for (i = mShadowTextures.begin(); i != iend; ++i) 03375 { 03376 RenderTexture* r = *i; 03377 // remove camera and destroy texture 03378 removeCamera(r->getViewport(0)->getCamera()); 03379 mDestRenderSystem->destroyRenderTexture(r->getName()); 03380 } 03381 mShadowTextures.clear(); 03382 03383 // Recreate shadow textures 03384 for (unsigned short t = 0; t < mShadowTextureCount; ++t) 03385 { 03386 String targName = baseName + StringConverter::toString(t); 03387 String matName = baseName + "Mat" + StringConverter::toString(t); 03388 String camName = baseName + "Cam" + StringConverter::toString(t); 03389 03390 RenderTexture* shadowTex; 03391 if (mShadowTechnique == SHADOWTYPE_TEXTURE_MODULATIVE) 03392 { 03393 shadowTex = mDestRenderSystem->createRenderTexture( 03394 targName, size, size ); 03395 } 03396 /* 03397 else if (mShadowTechnique == SHADOWTYPE_TEXTURE_SHADOWMAP) 03398 { 03399 // todo 03400 } 03401 */ 03402 03403 // Create a camera to go with this texture 03404 Camera* cam = createCamera(camName); 03405 cam->setAspectRatio(1.0f); 03406 // Create a viewport 03407 Viewport *v = shadowTex->addViewport(cam); 03408 v->setClearEveryFrame(true); 03409 // remove overlays 03410 v->setOverlaysEnabled(false); 03411 // Don't update automatically - we'll do it when required 03412 shadowTex->setAutoUpdated(false); 03413 mShadowTextures.push_back(shadowTex); 03414 03415 // Also create corresponding Material used for rendering this shadow 03416 Material* mat = (Material*)MaterialManager::getSingleton().getByName(matName); 03417 if (!mat) 03418 { 03419 mat = (Material*)MaterialManager::getSingleton().create(matName); 03420 } 03421 else 03422 { 03423 mat->getTechnique(0)->getPass(0)->removeAllTextureUnitStates(); 03424 } 03425 // create texture unit referring to render target texture 03426 TextureUnitState* texUnit = 03427 mat->getTechnique(0)->getPass(0)->createTextureUnitState(targName); 03428 // set projective based on camera 03429 texUnit->setProjectiveTexturing(true, cam); 03430 texUnit->setTextureAddressingMode(TextureUnitState::TAM_CLAMP); 03431 mat->touch(); 03432 03433 } 03434 } 03435 //--------------------------------------------------------------------- 03436 void SceneManager::prepareShadowTextures(Camera* cam, Viewport* vp) 03437 { 03438 // Set the illumination stage, prevents recursive calls 03439 IlluminationRenderStage savedStage = mIlluminationStage; 03440 mIlluminationStage = IRS_RENDER_TO_TEXTURE; 03441 03442 // Determine far shadow distance 03443 Real shadowDist = mShadowFarDist; 03444 if (!shadowDist) 03445 { 03446 // need a shadow distance, make one up 03447 shadowDist = cam->getNearClipDistance() * 300; 03448 } 03449 // set fogging to hide the shadow edge 03450 Real shadowOffset = shadowDist * mShadowTextureOffset; 03451 Real shadowEnd = shadowDist + shadowOffset; 03452 mShadowReceiverPass->setFog(true, FOG_LINEAR, ColourValue::White, 03453 0, shadowEnd * mShadowTextureFadeStart, shadowEnd * mShadowTextureFadeEnd); 03454 03455 // Iterate over the lights we've found, max out at the limit of light textures 03456 03457 LightList::iterator i, iend; 03458 ShadowTextureList::iterator si, siend; 03459 iend = mLightsAffectingFrustum.end(); 03460 siend = mShadowTextures.end(); 03461 for (i = mLightsAffectingFrustum.begin(), si = mShadowTextures.begin(); 03462 i != iend && si != siend; ++i) 03463 { 03464 Light* light = *i; 03465 RenderTexture* shadowTex = *si; 03466 // Skip non-shadowing lights 03467 if (!light->getCastShadows()) 03468 continue; 03469 03470 // Directional lights 03471 if (light->getType() == Light::LT_DIRECTIONAL) 03472 { 03473 03474 // set up the shadow texture 03475 Camera* texCam = shadowTex->getViewport(0)->getCamera(); 03476 // Set ortho projection 03477 texCam->setProjectionType(PT_ORTHOGRAPHIC); 03478 // set easy FOV and near dist so that texture covers far dist 03479 texCam->setFOVy(90); 03480 texCam->setNearClipDistance(shadowDist); 03481 03482 // Set size of projection 03483 03484 // Calculate look at position 03485 // We want to look at a spot shadowOffset away from near plane 03486 // 0.5 is a litle too close for angles 03487 Vector3 target = cam->getDerivedPosition() + 03488 (cam->getDerivedDirection() * shadowOffset); 03489 03490 // Calculate position 03491 // We want to be in the -ve direction of the light direction 03492 // far enough to project for the dir light extrusion distance 03493 Vector3 pos = target + 03494 (light->getDerivedDirection() * -mShadowDirLightExtrudeDist); 03495 03496 // Calculate orientation 03497 Vector3 dir = (pos - target); // backwards since point down -z 03498 dir.normalise(); 03499 /* 03500 // Next section (camera oriented shadow map) abandoned 03501 // Always point in the same direction, if we don't do this then 03502 // we get 'shadow swimming' as camera rotates 03503 // As it is, we get swimming on moving but this is less noticeable 03504 03505 // calculate up vector, we want it aligned with cam direction 03506 Vector3 up = cam->getDerivedDirection(); 03507 // Check it's not coincident with dir 03508 if (up.dotProduct(dir) >= 1.0f) 03509 { 03510 // Use camera up 03511 up = cam->getUp(); 03512 } 03513 */ 03514 Vector3 up = Vector3::UNIT_Y; 03515 // Check it's not coincident with dir 03516 if (up.dotProduct(dir) >= 1.0f) 03517 { 03518 // Use camera up 03519 up = Vector3::UNIT_Z; 03520 } 03521 // cross twice to rederive, only direction is unaltered 03522 Vector3 left = dir.crossProduct(up); 03523 left.normalise(); 03524 up = dir.crossProduct(left); 03525 up.normalise(); 03526 // Derive quaternion from axes 03527 Quaternion q; 03528 q.FromAxes(left, up, dir); 03529 texCam->setOrientation(q); 03530 03531 // Round local x/y position based on a world-space texel; this helps to reduce 03532 // jittering caused by the projection moving with the camera 03533 // Viewport is 2 * near clip distance across (90 degree fov) 03534 Real worldTexelSize = (texCam->getNearClipDistance() * 20) / mShadowTextureSize; 03535 pos.x -= fmod(pos.x, worldTexelSize); 03536 pos.y -= fmod(pos.y, worldTexelSize); 03537 pos.z -= fmod(pos.z, worldTexelSize); 03538 // Finally set position 03539 texCam->setPosition(pos); 03540 03541 if (mShadowTechnique == SHADOWTYPE_TEXTURE_MODULATIVE) 03542 shadowTex->getViewport(0)->setBackgroundColour(ColourValue::White); 03543 03544 // Update target 03545 shadowTex->update(); 03546 03547 ++si; 03548 } 03549 // Spotlight 03550 else if (light->getType() == Light::LT_SPOTLIGHT) 03551 { 03552 03553 // set up the shadow texture 03554 Camera* texCam = shadowTex->getViewport(0)->getCamera(); 03555 // Set perspective projection 03556 texCam->setProjectionType(PT_PERSPECTIVE); 03557 // set FOV slightly larger than the spotlight range to ensure coverage 03558 texCam->setFOVy(light->getSpotlightOuterAngle()*1.2); 03559 texCam->setPosition(light->getDerivedPosition()); 03560 texCam->setDirection(light->getDerivedDirection()); 03561 // set near clip the same as main camera, since they are likely 03562 // to both reflect the nature of the scene 03563 texCam->setNearClipDistance(cam->getNearClipDistance()); 03564 03565 if (mShadowTechnique == SHADOWTYPE_TEXTURE_MODULATIVE) 03566 shadowTex->getViewport(0)->setBackgroundColour(ColourValue::White); 03567 03568 // Update target 03569 shadowTex->update(); 03570 03571 ++si; 03572 } 03573 } 03574 // Set the illumination stage, prevents recursive calls 03575 mIlluminationStage = savedStage; 03576 } 03577 //--------------------------------------------------------------------- 03578 AxisAlignedBoxSceneQuery* 03579 SceneManager::createAABBQuery(const AxisAlignedBox& box, unsigned long mask) 03580 { 03581 DefaultAxisAlignedBoxSceneQuery* q = new DefaultAxisAlignedBoxSceneQuery(this); 03582 q->setBox(box); 03583 q->setQueryMask(mask); 03584 return q; 03585 } 03586 //--------------------------------------------------------------------- 03587 SphereSceneQuery* 03588 SceneManager::createSphereQuery(const Sphere& sphere, unsigned long mask) 03589 { 03590 DefaultSphereSceneQuery* q = new DefaultSphereSceneQuery(this); 03591 q->setSphere(sphere); 03592 q->setQueryMask(mask); 03593 return q; 03594 } 03595 //--------------------------------------------------------------------- 03596 PlaneBoundedVolumeListSceneQuery* 03597 SceneManager::createPlaneBoundedVolumeQuery(const PlaneBoundedVolumeList& volumes, 03598 unsigned long mask) 03599 { 03600 DefaultPlaneBoundedVolumeListSceneQuery* q = new DefaultPlaneBoundedVolumeListSceneQuery(this); 03601 q->setVolumes(volumes); 03602 q->setQueryMask(mask); 03603 return q; 03604 } 03605 03606 //--------------------------------------------------------------------- 03607 RaySceneQuery* 03608 SceneManager::createRayQuery(const Ray& ray, unsigned long mask) 03609 { 03610 DefaultRaySceneQuery* q = new DefaultRaySceneQuery(this); 03611 q->setRay(ray); 03612 q->setQueryMask(mask); 03613 return q; 03614 } 03615 //--------------------------------------------------------------------- 03616 IntersectionSceneQuery* 03617 SceneManager::createIntersectionQuery(unsigned long mask) 03618 { 03619 03620 DefaultIntersectionSceneQuery* q = new DefaultIntersectionSceneQuery(this); 03621 q->setQueryMask(mask); 03622 return q; 03623 } 03624 //--------------------------------------------------------------------- 03625 void SceneManager::destroyQuery(SceneQuery* query) 03626 { 03627 delete query; 03628 } 03629 //--------------------------------------------------------------------- 03630 DefaultIntersectionSceneQuery::DefaultIntersectionSceneQuery(SceneManager* creator) 03631 : IntersectionSceneQuery(creator) 03632 { 03633 // No world geometry results supported 03634 mSupportedWorldFragments.insert(SceneQuery::WFT_NONE); 03635 } 03636 //--------------------------------------------------------------------- 03637 DefaultIntersectionSceneQuery::~DefaultIntersectionSceneQuery() 03638 { 03639 } 03640 //--------------------------------------------------------------------- 03641 void DefaultIntersectionSceneQuery::execute(IntersectionSceneQueryListener* listener) 03642 { 03643 // TODO: BillboardSets? Will need per-billboard collision most likely 03644 // Entities only for now 03645 SceneManager::EntityList::const_iterator a, b, theEnd; 03646 theEnd = mParentSceneMgr->mEntities.end(); 03647 int numEntities; 03648 // Loop a from first to last-1 03649 a = mParentSceneMgr->mEntities.begin(); 03650 numEntities = (uint)mParentSceneMgr->mEntities.size(); 03651 for (int i = 0; i < (numEntities - 1); ++i, ++a) 03652 { 03653 // Skip if a does not pass the mask 03654 if (! (a->second->getQueryFlags() & mQueryMask)) 03655 continue; 03656 03657 // Loop b from a+1 to last 03658 b = a; 03659 for (++b; b != theEnd; ++b) 03660 { 03661 // Apply mask to b (both must pass) 03662 if (b->second->getQueryFlags() & mQueryMask) 03663 { 03664 const AxisAlignedBox& box1 = a->second->getWorldBoundingBox(); 03665 const AxisAlignedBox& box2 = b->second->getWorldBoundingBox(); 03666 03667 if (box1.intersects(box2)) 03668 { 03669 listener->queryResult(a->second, b->second); 03670 } 03671 } 03672 03673 } 03674 } 03675 } 03676 //--------------------------------------------------------------------- 03677 DefaultAxisAlignedBoxSceneQuery:: 03678 DefaultAxisAlignedBoxSceneQuery(SceneManager* creator) 03679 : AxisAlignedBoxSceneQuery(creator) 03680 { 03681 // No world geometry results supported 03682 mSupportedWorldFragments.insert(SceneQuery::WFT_NONE); 03683 } 03684 //--------------------------------------------------------------------- 03685 DefaultAxisAlignedBoxSceneQuery::~DefaultAxisAlignedBoxSceneQuery() 03686 { 03687 } 03688 //--------------------------------------------------------------------- 03689 void DefaultAxisAlignedBoxSceneQuery::execute(SceneQueryListener* listener) 03690 { 03691 // TODO: BillboardSets? Will need per-billboard collision most likely 03692 // Entities only for now 03693 SceneManager::EntityList::const_iterator i, iEnd; 03694 iEnd = mParentSceneMgr->mEntities.end(); 03695 for (i = mParentSceneMgr->mEntities.begin(); i != iEnd; ++i) 03696 { 03697 if (mAABB.intersects(i->second->getWorldBoundingBox())) 03698 { 03699 listener->queryResult(i->second); 03700 } 03701 } 03702 } 03703 //--------------------------------------------------------------------- 03704 DefaultRaySceneQuery:: 03705 DefaultRaySceneQuery(SceneManager* creator) : RaySceneQuery(creator) 03706 { 03707 // No world geometry results supported 03708 mSupportedWorldFragments.insert(SceneQuery::WFT_NONE); 03709 } 03710 //--------------------------------------------------------------------- 03711 DefaultRaySceneQuery::~DefaultRaySceneQuery() 03712 { 03713 } 03714 //--------------------------------------------------------------------- 03715 void DefaultRaySceneQuery::execute(RaySceneQueryListener* listener) 03716 { 03717 // Note that becuase we have no scene partitioning, we actually 03718 // perform a complete scene search even if restricted results are 03719 // requested; smarter scene manager queries can utilise the paritioning 03720 // of the scene in order to reduce the number of intersection tests 03721 // required to fulfil the query 03722 03723 // TODO: BillboardSets? Will need per-billboard collision most likely 03724 // Entities only for now 03725 SceneManager::EntityList::const_iterator i, iEnd; 03726 iEnd = mParentSceneMgr->mEntities.end(); 03727 for (i = mParentSceneMgr->mEntities.begin(); i != iEnd; ++i) 03728 { 03729 // Do ray / box test 03730 std::pair<bool, Real> result = 03731 mRay.intersects(i->second->getWorldBoundingBox()); 03732 03733 if (result.first) 03734 { 03735 listener->queryResult(i->second, result.second); 03736 } 03737 } 03738 03739 } 03740 //--------------------------------------------------------------------- 03741 DefaultSphereSceneQuery:: 03742 DefaultSphereSceneQuery(SceneManager* creator) : SphereSceneQuery(creator) 03743 { 03744 // No world geometry results supported 03745 mSupportedWorldFragments.insert(SceneQuery::WFT_NONE); 03746 } 03747 //--------------------------------------------------------------------- 03748 DefaultSphereSceneQuery::~DefaultSphereSceneQuery() 03749 { 03750 } 03751 //--------------------------------------------------------------------- 03752 void DefaultSphereSceneQuery::execute(SceneQueryListener* listener) 03753 { 03754 // TODO: BillboardSets? Will need per-billboard collision most likely 03755 // Entities only for now 03756 SceneManager::EntityList::const_iterator i, iEnd; 03757 iEnd = mParentSceneMgr->mEntities.end(); 03758 Sphere testSphere; 03759 for (i = mParentSceneMgr->mEntities.begin(); i != iEnd; ++i) 03760 { 03761 // Skip unattached 03762 if (!i->second->getParentNode()) 03763 continue; 03764 03765 // Do sphere / sphere test 03766 testSphere.setCenter(i->second->getParentNode()->_getDerivedPosition()); 03767 testSphere.setRadius(i->second->getBoundingRadius()); 03768 if (mSphere.intersects(testSphere)) 03769 { 03770 listener->queryResult(i->second); 03771 } 03772 } 03773 } 03774 //--------------------------------------------------------------------- 03775 DefaultPlaneBoundedVolumeListSceneQuery:: 03776 DefaultPlaneBoundedVolumeListSceneQuery(SceneManager* creator) 03777 : PlaneBoundedVolumeListSceneQuery(creator) 03778 { 03779 // No world geometry results supported 03780 mSupportedWorldFragments.insert(SceneQuery::WFT_NONE); 03781 } 03782 //--------------------------------------------------------------------- 03783 DefaultPlaneBoundedVolumeListSceneQuery::~DefaultPlaneBoundedVolumeListSceneQuery() 03784 { 03785 } 03786 //--------------------------------------------------------------------- 03787 void DefaultPlaneBoundedVolumeListSceneQuery::execute(SceneQueryListener* listener) 03788 { 03789 // Entities only for now 03790 SceneManager::EntityList::const_iterator i, iEnd; 03791 iEnd = mParentSceneMgr->mEntities.end(); 03792 Sphere testSphere; 03793 for (i = mParentSceneMgr->mEntities.begin(); i != iEnd; ++i) 03794 { 03795 PlaneBoundedVolumeList::iterator pi, piend; 03796 piend = mVolumes.end(); 03797 for (pi = mVolumes.begin(); pi != piend; ++pi) 03798 { 03799 PlaneBoundedVolume& vol = *pi; 03800 // Do AABB / plane volume test 03801 if (vol.intersects(i->second->getWorldBoundingBox())) 03802 { 03803 listener->queryResult(i->second); 03804 break; 03805 } 03806 } 03807 } 03808 } 03809 03810 }
Copyright © 2002-2003 by The OGRE Team
Last modified Fri May 14 23:22:44 2004