1 #ifndef __Lighting_H__ 2 #define __Lighting_H__ 3 4 #include "SdkSample.h" 5 6 using namespace Ogre; 7 using namespace OgreBites; 8 9 const uint8 cPriorityMain = 50; 10 const uint8 cPriorityQuery = 51; 11 const uint8 cPriorityLights = 55; 12 13 14 class _OgreSampleClassExport Sample_Lighting : public SdkSample, public RenderObjectListener 15 { 16 public: 17 Sample_Lighting()18 Sample_Lighting() : 19 mGreenLightAnimState(NULL), 20 mYellowLightAnimState(NULL), 21 mLight1BBFlare(NULL), 22 mLight1BBQueryArea(NULL), 23 mLight1BBQueryVisible(NULL), 24 mLight2BBFlare(NULL), 25 mLight2BBQueryArea(NULL), 26 mLight2BBQueryVisible(NULL), 27 mLight1QueryArea(NULL), 28 mLight1QueryVisible(NULL), 29 mLight2QueryArea(NULL), 30 mLight2QueryVisible(NULL), 31 mActiveQuery(NULL), 32 mUseOcclusionQuery(false), 33 mDoOcclusionQuery(false) 34 35 { 36 mInfo["Title"] = "Lighting"; 37 mInfo["Description"] = "Shows OGRE's lighting support. Also demonstrates " 38 "usage of occlusion queries and automatic time-relative behaviour " 39 "using billboards and controllers."; 40 mInfo["Thumbnail"] = "thumb_lighting.png"; 41 mInfo["Category"] = "Lighting"; 42 } 43 frameRenderingQueued(const FrameEvent & evt)44 bool frameRenderingQueued(const FrameEvent& evt) 45 { 46 // Move the lights along their paths 47 mGreenLightAnimState->addTime(evt.timeSinceLastFrame); 48 mYellowLightAnimState->addTime(evt.timeSinceLastFrame); 49 50 // Modulate the light flare according to performed occlusion queries 51 if (mUseOcclusionQuery) 52 { 53 // Stop occlusion queries until we get their information 54 // (may not happen on the same frame they are requested in) 55 mDoOcclusionQuery = false; 56 57 // Check if all query information available 58 if ((mLight1QueryArea->isStillOutstanding() == false) && 59 (mLight1QueryVisible->isStillOutstanding() == false) && 60 (mLight2QueryArea->isStillOutstanding() == false) && 61 (mLight2QueryVisible->isStillOutstanding() == false)) 62 { 63 // Modulate the lights according to the query data 64 unsigned int lightAreaCount; 65 unsigned int lightVisibleCount; 66 float ratio; 67 68 mLight1QueryArea->pullOcclusionQuery(&lightAreaCount); 69 mLight1QueryVisible->pullOcclusionQuery(&lightVisibleCount); 70 ratio = float(lightVisibleCount) / float(lightAreaCount); 71 mLight1BBFlare->setColour(mTrail->getInitialColour(0) * ratio); 72 73 mLight2QueryArea->pullOcclusionQuery(&lightAreaCount); 74 mLight2QueryVisible->pullOcclusionQuery(&lightVisibleCount); 75 ratio = float(lightVisibleCount) / float(lightAreaCount); 76 mLight2BBFlare->setColour(mTrail->getInitialColour(1) * ratio); 77 78 // Request new query data 79 mDoOcclusionQuery = true; 80 } 81 } 82 83 84 return SdkSample::frameRenderingQueued(evt); // don't forget the parent class updates! 85 } 86 87 protected: 88 setupContent()89 void setupContent() 90 { 91 // Set our camera to orbit around the origin at a suitable distance 92 mCameraMan->setStyle(CS_ORBIT); 93 mCameraMan->setYawPitchDist(Radian(0), Radian(0), 400); 94 95 mTrayMgr->showCursor(); 96 97 // Create an ogre head and place it at the origin 98 Entity* head = mSceneMgr->createEntity("Head", "ogrehead.mesh"); 99 head->setRenderQueueGroup(cPriorityMain); 100 mSceneMgr->getRootSceneNode()->attachObject(head); 101 102 setupLights(); 103 } 104 setupLights()105 void setupLights() 106 { 107 108 mSceneMgr->setAmbientLight(ColourValue(0.1, 0.1, 0.1)); // Dim ambient lighting 109 110 // Create a ribbon trail that our lights will leave behind 111 NameValuePairList params; 112 params["numberOfChains"] = "2"; 113 params["maxElements"] = "80"; 114 mTrail = (RibbonTrail*)mSceneMgr->createMovableObject("RibbonTrail", ¶ms); 115 mSceneMgr->getRootSceneNode()->attachObject(mTrail); 116 mTrail->setMaterialName("Examples/LightRibbonTrail"); 117 mTrail->setTrailLength(400); 118 mTrail->setRenderQueueGroup(cPriorityLights); 119 120 // Create the occlusion queries to be used in this sample 121 try { 122 RenderSystem* renderSystem = Ogre::Root::getSingleton().getRenderSystem(); 123 mLight1QueryArea = renderSystem->createHardwareOcclusionQuery(); 124 mLight1QueryVisible = renderSystem->createHardwareOcclusionQuery(); 125 mLight2QueryArea = renderSystem->createHardwareOcclusionQuery(); 126 mLight2QueryVisible = renderSystem->createHardwareOcclusionQuery(); 127 128 mUseOcclusionQuery = (mLight1QueryArea != NULL) && 129 (mLight1QueryVisible != NULL) && 130 (mLight2QueryArea != NULL) && 131 (mLight2QueryVisible != NULL); 132 } 133 catch (Ogre::Exception e) 134 { 135 mUseOcclusionQuery = false; 136 } 137 138 if (mUseOcclusionQuery == false) 139 { 140 LogManager::getSingleton().logMessage("Sample_Lighting - Error: failed to create hardware occlusion query", LML_CRITICAL); 141 } 142 143 // Create the materials to be used by the objects used fo the occlusion query 144 MaterialPtr matBase = MaterialManager::getSingleton().getByName("BaseWhiteNoLighting"); 145 MaterialPtr matQueryArea = matBase->clone("QueryArea"); 146 matQueryArea->setDepthWriteEnabled(false); 147 matQueryArea->setColourWriteEnabled(false); 148 matQueryArea->setDepthCheckEnabled(false); // Not occluded by objects 149 MaterialPtr matQueryVisible = matBase->clone("QueryVisible"); 150 matQueryVisible->setDepthWriteEnabled(false); 151 matQueryVisible->setColourWriteEnabled(false); 152 matQueryVisible->setDepthCheckEnabled(true); // Occluded by objects 153 154 SceneNode* node; 155 Animation* anim; 156 NodeAnimationTrack* track; 157 Light* light; 158 BillboardSet* bbs; 159 160 // Create a light node 161 node = mSceneMgr->getRootSceneNode()->createChildSceneNode(Vector3(50, 30, 0)); 162 163 // Create a 14 second animation with spline interpolation 164 anim = mSceneMgr->createAnimation("Path1", 14); 165 anim->setInterpolationMode(Animation::IM_SPLINE); 166 167 track = anim->createNodeTrack(1, node); // Create a node track for our animation 168 169 // Enter keyframes for our track to define a path for the light to follow 170 track->createNodeKeyFrame(0)->setTranslate(Vector3(50, 30, 0)); 171 track->createNodeKeyFrame(2)->setTranslate(Vector3(100, -30, 0)); 172 track->createNodeKeyFrame(4)->setTranslate(Vector3(120, -80, 150)); 173 track->createNodeKeyFrame(6)->setTranslate(Vector3(30, -80, 50)); 174 track->createNodeKeyFrame(8)->setTranslate(Vector3(-50, 30, -50)); 175 track->createNodeKeyFrame(10)->setTranslate(Vector3(-150, -20, -100)); 176 track->createNodeKeyFrame(12)->setTranslate(Vector3(-50, -30, 0)); 177 track->createNodeKeyFrame(14)->setTranslate(Vector3(50, 30, 0)); 178 179 // Create an animation state from the animation and enable it 180 mYellowLightAnimState = mSceneMgr->createAnimationState("Path1"); 181 mYellowLightAnimState->setEnabled(true); 182 183 // Set initial settings for the ribbon mTrail and add the light node 184 mTrail->setInitialColour(0, 1.0, 0.8, 0); 185 mTrail->setColourChange(0, 0.5, 0.5, 0.5, 0.5); 186 mTrail->setInitialWidth(0, 5); 187 mTrail->addNode(node); 188 189 190 // Attach a light with the same colour to the light node 191 light = mSceneMgr->createLight(); 192 light->setDiffuseColour(mTrail->getInitialColour(0)); 193 node->attachObject(light); 194 195 // Attach a flare with the same colour to the light node 196 bbs = mSceneMgr->createBillboardSet(1); 197 mLight1BBFlare = bbs->createBillboard(Vector3::ZERO, mTrail->getInitialColour(0)); 198 bbs->setMaterialName("Examples/Flare"); 199 bbs->setRenderQueueGroup(cPriorityLights); 200 node->attachObject(bbs); 201 202 if (mUseOcclusionQuery) 203 { 204 // Attach a billboard which will be used to get a relative area occupied by the light 205 mLight1BBQueryArea = mSceneMgr->createBillboardSet(1); 206 mLight1BBQueryArea->setDefaultDimensions(10,10); 207 mLight1BBQueryArea->createBillboard(Vector3::ZERO); 208 mLight1BBQueryArea->setMaterialName("QueryArea"); 209 mLight1BBQueryArea->setRenderQueueGroup(cPriorityQuery); 210 node->attachObject(mLight1BBQueryArea); 211 212 // Attach a billboard which will be used to get the visible area occupied by the light 213 mLight1BBQueryVisible = mSceneMgr->createBillboardSet(1); 214 mLight1BBQueryVisible->setDefaultDimensions(10,10); 215 mLight1BBQueryVisible->createBillboard(Vector3::ZERO); 216 mLight1BBQueryVisible->setMaterialName("QueryVisible"); 217 mLight1BBQueryVisible->setRenderQueueGroup(cPriorityQuery); 218 node->attachObject(mLight1BBQueryVisible); 219 } 220 221 // Create a second light node 222 node = mSceneMgr->getRootSceneNode()->createChildSceneNode(Vector3(-50, 100, 0)); 223 224 // Create a 10 second animation with spline interpolation 225 anim = mSceneMgr->createAnimation("Path2", 10); 226 anim->setInterpolationMode(Animation::IM_SPLINE); 227 228 track = anim->createNodeTrack(1, node); // Create a node track for our animation 229 230 // Enter keyframes for our track to define a path for the light to follow 231 track->createNodeKeyFrame(0)->setTranslate(Vector3(-50, 100, 0)); 232 track->createNodeKeyFrame(2)->setTranslate(Vector3(-100, 150, -30)); 233 track->createNodeKeyFrame(4)->setTranslate(Vector3(-200, 0, 40)); 234 track->createNodeKeyFrame(6)->setTranslate(Vector3(0, -150, 70)); 235 track->createNodeKeyFrame(8)->setTranslate(Vector3(50, 0, 30)); 236 track->createNodeKeyFrame(10)->setTranslate(Vector3(-50, 100, 0)); 237 238 // Create an animation state from the animation and enable it 239 mGreenLightAnimState = mSceneMgr->createAnimationState("Path2"); 240 mGreenLightAnimState->setEnabled(true); 241 242 // Set initial settings for the ribbon mTrail and add the light node 243 mTrail->setInitialColour(1, 0.0, 1.0, 0.4); 244 mTrail->setColourChange(1, 0.5, 0.5, 0.5, 0.5); 245 mTrail->setInitialWidth(1, 5); 246 mTrail->addNode(node); 247 248 // Attach a light with the same colour to the light node 249 light = mSceneMgr->createLight(); 250 light->setDiffuseColour(mTrail->getInitialColour(1)); 251 node->attachObject(light); 252 253 // Attach a flare with the same colour to the light node 254 bbs = mSceneMgr->createBillboardSet(1); 255 mLight2BBFlare = bbs->createBillboard(Vector3::ZERO, mTrail->getInitialColour(1)); 256 bbs->setMaterialName("Examples/Flare"); 257 bbs->setRenderQueueGroup(cPriorityLights); 258 node->attachObject(bbs); 259 260 if (mUseOcclusionQuery) 261 { 262 // Attach a billboard which will be used to get a relative area occupied by the light 263 mLight2BBQueryArea = mSceneMgr->createBillboardSet(1); 264 mLight2BBQueryArea->setDefaultDimensions(10,10); 265 mLight2BBQueryArea->createBillboard(Vector3::ZERO); 266 mLight2BBQueryArea->setMaterialName("QueryArea"); 267 mLight2BBQueryArea->setRenderQueueGroup(cPriorityQuery); 268 node->attachObject(mLight2BBQueryArea); 269 270 // Attach a billboard which will be used to get the visible area occupied by the light 271 mLight2BBQueryVisible = mSceneMgr->createBillboardSet(1); 272 mLight2BBQueryVisible->setDefaultDimensions(10,10); 273 mLight2BBQueryVisible->createBillboard(Vector3::ZERO); 274 mLight2BBQueryVisible->setMaterialName("QueryVisible"); 275 mLight2BBQueryVisible->setRenderQueueGroup(cPriorityQuery); 276 node->attachObject(mLight2BBQueryVisible); 277 } 278 279 // Setup the listener for the occlusion query 280 if (mUseOcclusionQuery) 281 { 282 mSceneMgr->addRenderObjectListener(this); 283 mDoOcclusionQuery = true; 284 } 285 } 286 287 // Event raised when render single object started. notifyRenderSingleObject(Renderable * rend,const Pass * pass,const AutoParamDataSource * source,const LightList * pLightList,bool suppressRenderStateChanges)288 virtual void notifyRenderSingleObject(Renderable* rend, const Pass* pass, const AutoParamDataSource* source, 289 const LightList* pLightList, bool suppressRenderStateChanges) 290 { 291 // 292 // The following code activates and deactivates the occlusion queries 293 // so that the queries only include the rendering of their intended targets 294 // 295 296 // Close the last occlusion query 297 // Each occlusion query should only last a single rendering 298 if (mActiveQuery != NULL) 299 { 300 mActiveQuery->endOcclusionQuery(); 301 mActiveQuery = NULL; 302 } 303 304 // Open a new occlusion query 305 if (mDoOcclusionQuery == true) 306 { 307 // Check if a the object being rendered needs 308 // to be occlusion queried, and by which query instance. 309 if (rend == mLight1BBQueryArea) 310 mActiveQuery = mLight1QueryArea; 311 else if (rend == mLight1BBQueryVisible) 312 mActiveQuery = mLight1QueryVisible; 313 else if (rend == mLight2BBQueryArea) 314 mActiveQuery = mLight2QueryArea; 315 else if (rend == mLight2BBQueryVisible) 316 mActiveQuery = mLight2QueryVisible; 317 318 if (mActiveQuery != NULL) 319 { 320 mActiveQuery->beginOcclusionQuery(); 321 } 322 } 323 } 324 cleanupContent()325 void cleanupContent() 326 { 327 RenderSystem* renderSystem = Ogre::Root::getSingleton().getRenderSystem(); 328 if (mLight1QueryArea != NULL) 329 renderSystem->destroyHardwareOcclusionQuery(mLight1QueryArea); 330 if (mLight1QueryVisible != NULL) 331 renderSystem->destroyHardwareOcclusionQuery(mLight1QueryVisible); 332 if (mLight2QueryArea != NULL) 333 renderSystem->destroyHardwareOcclusionQuery(mLight2QueryArea); 334 if (mLight2QueryVisible != NULL) 335 renderSystem->destroyHardwareOcclusionQuery(mLight2QueryVisible); 336 } 337 338 AnimationState* mGreenLightAnimState; 339 AnimationState* mYellowLightAnimState; 340 341 RibbonTrail* mTrail; 342 343 Billboard* mLight1BBFlare; 344 BillboardSet* mLight1BBQueryArea; 345 BillboardSet* mLight1BBQueryVisible; 346 Billboard* mLight2BBFlare; 347 BillboardSet* mLight2BBQueryArea; 348 BillboardSet* mLight2BBQueryVisible; 349 350 HardwareOcclusionQuery* mLight1QueryArea; 351 HardwareOcclusionQuery* mLight1QueryVisible; 352 HardwareOcclusionQuery* mLight2QueryArea; 353 HardwareOcclusionQuery* mLight2QueryVisible; 354 HardwareOcclusionQuery* mActiveQuery; 355 356 bool mUseOcclusionQuery; 357 bool mDoOcclusionQuery; 358 }; 359 360 #endif 361