00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "CaelumPrecompiled.h"
00022 #include "CaelumExceptions.h"
00023 #include "DepthComposer.h"
00024
00025 using namespace Ogre;
00026
00027 namespace Caelum
00028 {
00029 DepthComposer::DepthComposer
00030 (
00031 Ogre::SceneManager *sceneMgr
00032 ):
00033 mSceneMgr (sceneMgr),
00034 mDebugDepthRender (false),
00035 mSkyDomeHazeEnabled (false),
00036 mGroundFogEnabled (false),
00037 mGroundFogDensity (0.1),
00038 mGroundFogBaseLevel (5),
00039 mGroundFogVerticalDecay (0.2),
00040 mGroundFogColour (ColourValue::Black)
00041 {
00042 }
00043
00044 DepthComposer::~DepthComposer()
00045 {
00046 destroyAllViewportInstances();
00047 }
00048
00049 void DepthComposer::setDebugDepthRender (bool value)
00050 {
00051 if (mDebugDepthRender == value) {
00052 return;
00053 }
00054 mDebugDepthRender = value;
00055 onCompositorMaterialChanged ();
00056 }
00057
00058 void DepthComposer::setSkyDomeHazeEnabled (bool value)
00059 {
00060 if (mSkyDomeHazeEnabled == value) {
00061 return;
00062 }
00063 mSkyDomeHazeEnabled = value;
00064 onCompositorMaterialChanged ();
00065 }
00066
00067 void DepthComposer::setGroundFogEnabled (bool value)
00068 {
00069 if (mGroundFogEnabled == value) {
00070 return;
00071 }
00072 mGroundFogEnabled = value;
00073 onCompositorMaterialChanged ();
00074 }
00075
00076 const String& DepthComposer::getCompositorName ()
00077 {
00078
00079 static const Ogre::String CompositorName_DebugDepthRender =
00080 "Caelum/DepthComposer_DebugDepthRender";
00081 static const Ogre::String CompositorName_Dummy =
00082 "Caelum/DepthComposer_Dummy";
00083 static const Ogre::String CompositorName_ExpGroundFog =
00084 "Caelum/DepthComposer_ExpGroundFog";
00085 static const Ogre::String CompositorName_SkyDomeHaze =
00086 "Caelum/DepthComposer_SkyDomeHaze";
00087 static const Ogre::String CompositorName_SkyDomeHaze_ExpGroundFog =
00088 "Caelum/DepthComposer_SkyDomeHaze_ExpGroundFog";
00089
00090
00091 if (mDebugDepthRender) {
00092 return CompositorName_DebugDepthRender;
00093 } else if (mSkyDomeHazeEnabled == false && mGroundFogEnabled == false) {
00094 return CompositorName_Dummy;
00095 } else if (mSkyDomeHazeEnabled == false && mGroundFogEnabled == true) {
00096 return CompositorName_ExpGroundFog;
00097 } else if (mSkyDomeHazeEnabled == true && mGroundFogEnabled == false) {
00098 return CompositorName_SkyDomeHaze;
00099 } else if (mSkyDomeHazeEnabled == true && mGroundFogEnabled == true) {
00100 return CompositorName_SkyDomeHaze_ExpGroundFog;
00101 } else {
00102 assert (0);
00103 return CompositorName_Dummy;
00104 }
00105 }
00106
00107 void DepthComposer::onCompositorMaterialChanged ()
00108 {
00109 ViewportInstanceMap::const_iterator it;
00110 ViewportInstanceMap::const_iterator begin = mViewportInstanceMap.begin();
00111 ViewportInstanceMap::const_iterator end = mViewportInstanceMap.end();
00112 for (it = begin; it != end; ++it) {
00113 it->second->removeCompositor ();
00114 it->second->addCompositor ();
00115 }
00116 }
00117
00118 void DepthComposer::update ()
00119 {
00120 ViewportInstanceMap::const_iterator it;
00121 ViewportInstanceMap::const_iterator begin = mViewportInstanceMap.begin();
00122 ViewportInstanceMap::const_iterator end = mViewportInstanceMap.end();
00123 for (it = begin; it != end; ++it) {
00124 assert(it->first == it->second->getViewport());
00125 it->second->_update ();
00126 }
00127 }
00128
00129 DepthComposerInstance::DepthComposerInstance
00130 (
00131 DepthComposer* parent,
00132 Ogre::Viewport* viewport
00133 ):
00134 mParent(parent),
00135 mViewport(viewport),
00136 mCompInst(0)
00137 {
00138 LogManager::getSingleton().logMessage (
00139 "Caelum::DepthComposer: Attaching screen-space fog instance"
00140 " to viewport \'" + StringConverter::toString ((long)getViewport ()) + "\'"
00141 " of render target \'" + getViewport()->getTarget ()->getName () + "\'");
00142
00143 addCompositor ();
00144 mDepthRenderer.reset (new DepthRenderer (getViewport ()));
00145 }
00146
00147 DepthComposerInstance::~DepthComposerInstance()
00148 {
00149 removeCompositor ();
00150 mDepthRenderer.reset ();
00151
00152 LogManager::getSingleton().logMessage (
00153 "Caelum::DepthComposer: Detached screen-space fog instance"
00154 " from viewport \'" + StringConverter::toString ((long)getViewport ()) + "\'"
00155 " of render target \'" + getViewport()->getTarget ()->getName () + "\'");
00156 }
00157
00158 void DepthComposerInstance::addCompositor ()
00159 {
00160 CompositorManager* compMgr = CompositorManager::getSingletonPtr();
00161
00162 const String& compositorName = getParent ()->getCompositorName ();
00163 mCompInst = compMgr->addCompositor(mViewport, compositorName);
00164 if (!mCompInst) {
00165 CAELUM_THROW_UNSUPPORTED_EXCEPTION (
00166 "Can't add \'" + compositorName + "\' compositor.",
00167 "DepthComposer");
00168 }
00169 assert(mCompInst);
00170 mCompInst->setEnabled (true);
00171 mCompInst->addListener (this);
00172 }
00173
00174 void DepthComposerInstance::removeCompositor ()
00175 {
00176 CompositorManager* compMgr = CompositorManager::getSingletonPtr();
00177 compMgr->removeCompositor (mViewport, mCompInst->getCompositor ()->getName ());
00178 mCompInst = 0;
00179 }
00180
00181 void DepthComposerInstance::notifyMaterialSetup(uint pass_id, Ogre::MaterialPtr &mat)
00182 {
00183
00184
00185
00186 Pass* pass = mat->getBestTechnique ()->getPass (0);
00187
00188 TextureUnitState *depthTus = pass->getTextureUnitState(1);
00189 if (depthTus->getTextureName () != mDepthRenderer->getDepthRenderTexture ()->getName()) {
00190 depthTus->setTextureName (mDepthRenderer->getDepthRenderTexture ()->getName ());
00191 LogManager::getSingleton ().logMessage (
00192 "Caelum::DepthComposer: Assigned depth texture in compositor material");
00193 }
00194
00195 mParams.setup(pass->getFragmentProgramParameters ());
00196 }
00197
00198 void DepthComposerInstance::Params::setup(Ogre::GpuProgramParametersSharedPtr fpParams)
00199 {
00200 this->fpParams = fpParams;
00201 invViewProjMatrix.bind(fpParams, "invViewProjMatrix");
00202 worldCameraPos.bind(fpParams, "worldCameraPos");
00203 groundFogDensity.bind(fpParams, "groundFogDensity");
00204 groundFogVerticalDecay.bind(fpParams, "groundFogVerticalDecay");
00205 groundFogBaseLevel.bind(fpParams, "groundFogBaseLevel");
00206 groundFogColour.bind(fpParams, "groundFogColour");
00207 sunDirection.bind(fpParams, "sunDirection");
00208 hazeColour.bind(fpParams, "hazeColour");
00209 }
00210
00211 void DepthComposerInstance::notifyMaterialRender(uint pass_id, Ogre::MaterialPtr &mat)
00212 {
00213 Camera* camera = getViewport ()->getCamera ();
00214
00215 assert(mParams.fpParams == mat->getBestTechnique ()->getPass (0)->getFragmentProgramParameters ());
00216
00217
00218
00219
00220 Matrix4 projMatrix = camera->getProjectionMatrixWithRSDepth();
00221 Matrix4 viewMatrix = camera->getViewMatrix();
00222
00223 mParams.invViewProjMatrix.set(mParams.fpParams, (projMatrix * viewMatrix).inverse());
00224
00225 mParams.worldCameraPos.set(mParams.fpParams, camera->getDerivedPosition ());
00226
00227 mParams.groundFogDensity.set(mParams.fpParams, getParent ()->getGroundFogDensity ());
00228 mParams.groundFogVerticalDecay.set(mParams.fpParams, getParent ()->getGroundFogVerticalDecay ());
00229 mParams.groundFogBaseLevel.set(mParams.fpParams, getParent ()->getGroundFogBaseLevel ());
00230 mParams.groundFogColour.set(mParams.fpParams, getParent ()->getGroundFogColour ());
00231
00232 mParams.sunDirection.set(mParams.fpParams, getParent ()->getSunDirection ());
00233 mParams.hazeColour.set(mParams.fpParams, getParent ()->getHazeColour ());
00234 }
00235
00236 void DepthComposerInstance::_update ()
00237 {
00238 mDepthRenderer->update ();
00239 }
00240
00241 DepthComposerInstance* DepthComposer::createViewportInstance(Ogre::Viewport* vp)
00242 {
00243 ViewportInstanceMap::const_iterator it = mViewportInstanceMap.find(vp);
00244 if (it == mViewportInstanceMap.end()) {
00245 std::auto_ptr<DepthComposerInstance> inst(new DepthComposerInstance(this, vp));
00246 mViewportInstanceMap.insert(std::make_pair(vp, inst.get()));
00247
00248 return inst.release();
00249 } else {
00250 return it->second;
00251 }
00252 }
00253
00254 DepthComposerInstance* DepthComposer::getViewportInstance(Ogre::Viewport* vp) {
00255 ViewportInstanceMap::iterator it = mViewportInstanceMap.find(vp);
00256 if (it != mViewportInstanceMap.end()) {
00257 return it->second;
00258 } else {
00259 return 0;
00260 }
00261 }
00262
00263 void DepthComposer::destroyViewportInstance(Viewport* vp)
00264 {
00265 ViewportInstanceMap::iterator it = mViewportInstanceMap.find(vp);
00266 if (it != mViewportInstanceMap.end()) {
00267 DepthComposerInstance* inst = it->second;
00268 delete inst;
00269 mViewportInstanceMap.erase(it);
00270 }
00271 }
00272
00273 void DepthComposer::destroyAllViewportInstances() {
00274 ViewportInstanceMap::const_iterator it;
00275 ViewportInstanceMap::const_iterator begin = mViewportInstanceMap.begin();
00276 ViewportInstanceMap::const_iterator end = mViewportInstanceMap.end();
00277 for (it = begin; it != end; ++it) {
00278 assert(it->first == it->second->getViewport());
00279 delete it->second;
00280 }
00281 mViewportInstanceMap.clear();
00282 }
00283
00284 const String DepthRenderer::DEFAULT_CUSTOM_DEPTH_SCHEME_NAME = "CaelumDepth";
00285
00286 DepthRenderer::DepthRenderer
00287 (
00288 Viewport* masterViewport
00289 ):
00290 mMasterViewport (masterViewport),
00291 mDepthRenderViewport (0),
00292 mDepthRenderingNow (false),
00293 mViewportVisibilityMask (~0),
00294 mUseCustomDepthScheme (true),
00295 mCustomDepthSchemeName (DEFAULT_CUSTOM_DEPTH_SCHEME_NAME)
00296 {
00297 disableRenderGroupRangeFilter ();
00298
00299 Ogre::String uniqueId = Ogre::StringConverter::toString ((size_t)this);
00300
00301
00302 mDepthRenderMaterial = MaterialManager::getSingleton ().getByName ("Caelum/DepthRender");
00303 mDepthRenderMaterial->load();
00304 if (!mDepthRenderMaterial->getBestTechnique ()) {
00305 CAELUM_THROW_UNSUPPORTED_EXCEPTION (
00306 "Can't load depth render material: " +
00307 mDepthRenderMaterial->getUnsupportedTechniquesExplanation(),
00308 "DepthComposer");
00309 }
00310
00311 TextureManager* texMgr = TextureManager::getSingletonPtr();
00312
00313 int width = getMasterViewport ()->getActualWidth ();
00314 int height = getMasterViewport ()->getActualHeight ();
00315 LogManager::getSingleton ().logMessage (
00316 "Caelum::DepthRenderer: Creating depth render texture size " +
00317 StringConverter::toString (width) +
00318 "x" +
00319 StringConverter::toString (height));
00320
00321 PixelFormat desiredFormat = PF_FLOAT32_R;
00322 PixelFormat requestFormat = desiredFormat;
00323 if (texMgr->isFormatSupported (TEX_TYPE_2D, desiredFormat, TU_RENDERTARGET)) {
00324 LogManager::getSingleton ().logMessage (
00325 "Caelum::DepthRenderer: RenderSystem has native support for " +
00326 PixelUtil::getFormatName (desiredFormat));
00327 } else if (texMgr->isEquivalentFormatSupported (TEX_TYPE_2D, desiredFormat, TU_RENDERTARGET)) {
00328 PixelFormat equivFormat = texMgr->getNativeFormat (TEX_TYPE_2D, desiredFormat, TU_RENDERTARGET);
00329 LogManager::getSingleton ().logMessage (
00330 "Caelum::DepthRenderer: RenderSystem supports " +
00331 PixelUtil::getFormatName (equivFormat) +
00332 " instead of " +
00333 PixelUtil::getFormatName (desiredFormat));
00334 requestFormat = equivFormat;
00335 } else {
00336 CAELUM_THROW_UNSUPPORTED_EXCEPTION (
00337 PixelUtil::getFormatName(desiredFormat) + " or equivalent not supported",
00338 "DepthRenderer");
00339 }
00340
00341 if (texMgr->isHardwareFilteringSupported (TEX_TYPE_2D, requestFormat, TU_RENDERTARGET)) {
00342 LogManager::getSingleton ().logMessage (
00343 "Caelum::DepthRenderer: RenderSystem supports hardware filtering for " +
00344 PixelUtil::getFormatName (requestFormat));
00345 } else {
00346 LogManager::getSingleton ().logMessage (
00347 "Caelum::DepthRenderer: RenderSystem does not support hardware filtering for " +
00348 PixelUtil::getFormatName (requestFormat));
00349 }
00350
00351
00352
00353 mDepthRenderTexture = texMgr->createManual(
00354 "Caelum/DepthComposer/" + uniqueId + "/DepthTexture",
00355 Caelum::RESOURCE_GROUP_NAME,
00356 TEX_TYPE_2D,
00357 width, height, 1,
00358 0,
00359 requestFormat,
00360 TU_RENDERTARGET,
00361 0);
00362
00363 assert(getDepthRenderTarget());
00364
00365
00366 LogManager::getSingleton().logMessage (
00367 "Caelum::DepthRenderer: Created depth render texture"
00368 " actual format " + PixelUtil::getFormatName (getDepthRenderTexture()->getFormat ()) +
00369 " desired format " + PixelUtil::getFormatName (getDepthRenderTexture()->getDesiredFormat ()));
00370
00371
00372 getDepthRenderTarget()->setAutoUpdated (false);
00373
00374
00375 mDepthRenderViewport = getDepthRenderTarget()->addViewport(0);
00376 getDepthRenderViewport ()->setShadowsEnabled (false);
00377 getDepthRenderViewport ()->setOverlaysEnabled (false);
00378 getDepthRenderViewport ()->setClearEveryFrame (true);
00379
00380
00381
00382 getDepthRenderViewport ()->setBackgroundColour (Ogre::ColourValue (1, 1, 1, 1));
00383 }
00384
00385 DepthRenderer::~DepthRenderer()
00386 {
00387 TextureManager* texMgr = TextureManager::getSingletonPtr();
00388
00389
00390 if (!mDepthRenderTexture.isNull ()) {
00391 texMgr->remove (mDepthRenderTexture->getHandle ());
00392 mDepthRenderTexture.setNull ();
00393 }
00394 }
00395
00396 void DepthRenderer::update ()
00397 {
00398 Camera* camera = getMasterViewport ()->getCamera ();
00399 Viewport* oldCameraViewport = camera->getViewport ();
00400 SceneManager *sceneManager = camera->getSceneManager ();
00401
00402 assert (oldCameraViewport == getMasterViewport ());
00403 assert (getDepthRenderViewport ()->getActualWidth () == getMasterViewport()->getActualWidth ());
00404 assert (getDepthRenderViewport ()->getActualHeight () == getMasterViewport()->getActualHeight ());
00405
00406 getDepthRenderViewport ()->setVisibilityMask (mViewportVisibilityMask);
00407 getDepthRenderViewport ()->setCamera (camera);
00408 if (this->getUseCustomDepthScheme ()) {
00409 getDepthRenderViewport ()->setMaterialScheme (this->getCustomDepthSchemeName ());
00410 }
00411
00412
00413
00414 RenderQueue::RenderableListener* oldListener = sceneManager->getRenderQueue ()->getRenderableListener();
00415 if (oldListener) {
00416
00417
00418 }
00419 sceneManager->getRenderQueue ()->setRenderableListener (this);
00420
00421 mDepthRenderingNow = true;
00422
00423 getDepthRenderTarget ()->update ();
00424
00425 mDepthRenderingNow = false;
00426
00427 sceneManager->getRenderQueue ()->setRenderableListener (oldListener);
00428 oldListener = 0;
00429
00430
00431 camera->_notifyViewport (oldCameraViewport);
00432 }
00433
00434 #if OGRE_VERSION < 0x00010600
00435 bool DepthRenderer::renderableQueued(
00436 Ogre::Renderable* rend,
00437 Ogre::uint8 groupId,
00438 Ogre::ushort priority,
00439 Ogre::Technique** ppTech)
00440 #else
00441 bool DepthRenderer::renderableQueued(
00442 Ogre::Renderable* rend,
00443 Ogre::uint8 groupId,
00444 Ogre::ushort priority,
00445 Ogre::Technique** ppTech,
00446 Ogre::RenderQueue* pQueue)
00447 #endif // OGRE_VERSION
00448 {
00449 assert (mDepthRenderingNow);
00450
00451
00452
00453
00454
00455
00456
00457 if (groupId < mMinRenderGroupId || groupId > mMaxRenderGroupId) {
00458 return false;
00459 }
00460
00461 if (this->getUseCustomDepthScheme () && (*ppTech)->getSchemeName () == this->getCustomDepthSchemeName ()) {
00462
00463
00464
00465
00466
00467
00468
00469 return true;
00470 }
00471
00472
00473 Material* depthMaterial = getDepthRenderMaterial ();
00474 Technique* tech = depthMaterial->getBestTechnique ();
00475
00476
00477 *ppTech = tech;
00478 return true;
00479 }
00480
00481 void DepthRenderer::setRenderGroupRangeFilter (int minGroup, int maxGroup)
00482 {
00483 mMinRenderGroupId = minGroup;
00484 mMaxRenderGroupId = maxGroup;
00485 }
00486
00487 void DepthRenderer::disableRenderGroupRangeFilter()
00488 {
00489 setRenderGroupRangeFilter(Ogre::RENDER_QUEUE_BACKGROUND, Ogre::RENDER_QUEUE_MAX);
00490 }
00491 }