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

Revision 4482, 10.9 kB (checked in by robert, 9 years ago)

Add comments explain how example works.

  • 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
17#include <map>
18#include <list>
19#include <iostream>
20
21
22
23////////////////////////////////////////////////////////////////////////////////
24//
25//
26//  **************** THIS IS AN EXPERIMENTAL IMPLEMENTATION ***************
27//  ************************** PLEASE DO NOT COPY  ************************
28//
29//
30///////////////////////////////////////////////////////////////////////////////
31
32
33// Compile operation, that compile OpenGL objects.
34struct CompileOperation : public osg::GraphicsThread::Operation
35{
36    CompileOperation(osg::Node* scene):
37        osg::GraphicsThread::Operation("Compile",false),
38        _scene(scene)
39    {
40    }
41   
42    virtual void operator () (osg::GraphicsContext* context)
43    {
44        std::cout<<"Compile"<<std::endl;
45   
46        osgUtil::GLObjectsVisitor compileVisitor;
47        compileVisitor.setState(context->getState());
48
49        // do the compile traversal
50        _scene->accept(compileVisitor);
51    }
52   
53    osg::ref_ptr<osg::Node> _scene;
54};
55
56// Frame operation, that does a cull and draw on the scene graph.
57struct FrameOperation : public osg::GraphicsThread::Operation
58{
59    FrameOperation(osg::CameraNode* camera, osg::FrameStamp* frameStamp):
60        osg::GraphicsThread::Operation("Frame",true),
61        _camera(camera),
62        _frameStamp(frameStamp)
63    {
64        _sceneView = new osgUtil::SceneView;
65        _sceneView->setDefaults();
66        _sceneView->setFrameStamp(_frameStamp.get());
67           
68        if (camera->getNumChildren()>=1)
69        {
70            _sceneView->setSceneData(camera->getChild(0));
71        }
72    }
73   
74    virtual void operator () (osg::GraphicsContext* context)
75    {
76        _sceneView->setState(context->getState());
77        _sceneView->setProjectionMatrix(_camera->getProjectionMatrix());
78        _sceneView->setViewMatrix(_camera->getViewMatrix());
79        _sceneView->setViewport(_camera->getViewport());
80       
81        _sceneView->cull();
82        _sceneView->draw();
83    }
84   
85    osg::ref_ptr<osg::CameraNode>    _camera;
86    osg::ref_ptr<osg::FrameStamp>    _frameStamp;
87    osg::ref_ptr<osgUtil::SceneView> _sceneView;
88};
89
90
91// main does the following steps to create a multi-thread, multiple camera/graphics context view of a scene graph.
92//
93// 1) load the scene graph
94//
95// 2) create a list of camera, each with their own graphis context, with a graphics thread for each context.
96//
97// 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
98//
99// 4) set up the graphics thread so that it has all the graphics ops required for the main loop, these ops are:
100// 4.a) frame begin barrair, syncronizes all the waiting graphic threads so they don't run while update is occuring
101// 4.b) frame operation - the cull and draw for each camera
102// 4.c) frame end barrier, releases the update thread once all graphic threads have dispatched all their OpenGL commands
103// 4.d) pre swap barrier, barrier which ensures that all graphics threads have sent their data down to the gfx card.
104// 4.e) swap buffers, do the swap buffers on all the graphics contexts.
105//
106// 5. The main loop:
107// 5.a) update
108// 5.b) join the frame begin barrrier, releasing all the graphics threads to do their stuff
109// 5.c) block on the frame end barrier, waiting till all the graphics threads have done their cull/draws.
110// 5.d) check to see if any of the windows has been closed.
111//
112int main( int argc, char **argv )
113{
114    if (argc<2)
115    {
116        std::cout << argv[0] <<": requires filename argument." << std::endl;
117        return 1;
118    }
119
120    // load the scene.
121    osg::ref_ptr<osg::Node> loadedModel = osgDB::readNodeFile(argv[1]);
122    if (!loadedModel)
123    {
124        std::cout << argv[0] <<": No data loaded." << std::endl;
125        return 1;
126    }
127
128   
129    // set up the frame stamp for current frame to record the current time and frame number so that animtion code can advance correctly
130    osg::ref_ptr<osg::FrameStamp> frameStamp = new osg::FrameStamp;
131
132    unsigned int frameNum = 0;
133
134    osgUtil::UpdateVisitor updateVisitor;
135    updateVisitor.setFrameStamp(frameStamp.get());
136
137
138    unsigned int numberCameras = 3;
139    unsigned int xpos = 0;
140    unsigned int ypos = 400;
141    unsigned int width = 400;
142    unsigned int height = 400;
143   
144    typedef std::list< osg::ref_ptr<osg::CameraNode> > CameraList;
145    typedef std::set< osg::GraphicsContext* > GraphicsContextSet;
146
147    CameraList cameraList;
148    GraphicsContextSet graphicsContextSet;
149
150    // create the cameras, graphic contexts and graphic threads.
151    bool shareContexts = false;
152    osg::GraphicsContext* previousContext = 0;
153    for(unsigned int i=0; i< numberCameras; ++i)
154    {
155        osg::ref_ptr<osg::CameraNode> camera = new osg::CameraNode;
156        camera->addChild(loadedModel.get());
157
158        osg::ref_ptr<osg::GraphicsContext::Traits> traits = new osg::GraphicsContext::Traits;
159        traits->_windowName = "osgcamera";
160        traits->_x = xpos;
161        traits->_y = ypos;
162        traits->_width = width;
163        traits->_height = height;
164        traits->_windowDecoration = true;
165        traits->_doubleBuffer = true;
166        traits->_sharedContext = shareContexts ? previousContext : 0;
167       
168        xpos += width;
169
170        osg::ref_ptr<osg::GraphicsContext> gfxc = osg::GraphicsContext::createGraphicsContext(traits.get());
171
172        if (!gfxc)
173        {
174            std::cout<<"Unable to create window."<<std::endl;
175            return 1;
176        }
177
178        camera->setGraphicsContext(gfxc.get());
179
180        // initialize the view to look at the center of the scene graph
181        const osg::BoundingSphere& bs = loadedModel->getBound();
182        osg::Matrix viewMatrix;
183        viewMatrix.makeLookAt(bs.center()-osg::Vec3(0.0,2.0f*bs.radius(),0.0),bs.center(),osg::Vec3(0.0f,0.0f,1.0f));
184
185        camera->setViewport(0,0,traits->_width,traits->_height);
186        camera->setProjectionMatrixAsPerspective(50.0f,1.4f,1.0f,10000.0f);
187        camera->setViewMatrix(viewMatrix);
188
189        // graphics thread will realize the window.
190        gfxc->createGraphicsThread();
191
192        cameraList.push_back(camera);
193
194        previousContext = gfxc.get();
195    }
196
197
198    // build the list of unique graphics contexts.
199    CameraList::iterator citr;
200    for(citr = cameraList.begin();
201        citr != cameraList.end();
202        ++citr)
203    {
204        graphicsContextSet.insert(const_cast<osg::GraphicsContext*>((*citr)->getGraphicsContext()));
205    }
206
207
208    std::cout<<"Number of cameras = "<<cameraList.size()<<std::endl;
209    std::cout<<"Number of graphics contexts = "<<graphicsContextSet.size()<<std::endl;
210
211
212    // first the compile of the GL Objects, do it syncronously.
213    GraphicsContextSet::iterator gitr;
214    osg::ref_ptr<CompileOperation> compileOp = new CompileOperation(loadedModel.get());
215    for(gitr = graphicsContextSet.begin();
216        gitr != graphicsContextSet.end();
217        ++gitr)
218    {
219        osg::GraphicsContext* context = *gitr;
220        context->getGraphicsThread()->add(compileOp.get(), true);
221    }
222
223
224    // second the begin frame barrier to all graphics threads
225    osg::ref_ptr<osg::BarrierOperation> frameBeginBarrierOp = new osg::BarrierOperation(graphicsContextSet.size()+1, osg::BarrierOperation::NO_OPERATION);
226    for(gitr = graphicsContextSet.begin();
227        gitr != graphicsContextSet.end();
228        ++gitr)
229    {
230        osg::GraphicsContext* context = *gitr;
231        context->getGraphicsThread()->add(frameBeginBarrierOp.get(), false);
232    }
233
234    // third add the frame for each camera.
235    for(citr = cameraList.begin();
236        citr != cameraList.end();
237        ++citr)
238    {
239        osg::CameraNode* camera = citr->get();
240        camera->getGraphicsContext()->getGraphicsThread()->add( new FrameOperation(camera, frameStamp.get()), false);
241    }
242
243    // fourth add the frame end barrier, the pre swap barrier and finally the swap buffers to each graphics thread.
244    // The frame end barrier tells the main thead that the draw dispatch/read phase of the scene graph is complete.
245    // The pre swap barrier is an optional extra, which does a flush before joining the barrier, using this all graphics threads
246    // are held back until they have all dispatched their fifo to the graphics hardware. 
247    // The swapOp just issues a swap buffers for each of the graphics contexts.
248    // The post swap barrier is an optional extra which does a glFinish after the swap buffers.
249    osg::ref_ptr<osg::BarrierOperation> frameEndBarrierOp = new osg::BarrierOperation(graphicsContextSet.size()+1, osg::BarrierOperation::NO_OPERATION);
250    osg::ref_ptr<osg::BarrierOperation> preSwapBarrierOp = new osg::BarrierOperation(graphicsContextSet.size(), osg::BarrierOperation::GL_FLUSH);
251    osg::ref_ptr<osg::SwapBuffersOperation> swapOp = new osg::SwapBuffersOperation();
252    osg::ref_ptr<osg::BarrierOperation> postSwapBarrierOp = new osg::BarrierOperation(graphicsContextSet.size(), osg::BarrierOperation::GL_FINISH);
253    bool waitTillSwapBufferFinished = false;
254    for(gitr = graphicsContextSet.begin();
255        gitr != graphicsContextSet.end();
256        ++gitr)
257    {
258        osg::GraphicsContext* context = *gitr;
259        context->getGraphicsThread()->add(frameEndBarrierOp.get(), false);
260        context->getGraphicsThread()->add(preSwapBarrierOp.get(), false);
261        context->getGraphicsThread()->add(swapOp.get(), false);
262        if (waitTillSwapBufferFinished) context->getGraphicsThread()->add(postSwapBarrierOp.get(), false);
263    }
264
265
266    // record the timer tick at the start of rendering.   
267    osg::Timer_t start_tick = osg::Timer::instance()->tick();
268    osg::Timer_t previous_tick = start_tick;
269   
270    bool done = false;   
271
272    // main loop -  update scene graph, dispatch frame, wait for frame done.
273    while( !done )
274    {
275
276        osg::Timer_t current_tick = osg::Timer::instance()->tick();
277
278        frameStamp->setReferenceTime(osg::Timer::instance()->delta_s(start_tick,current_tick));
279        frameStamp->setFrameNumber(frameNum++);
280       
281        std::cout<<"Frame rate "<<1.0/osg::Timer::instance()->delta_s(previous_tick,current_tick)<<std::endl;
282        previous_tick = current_tick;
283
284
285        // do the update traversal.
286        loadedModel->accept(updateVisitor);
287
288        // dispatch the frame.
289        frameBeginBarrierOp->block();
290       
291        // wait till the frame is done.
292        frameEndBarrierOp->block();
293
294        // check if any of the windows are closed
295        for(gitr = graphicsContextSet.begin();
296            gitr != graphicsContextSet.end();
297            ++gitr)
298        {
299            osg::GraphicsContext* context = *gitr;
300            if (!context->isRealized()) done = true;
301        }
302
303    }
304    return 0;
305}
Note: See TracBrowser for help on using the browser.