root/OpenSceneGraph/trunk/examples/osgcamera/osgcamera.cpp @ 4488

Revision 4488, 12.6 kB (checked in by robert, 9 years ago)

Removed circular reference of osg::CameraNode?, fixing memory leak. Added
a auto exit after a maximum number of frames are completed.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1// C++ source file - (C) 2003 Robert Osfield, released under the OSGPL.
2//
3// Simple example of use of Producer::RenderSurface to create an OpenGL
4// graphics window, and OSG for rendering.
5
6#include <osg/Timer>
7#include <osg/GraphicsContext>
8#include <osg/GraphicsThread>
9
10#include <osgUtil/UpdateVisitor>
11#include <osgUtil/CullVisitor>
12#include <osgUtil/SceneView>
13#include <osgUtil/GLObjectsVisitor>
14
15#include <osgDB/ReadFile>
16#include <osgDB/DynamicLibrary>
17#include <osgDB/Registry>
18
19#include <map>
20#include <list>
21#include <iostream>
22
23
24
25////////////////////////////////////////////////////////////////////////////////
26//
27//
28//  **************** THIS IS AN EXPERIMENTAL IMPLEMENTATION ***************
29//  ************************** PLEASE DO NOT COPY  ************************
30//
31//
32///////////////////////////////////////////////////////////////////////////////
33
34
35// Compile operation, that compile OpenGL objects.
36struct CompileOperation : public osg::GraphicsThread::Operation
37{
38    CompileOperation(osg::Node* scene):
39        osg::GraphicsThread::Operation("Compile",false),
40        _scene(scene)
41    {
42    }
43   
44    virtual void operator () (osg::GraphicsContext* context)
45    {
46        std::cout<<"Compile"<<std::endl;
47   
48        osgUtil::GLObjectsVisitor compileVisitor;
49        compileVisitor.setState(context->getState());
50
51        // do the compile traversal
52        _scene->accept(compileVisitor);
53    }
54   
55    osg::ref_ptr<osg::Node> _scene;
56};
57
58// Cull operation, that does a cull on the scene graph.
59struct CullOperation : public osg::GraphicsThread::Operation
60{
61    CullOperation(osg::CameraNode* camera, osgUtil::SceneView* sceneView):
62        osg::GraphicsThread::Operation("Cull",true),
63        _camera(camera),
64        _sceneView(sceneView)
65    {
66    }
67   
68    virtual void operator () (osg::GraphicsContext* context)
69    {
70        _sceneView->setState(context->getState());
71        _sceneView->setProjectionMatrix(_camera->getProjectionMatrix());
72        _sceneView->setViewMatrix(_camera->getViewMatrix());
73        _sceneView->setViewport(_camera->getViewport());
74       
75        _sceneView->cull();
76    }
77   
78    osg::CameraNode*                 _camera;
79    osg::ref_ptr<osgUtil::SceneView> _sceneView;
80};
81
82// Draw operation, that does a draw on the scene graph.
83struct DrawOperation : public osg::GraphicsThread::Operation
84{
85    DrawOperation(osgUtil::SceneView* sceneView):
86        osg::GraphicsThread::Operation("Draw",true),
87        _sceneView(sceneView)
88    {
89    }
90   
91    virtual void operator () (osg::GraphicsContext*)
92    {
93        _sceneView->draw();
94    }
95   
96    osg::ref_ptr<osgUtil::SceneView> _sceneView;
97};
98
99
100// main does the following steps to create a multi-thread, multiple camera/graphics context view of a scene graph.
101//
102// 1) load the scene graph
103//
104// 2) create a list of camera, each with their own graphis context, with a graphics thread for each context.
105//
106// 3) set up the graphic threads so that the do an initial compile OpenGL objects operation, this is done once, and then this compile op is disgarded
107//
108// 4) set up the graphics thread so that it has all the graphics ops required for the main loop, these ops are:
109// 4.a) frame begin barrair, syncronizes all the waiting graphic threads so they don't run while update is occuring
110// 4.b) frame operation - the cull and draw for each camera
111// 4.c) frame end barrier, releases the update thread once all graphic threads have dispatched all their OpenGL commands
112// 4.d) pre swap barrier, barrier which ensures that all graphics threads have sent their data down to the gfx card.
113// 4.e) swap buffers, do the swap buffers on all the graphics contexts.
114//
115// 5. The main loop:
116// 5.a) update
117// 5.b) join the frame begin barrrier, releasing all the graphics threads to do their stuff
118// 5.c) block on the frame end barrier, waiting till all the graphics threads have done their cull/draws.
119// 5.d) check to see if any of the windows has been closed.
120//
121int main( int argc, char **argv )
122{
123
124    if (argc<2)
125    {
126        std::cout << argv[0] <<": requires filename argument." << std::endl;
127        return 1;
128    }
129
130    // load the osgProducer library manually.
131    osg::ref_ptr<osgDB::DynamicLibrary> osgProducerLib =
132            osgDB::DynamicLibrary::loadLibrary(osgDB::Registry::instance()->createLibraryNameForNodeKit("osgProducer"));
133
134
135    // load the scene.
136    osg::ref_ptr<osg::Node> loadedModel = osgDB::readNodeFile(argv[1]);
137    if (!loadedModel)
138    {
139        std::cout << argv[0] <<": No data loaded." << std::endl;
140        return 1;
141    }
142
143   
144    // set up the frame stamp for current frame to record the current time and frame number so that animtion code can advance correctly
145    osg::ref_ptr<osg::FrameStamp> frameStamp = new osg::FrameStamp;
146
147    unsigned int frameNum = 0;
148
149    osgUtil::UpdateVisitor updateVisitor;
150    updateVisitor.setFrameStamp(frameStamp.get());
151
152
153    unsigned int numberCameras = 3;
154    unsigned int xpos = 0;
155    unsigned int ypos = 400;
156    unsigned int width = 400;
157    unsigned int height = 400;
158   
159    typedef std::list< osg::ref_ptr<osg::CameraNode> > CameraList;
160    typedef std::set< osg::GraphicsContext* > GraphicsContextSet;
161
162    CameraList cameraList;
163    GraphicsContextSet graphicsContextSet;
164
165    // create the cameras, graphic contexts and graphic threads.
166    bool shareContexts = false;
167    osg::GraphicsContext* previousContext = 0;
168    for(unsigned int i=0; i< numberCameras; ++i)
169    {
170        osg::ref_ptr<osg::CameraNode> camera = new osg::CameraNode;
171        camera->addChild(loadedModel.get());
172
173        osg::ref_ptr<osg::GraphicsContext::Traits> traits = new osg::GraphicsContext::Traits;
174        traits->_windowName = "osgcamera";
175        traits->_x = xpos;
176        traits->_y = ypos;
177        traits->_width = width;
178        traits->_height = height;
179        traits->_windowDecoration = true;
180        traits->_doubleBuffer = true;
181        traits->_sharedContext = shareContexts ? previousContext : 0;
182       
183        xpos += width;
184
185        osg::ref_ptr<osg::GraphicsContext> gfxc = osg::GraphicsContext::createGraphicsContext(traits.get());
186
187        if (!gfxc)
188        {
189            std::cout<<"Unable to create window."<<std::endl;
190            return 1;
191        }
192
193        camera->setGraphicsContext(gfxc.get());
194
195        // initialize the view to look at the center of the scene graph
196        const osg::BoundingSphere& bs = loadedModel->getBound();
197        osg::Matrix viewMatrix;
198        viewMatrix.makeLookAt(bs.center()-osg::Vec3(0.0,2.0f*bs.radius(),0.0),bs.center(),osg::Vec3(0.0f,0.0f,1.0f));
199
200        camera->setViewport(0,0,traits->_width,traits->_height);
201        camera->setProjectionMatrixAsPerspective(50.0f,1.4f,1.0f,10000.0f);
202        camera->setViewMatrix(viewMatrix);
203
204        // graphics thread will realize the window.
205        gfxc->createGraphicsThread();
206
207        cameraList.push_back(camera);
208
209        previousContext = gfxc.get();
210    }
211
212
213    // build the list of unique graphics contexts.
214    CameraList::iterator citr;
215    for(citr = cameraList.begin();
216        citr != cameraList.end();
217        ++citr)
218    {
219        graphicsContextSet.insert(const_cast<osg::GraphicsContext*>((*citr)->getGraphicsContext()));
220    }
221
222
223    std::cout<<"Number of cameras = "<<cameraList.size()<<std::endl;
224    std::cout<<"Number of graphics contexts = "<<graphicsContextSet.size()<<std::endl;
225
226
227    // first the compile of the GL Objects, do it syncronously.
228    GraphicsContextSet::iterator gitr;
229    osg::ref_ptr<CompileOperation> compileOp = new CompileOperation(loadedModel.get());
230    for(gitr = graphicsContextSet.begin();
231        gitr != graphicsContextSet.end();
232        ++gitr)
233    {
234        osg::GraphicsContext* context = *gitr;
235        context->getGraphicsThread()->add(compileOp.get(), false);
236    }
237
238
239    // second the begin frame barrier to all graphics threads
240    osg::ref_ptr<osg::BarrierOperation> frameBeginBarrierOp = new osg::BarrierOperation(graphicsContextSet.size()+1, osg::BarrierOperation::NO_OPERATION);
241    for(gitr = graphicsContextSet.begin();
242        gitr != graphicsContextSet.end();
243        ++gitr)
244    {
245        osg::GraphicsContext* context = *gitr;
246        context->getGraphicsThread()->add(frameBeginBarrierOp.get(), false);
247    }
248
249    osg::ref_ptr<osg::BarrierOperation> glFinishBarrierOp = new osg::BarrierOperation(graphicsContextSet.size(), osg::BarrierOperation::GL_FINISH);
250
251    // we can put a finish in to gate rendering throughput, so that each new frame starts with a clean sheet.
252    // you should only enable one of these, doFinishBeforeNewDraw will allow for the better parallism of the two finish approaches
253    // note, both are disabled right now, as glFinish is spin locking the CPU, not something that we want...
254    bool doFinishBeforeNewDraw = false;
255    bool doFinishAfterSwap = false;
256
257    // third add the frame for each camera.
258    for(citr = cameraList.begin();
259        citr != cameraList.end();
260        ++citr)
261    {
262        osg::CameraNode* camera = citr->get();
263       
264        // create a scene view to do the cull and draw
265        osgUtil::SceneView* sceneView = new osgUtil::SceneView;
266        sceneView->setDefaults();
267        sceneView->setFrameStamp(frameStamp.get());
268           
269        if (camera->getNumChildren()>=1)
270        {
271            sceneView->setSceneData(camera->getChild(0));
272        }
273
274        // cull traversal operation
275        camera->getGraphicsContext()->getGraphicsThread()->add( new CullOperation(camera, sceneView), false);
276
277        // optionally add glFinish barrier to ensure that all OpenGL commands are completed before we start dispatching a new frame
278        if (doFinishBeforeNewDraw) camera->getGraphicsContext()->getGraphicsThread()->add( glFinishBarrierOp.get(), false);
279
280        // draw traversal operation.
281        camera->getGraphicsContext()->getGraphicsThread()->add( new DrawOperation(sceneView), false);
282    }
283
284    // fourth add the frame end barrier, the pre swap barrier and finally the swap buffers to each graphics thread.
285    // The frame end barrier tells the main thead that the draw dispatch/read phase of the scene graph is complete.
286    // The pre swap barrier is an optional extra, which does a flush before joining the barrier, using this all graphics threads
287    // are held back until they have all dispatched their fifo to the graphics hardware. 
288    // The swapOp just issues a swap buffers for each of the graphics contexts.
289    osg::ref_ptr<osg::BarrierOperation> frameEndBarrierOp = new osg::BarrierOperation(graphicsContextSet.size()+1, osg::BarrierOperation::NO_OPERATION);
290    osg::ref_ptr<osg::BarrierOperation> preSwapBarrierOp = new osg::BarrierOperation(graphicsContextSet.size(), osg::BarrierOperation::GL_FLUSH);
291    osg::ref_ptr<osg::SwapBuffersOperation> swapOp = new osg::SwapBuffersOperation();
292    for(gitr = graphicsContextSet.begin();
293        gitr != graphicsContextSet.end();
294        ++gitr)
295    {
296        osg::GraphicsContext* context = *gitr;
297
298        context->getGraphicsThread()->add(frameEndBarrierOp.get(), false);
299        // context->getGraphicsThread()->add(preSwapBarrierOp.get(), false);
300        context->getGraphicsThread()->add(swapOp.get(), false);
301       
302        // optionally add finish barrier to ensure that we don't do any other graphics work till the current OpenGL commands are complete.
303        if (doFinishAfterSwap) context->getGraphicsThread()->add(glFinishBarrierOp.get(), false);
304    }
305
306
307    // record the timer tick at the start of rendering.   
308    osg::Timer_t start_tick = osg::Timer::instance()->tick();
309    osg::Timer_t previous_tick = start_tick;
310   
311    bool done = false;
312    unsigned int maxNumFrames = 500;
313
314    // main loop -  update scene graph, dispatch frame, wait for frame done.
315    while( !done && frameNum<maxNumFrames)
316    {
317
318        osg::Timer_t current_tick = osg::Timer::instance()->tick();
319
320        frameStamp->setReferenceTime(osg::Timer::instance()->delta_s(start_tick,current_tick));
321        frameStamp->setFrameNumber(frameNum++);
322       
323        //std::cout<<"Frame rate "<<1.0/osg::Timer::instance()->delta_s(previous_tick,current_tick)<<std::endl;
324        previous_tick = current_tick;
325
326
327        // do the update traversal.
328        loadedModel->accept(updateVisitor);
329
330        // dispatch the frame.
331        frameBeginBarrierOp->block();
332       
333        // wait till the frame is done.
334        frameEndBarrierOp->block();
335
336        // check if any of the windows are closed
337        for(gitr = graphicsContextSet.begin();
338            gitr != graphicsContextSet.end();
339            ++gitr)
340        {
341            osg::GraphicsContext* context = *gitr;
342            if (!context->isRealized()) done = true;
343        }
344
345    }
346
347    // delete the cameras, associated contexts and threads.
348    cameraList.clear();
349   
350    std::cout<<"Exiting application"<<std::endl;
351
352    return 0;
353}
Note: See TracBrowser for help on using the browser.