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

Revision 4631, 12.6 kB (checked in by robert, 8 years ago)

Moved SceneView? across to use an osg::CameraNode? to store the projection and view matrices,
the viewport, the clear colour and the subgraph needing rendered. This is done
transparently so all existing functionality will behave as before. What it does
add is the ability to set a SceneView? directly by a single osg::CameraNode? when required.

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