source: OGRE/trunk/ogrenew/Samples/DeferredShading/src/DeferredShadingDemo.cpp @ 692

Revision 692, 19.8 KB checked in by mattausch, 18 years ago (diff)

adding ogre 1.2 and dependencies

Line 
1/**
2Demo of Deferred Shading in OGRE using Multiple Render Targets and HLSL/GLSL high level
3language shaders.
4        // W.J. :wumpus: van der Laan 2005 //
5
6Deferred shading renders the scene to a 'fat' texture format, using a shader that outputs colour,
7normal, depth, and possible other attributes per fragment. Multi Render Target is required as we
8are dealing with many outputs which get written into multiple render textures in the same pass.
9
10After rendering the scene in this format, the shading (lighting) can be done as a post process.
11This means that lighting is done in screen space. Adding them requires nothing more than rendering
12a screenful quad; thus the method allows for an enormous amount of lights without noticable
13performance loss.
14
15Little lights affecting small area ("Minilights") can be even further optimised by rendering
16their convex bounding geometry. This is also shown in this demo by 6 swarming lights.
17
18The paper for GDC2004 on Deferred Shading can be found here:
19  http://www.talula.demon.co.uk/DeferredShading.pdf
20
21This demo source file is in the public domain.
22*/
23
24#include "Ogre.h"
25#include "ExampleApplication.h"
26#include "ExampleFrameListener.h"
27
28#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
29#define WIN32_LEAN_AND_MEAN
30#include "windows.h"
31#endif
32
33#include "DeferredShading.h"
34#include "MLight.h"
35#include "CreateSphere.h"
36class SharedData : public Ogre::Singleton<SharedData> {
37
38public:
39
40        SharedData()
41                : iRoot(0),
42                  iCamera(0),
43                  iWindow(0),
44                  mAnimState(0),
45                  mMLAnimState(0),
46                  iLight1(0), iLight2(0)
47        {
48                iActivate = false;
49        }
50
51                ~SharedData() {}
52
53                // shared data across the application
54                Real iLastFrameTime;
55                Root *iRoot;
56                Camera *iCamera;
57                RenderWindow *iWindow;
58
59                DeferredShadingSystem *iSystem;
60                bool iActivate;
61                bool iGlobalActivate;
62
63                // Animation state for big lights
64                AnimationState* mAnimState;
65                // Animation state for light swarm
66                AnimationState* mMLAnimState;
67
68                // overlay stuff.. too lazy to do a good thing for it
69                SceneManager *iSceneMgr;
70                RenderTarget *iSceneTarget;
71
72                MLight *iLight1, *iLight2;
73
74                std::vector<Node*> mLightNodes;
75
76};
77template<> SharedData* Singleton<SharedData>::ms_Singleton = 0;
78
79class RenderToTextureFrameListener : public ExampleFrameListener
80{
81protected:
82        Real timeoutDelay ;
83        Vector3 oldCamPos;
84        Quaternion oldCamOri;
85        DeferredShadingSystem::DSMode mode;
86public:
87        RenderToTextureFrameListener(RenderWindow* window, Camera* maincam)
88                :ExampleFrameListener(window, maincam),
89                oldCamPos(0,0,0), oldCamOri(0,0,0,0)
90        {
91                timeoutDelay = 0;
92                mMoveSpeed = 200;
93                mode = (DeferredShadingSystem::DSMode)1;
94        }
95
96        bool frameStarted(const FrameEvent& evt)
97        {
98                bool result = ExampleFrameListener::frameStarted(evt);
99                SharedData::getSingleton().iLastFrameTime = evt.timeSinceLastFrame;
100
101                if (SharedData::getSingleton().mAnimState)
102            SharedData::getSingleton().mAnimState->addTime(evt.timeSinceLastFrame);
103                if (SharedData::getSingleton().mMLAnimState)
104            SharedData::getSingleton().mMLAnimState->addTime(evt.timeSinceLastFrame);
105               
106                // Only update fat buffer if something changed
107                bool somethingChanged = false;
108                if(mCamera->getPosition()!=oldCamPos || mCamera->getOrientation()!=oldCamOri)
109                {
110                        somethingChanged = true;
111                        oldCamPos = mCamera->getPosition();
112                        oldCamOri = mCamera->getOrientation();
113                }
114               
115                if(somethingChanged)
116                        SharedData::getSingleton().iSystem->update();
117                return result;       
118        }
119
120        virtual bool processUnbufferedKeyInput(const FrameEvent& evt) {
121
122                bool retval = ExampleFrameListener::processUnbufferedKeyInput(evt);
123
124                // "C" switch filters
125                if (mInputDevice->isKeyDown(KC_C) && timeoutDelay==0)
126                {
127                        timeoutDelay = 0.5f;
128
129                        mode = (DeferredShadingSystem::DSMode)((int)mode+1);
130                        if(mode == DeferredShadingSystem::DSM_COUNT)
131                                mode = (DeferredShadingSystem::DSMode)1;
132
133                        SharedData::getSingleton().iSystem->setMode( mode );
134
135                        updateOverlays();
136                }
137
138                // "B" activate/deactivate minilight rendering
139                if (mInputDevice->isKeyDown(KC_B) && timeoutDelay==0)
140                {
141                        timeoutDelay = 0.5f;
142                        SharedData::getSingleton().iActivate = !SharedData::getSingleton().iActivate;
143                        // Hide/show all minilights
144                        std::vector<Node*>::iterator i = SharedData::getSingleton().mLightNodes.begin();
145                        std::vector<Node*>::iterator iend = SharedData::getSingleton().mLightNodes.end();
146                        for(; i!=iend; ++i)
147                        {
148                                static_cast<SceneNode*>(*i)->setVisible(SharedData::getSingleton().iActivate, true);
149                        }
150                       
151                        updateOverlays();
152                }
153                // "G" activate/deactivate global light rendering
154                if (mInputDevice->isKeyDown(KC_G) && timeoutDelay==0)
155                {
156                        timeoutDelay = 0.5f;
157                        SharedData::getSingleton().iGlobalActivate = !SharedData::getSingleton().iGlobalActivate;
158                        SharedData::getSingleton().iLight1->setVisible(SharedData::getSingleton().iGlobalActivate);
159                        SharedData::getSingleton().iLight2->setVisible(SharedData::getSingleton().iGlobalActivate);
160                        updateOverlays();
161                }
162
163                timeoutDelay -= evt.timeSinceLastFrame;
164                if (timeoutDelay <= 0) timeoutDelay = 0;
165
166                return retval;
167        }
168
169        void updateOverlays()
170        {
171
172                OverlayManager::getSingleton().getOverlayElement( "Example/Shadows/ShadowTechniqueInfo" )
173                        ->setCaption( "" );
174
175                OverlayManager::getSingleton().getOverlayElement( "Example/Shadows/MaterialInfo" )
176                        ->setCaption( "");
177
178                OverlayManager::getSingleton().getOverlayElement( "Example/Shadows/ShadowTechnique" )
179                        ->setCaption( "[B] MiniLights active: " + StringConverter::toString( SharedData::getSingleton().iActivate ) );
180
181                std::string name;
182                switch(mode)
183                {
184                case DeferredShadingSystem::DSM_SINGLEPASS:
185                        name="SinglePass"; break;
186                case DeferredShadingSystem::DSM_MULTIPASS:
187                        name="MultiPass"; break;
188                case DeferredShadingSystem::DSM_SHOWCOLOUR:
189                        name="ShowColour"; break;
190                case DeferredShadingSystem::DSM_SHOWNORMALS:
191                        name="ShowNormals"; break;
192                case DeferredShadingSystem::DSM_SHOWDSP:
193                        name="ShowDSP"; break;
194                }
195                OverlayManager::getSingleton().getOverlayElement( "Example/Shadows/Materials" )
196                        ->setCaption( "[C] Change mode, current is \"" + name + "\"");
197
198                OverlayManager::getSingleton().getOverlayElement( "Example/Shadows/Info" )
199                        ->setCaption( "[G] Global lights active: " + StringConverter::toString( SharedData::getSingleton().iGlobalActivate ) );
200
201        }
202};
203
204
205class RenderToTextureApplication : public ExampleApplication, public RenderTargetListener
206{
207public:
208    RenderToTextureApplication() : mPlane(0) {
209                new SharedData();
210                mPlane = 0;
211                mSystem = 0;
212        }
213   
214        ~RenderToTextureApplication()
215    {
216                delete ( SharedData::getSingletonPtr() );
217
218        delete mPlane;
219                delete mSystem;
220        }
221
222
223protected:
224    MovablePlane* mPlane;
225    Entity* mPlaneEnt;
226    SceneNode* mPlaneNode;
227        DeferredShadingSystem *mSystem;
228
229    // Just override the mandatory create scene method
230    void createScene(void)
231    {
232                RenderSystem *rs = Root::getSingleton().getRenderSystem();
233                const RenderSystemCapabilities* caps = rs->getCapabilities();
234        if (!caps->hasCapability(RSC_VERTEX_PROGRAM) || !(caps->hasCapability(RSC_FRAGMENT_PROGRAM)))
235        {
236            OGRE_EXCEPT(1, "Your card does not support vertex and fragment programs (or you selected D3D7), so cannot "
237                "run this demo. Sorry!",
238                "DeferredShading::createScene");
239        }
240                if (caps->numMultiRenderTargets()<2)
241        {
242            OGRE_EXCEPT(1, "Your card does not support at least two simulataneous render targets, so cannot "
243                "run this demo. Sorry!",
244                "DeferredShading::createScene");
245        }
246                MovableObject::setDefaultVisibilityFlags(0x00000001);
247                mSceneMgr->setVisibilityMask(0x00000001);
248                // Prepare athene mesh for normalmapping
249        MeshPtr pAthene = MeshManager::getSingleton().load("athene.mesh",
250            ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
251        unsigned short src, dest;
252        if (!pAthene->suggestTangentVectorBuildParams(src, dest))
253            pAthene->buildTangentVectors(src, dest);
254                // Prepare knot mesh for normal mapping
255                pAthene = MeshManager::getSingleton().load("knot.mesh",
256            ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
257        if (!pAthene->suggestTangentVectorBuildParams(src, dest))
258            pAthene->buildTangentVectors(src, dest);
259
260        // Set ambient light
261        mSceneMgr->setAmbientLight(ColourValue(0.2, 0.2, 0.15));
262        // Skybox
263        mSceneMgr->setSkyBox(true, "Test13/SkyBox");
264
265                // Create "root" node
266                SceneNode* rootNode = mSceneMgr->getRootSceneNode()->createChildSceneNode();
267
268        // Create a prefab plane
269        mPlane = new MovablePlane("ReflectPlane");
270        mPlane->d = 0;
271        mPlane->normal = Vector3::UNIT_Y;
272        MeshManager::getSingleton().createCurvedPlane("ReflectionPlane",
273            ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
274                        *mPlane,
275                        2000, 2000, -1000,
276            20, 20,
277                        true, 1, 10, 10, Vector3::UNIT_Z);
278        mPlaneEnt = mSceneMgr->createEntity( "Plane", "ReflectionPlane" );
279                mPlaneNode = rootNode->createChildSceneNode();
280        mPlaneNode->attachObject(mPlaneEnt);
281        mPlaneNode->translate(-5, -30, 0);
282        //mPlaneNode->roll(Degree(5));
283        mPlaneEnt->setMaterialName("Test13/Ground");
284
285        // Create an entity from a model (will be loaded automatically)
286        Entity* knotEnt = mSceneMgr->createEntity("Knot", "knot.mesh");
287                knotEnt->setMaterialName("Test13/RockWall");
288                knotEnt->setMeshLodBias(0.25f);
289
290        // Create an entity from a model (will be loaded automatically)
291        Entity* ogreHead = mSceneMgr->createEntity("Head", "ogrehead.mesh");
292                ogreHead->getSubEntity(0)->setMaterialName("Test13/DeferredOgre/Eyes");// eyes
293                ogreHead->getSubEntity(1)->setMaterialName("Test13/DeferredOgre/Skin");
294                ogreHead->getSubEntity(2)->setMaterialName("Test13/DeferredOgre/EarRing"); // earrings
295                ogreHead->getSubEntity(3)->setMaterialName("Test13/DeferredOgre/Tusks"); // tusks
296                rootNode->createChildSceneNode( "Head" )->attachObject( ogreHead );
297
298        Entity* athena = mSceneMgr->createEntity("Athena", "athene.mesh");
299                athena->setMaterialName("Test13/DeferredAthena");
300                SceneNode *aNode = rootNode->createChildSceneNode();
301                aNode->attachObject( athena );
302                aNode->setPosition(-100, 40, 100);
303
304        // Add a whole bunch of extra entities to fill the scene a bit
305        Entity *cloneEnt;
306                int N=4;
307        for (int n = 0; n < N; ++n)
308        {
309                        float theta = 2.0f*Math::PI*(float)n/(float)N;
310            // Create a new node under the root
311            SceneNode* node = mSceneMgr->createSceneNode();
312            // Random translate
313            Vector3 nodePos;
314            nodePos.x = Math::SymmetricRandom() * 40.0 + Math::Sin(theta) * 500.0;
315            nodePos.y = Math::SymmetricRandom() * 20.0 - 40.0;
316            nodePos.z = Math::SymmetricRandom() * 40.0 + Math::Cos(theta) * 500.0;
317            node->setPosition(nodePos);
318                        Quaternion orientation(Math::SymmetricRandom(),Math::SymmetricRandom(),Math::SymmetricRandom(),Math::SymmetricRandom());
319                        orientation.normalise();
320                        node->setOrientation(orientation);
321            rootNode->addChild(node);
322            // Clone knot
323            char cloneName[12];
324            sprintf(cloneName, "Knot%d", n);
325            cloneEnt = knotEnt->clone(cloneName);
326            // Attach to new node
327            node->attachObject(cloneEnt);
328
329        }
330
331        mCamera->setPosition(-50, 100, 500);
332        mCamera->lookAt(0,0,0);
333
334                // show overlay
335                Overlay* overlay = OverlayManager::getSingleton().getByName("Example/ShadowsOverlay");   
336                overlay->show();
337
338                mSystem = new DeferredShadingSystem(mWindow->getViewport(0), mSceneMgr, mCamera);
339
340               
341                // Create a light
342        MLight* l = mSystem->createMLight();//"SunLight");
343        //l->setType(Light::LT_POINT);
344        //l->setPosition(600.0, 1000.0, 200.0);
345        l->setDiffuseColour(1.0f, 0.6f, 0.2f);
346        l->setSpecularColour(0.3f, 0.15f, 0.06f);
347                //l->setDiffuseColour(0.0f, 0.0f, 0.0f);
348                //l->setSpecularColour(0.0f, 0.0f, 0.0f);
349               
350                // Create moving light
351                MLight* l2 = mSystem->createMLight();//"MainLight2");
352        //l2->setType(Light::LT_POINT);
353        l2->setDiffuseColour(0.75f, 0.7f, 0.8f);
354                l2->setSpecularColour(0.85f, 0.9f, 1.0f);
355               
356                SceneNode *lightNode = mSceneMgr->getRootSceneNode()->createChildSceneNode();
357                lightNode->attachObject(l2);
358
359                // Create a track for the light
360        Animation* anim = mSceneMgr->createAnimation("LightTrack", 16);
361        // Spline it for nice curves
362        anim->setInterpolationMode(Animation::IM_SPLINE);
363        // Create a track to animate the camera's node
364        NodeAnimationTrack* track = anim->createNodeTrack(0, lightNode);
365        // Setup keyframes
366        TransformKeyFrame* key = track->createNodeKeyFrame(0); // A startposition
367        key->setTranslate(Vector3(300,300,-300));
368        key = track->createNodeKeyFrame(4);//B
369        key->setTranslate(Vector3(300,300,300));
370        key = track->createNodeKeyFrame(8);//C
371        key->setTranslate(Vector3(-300,300,300));
372        key = track->createNodeKeyFrame(12);//D
373        key->setTranslate(Vector3(-300,300,-300));
374                key = track->createNodeKeyFrame(16);//D
375        key->setTranslate(Vector3(300,300,-300));
376        // Create a new animation state to track this
377        SharedData::getSingleton().mAnimState = mSceneMgr->createAnimationState("LightTrack");
378        SharedData::getSingleton().mAnimState->setEnabled(true);
379
380                // Create some happy little lights
381                createSampleLights();
382
383                // safely setup application's (not postfilter!) shared data
384                SharedData::getSingleton().iCamera = mCamera;
385                SharedData::getSingleton().iRoot = mRoot;
386                SharedData::getSingleton().iWindow = mWindow;
387                SharedData::getSingleton().iActivate = true;
388                SharedData::getSingleton().iGlobalActivate = true;
389                SharedData::getSingleton().iSceneMgr = mSceneMgr;
390                SharedData::getSingleton().iSystem = mSystem;
391                SharedData::getSingleton().iLight1 = l;
392                SharedData::getSingleton().iLight2 = l2;
393        }
394
395    void createFrameListener(void)
396    {
397        mFrameListener= new RenderToTextureFrameListener(mWindow, mCamera);
398                // initialize overlays
399                static_cast<RenderToTextureFrameListener*>(mFrameListener)->updateOverlays();
400        mRoot->addFrameListener(mFrameListener);
401    }
402
403        void createSampleLights()
404        {
405                // Create some lights           
406                std::vector<MLight*> lights;
407                SceneNode *parentNode = mSceneMgr->getRootSceneNode()->createChildSceneNode("LightsParent");
408                // Create light nodes
409                std::vector<Node*> nodes;
410
411                MLight *a = mSystem->createMLight();
412                SceneNode *an = parentNode->createChildSceneNode();
413                an->attachObject(a);
414                a->setAttenuation(1.0f, 0.001f, 0.002f);
415                //a->setAttenuation(1.0f, 0.000f, 0.000f);
416                an->setPosition(0,0,25);
417                a->setDiffuseColour(1,0,0);
418                //a->setSpecularColour(0.5,0,0);
419                lights.push_back(a);
420                nodes.push_back(an);
421
422                MLight *b = mSystem->createMLight();
423                SceneNode *bn = parentNode->createChildSceneNode();
424                bn->attachObject(b);
425                b->setAttenuation(1.0f, 0.001f, 0.003f);
426                bn->setPosition(25,0,0);
427                b->setDiffuseColour(1,1,0);
428                //b->setSpecularColour(0.5,0.5,0);
429                lights.push_back(b);
430                nodes.push_back(bn);
431
432                MLight *c = mSystem->createMLight();
433                SceneNode *cn = parentNode->createChildSceneNode();
434                cn->attachObject(c);
435                c->setAttenuation(1.0f, 0.001f, 0.004f);
436                cn->setPosition(0,0,-25);
437                c->setDiffuseColour(0,1,1);
438                c->setSpecularColour(0.25,1.0,1.0); // Cyan light has specular component
439                lights.push_back(c);
440                nodes.push_back(cn);
441
442                MLight *d = mSystem->createMLight();
443                SceneNode *dn = parentNode->createChildSceneNode();
444                dn->attachObject(d);
445                d->setAttenuation(1.0f, 0.002f, 0.002f);
446                dn->setPosition(-25,0,0);
447                d->setDiffuseColour(1,0,1);
448                d->setSpecularColour(0.0,0,0.0);
449                lights.push_back(d);
450                nodes.push_back(dn);
451
452                MLight *e = mSystem->createMLight();
453                SceneNode *en = parentNode->createChildSceneNode();
454                en->attachObject(e);
455                e->setAttenuation(1.0f, 0.002f, 0.0025f);
456                en->setPosition(25,0,25);
457                e->setDiffuseColour(0,0,1);
458                e->setSpecularColour(0,0,0);
459                lights.push_back(e);
460                nodes.push_back(en);
461               
462                MLight *f = mSystem->createMLight();
463                SceneNode *fn = parentNode->createChildSceneNode();
464                fn->attachObject(f);
465                f->setAttenuation(1.0f, 0.0015f, 0.0021f);
466                fn->setPosition(-25,0,-25);
467                f->setDiffuseColour(0,1,0);
468                f->setSpecularColour(0,0.0,0.0);
469                lights.push_back(f);
470                nodes.push_back(fn);
471
472                // Create marker meshes to show user where the lights are
473                Entity *ent;
474                createSphere("PointLightMesh", 1.0f, 5, 5);
475                for(std::vector<MLight*>::iterator i=lights.begin(); i!=lights.end(); ++i)
476                {
477                        ent = mSceneMgr->createEntity((*i)->getName()+"v", "PointLightMesh");
478                        String matname = (*i)->getName()+"m";
479                        // Create coloured material
480                        MaterialPtr mat = MaterialManager::getSingleton().create(matname,
481                ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
482            Pass* pass = mat->getTechnique(0)->getPass(0);
483            pass->setDiffuse(0.0f,0.0f,0.0f,1.0f);
484                        pass->setAmbient(0.0f,0.0f,0.0f);
485                        pass->setSelfIllumination((*i)->getDiffuseColour());
486
487                        ent->setMaterialName(matname);
488                        ent->setVisibilityFlags(DeferredShadingSystem::PostVisibilityMask);
489                        static_cast<SceneNode*>((*i)->getParentNode())->attachObject(ent);
490                }               
491
492                // Store nodes for hiding/showing
493                SharedData::getSingleton().mLightNodes = nodes;
494
495                // Do some animation for node a-f
496                // Generate helix structure
497                float seconds_per_station = 1.0f;
498                float r=35;
499                //Vector3 base(0,-30,0);
500                Vector3 base(-100, -30, 85);
501
502                float h=120;
503                const size_t s_to_top = 16;
504                const size_t stations = s_to_top*2-1;
505                float ascend = h/((float)s_to_top);
506                float stations_per_revolution = 3.5f;
507                size_t skip = 2; // stations between lights
508                Vector3 station_pos[stations];
509                for(int x=0; x<s_to_top; ++x)
510                {
511                        float theta = ((float)x/stations_per_revolution)*2.0f*Math::PI;
512                        station_pos[x] = base+Vector3(Math::Sin(theta)*r, ascend*x, Math::Cos(theta)*r);
513                }
514                for(int x=s_to_top; x<stations; ++x)
515                {
516                        float theta = ((float)x/stations_per_revolution)*2.0f*Math::PI;
517                        station_pos[x] = base+Vector3(Math::Sin(theta)*r, h-ascend*(x-s_to_top), Math::Cos(theta)*r);
518                }
519                // Create a track for the light swarm
520                Animation* anim = mSceneMgr->createAnimation("LightSwarmTrack", stations*seconds_per_station);
521                // Spline it for nice curves
522                anim->setInterpolationMode(Animation::IM_SPLINE);
523                for(unsigned int x=0; x<nodes.size(); ++x)
524                {
525                        // Create a track to animate the camera's node
526                        NodeAnimationTrack* track = anim->createNodeTrack(x, nodes[x]);
527                        for(int y=0; y<=stations; ++y)
528                        {
529                                // Setup keyframes
530                                TransformKeyFrame* key = track->createNodeKeyFrame(y*seconds_per_station); // A startposition
531                                key->setTranslate(station_pos[(x*skip+y)%stations]);
532                                // Make sure size of light doesn't change
533                                key->setScale(nodes[x]->getScale());
534                        }
535                }
536                // Create a new animation state to track this
537                SharedData::getSingleton().mMLAnimState = mSceneMgr->createAnimationState("LightSwarmTrack");
538                SharedData::getSingleton().mMLAnimState->setEnabled(true);
539        }
540
541};
542
543
544
545
546
547#ifdef __cplusplus
548extern "C" {
549#endif
550
551//#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
552//      INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE, LPSTR strCmdLine, INT )
553//#else
554        int main(int argc, char *argv[])
555//#endif
556        {
557                // Create application object
558                RenderToTextureApplication app;
559
560                SET_TERM_HANDLER;
561
562                try {
563                        app.go();
564                } catch( Ogre::Exception& e ) {
565#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
566                        MessageBox( NULL, e.getFullDescription().c_str(), "An exception has occured!", MB_OK | MB_ICONERROR | MB_TASKMODAL);
567#else
568                        std::cerr << "An exception has occured: " <<
569                                e.getFullDescription().c_str() << std::endl;
570#endif
571                }
572
573                return 0;
574        }
575
576#ifdef __cplusplus
577}
578#endif
579
580
Note: See TracBrowser for help on using the repository browser.