SO3Engine
SO3DynamicReflectionMap.cpp
Go to the documentation of this file.
1
12#include "SO3Renderer/SO3Root.h"
15
16#include <OgreDepthBuffer.h>
17
18namespace SO3
19{
20
21 SDynamicReflectionMap::SDynamicReflectionMap() : SNode(0, "", SNode::DYNAMIC_REFLECTION_MAP_ID)
22 {
23 // Forbiden (private)
24 }
25
26 SDynamicReflectionMap::SDynamicReflectionMap(SScene* parent, SViewPort* viewport, const std::string& dynamicReflectionMapName) : SNode(parent, dynamicReflectionMapName, SNode::DYNAMIC_REFLECTION_MAP_ID)
27 {
28 // Store the scheme that we will use to hide objects we dont want on the reflectionMap.
29 reflectionMapScheme = dynamicReflectionMapName + "_SO3_DynamicReflectionMap_Scheme";
30 material.reset();
31 size = 256;
32 revertClipPlane = false;
33 needTextureUpdate = false;
34 state = false;
35 renderingEnable = false;
36 flipClipPlane = false;
37 techIndex = 0;
38 passIndex = 0;
39 unitIndex = 0;
40
41 reflectionMapTargets = 0;
42 reflectionMapViewport = viewport;
43
44 // create reflection plane
45 reflectionMapPlane = new Ogre::MovablePlane("reflectionPlane" + reflectionMapScheme);
46 reflectionMapPlane->redefine(Ogre::Vector3::UNIT_Y, Ogre::Vector3::ZERO);
47 O3SceneNode->attachObject(reflectionMapPlane);
48 reflectionMapPlane->setVisible(false);
49 reflectionMapPlane->normal = Ogre::Vector3::UNIT_Y;
50
51 // create clip plane
52 cameraClipPlane = new Ogre::MovablePlane("CameraClipPlane" + reflectionMapScheme);
53 cameraClipPlane->redefine(Ogre::Vector3::UNIT_Y, Ogre::Vector3::ZERO);
54 O3SceneNode->attachObject(cameraClipPlane);
55 cameraClipPlane->normal = Ogre::Vector3::UNIT_Y;
56 cameraClipPlane->setVisible(false);
57
58 // create the camera used to render to our cubemap
59 reflectionMapCamera = currentScene->GetOgreScenePointer()->createCamera("camera_" + reflectionMapScheme);
60 camNode = currentScene->GetOgreScenePointer()->createSceneNode();
61 camNode->attachObject(reflectionMapCamera);
62 O3SceneNode->addChild(camNode);
63
64 reflectionMapCamera->setFOVy(Ogre::Degree(45));
65 reflectionMapCamera->setAspectRatio(1);
66 reflectionMapCamera->setNearClipDistance(Ogre::Real(0.001));
67
68 // enable reflection plane
69 reflectionMapCamera->enableReflection(reflectionMapPlane);
70
71 // cut the geometry under the reflection plan
72 reflectionMapCamera->enableCustomNearClipPlane(cameraClipPlane);
73
74 // create our dynamic reflection map texture
75 _CreateReflectionMapTexture(size);
76
77 // Create a new transparent material and set a transparent technique
78 materialTransparent = Ogre::MaterialManager::getSingleton().create("SO3_Material_" + reflectionMapScheme, SO3_INTERNAL_DYNAMIC_RESOURCE_GROUP);
79 materialTransparent->getTechnique(0)->setColourWriteEnabled(false);
80 materialTransparent->getTechnique(0)->setDepthCheckEnabled(false);
81 materialTransparent->getTechnique(0)->setDepthWriteEnabled(false);
82 materialTransparent->getTechnique(0)->getPass(0)->setName("SO3/TRANSPARENT/REFMAP");
83 materialTransparent->getTechnique(0)->getPass(0)->setVertexProgram("SO3/Internal/Default_nolight_vp");
84 materialTransparent->getTechnique(0)->getPass(0)->setFragmentProgram("SO3/Internal/Default_fp");
85 materialTransparent->load();
86 }
87
89 {
90 // disable first
91 SetEnable(false);
92
93 // Delete the reflectionMap texture.
94 _DeleteReflectionMapTexture();
95
96 // Delete the transparent material
97 //update generated materials
98 SRoot::getSingletonPtr()->RemoveGeneratedMaterial(materialTransparent.get());
99
100 Ogre::MaterialManager::getSingleton().remove(materialTransparent->getHandle());
101 materialTransparent.reset();
102 reflectionMapCamera->disableCustomNearClipPlane();
103 reflectionMapCamera->disableReflection();
104
105 currentScene->GetOgreScenePointer()->destroyCamera(reflectionMapCamera);
106 currentScene->GetOgreScenePointer()->destroySceneNode(camNode);
107
108 O3SceneNode->detachObject(reflectionMapPlane);
109 SO3_SAFE_DELETE(reflectionMapPlane);
110
111 O3SceneNode->detachObject(cameraClipPlane);
112 SO3_SAFE_DELETE(cameraClipPlane);
113 }
114
115 void SDynamicReflectionMap::SetSize(const unsigned int& newSize)
116 {
117 if (size != newSize)
118 {
119 // is new size valid (2^n)?
120 double result = log((double)newSize) / log((double)2.0);
121 double fractpart, intpart;
122 fractpart = modf(result, &intpart);
123 if (fractpart == 0)
124 {
125 bool savedState = state;
126
127 // Remove the render target listeners.
128 SetEnable(false);
129
130 _CreateReflectionMapTexture(newSize);
131 size = newSize;
132
133 SetEnable(savedState);
134 }
135 else
136 {
137 OGRE_EXCEPT(Ogre::Exception::ERR_INVALIDPARAMS, "Reflection map texture size must be a power of 2 number!", "SDynamicReflectionMap::SetSize");
138 }
139 }
140 }
141
143 {
144 return size;
145 }
146
147 void SDynamicReflectionMap::SetMaterial(SMaterial* targetMaterial, const int& targetTechnique, const int& targetPass, const int& targetTextureUnit)
148 {
149 if (targetMaterial != 0)
150 {
151 bool savedState = state;
152 SetEnable(false);
153
154 material = targetMaterial->getOgreMaterialPointer();
155 techIndex = targetTechnique;
156 passIndex = targetPass;
157 unitIndex = targetTextureUnit;
158
159 if (!material)
160 return;
161
162 SetEnable(savedState);
163 }
164 }
165
166 void SDynamicReflectionMap::SetTextureUnit()
167 {
168 if (!material)
169 return;
170
171 Ogre::Material::Techniques suptechs = material->getSupportedTechniques();
172 Ogre::Material::Techniques techs = material->getTechniques();
173
174 if (techIndex >= techs.size() || (suptechs.size() == 0))
175 return;
176
177 Ogre::Technique::Passes matPasses;
178 Ogre::Pass* tmpPass = 0;
179 const Ogre::RenderSystemCapabilities* caps = SRoot::getSingletonPtr()->GetOgreRenderSystem()->getCapabilities();
180 if (caps && caps->hasCapability(Ogre::RSC_FIXED_FUNCTION) == false)
181 {
182 matPasses = suptechs[0]->getPasses();
183 if (passIndex >= matPasses.size())
184 return;
185
186 tmpPass = matPasses[passIndex];
187 }
188 else
189 {
190 matPasses = techs[techIndex]->getPasses();
191 if (techIndex >= matPasses.size())
192 return;
193
194 tmpPass = matPasses[techIndex];
195 }
196
197 // Check if the targetTextureUnit is inbound
198 Ogre::TextureUnitState* texState = 0;
199 Ogre::Pass::TextureUnitStates texs = tmpPass->getTextureUnitStates();
200 if ((texs.size() > 0) && (unitIndex < texs.size()))
201 texState = texs[unitIndex];
202
203 if (texState != 0)
204 {
205 oldTexture = texState->_getTexturePtr();
206 oldTextureType = texState->getTextureType();
207 oldAdressingMode = texState->getTextureAddressingMode();
208
209 Ogre::TextureUnitState::EffectMap effects = texState->getEffects();
210 Ogre::TextureUnitState::EffectMap::iterator ei = effects.find(Ogre::TextureUnitState::ET_ENVIRONMENT_MAP);
211 oldTextureEnvState = ei != effects.end();
212
213 if (oldTextureEnvState)
214 oldTextureEnvType = (Ogre::TextureUnitState::EnvMapType)ei->second.subtype;
215
216 texState->setTexture(reflectionMapTexture);
217 texState->setTextureAddressingMode(Ogre::TextureUnitState::TAM_CLAMP);
218 texState->setEnvironmentMap(false);
219 texState->setProjectiveTexturing(true, reflectionMapCamera);
220
221 Ogre::Any bindedSPass = tmpPass->getUserObjectBindings().getUserAny("SPass");
222 if (bindedSPass.has_value())
223 {
224 SPass* pass = Ogre::any_cast<SPass*> (bindedSPass);
225 pass->BuildShader();
226 }
227
229 }
230 }
231
232 void SDynamicReflectionMap::ResetTextureUnit()
233 {
234 Ogre::Material::Techniques suptechs = material->getSupportedTechniques();
235 Ogre::Material::Techniques techs = material->getTechniques();
236
237 if (techIndex >= techs.size() || (suptechs.size() == 0))
238 return;
239
240 Ogre::Technique::Passes matPasses;
241 Ogre::Pass* tmpPass = 0;
242 const Ogre::RenderSystemCapabilities* caps = SRoot::getSingletonPtr()->GetOgreRenderSystem()->getCapabilities();
243 if (caps && caps->hasCapability(Ogre::RSC_FIXED_FUNCTION) == false)
244 {
245 matPasses = suptechs[0]->getPasses();
246 if (passIndex >= matPasses.size())
247 return;
248
249 tmpPass = matPasses[passIndex];
250 }
251 else
252 {
253 matPasses = techs[techIndex]->getPasses();
254 if (techIndex >= matPasses.size())
255 return;
256
257 tmpPass = matPasses[techIndex];
258 }
259
260 // Check if the targetTextureUnit is inbound
261 Ogre::TextureUnitState* texState = 0;
262 Ogre::Pass::TextureUnitStates texs = tmpPass->getTextureUnitStates();
263 if ((texs.size() > 0) && (unitIndex < texs.size()))
264 texState = texs[unitIndex];
265
266 if (texState != 0)
267 {
268 texState->setProjectiveTexturing(false);
269 texState->setTextureAddressingMode(oldAdressingMode);
270
271 if (oldTextureEnvState)
272 texState->setEnvironmentMap(oldTextureEnvState, oldTextureEnvType);
273
274 if (!oldTexture)
275 texState->setBlank();
276 else
277 texState->setTexture(oldTexture);
278
279 Ogre::Any bindedSPass = tmpPass->getUserObjectBindings().getUserAny("SPass");
280 if (bindedSPass.has_value())
281 {
282 SPass* pass = Ogre::any_cast<SPass*> (bindedSPass);
283 pass->BuildShader();
284 }
285
287 }
288 oldTexture.reset();
289 }
290
291 void SDynamicReflectionMap::SetEnable(const bool& newState)
292 {
293 if (reflectionMapTexture)
294 {
295 if (!material)
296 return;
297
298 if ((newState == true) && (state == false))
299 {
300 state = true;
301 SetTextureUnit();
302 EnableRendering();
303 }
304 else if ((newState == false) && (state == true))
305 {
306 DisableRendering();
307 state = false;
308 ResetTextureUnit();
309 }
310 }
311 }
312
314 {
315 return state;
316 }
317
318 void SDynamicReflectionMap::FlipPlane(const bool& newFlip)
319 {
320 if (newFlip != flipClipPlane)
321 {
322 flipClipPlane = newFlip;
323
324 //redefine clip plane is not enought since the skies are not rendered in texture while the node is not modified
325 reflectionMapCamera->disableCustomNearClipPlane();
326 reflectionMapCamera->disableReflection();
327
328 // delete the current clip plane
329 O3SceneNode->detachObject(cameraClipPlane);
330 SO3_SAFE_DELETE(cameraClipPlane);
331
332 // delete the current reflection plane
333 O3SceneNode->detachObject(reflectionMapPlane);
334 SO3_SAFE_DELETE(reflectionMapPlane);
335
336 // create clip plane
337 cameraClipPlane = new Ogre::MovablePlane("CameraClipPlane" + reflectionMapScheme);
338 cameraClipPlane->redefine(((flipClipPlane && !revertClipPlane) || (revertClipPlane && !flipClipPlane)) ? Ogre::Vector3::NEGATIVE_UNIT_Y : Ogre::Vector3::UNIT_Y, Ogre::Vector3::ZERO);
339 O3SceneNode->attachObject(cameraClipPlane);
340
341 cameraClipPlane->normal = Ogre::Vector3::UNIT_Y;
342 cameraClipPlane->setVisible(false);
343
344 // create reflection plane
345 reflectionMapPlane = new Ogre::MovablePlane("reflectionPlane" + reflectionMapScheme);
346 reflectionMapPlane->redefine(flipClipPlane ? (Ogre::Vector3::NEGATIVE_UNIT_Y) : (Ogre::Vector3::UNIT_Y), Ogre::Vector3::ZERO);
347 O3SceneNode->attachObject(reflectionMapPlane);
348
349 reflectionMapPlane->normal = Ogre::Vector3::UNIT_Y;
350 reflectionMapPlane->setVisible(false);
351
352 // cut the geometry under the reflection plan
353 reflectionMapCamera->enableCustomNearClipPlane(cameraClipPlane);
354
355 //apply reflection
356 if (!revertClipPlane)
357 reflectionMapCamera->enableReflection(reflectionMapPlane);
358 }
359 }
360
361 void SDynamicReflectionMap::SetRevertClipPlane(const bool& newRevertClipPlaneValue)
362 {
363 if (newRevertClipPlaneValue != revertClipPlane)
364 {
365 revertClipPlane = newRevertClipPlaneValue;
366
367 //redefine clip plane is not enought since the skies are not rendered in texture while the node is not modified
368 reflectionMapCamera->disableCustomNearClipPlane();
369
370 // delete the current clip plane
371 O3SceneNode->detachObject(cameraClipPlane);
372 SO3_SAFE_DELETE(cameraClipPlane);
373
374 // create clip plane
375 cameraClipPlane = new Ogre::MovablePlane("CameraClipPlane" + reflectionMapScheme);
376 cameraClipPlane->redefine(revertClipPlane ? -Ogre::Vector3::UNIT_Y : Ogre::Vector3::UNIT_Y, Ogre::Vector3::ZERO);
377 O3SceneNode->attachObject(cameraClipPlane);
378 cameraClipPlane->setVisible(false);
379
380 // cut the geometry under the reflection plan
381 reflectionMapCamera->enableCustomNearClipPlane(cameraClipPlane);
382
383 // disable reflection plane for refract
384 if (revertClipPlane)
385 reflectionMapCamera->disableReflection();
386 else
387 reflectionMapCamera->enableReflection(reflectionMapPlane);
388 }
389 }
390
392 {
393 return revertClipPlane;
394 }
395
396
397 void SDynamicReflectionMap::EnableRendering()
398 {
399 if (!renderingEnable)
400 {
401 reflectionMapTargets->addListener(this);
402 reflectionMapTargets->setAutoUpdated(true);
403
404 //Ogre::MaterialManager::getSingleton().addListener(this);
405 renderingEnable = true;
406 }
407 }
408
409 void SDynamicReflectionMap::DisableRendering()
410 {
411 if (renderingEnable)
412 {
413 reflectionMapTargets->removeListener(this);
414 reflectionMapTargets->setAutoUpdated(false);
415
416 //Ogre::MaterialManager::getSingleton().removeListener(this);
417 renderingEnable = false;
418 }
419 }
420
421 void SDynamicReflectionMap::_CreateReflectionMapTexture(const unsigned int& newSize)
422 {
423 _DeleteReflectionMapTexture();
424 try
425 {
426 Ogre::PixelFormat rttformat;
428
429 reflectionMapTexture = Ogre::TextureManager::getSingleton().createManual("texture_" + reflectionMapScheme, SO3_INTERNAL_DYNAMIC_READABLE_RESOURCE_GROUP, Ogre::TEX_TYPE_2D, newSize, newSize, Ogre::MIP_DEFAULT, rttformat, Ogre::TU_RENDERTARGET | Ogre::TU_AUTOMIPMAP);
430 reflectionMapTargets = reflectionMapTexture->getBuffer()->getRenderTarget();
431
432#if defined (RPI)
433 reflectionMapTargets->setDepthBufferPool(Ogre::DepthBuffer::POOL_NO_DEPTH);
434#endif
435
436 Ogre::Viewport* viewport = reflectionMapTargets->addViewport(reflectionMapCamera);
437 viewport->setOverlaysEnabled(false);
438 viewport->setMaterialScheme(reflectionMapScheme);
439 }
440 catch (Ogre::Exception &e)
441 {
442 Ogre::LogManager::getSingleton().getDefaultLog()->logMessage("An exception has occurred: " + e.getDescription());
443 reflectionMapTexture.reset();
444 }
445 }
446
447 void SDynamicReflectionMap::_DeleteReflectionMapTexture()
448 {
449 if (reflectionMapTexture)
450 {
451 // IMPORTANT! Do not forget to detach the target, otherwise, the texture will not be deleted cause TexturePtr ref count still will be > 1
452 if (reflectionMapTargets)
453 {
454 reflectionMapTargets->removeAllViewports();
455 Ogre::Root::getSingleton().detachRenderTarget(reflectionMapTargets);
456 reflectionMapTargets = 0;
457 }
458
459 Ogre::TextureManager::getSingleton().remove(reflectionMapTexture->getHandle());
460 reflectionMapTexture.reset();
461 }
462 }
463
464 void SDynamicReflectionMap::preRenderTargetUpdate(const Ogre::RenderTargetEvent& evt)
465 {
466 if (needTextureUpdate)
467 {
468 _CreateReflectionMapTexture(size);
469 needTextureUpdate = false;
470 }
471
472 // Get the current viewport camera
473 SCamera* camera = reflectionMapViewport->GetCamera();
474
475 // Reposition the reflection camera
476 camNode->_setDerivedPosition(camera->GetGlobalPosition());
477 camNode->_setDerivedOrientation(camera->GetGlobalOrientation());
478
479 //reflectionMapPlane->redefine(Ogre::Vector3::UNIT_Y, O3SceneNode->_getDerivedPosition());
480 //cameraClipPlane->redefine(Ogre::Vector3::UNIT_Y, O3SceneNode->_getDerivedPosition());
481
482 reflectionMapCamera->setFOVy(camera->GetOgreCameraPointer()->getFOVy());
483 reflectionMapCamera->setNearClipDistance(camera->GetNearClipDistance());
484 reflectionMapCamera->setFarClipDistance(camera->GetFarClipDistance());
485 reflectionMapCamera->setAspectRatio(camera->GetOgreCameraPointer()->getAspectRatio());
486 reflectionMapCamera->setCustomProjectionMatrix(camera->GetOgreCameraPointer()->isCustomProjectionMatrixEnabled(), camera->GetProjectionMatrix());
487 reflectionMapCamera->setCullingFrustum(camera->GetOgreCameraPointer()->getCullingFrustum());
488
489 // flip plane if needed to camera direction
490 if (reflectionMapPlane->getSide((GetTransformationMatrix().inverse() * camera->GetTransformationMatrix()).getTrans()) == Ogre::Plane::NEGATIVE_SIDE)
491 FlipPlane(!flipClipPlane);
492 }
493
494 void SDynamicReflectionMap::postRenderTargetUpdate(const Ogre::RenderTargetEvent& evt)
495 {
496 }
497
498 Ogre::Technique* SDynamicReflectionMap::handleSchemeNotFound(unsigned short schemeIndex, const Ogre::String& schemeName, Ogre::Material* originalMaterial, unsigned short lodIndex, const Ogre::Renderable* rend)
499 {
500 Ogre::Material::Techniques suptechs = materialTransparent->getTechniques();
501 if ((reflectionMapScheme == schemeName) && (originalMaterial == material.get()) && (suptechs.size() > 0))
502 {
503 // Set a transparent technique
504 return suptechs[0];
505 }
506
507 return 0;
508 }
509
510}
Ogre::Camera * GetOgreCameraPointer()
Definition SO3Camera.cpp:50
float GetNearClipDistance()
const Ogre::Matrix4 & GetProjectionMatrix()
float GetFarClipDistance()
void SetSize(const unsigned int &newSize)
virtual Ogre::Technique * handleSchemeNotFound(unsigned short schemeIndex, const Ogre::String &schemeName, Ogre::Material *originalMaterial, unsigned short lodIndex, const Ogre::Renderable *rend)
void SetRevertClipPlane(const bool &newRevertClipPlaneValue)
void FlipPlane(const bool &newFlip)
virtual void postRenderTargetUpdate(const Ogre::RenderTargetEvent &evt)
void SetEnable(const bool &newState)
void SetMaterial(SMaterial *targetMaterial, const int &targetTechnique, const int &targetPass, const int &targetTextureUnit)
virtual void preRenderTargetUpdate(const Ogre::RenderTargetEvent &evt)
Ogre::MaterialPtr getOgreMaterialPointer()
virtual Ogre::Quaternion GetGlobalOrientation()
SScene * currentScene
Definition SO3NodeScol.h:68
Ogre::SceneNode * O3SceneNode
Definition SO3NodeScol.h:69
virtual Ogre::Vector3 GetGlobalPosition()
virtual Ogre::Matrix4 GetTransformationMatrix()
bool GetRttPixelFormat(Ogre::PixelFormat &format, bool alpha=false, bool floattex=false)
Definition SO3Root.cpp:650
Ogre::RenderSystem * GetOgreRenderSystem()
Definition SO3Root.cpp:865
void RemoveGeneratedMaterial(Ogre::Material *mat)
Definition SO3Root.cpp:2343
static SRoot & getSingleton()
Definition SO3Root.cpp:116
static SRoot * getSingletonPtr()
Definition SO3Root.cpp:111
Ogre::SceneManager * GetOgreScenePointer()
Definition SO3Scene.cpp:449
SCamera * GetCamera()