1 /* 2 ----------------------------------------------------------------------------- 3 This source file is part of OGRE 4 (Object-oriented Graphics Rendering Engine) 5 For the latest info, see http://www.ogre3d.org/ 6 7 Copyright (c) 2000-2014 Torus Knot Software Ltd 8 Also see acknowledgements in Readme.html 9 10 You may use this sample code for anything you like, it is not covered by the 11 same license as the rest of the engine. 12 ----------------------------------------------------------------------------- 13 */ 14 15 /** 16 Implementation of a Deferred Shading engine in OGRE, using Multiple Render Targets and 17 CG high level language shaders. 18 // W.J. :wumpus: van der Laan 2005 / Noam Gat 2009 // 19 20 Deferred shading renders the scene to a 'fat' texture format, using a shader that outputs colour, 21 normal, depth, and possible other attributes per fragment. Multi Render Target is required as we 22 are dealing with many outputs which get written into multiple render textures in the same pass. 23 24 After rendering the scene in this format, the shading (lighting) can be done as a post process. 25 This means that lighting is done in screen space, using light-representing geometry (sphere for 26 point light, cone for spot light and quad for directional) to render their contribution. 27 28 The wiki article explaining this demo can be found here : 29 http://www.ogre3d.org/wiki/index.php/Deferred_Shading 30 */ 31 32 #ifndef H_DeferredShadingDemo 33 #define H_DeferredShadingDemo 34 35 #include "SdkSample.h" 36 37 #if OGRE_PLATFORM == OGRE_PLATFORM_WIN32 38 #define WIN32_LEAN_AND_MEAN 39 #include "windows.h" 40 #endif 41 42 #include "SharedData.h" 43 #include "OgreCompositorInstance.h" 44 #include "OgreSceneManager.h" 45 #include "OgreSceneNode.h" 46 #include "OgreMaterial.h" 47 #include "OgreRenderTargetListener.h" 48 #include "GeomUtils.h" 49 50 using namespace Ogre; 51 using namespace OgreBites; 52 53 const ColourValue SAMPLE_COLORS[] = 54 { ColourValue::Red, ColourValue::Green, ColourValue::Blue, 55 ColourValue::White, ColourValue(1,1,0,1), ColourValue(1,0,1,1) 56 }; 57 58 class _OgreSampleClassExport Sample_DeferredShading : public SdkSample, public RenderTargetListener 59 { 60 protected: 61 DeferredShadingSystem *mSystem; 62 SelectMenu* mDisplayModeMenu; 63 64 public: Sample_DeferredShading()65 Sample_DeferredShading() 66 { 67 mInfo["Title"] = "Deferred Shading"; 68 mInfo["Description"] = "A sample implementation of a deferred renderer using the compositor framework."; 69 mInfo["Thumbnail"] = "thumb_deferred.png"; 70 mInfo["Category"] = "Lighting"; 71 mInfo["Help"] = "See http://www.ogre3d.org/wiki/index.php/Deferred_Shading for more info"; 72 } 73 74 protected: 75 cleanupContent(void)76 void cleanupContent(void) 77 { 78 delete ( SharedData::getSingletonPtr() ); 79 80 delete mSystem; 81 } 82 setupControls()83 void setupControls() 84 { 85 mTrayMgr->showCursor(); 86 87 // create checkboxs to toggle ssao and shadows 88 mTrayMgr->createCheckBox(TL_TOPLEFT, "DeferredShading", "Deferred Shading", 220)->setChecked(true, false); 89 mTrayMgr->createCheckBox(TL_TOPLEFT, "SSAO", "Ambient Occlusion", 220)->setChecked(false, false); 90 mTrayMgr->createCheckBox(TL_TOPLEFT, "GlobalLight", "Global Light", 220)->setChecked(true, false); 91 mTrayMgr->createCheckBox(TL_TOPLEFT, "Shadows", "Shadows", 220)->setChecked(true, false); 92 93 // create a menu to choose the model displayed 94 mDisplayModeMenu = mTrayMgr->createThickSelectMenu(TL_TOPLEFT, "DisplayMode", "Display Mode", 220, 4); 95 mDisplayModeMenu->addItem("Regular view"); 96 mDisplayModeMenu->addItem("Debug colours"); 97 mDisplayModeMenu->addItem("Debug normals"); 98 mDisplayModeMenu->addItem("Debug depth / specular"); 99 } 100 itemSelected(SelectMenu * menu)101 void itemSelected(SelectMenu* menu) 102 { 103 //Options are aligned with the mode enum 104 SharedData::getSingleton().iSystem->setMode( 105 (DeferredShadingSystem::DSMode)menu->getSelectionIndex()); 106 } 107 checkBoxToggled(CheckBox * box)108 void checkBoxToggled(CheckBox* box) 109 { 110 if (box->getName() == "SSAO") 111 { 112 SharedData::getSingleton().iSystem->setSSAO(box->isChecked()); 113 } 114 else if (box->getName() == "GlobalLight") 115 { 116 SharedData::getSingleton().iGlobalActivate = box->isChecked(); 117 SharedData::getSingleton().iMainLight->setVisible(box->isChecked()); 118 } 119 else if (box->getName() == "Shadows") 120 { 121 mSceneMgr->setShadowTechnique(box->isChecked() ? 122 SHADOWTYPE_TEXTURE_ADDITIVE : 123 SHADOWTYPE_NONE); 124 } 125 else if (box->getName() == "DeferredShading") 126 { 127 SharedData::getSingleton().iSystem->setActive(box->isChecked()); 128 } 129 } 130 131 //Utility function to help set scene up setEntityHeight(Entity * ent,Real newHeight)132 void setEntityHeight(Entity* ent, Real newHeight) 133 { 134 Real curHeight = ent->getMesh()->getBounds().getSize().y; 135 Real scaleFactor = newHeight / curHeight; 136 137 SceneNode* parentNode = ent->getParentSceneNode(); 138 parentNode->setScale(scaleFactor, scaleFactor, scaleFactor); 139 } 140 createAtheneScene(SceneNode * rootNode)141 void createAtheneScene(SceneNode* rootNode) 142 { 143 // Prepare athene mesh for normalmapping 144 MeshPtr pAthene = MeshManager::getSingleton().load("athene.mesh", 145 ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME); 146 unsigned short src, dest; 147 if (!pAthene->suggestTangentVectorBuildParams(VES_TANGENT, src, dest)) 148 pAthene->buildTangentVectors(VES_TANGENT, src, dest); 149 150 //Create an athena statue 151 Entity* athena = mSceneMgr->createEntity("Athena", "athene.mesh"); 152 athena->setMaterialName("DeferredDemo/DeferredAthena"); 153 SceneNode *aNode = rootNode->createChildSceneNode(); 154 aNode->attachObject( athena ); 155 aNode->setPosition(-8.5, 4.5, 0); 156 setEntityHeight(athena, 4.0); 157 aNode->yaw(Ogre::Degree(90)); 158 // Create some happy little lights to decorate the athena statue 159 createSampleLights(); 160 } 161 createKnotScene(SceneNode * rootNode)162 void createKnotScene(SceneNode* rootNode) 163 { 164 // Prepare knot mesh for normal mapping 165 MeshPtr pKnot = MeshManager::getSingleton().load("knot.mesh", 166 ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME); 167 unsigned short src, dest; 168 if (!pKnot->suggestTangentVectorBuildParams(VES_TANGENT, src, dest)) 169 pKnot->buildTangentVectors(VES_TANGENT, src, dest); 170 171 // Create a bunch of knots with spotlights hanging from above 172 Entity* knotEnt = mSceneMgr->createEntity("Knot", "knot.mesh"); 173 knotEnt->setMaterialName("DeferredDemo/RockWall"); 174 //knotEnt->setMeshLodBias(0.25f); 175 Vector3 knotStartPos(25.5, 2, 5.5); 176 Vector3 knotDiff(-3.7, 0, 0); 177 for (int i=0; i < 5; i++) 178 { 179 Entity* cloneKnot = knotEnt->clone(StringUtil::format("Knot%d", i)); 180 Vector3 clonePos = knotStartPos + knotDiff*i; 181 SceneNode* cloneNode = rootNode->createChildSceneNode(clonePos); 182 cloneNode->attachObject(cloneKnot); 183 setEntityHeight(cloneKnot, 3); 184 cloneNode->yaw(Degree(i*17)); 185 cloneNode->roll(Degree(i*31)); 186 187 Light* knotLight = mSceneMgr->createLight(StringUtil::format("KnotLight%d", i)); 188 SceneNode* ln = rootNode->createChildSceneNode(clonePos + Vector3(0,3,0)); 189 ln->setDirection(Vector3::NEGATIVE_UNIT_Y); 190 ln->attachObject(knotLight); 191 knotLight->setType(Light::LT_SPOTLIGHT); 192 knotLight->setDiffuseColour(SAMPLE_COLORS[i]); 193 knotLight->setSpecularColour(ColourValue::White); 194 knotLight->setSpotlightRange(Degree(25), Degree(45), 1); 195 knotLight->setAttenuation(6, 1, 0.2, 0); 196 } 197 } 198 createObjects(SceneNode * rootNode)199 void createObjects(SceneNode* rootNode) 200 { 201 // Create ogre heads to decorate the wall 202 Entity* ogreHead = mSceneMgr->createEntity("Head", "ogrehead.mesh"); 203 //rootNode->createChildSceneNode( "Head" )->attachObject( ogreHead ); 204 Vector3 headStartPos[2] = { Vector3(25.25,11,3), Vector3(25.25,11,-3) }; 205 Vector3 headDiff(-3.7,0,0); 206 for (int i=0; i < 12; i++) 207 { 208 Entity* cloneHead = ogreHead->clone(StringUtil::format("OgreHead%d", i)); 209 Vector3 clonePos = headStartPos[i%2] + headDiff*(i/2); 210 if ((i/2) >= 4) clonePos.x -= 0.75; 211 SceneNode* cloneNode = rootNode->createChildSceneNode(clonePos); 212 cloneNode->attachObject(cloneHead); 213 setEntityHeight(cloneHead, 1.5); 214 if (i % 2 == 0) 215 { 216 cloneNode->yaw(Degree(180)); 217 } 218 } 219 220 // Create a pile of wood pallets 221 Entity* woodPallet = mSceneMgr->createEntity("Pallet", "WoodPallet.mesh"); 222 Vector3 woodStartPos(10, 0.5, -5.5); 223 Vector3 woodDiff(0, 0.3, 0); 224 for (int i=0; i < 5; i++) 225 { 226 Entity* clonePallet = woodPallet->clone(StringUtil::format("WoodPallet%d", i)); 227 Vector3 clonePos = woodStartPos + woodDiff*i; 228 SceneNode* cloneNode = rootNode->createChildSceneNode(clonePos); 229 cloneNode->attachObject(clonePallet); 230 setEntityHeight(clonePallet, 0.3); 231 cloneNode->yaw(Degree(i*20)); 232 } 233 234 } 235 getRequiredPlugins()236 StringVector getRequiredPlugins() 237 { 238 StringVector names; 239 if (!GpuProgramManager::getSingleton().isSyntaxSupported("glsles") && !GpuProgramManager::getSingleton().isSyntaxSupported("glsl150")) 240 names.push_back("Cg Program Manager"); 241 return names; 242 } 243 testCapabilities(const RenderSystemCapabilities * caps)244 void testCapabilities(const RenderSystemCapabilities* caps) 245 { 246 if (!caps->hasCapability(RSC_VERTEX_PROGRAM) || !(caps->hasCapability(RSC_FRAGMENT_PROGRAM))) 247 { 248 OGRE_EXCEPT(Exception::ERR_NOT_IMPLEMENTED, "Your card does not support vertex and fragment programs, so cannot " 249 "run this demo. Sorry!", 250 "DeferredShading::testCapabilities"); 251 } 252 if (caps->getNumMultiRenderTargets()<2) 253 { 254 OGRE_EXCEPT(Exception::ERR_NOT_IMPLEMENTED, "Your card does not support at least two simultaneous render targets, so cannot " 255 "run this demo. Sorry!", 256 "DeferredShading::testCapabilities"); 257 } 258 259 if (!GpuProgramManager::getSingleton().isSyntaxSupported("vs_1_1") && 260 !GpuProgramManager::getSingleton().isSyntaxSupported("arbvp1") && 261 !GpuProgramManager::getSingleton().isSyntaxSupported("vs_4_0") && 262 !GpuProgramManager::getSingleton().isSyntaxSupported("glsl300es") && 263 !GpuProgramManager::getSingleton().isSyntaxSupported("glsl150")) 264 { 265 OGRE_EXCEPT(Exception::ERR_NOT_IMPLEMENTED, "Your graphics card does not support advanced vertex" 266 " programs, so you cannot run this sample. Sorry!", "DeferredShading::testCapabilities"); 267 } 268 } 269 270 // Just override the mandatory create scene method setupContent(void)271 void setupContent(void) 272 { 273 mCameraMan->setTopSpeed(20.0); 274 new SharedData(); 275 mSystem = 0; 276 277 // Set ambient light 278 mSceneMgr->setAmbientLight(ColourValue(0.15, 0.00, 0.00)); 279 // Skybox 280 mSceneMgr->setSkyBox(true, "DeferredDemo/SkyBox", 500); 281 // Create main, static light 282 Light* l1 = mSceneMgr->createLight(); 283 l1->setType(Light::LT_DIRECTIONAL); 284 l1->setDiffuseColour(0.5f, 0.45f, 0.1f); 285 l1->setDirection(1, -0.5, -0.2); 286 l1->setShadowFarClipDistance(250); 287 l1->setShadowFarDistance(75); 288 //Turn this on to have the directional light cast shadows 289 l1->setCastShadows(false); 290 291 mCameraNode->setPosition(25, 5, 0); 292 mCameraNode->lookAt(Vector3::ZERO, Node::TS_PARENT); 293 mCamera->setFarClipDistance(1000.0); 294 mCamera->setNearClipDistance(0.5); 295 setDragLook(true); 296 297 mSystem = new DeferredShadingSystem(mWindow->getViewport(0), mSceneMgr, mCamera); 298 SharedData::getSingleton().iSystem = mSystem; 299 mSystem->initialize(); 300 301 // safely setup application's (not postfilter!) shared data 302 SharedData::getSingleton().iCamera = mCamera; 303 SharedData::getSingleton().iRoot = mRoot; 304 SharedData::getSingleton().iWindow = mWindow; 305 SharedData::getSingleton().iActivate = true; 306 SharedData::getSingleton().iGlobalActivate = true; 307 SharedData::getSingleton().iMainLight = l1; 308 309 //Create the scene 310 // Create "root" node 311 SceneNode* rootNode = mSceneMgr->getRootSceneNode()->createChildSceneNode(); 312 313 // Create the cathedral - this will be the static scene 314 Entity* cathedralEnt = mSceneMgr->createEntity("Cathedral", "sibenik.mesh"); 315 SceneNode* cathedralNode = rootNode->createChildSceneNode(); 316 cathedralNode->attachObject(cathedralEnt); 317 318 createAtheneScene(rootNode); 319 createKnotScene(rootNode); 320 createObjects(rootNode); 321 322 setupControls(); 323 } 324 createSampleLights()325 void createSampleLights() 326 { 327 // Create some lights 328 std::vector<Light*> lights; 329 SceneNode *parentNode = mSceneMgr->getRootSceneNode()->createChildSceneNode("LightsParent"); 330 // Create light nodes 331 std::vector<Node*> nodes; 332 333 Vector4 attParams = Vector4(4,1,0,7); 334 Real lightRadius = 25; 335 336 Light *a = mSceneMgr->createLight(); 337 SceneNode *an = parentNode->createChildSceneNode(); 338 an->attachObject(a); 339 a->setAttenuation(attParams.x, attParams.y, attParams.z, attParams.w); 340 //a->setAttenuation(1.0f, 0.000f, 0.000f); 341 an->setPosition(0,0,lightRadius); 342 a->setDiffuseColour(1,0,0); 343 //a->setSpecularColour(0.5,0,0); 344 lights.push_back(a); 345 nodes.push_back(an); 346 347 Light *b = mSceneMgr->createLight(); 348 SceneNode *bn = parentNode->createChildSceneNode(); 349 bn->attachObject(b); 350 b->setAttenuation(attParams.x, attParams.y, attParams.z, attParams.w); 351 bn->setPosition(lightRadius,0,0); 352 b->setDiffuseColour(1,1,0); 353 //b->setSpecularColour(0.5,0.5,0); 354 lights.push_back(b); 355 nodes.push_back(bn); 356 357 Light *c = mSceneMgr->createLight(); 358 SceneNode *cn = parentNode->createChildSceneNode(); 359 cn->attachObject(c); 360 c->setAttenuation(attParams.x, attParams.y, attParams.z, attParams.w); 361 cn->setPosition(0,0,-lightRadius); 362 c->setDiffuseColour(0,1,1); 363 c->setSpecularColour(0.25,1.0,1.0); // Cyan light has specular component 364 lights.push_back(c); 365 nodes.push_back(cn); 366 367 Light *d = mSceneMgr->createLight(); 368 SceneNode *dn = parentNode->createChildSceneNode(); 369 dn->attachObject(d); 370 d->setAttenuation(attParams.x, attParams.y, attParams.z, attParams.w); 371 dn->setPosition(-lightRadius,0,0); 372 d->setDiffuseColour(1,0,1); 373 d->setSpecularColour(0.0,0,0.0); 374 lights.push_back(d); 375 nodes.push_back(dn); 376 377 Light *e = mSceneMgr->createLight(); 378 SceneNode *en = parentNode->createChildSceneNode(); 379 en->attachObject(e); 380 e->setAttenuation(attParams.x, attParams.y, attParams.z, attParams.w); 381 en->setPosition(lightRadius,0,lightRadius); 382 e->setDiffuseColour(0,0,1); 383 e->setSpecularColour(0,0,0); 384 lights.push_back(e); 385 nodes.push_back(en); 386 387 Light *f = mSceneMgr->createLight(); 388 SceneNode *fn = parentNode->createChildSceneNode(); 389 fn->attachObject(f); 390 f->setAttenuation(attParams.x, attParams.y, attParams.z, attParams.w); 391 fn->setPosition(-lightRadius,0,-lightRadius); 392 f->setDiffuseColour(0,1,0); 393 f->setSpecularColour(0,0.0,0.0); 394 lights.push_back(f); 395 nodes.push_back(fn); 396 397 // Create marker meshes to show user where the lights are 398 Entity *ent; 399 GeomUtils::createSphere("PointLightMesh", 0.05f, 5, 5, true, true); 400 for(std::vector<Light*>::iterator i=lights.begin(); i!=lights.end(); ++i) 401 { 402 Light* light = *i; 403 ent = mSceneMgr->createEntity(light->getName()+"v", "PointLightMesh"); 404 String matname = light->getName()+"m"; 405 // Create coloured material 406 MaterialPtr mat = MaterialManager::getSingleton().create(matname, 407 ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME); 408 Pass* pass = mat->getTechnique(0)->getPass(0); 409 pass->setDiffuse(0.0f,0.0f,0.0f,1.0f); 410 pass->setAmbient(0.0f,0.0f,0.0f); 411 pass->setSelfIllumination(light->getDiffuseColour()); 412 413 ent->setMaterialName(matname); 414 //ent->setRenderQueueGroup(light->getRenderQueueGroup()); 415 ent->setRenderQueueGroup(DeferredShadingSystem::POST_GBUFFER_RENDER_QUEUE); 416 static_cast<SceneNode*>(light->getParentNode())->attachObject(ent); 417 ent->setVisible(true); 418 } 419 420 // Store nodes for hiding/showing 421 SharedData::getSingleton().mLightNodes = nodes; 422 423 // Do some animation for node a-f 424 // Generate helix structure 425 float seconds_per_station = 1.0f; 426 float r = 1.0; 427 //Vector3 base(0,-30,0); 428 Vector3 base(-8.75, 3.5, 0); 429 430 float h=3; 431 const size_t s_to_top = 16; 432 const size_t stations = s_to_top*2-1; 433 float ascend = h/((float)s_to_top); 434 float stations_per_revolution = 3.5f; 435 size_t skip = 2; // stations between lights 436 Vector3 station_pos[stations]; 437 for(size_t x=0; x<s_to_top; ++x) 438 { 439 float theta = ((float)x/stations_per_revolution)*2.0f*Math::PI; 440 station_pos[x] = base+Vector3(Math::Sin(theta)*r, ascend*x, Math::Cos(theta)*r); 441 } 442 for(size_t x=s_to_top; x<stations; ++x) 443 { 444 float theta = ((float)x/stations_per_revolution)*2.0f*Math::PI; 445 station_pos[x] = base+Vector3(Math::Sin(theta)*r, h-ascend*(x-s_to_top), Math::Cos(theta)*r); 446 } 447 // Create a track for the light swarm 448 Animation* anim = mSceneMgr->createAnimation("LightSwarmTrack", stations*seconds_per_station); 449 // Spline it for nice curves 450 anim->setInterpolationMode(Animation::IM_SPLINE); 451 for(unsigned int x=0; x<nodes.size(); ++x) 452 { 453 // Create a track to animate the camera's node 454 NodeAnimationTrack* track = anim->createNodeTrack(x, nodes[x]); 455 for(size_t y=0; y<=stations; ++y) 456 { 457 // Setup keyframes 458 TransformKeyFrame* key = track->createNodeKeyFrame(y*seconds_per_station); // A start position 459 key->setTranslate(station_pos[(x*skip+y)%stations]); 460 // Make sure size of light doesn't change 461 key->setScale(nodes[x]->getScale()); 462 } 463 } 464 // Create a new animation state to track this 465 auto animState = mSceneMgr->createAnimationState("LightSwarmTrack"); 466 animState->setEnabled(true); 467 468 auto& controllerMgr = ControllerManager::getSingleton(); 469 controllerMgr.createFrameTimePassthroughController(AnimationStateControllerValue::create(animState, true)); 470 471 /*Light* spotLight = mSceneMgr->createLight("Spotlight1"); 472 spotLight->setType(Light::LT_SPOTLIGHT); 473 spotLight->setAttenuation(200, 1.0f, 0, 0); 474 spotLight->setSpotlightRange(Degree(30.0), Degree(45.0), 0.8); 475 spotLight->setPosition(0,120,0); 476 spotLight->setDirection(0, -1, 0); 477 spotLight->setDiffuseColour(1,1,1); 478 spotLight->setSpecularColour(1,1,1);*/ 479 } 480 }; 481 482 #endif 483