SO3Engine
SO3LightShaft.cpp
Go to the documentation of this file.
1
11#include "SO3Renderer/SO3Root.h"
12
13namespace SO3
14{
15
16 SLightShaft::SLightShaft()
17 {
18 }
19
20 SLightShaft::SLightShaft(SNode* parent, float minStep, float nearClip, float farClip, Ogre::Radian fov)
21 {
22 mParent = parent;
23 mBillboardSet = 0;
25 currentScene = parent->GetParentScene();
26 mLightCamera = 0;
27 mMinStep = minStep;
28 mNeedUpdate = true;
29
30 mShaftMaterial.reset();
31 mDepthMaterial.reset();
32 mDepthTexture.reset();
33
34 // create a material copy
35 // set default parameters
36
37 mLightCamera = mSceneMgr->createCamera(mParent->GetName() + "_LightCamera");
38 mLightCamera->setProjectionType(Ogre::PT_PERSPECTIVE);
39
40 // Not forget to set near+far distance in materials
41 mParent->GetOgreSceneNodePointer()->attachObject(mLightCamera);
42
43 mBillboardSet = mSceneMgr->createBillboardSet(mParent->GetName() + "_LightBillboardSet", 60);
44 mBillboardSet->setBillboardRotationType(Ogre::BBR_VERTEX);
45 mBillboardSet->setBillboardType(Ogre::BBT_POINT);
46 mBillboardSet->setCastShadows(false);
47 mBillboardSet->setSortingEnabled(false);
48 mBillboardSet->setDefaultWidth(1.0f);
49 mBillboardSet->setDefaultHeight(1.0f);
50
51 mParent->GetOgreSceneNodePointer()->attachObject(mBillboardSet);
52
53 bool isrect = false;
54 if (mParent->GetNodeType() == SNode::LIGHT_TYPE_ID)
55 isrect = static_cast<SLight*>(mParent)->GetType() == SLight::SO3_RECT_LIGHT;
56
57 // Create our billboardset for volumetric rendering
58 try
59 {
60 Ogre::MaterialPtr smat = static_cast<Ogre::MaterialPtr>(isrect ? Ogre::MaterialManager::getSingleton().getByName("SO3/LightShaftsRect") : Ogre::MaterialManager::getSingleton().getByName("SO3/LightShafts"));
61 if (smat)
62 {
63 mShaftMaterial = smat->clone(mParent->GetName() + "/SO3/LightShafts", "SO3/Internal");
64 mShaftMaterial->getTechnique(0)->setSchemeName("SO3/LIGHTSHAFT");
65 mShaftMaterial->setReceiveShadows(false);
66 mShaftMaterial->load();
67 mBillboardSet->setMaterialName(mShaftMaterial->getName());
68 }
69
70 Ogre::MaterialPtr dmat = static_cast<Ogre::MaterialPtr>(Ogre::MaterialManager::getSingleton().getByName("SO3/LightShaftsDepth"));
71 if (dmat)
72 {
73 mDepthMaterial = dmat->clone(mParent->GetName() + "/SO3/LightShaftsDepth", "SO3/Internal");
74 mDepthMaterial->setReceiveShadows(false);
75 mDepthMaterial->load();
76 }
77 }
78 catch (Ogre::Exception &)
79 {
80 // material error
81 mShaftMaterial.reset();
82 mDepthMaterial.reset();
83 }
84
85 // Create a rush of billboards according to the frustum of the camera(mLightCamera)
86 SetLightClipping(nearClip, farClip);
87 CreateLightCameraRTT();
88 Ogre::MaterialManager::getSingleton().addListener(this, "SO3/" + mParent->GetName() + "/LightShafts");
89 }
90
92 {
93 Ogre::MaterialManager::getSingleton().removeListener(this, "SO3/" + mParent->GetName() + "/LightShafts");
94
95 mBillboardSet->clear();
96 mSceneMgr->destroyBillboardSet(mBillboardSet->getName());
97
98
99 if (mShaftMaterial)
100 {
101 mShaftMaterial->unload();
102 Ogre::MaterialManager::getSingletonPtr()->remove(mShaftMaterial->getHandle());
103 }
104
105 if (mDepthMaterial)
106 {
107 mDepthMaterial->unload();
108 Ogre::MaterialManager::getSingletonPtr()->remove(mDepthMaterial->getHandle());
109 }
110
111 mShaftMaterial.reset();
112 mDepthMaterial.reset();
113
114 if (mDepthTexture)
115 {
116 Ogre::RenderTarget* RT_Texture = mDepthTexture->getBuffer()->getRenderTarget();
117 RT_Texture->removeAllViewports();
118 Ogre::Root::getSingleton().detachRenderTarget(RT_Texture);
119 Ogre::TextureManager::getSingleton().remove(mDepthTexture->getHandle());
120 }
121
122 mDepthTexture.reset();
123 mSceneMgr->destroyCamera(mLightCamera);
124 }
125
126 Ogre::Technique* SLightShaft::handleSchemeNotFound(unsigned short schemeIndex, const Ogre::String& schemeName, Ogre::Material* originalMaterial, unsigned short lodIndex, const Ogre::Renderable* rend)
127 {
128 return mDepthMaterial->getTechniques()[0];
129 }
130
131 void SLightShaft::preRenderTargetUpdate(const Ogre::RenderTargetEvent& evt)
132 {
133 Update();
134 mMaterials.empty();
135 UpdatePosition();
136 mBillboardSet->setVisible(false);
137 }
138
139 void SLightShaft::postRenderTargetUpdate(const Ogre::RenderTargetEvent& evt)
140 {
141 mBillboardSet->setVisible(true);
142 }
143
144 void SLightShaft::UpdatePosition()
145 {
146 // Upload current position to light shafts materials
147 if (mShaftMaterial)
148 mShaftMaterial->getTechnique(0)->getPass(0)->getFragmentProgramParameters()->setNamedConstant("uLightPosition", mParent->GetGlobalPosition());
149
150 if (mDepthMaterial)
151 mDepthMaterial->getTechnique(0)->getPass(0)->getFragmentProgramParameters()->setNamedConstant("uLightPosition", mParent->GetGlobalPosition());
152
153 // We've to update the texture projection matrix
154 UpdateTextureProjectionMatrix();
155 }
156
157 void SLightShaft::UpdateTextureProjectionMatrix()
158 {
159 const Ogre::Matrix4 PROJECTIONCLIPSPACE2DTOIMAGESPACE_PERSPECTIVE(
160 0.5, 0, 0, 0.5,
161 0, -0.5, 0, 0.5,
162 0, 0, 1, 0,
163 0, 0, 0, 1);
164
165 Ogre::Matrix4 TexViewProj = PROJECTIONCLIPSPACE2DTOIMAGESPACE_PERSPECTIVE * mLightCamera->getProjectionMatrixWithRSDepth() * mLightCamera->getViewMatrix();
166 if (mShaftMaterial)
167 mShaftMaterial->getTechnique(0)->getPass(0)->getVertexProgramParameters()->setNamedConstant("uTexViewProj", TexViewProj);
168 }
169
170 void SLightShaft::CreateLightShafts()
171 {
172 if (mShaftMaterial)
173 {
174 // Get frustum corners to calculate near/far planes dimensions
175 const Ogre::Vector3 *FrustumCorners = mLightCamera->getWorldSpaceCorners();
176
177 // Calcule near and far planes dimensions
178 float NearWidth = (FrustumCorners[0] - FrustumCorners[1]).length(),
179 NearHeigth = (FrustumCorners[1] - FrustumCorners[2]).length(),
180 FarWidth = (FrustumCorners[4] - FrustumCorners[5]).length(),
181 FarHeigth = (FrustumCorners[5] - FrustumCorners[6]).length();
182
183 //clear the billboard set
184 mBillboardSet->clear();
185
186 // Add billboards
187 Ogre::Billboard *CurrentBB = 0;
188
189 float diff = FarWidth - NearWidth;
190 float dist = 0.0f;
191 float clip = mLightCamera->getFarClipDistance() - mLightCamera->getNearClipDistance();
192
193#ifdef _WIN32
194 int maxCount = 60;
195#else
196 int maxCount = 40;
197#endif
198
199 bool isrect = false;
200 Ogre::Vector2f rect;
201 if (mParent->GetNodeType() == SNode::LIGHT_TYPE_ID)
202 {
203 SLight* light = static_cast<SLight*>(mParent);
204 isrect = light->GetType() == SLight::SO3_RECT_LIGHT;
205 rect = light->GetSourceSize();
206 }
207
208 for (int k = 0; dist < mLightCamera->getFarClipDistance() && (k < maxCount); k++)
209 {
210 dist = mMinStep * k * k * diff * 0.5f;
211 float width = isrect ? rect.x + (dist / clip * diff) : dist / clip * diff;
212 float height = isrect ? rect.y + (dist / clip * diff) : dist / clip * diff;
213
214 CurrentBB = mBillboardSet->createBillboard(Ogre::Vector3(0, 0, -dist));
215 CurrentBB->setDimensions(width, height);
216 }
217 }
218 }
219
221 {
222 if (mNeedUpdate)
223 {
224 CreateLightShafts();
225 mNeedUpdate = false;
226 }
227 }
228
229 void SLightShaft::CreateLightCameraRTT()
230 {
231 if (mShaftMaterial)
232 {
233 Ogre::PixelFormat rttformat;
234 bool pfsupport = SRoot::getSingleton().GetRttPixelFormat(rttformat, false, true);
235 if (!pfsupport)
236 pfsupport = SRoot::getSingleton().GetRttPixelFormat(rttformat, true, true);
237
238 if (!pfsupport)
239 rttformat = Ogre::PF_R8G8B8;
240
241 // Creat a texture for use as rtt
242 mDepthTexture = Ogre::TextureManager::getSingleton().createManual(mParent->GetName() + "_LightDepthMap", "SO3/Internal", Ogre::TEX_TYPE_2D, 128, 128, 0, rttformat, Ogre::TU_RENDERTARGET);
243 Ogre::RenderTarget* RT_Texture = mDepthTexture->getBuffer()->getRenderTarget();
244 Ogre::Viewport* RT_Texture_Viewport = RT_Texture->addViewport(mLightCamera);
245 RT_Texture_Viewport->setClearEveryFrame(true);
246 RT_Texture_Viewport->setBackgroundColour(Ogre::ColourValue::White);
247 RT_Texture_Viewport->setOverlaysEnabled(false);
248 RT_Texture_Viewport->setSkiesEnabled(false);
249 RT_Texture_Viewport->setShadowsEnabled(false);
250 RT_Texture_Viewport->setMaterialScheme("SO3/" + mParent->GetName() + "/LightShafts");
251
252 // Add our depth listener
253 RT_Texture->addListener(this);
254
255 // Fill the texture in our material
256 mShaftMaterial->getTechnique(0)->getPass(0)->getTextureUnitState(0)->setTexture(mDepthTexture);
257 }
258 }
259
260 void SLightShaft::SetMinStep(const float minStep)
261 {
262 mMinStep = minStep;
263 mNeedUpdate = true;
264 }
265
266 void SLightShaft::SetCookieTexture(std::string path)
267 {
268 }
269
270 void SLightShaft::SetLightClipping(float nearClip, float farClip)
271 {
272 if (nearClip < 0.1)
273 nearClip = 0.1;
274
275 if (farClip < 0.2)
276 farClip = 0.2;
277
278 if (farClip > 1000.0)
279 farClip = 1000.0;
280
281 if (nearClip >= farClip)
282 nearClip = farClip / 8.0f;
283
284 mLightCamera->setProjectionType(Ogre::PT_PERSPECTIVE);
285 mLightCamera->setNearClipDistance(nearClip);
286 mLightCamera->setFarClipDistance(farClip);
287 mLightCamera->setAspectRatio(1.0f);
288 mLightCamera->setDebugDisplayEnabled(false);
289 mLightCamera->setVisible(true);
290
291 if (mShaftMaterial)
292 mShaftMaterial->getTechnique(0)->getPass(0)->getFragmentProgramParameters()->setNamedConstant("uLightFarClipDistance", farClip + nearClip);
293
294 if (mDepthMaterial)
295 mDepthMaterial->getTechnique(0)->getPass(0)->getFragmentProgramParameters()->setNamedConstant("uLightFarClipDistance", farClip + nearClip);
296
297 mNeedUpdate = true;
298 }
299
300 void SLightShaft::SetAttenuation(Ogre::Vector4 attenuation)
301 {
302 if (mShaftMaterial)
303 mShaftMaterial->getTechnique(0)->getPass(0)->getFragmentProgramParameters()->setNamedConstant("uAttenuation", attenuation);
304 }
305
306 void SLightShaft::SetLightFov(Ogre::Radian fov)
307 {
308 mLightCamera->setFOVy(fov);
309 mNeedUpdate = true;
310 }
311
312 void SLightShaft::SetColor(Ogre::ColourValue col)
313 {
314 if (mShaftMaterial)
315 mShaftMaterial->getTechnique(0)->getPass(0)->getFragmentProgramParameters()->setNamedConstant("uLightColor", col);
316 }
317
318}
std::string GetName() const
@ SO3_RECT_LIGHT
Definition SO3Light.h:51
virtual Ogre::Technique * handleSchemeNotFound(unsigned short schemeIndex, const Ogre::String &schemeName, Ogre::Material *originalMaterial, unsigned short lodIndex, const Ogre::Renderable *rend)
SScene * currentScene
void SetMinStep(const float minStep)
void SetLightClipping(float nearClip, float farClip)
void SetCookieTexture(std::string path)
void SetColor(Ogre::ColourValue col)
Ogre::SceneManager * mSceneMgr
void SetAttenuation(Ogre::Vector4 attenuation)
void SetLightFov(Ogre::Radian fov)
SScene * GetParentScene()
NodeType GetNodeType()
virtual Ogre::Vector3 GetGlobalPosition()
Ogre::SceneNode * GetOgreSceneNodePointer()
bool GetRttPixelFormat(Ogre::PixelFormat &format, bool alpha=false, bool floattex=false)
Definition SO3Root.cpp:650
static SRoot & getSingleton()
Definition SO3Root.cpp:116
Ogre::SceneManager * GetOgreScenePointer()
Definition SO3Scene.cpp:449