#include "OgreIlluminationManager.h" #include "OgreParticleSystemRenderer.h" #include "OgreBillboardParticleRenderer.h" #include "SpriteParticleRenderer.h" OgreIlluminationManager* OgreIlluminationManager::instance = NULL; Vector3 sortfrom; RenderingRunType sortType; class sortFromVector { public: bool operator()(OgreSharedRuns* a, OgreSharedRuns* b) { float dist1 = (a->getRootPosition() - sortfrom).length(); float dist2 = (b->getRootPosition() - sortfrom).length(); return dist1 > dist2; } }; class sortFromVectorWithRunType { public: bool operator()(OgreSharedRuns* a, OgreSharedRuns* b) { float dist1 = (a->getRootPosition(sortType) - sortfrom).length(); float dist2 = (b->getRootPosition(sortType) - sortfrom).length(); return dist1 > dist2; } }; class VisibleFinderVisitor : public QueuedRenderableVisitor { private: std::vector* visibleObjects; public: VisibleFinderVisitor(std::vector* visibleObjectsVector) { this->visibleObjects = visibleObjectsVector; } void visit(const Renderable* r) { OgreTechniqueGroup* tg = (OgreTechniqueGroup*) r->getRenderTechniqueGroup(); if(tg != 0) { tg->validateSharedRuns(); visibleObjects->push_back(r); } } bool visit(const Pass* p) { return true; } void visit(const RenderablePass* rp) { Renderable* r = rp->renderable; OgreTechniqueGroup* tg = (OgreTechniqueGroup*) r->getRenderTechniqueGroup(); if(tg != 0) { tg->validateSharedRuns(); visibleObjects->push_back(r); } } }; OgreIlluminationManager::OgreIlluminationManager() { visitor = new VisibleFinderVisitor(&visibleObjects); maxRad = 400; focusingMapSize = 32; shadowMapSize = 512; phaseTextureSize = 256; useLISPSM = false; useVSM = false; blurSM = false; focusingSM = true; shadowMapMaterialName = "GameTools/ShadowMapDepth"; for(int i = 0; i < RUN_TYPE_COUNT; i++) { maxRads[(RenderingRunType)i] = (float) maxRad; } //register rendertechnique factories OgreColorCubeMapRenderTechniqueFactory* colorcube = new OgreColorCubeMapRenderTechniqueFactory(); addRenderTechniqueFactory(colorcube); OgreDistanceCubeMapRenderTechniqueFactory* distcube = new OgreDistanceCubeMapRenderTechniqueFactory(); addRenderTechniqueFactory(distcube); OgreConvoledCubeMapRenderTechniqueFactory* convcube = new OgreConvoledCubeMapRenderTechniqueFactory(); addRenderTechniqueFactory(convcube); OgreCausticCasterRenderTechniqueFactory* caucast = new OgreCausticCasterRenderTechniqueFactory(); addRenderTechniqueFactory(caucast); OgreCausticRecieverRenderTechniqueFactory* caurec = new OgreCausticRecieverRenderTechniqueFactory(); addRenderTechniqueFactory(caurec); OgreDepthShadowRecieverRenderTechniqueFactory* dsrec = new OgreDepthShadowRecieverRenderTechniqueFactory(); addRenderTechniqueFactory(dsrec); OgreSBBRenderTechniqueFactory* sbb = new OgreSBBRenderTechniqueFactory(); addRenderTechniqueFactory(sbb); OgreFireRenderTechniqueFactory* fire = new OgreFireRenderTechniqueFactory(); addRenderTechniqueFactory(fire); OgreHierarchicalParticleSystemTechniqueFactory* HPSF = new OgreHierarchicalParticleSystemTechniqueFactory(); addRenderTechniqueFactory(HPSF); OgreIllumVolumeRenderTechniqueFactory* illumVolume = new OgreIllumVolumeRenderTechniqueFactory(); addRenderTechniqueFactory(illumVolume); } OgreIlluminationManager::~OgreIlluminationManager() { } OgreIlluminationManager& OgreIlluminationManager::getSingleton() { if(instance == NULL) instance= new OgreIlluminationManager(); return *instance; } void OgreIlluminationManager::fillVisibleList( RenderQueue * rq ) { visibleObjects.clear(); RenderQueue::QueueGroupIterator queueIt = rq->_getQueueGroupIterator(); while (queueIt.hasMoreElements()) { RenderQueueGroup* pGroup = queueIt.getNext(); RenderQueueGroup::PriorityMapIterator groupIt = pGroup->getIterator(); while (groupIt.hasMoreElements()) { RenderPriorityGroup* pPriorityGrp = groupIt.getNext(); const QueuedRenderableCollection& solids = pPriorityGrp->getSolidsBasic(); const QueuedRenderableCollection& transparents = pPriorityGrp->getTransparents(); solids.acceptVisitor(visitor, QueuedRenderableCollection::OM_PASS_GROUP); transparents.acceptVisitor(visitor, QueuedRenderableCollection::OM_SORT_ASCENDING); } } rq->clear(); } BillboardSet* OgreIlluminationManager::findRenderableInParticleSystem(ParticleSystem* system) { ParticleSystemRenderer* renderer = system->getRenderer(); const String rendererType = renderer->getType(); if(rendererType == "billboard") { BillboardSet* bbSet = ((BillboardParticleRenderer*) renderer)->getBillboardSet(); return bbSet; } if(rendererType == "sprite") { BillboardSet* bbSet = ((SpriteParticleRenderer*) renderer)->getSpriteSet(); return bbSet; } OGRE_EXCEPT(0, "Unsupported particle renderable type", "OgreIlluminationManager::findRenderableInParticleSystem"); return NULL; } void OgreIlluminationManager::initTechniques(Entity* e) { if( e->getParentSceneNode() == 0 )//Entity not attached return; OgreSharedRuns* sharedruns = 0; for(unsigned int s = 0; s < e->getNumSubEntities(); s++) { SubEntity* sube = e->getSubEntity(s); Material* mat = sube->getMaterial().getPointer(); OgreRenderable* rend = 0; OgreTechniqueGroup* group = 0; for(unsigned int t = 0 ; t < mat->getNumTechniques() ; t++) { Technique* tech = mat->getTechnique(t); for(unsigned int p = 0; p< tech->getNumPasses(); p++) { Pass* pass = tech->getPass(p); std::vector& techniques = pass->getIllumTechniques(); std::vector::iterator i = techniques.begin(); std::vector::iterator iend = techniques.end(); while( i != iend) { IllumTechniqueParams* params = *i; if(rend == 0) { rend = new OgreRenderable(e, s); group = new OgreTechniqueGroup(); sube->setRenderTechniqueGroup(group); if( sharedruns == 0) { sharedruns = new OgreSharedRuns(); addSharedRuns(sharedruns); } group->addSharedRun(sharedruns); sharedruns->addRenderable(rend); sharedruns->updateBounds(); } createTechnique(params, pass, rend, sharedruns); i++; } } } } } void OgreIlluminationManager::initTechniques(BillboardSet* bbs, ParticleSystem* sys) { if( bbs->getParentSceneNode() == 0 )//billboardset not attached return; OgreSharedRuns* sharedruns = 0; Material* mat = bbs->getMaterial().getPointer(); OgreRenderable* rend = 0; OgreTechniqueGroup* group = 0; for(unsigned int t = 0 ; t < mat->getNumTechniques() ; t++) { Technique* tech = mat->getTechnique(t); for(unsigned int p = 0; p< tech->getNumPasses(); p++) { Pass* pass = tech->getPass(p); std::vector& techniques = pass->getIllumTechniques(); std::vector::iterator i = techniques.begin(); std::vector::iterator iend = techniques.end(); while( i != iend) { IllumTechniqueParams* params = *i; if(rend == 0) { rend = new OgreRenderable(bbs, sys); group = new OgreTechniqueGroup(); bbs->setRenderTechniqueGroup(group); if( sharedruns == 0) { sharedruns = new OgreSharedRuns(); addSharedRuns(sharedruns); } group->addSharedRun(sharedruns); sharedruns->addRenderable(rend); sharedruns->updateBounds(); } createTechnique(params, pass, rend, sharedruns); i++; } } } } void OgreIlluminationManager::initTechniques() { { //Entities SceneManager::MovableObjectIterator it = Root::getSingleton()._getCurrentSceneManager() ->getMovableObjectIterator("Entity"); while(it.hasMoreElements()) { MovableObject* o = it.getNext(); Entity* e = (Entity*) o; initTechniques(e); } } { //ParticleSystems SceneManager::MovableObjectIterator it = Root::getSingleton()._getCurrentSceneManager() ->getMovableObjectIterator("ParticleSystem"); while(it.hasMoreElements()) { MovableObject* o = it.getNext(); ParticleSystem* psys = (ParticleSystem*) o; try { BillboardSet* bbset = findRenderableInParticleSystem(psys); bbset->setMaterialName(psys->getMaterialName()); initTechniques(bbset, psys); } catch( ... ) { //unsupported particle renderer, skip init } } } } void OgreIlluminationManager::createTechnique(IllumTechniqueParams* params, Pass* pass, OgreRenderable* rend, OgreSharedRuns* sRuns) { std::list::iterator it = techniqueFactories.begin(); std::list::iterator itend = techniqueFactories.end(); OgreTechniqueGroup* group = (OgreTechniqueGroup*) rend->getRenderable()->getRenderTechniqueGroup(); while(it != itend) { RenderTechniqueFactory* factory = *it; if(factory->isType(params->getTypeName())) { RenderTechnique* newTechnique = factory->createInstance(params, pass, rend, group ); group->addRenderTechnique(newTechnique); } it++; } } void OgreIlluminationManager::preAllUpdates() { std::vector::iterator it = updateListeners.begin(); std::vector::iterator itend = updateListeners.end(); while(it != itend) { UpdateListener* l = *it; l->preAllUpdates(); it++; } } void OgreIlluminationManager::postAllUpdates() { std::vector::iterator it = updateListeners.begin(); std::vector::iterator itend = updateListeners.end(); while(it != itend) { UpdateListener* l = *it; l->postAllUpdates(); it++; } } void OgreIlluminationManager::update(unsigned long frameNumber, RenderTarget* rt) { RenderSystem* renderSystem = Root::getSingleton().getRenderSystem(); SceneManager* sceneManager = Root::getSingleton()._getCurrentSceneManager(); for(unsigned short i = 0; igetNumViewports();i++) { //find visible objects from the camera RenderQueue* rq = sceneManager->getRenderQueue(); rq->clear(); RenderQueue::QueueGroupIterator groupIter = rq->_getQueueGroupIterator(); while (groupIter.hasMoreElements()) { RenderQueueGroup* g = groupIter.getNext(); //g->addOrganisationMode(QueuedRenderableCollection::OM_SORT_ASCENDING); g->defaultOrganisationMode(); } sceneManager->_findVisibleObjects(rt->getViewport(i)->getCamera(),false); fillVisibleList(rq); // int l = visibleObjects.size(); //debug joinSharedRuns(); // int ll = sharedRunRoots.size(); //debug //update precomputings std::vector::iterator iter = visibleObjects.begin(); const std::vector::iterator iend = visibleObjects.end(); preAllUpdates(); while(iter != iend) { const Renderable* rend = *iter; OgreTechniqueGroup* techniqueGroup = (OgreTechniqueGroup*) rend->getRenderTechniqueGroup(); if(techniqueGroup != 0) { techniqueGroup->update(frameNumber); } iter++; } postAllUpdates(); } } void OgreIlluminationManager::sharedRunSplit(SharedRuns* old, SharedRuns* new1, SharedRuns* new2) { sharedRunRoots.remove(old); sharedRunRoots.push_back(new1); sharedRunRoots.push_back(new2); } void OgreIlluminationManager::sharedRunJoin(SharedRuns* old1, SharedRuns* old2, SharedRuns* newsr) { sharedRunRoots.remove(old1); sharedRunRoots.remove(old2); sharedRunRoots.push_back(newsr); } void OgreIlluminationManager::joinSharedRuns() { std::list::iterator it1 = sharedRunRoots.begin(); std::list::iterator itend = sharedRunRoots.end(); bool again = false; while(it1 != itend) { std::list::iterator it2 = sharedRunRoots.begin(); while(it2 != itend) { if( it1 != it2 && OgreSharedRuns::canJoin(*it1, *it2)) { SharedRuns* newruns = (*it1)->joinRuns(*it2); sharedRunJoin(*it1, *it2, newruns); again = true; break; } it2++; } if(again) break; it1++; } if(again) joinSharedRuns(); } void OgreIlluminationManager::addSharedRuns(SharedRuns* runs) { sharedRunRoots.push_back(runs); } void OgreIlluminationManager::getNearestCausticCasters(Vector3 position, std::vector* nearestcasters, unsigned int maxCount) { sortfrom = position; std::vector allcasters; //fill casters std::list::iterator it = sharedRunRoots.begin(); std::list::iterator itend = sharedRunRoots.end(); while(it != itend) { OgreSharedRuns* sr = (OgreSharedRuns*) (*it); sr->findSharedRootsForType(ILLUMRUN_CAUSTIC_CUBEMAP, allcasters); it++; } //sort std::stable_sort(allcasters.begin(), allcasters.end(), sortFromVector()); for(unsigned int i = 0; i < maxCount && i < allcasters.size(); i++) { nearestcasters->push_back(allcasters.at(i)); } } void OgreIlluminationManager::createGlobalRun(RenderingRunType runType) { switch(runType) { case ILLUMRUN_SCENE_CAMERA_DEPTH: if(globalSharedRuns.getRun(ILLUMRUN_SCENE_CAMERA_DEPTH) == 0) { OgreSceneCameraDepthRenderingRun* run = new OgreSceneCameraDepthRenderingRun (&globalSharedRuns, "ILLUMMODULE_SCENE_CAMERA_DEPTH", mainViewport); globalSharedRuns.addRun(ILLUMRUN_SCENE_CAMERA_DEPTH, run); } case ILLUMRUN_FOCUSING_MAP: if(globalSharedRuns.getRun(ILLUMRUN_FOCUSING_MAP) == 0) { OgreFocusingMapRenderingRun* run = new OgreFocusingMapRenderingRun( "LIGHT_FOCUSING_MAP", Matrix4::IDENTITY, focusingMapSize ); globalSharedRuns.addRun(ILLUMRUN_FOCUSING_MAP, run); } case ILLUMRUN_PHASE_TEXTURE: if(globalSharedRuns.getRun(ILLUMRUN_PHASE_TEXTURE) == 0) { OgrePhaseTextureRenderingRun* run = new OgrePhaseTextureRenderingRun( "PHASE_TEXTURE", phaseTextureSize, phaseTextureSize, "Phase_HenyeyGreenStein"); globalSharedRuns.addRun(ILLUMRUN_PHASE_TEXTURE, run); } break; } } void OgreIlluminationManager::savePhaseTextureToFile(String filename) { OgrePhaseTextureRenderingRun* r = (OgrePhaseTextureRenderingRun*) globalSharedRuns.getRun(ILLUMRUN_PHASE_TEXTURE)->asOgreRenderingRun(); Texture* t = (Texture*) TextureManager::getSingleton().getByName(r->getPhaseTextureName()).getPointer(); t->getBuffer()->getRenderTarget()->writeContentsToFile(filename); } RenderingRun* OgreIlluminationManager::getGlobalRun(RenderingRunType runType) { if(globalSharedRuns.getRun(runType) == 0) createGlobalRun(runType); return globalSharedRuns.getRun(runType); } GlobalUseRenderTarget* OgreIlluminationManager::getGlobalTarget(GlobalTargetType type) { std::map::iterator it = globalTargets.find(type); if( it != globalTargets.end()) return (*it).second; return 0; } void OgreIlluminationManager::addGlobalTarget(GlobalTargetType type, GlobalUseRenderTarget* target) { globalTargets[type] = target; } void OgreIlluminationManager::updateGlobalRun(RenderingRunType runType, unsigned long frameNum) { globalSharedRuns.updateRun(runType, frameNum); } void OgreIlluminationManager::createPerLightRun(String lightName, RenderingRunType runType) { OgreSharedRuns* runs = 0; if(perLightRuns.find(lightName) == perLightRuns.end()) {///create sharedruns OgreSharedRuns* newruns = new OgreSharedRuns(); perLightRuns[lightName] = newruns; } runs = perLightRuns[lightName]; switch(runType) { case ILLUMRUN_DEPTH_SHADOWMAP: if(runs->getRun(ILLUMRUN_DEPTH_SHADOWMAP) == 0) { SceneManager* sm = Root::getSingleton()._getCurrentSceneManager(); OgreDepthShadowMapRenderingRun* run = new OgreDepthShadowMapRenderingRun( runs, lightName + "DEPTH_SHADOW_MAP", sm->getLight(lightName), shadowMapSize, shadowMapSize, shadowMapMaterialName //TODO ); runs->addRun(ILLUMRUN_DEPTH_SHADOWMAP, run); } break; } } RenderingRun* OgreIlluminationManager::getPerLightRun(String lightName, RenderingRunType runType) { return perLightRuns[lightName]->getRun(runType); } void OgreIlluminationManager::updatePerLightRun(String lightName, RenderingRunType runType, unsigned long frameNum) { perLightRuns[lightName]->updateRun(runType, frameNum); }