OpenSceneGraph的例子中有如何在MFC中使用OSG的,也有如何在控制台中使用多视图多窗口渲染的例子,但是如果只是将这两个例子简单的结合在一起的话程序是会出问题的。还有一些细节上面的变化需要注意,在这里记录一下。主要的修改步骤如下,在OSG自带的结合MFC的例子中做的修改。
1.在cOSG中还添加两个成员变量,修改之前默认的mViewer对象的类型
osg::ref_ptr<osgViewer::CompositeViewer> viewer ; osg::ref_ptr<osgViewer::View> view2; osgViewer::View* mViewer;
这样这个工程里面就有了一个osgViewer::CompositeViewer对象,两个osgViewer::View类的对象(注意是osgViewer::View类而不是osgViewer::Viewer类)。
2.修改之前的getViewer函数如下:
osgViewer::CompositeViewer* getViewer() { return viewer; }
3.修改cOSG的析构函数,这是最重要的,之前就是这个地方没改好结果程序各种问题。修改的析构函数如下:
cOSG::~cOSG() { viewer->setDone(true); Sleep(1000); viewer->stopThreading(); //delete viewer; }
4.接来下在InitCameraConfig函数中初始化另外对象,并按照OSG中的使用多个viewer的例子修改代码。
void cOSG::InitCameraConfig(void) { // Local Variable to hold window size data RECT rect; viewer = new osgViewer::CompositeViewer() ; // Create the viewer for this window mViewer = new osgViewer::View(); view2 = new osgViewer::View; // Add a Stats Handler to the viewer mViewer->addEventHandler(new osgViewer::StatsHandler); // Get the current window size ::GetWindowRect(m_hWnd, &rect); // Init the GraphicsContext Traits osg::ref_ptr<osg::GraphicsContext::Traits> traits = new osg::GraphicsContext::Traits; // Init the Windata Variable that holds the handle for the Window to display OSG in. osg::ref_ptr<osg::Referenced> windata = new osgViewer::GraphicsWindowWin32::WindowData(m_hWnd); // Setup the traits parameters traits->x = 0; traits->y = 0; traits->width = rect.right - rect.left; traits->height = rect.bottom - rect.top; traits->windowDecoration = false; traits->doubleBuffer = true; traits->sharedContext = 0; traits->setInheritedWindowPixelFormat = true; traits->inheritedWindowData = windata; // Create the Graphics Context osg::GraphicsContext* gc = osg::GraphicsContext::createGraphicsContext(traits.get()); // Init a new Camera (Master for this View) osg::ref_ptr<osg::Camera> camera = new osg::Camera; // Assign Graphics Context to the Camera camera->setGraphicsContext(gc); // Set the viewport for the Camera camera->setViewport(new osg::Viewport(traits->x, traits->y, traits->width, traits->height)); // Set projection matrix and camera attribtues camera->setClearMask(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); camera->setClearColor(osg::Vec4f(0.2f, 0.2f, 0.4f, 1.0f)); camera->setProjectionMatrixAsPerspective( 30.0f, static_cast<double>(traits->width)/static_cast<double>(traits->height), 1.0, 1000.0); // Add the Camera to the Viewer //mViewer->addSlave(camera.get()); mViewer->setCamera(camera.get()); // Add the Camera Manipulator to the Viewer mViewer->setCameraManipulator(keyswitchManipulator.get()); // Set the Scene Data mViewer->setSceneData(mRoot.get()); { osg::ref_ptr<osg::GraphicsContext::Traits> traits2 = new osg::GraphicsContext::Traits(); traits2->x = 100; traits2->y = 100; traits2->width = 900; traits2->height = 700; traits2->windowDecoration = true; traits2->doubleBuffer = true; traits2->sharedContext = 0; //创建图形环境特性 osg::ref_ptr<osg::GraphicsContext> gc2 = osg::GraphicsContext::createGraphicsContext(traits2.get()); osg::ref_ptr<osg::Node> cessna=osgDB::readNodeFile("cessna.osg"); view2->setSceneData(cessna.get()); // Set projection matrix and camera attribtues view2->getCamera()->setClearMask(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); view2->getCamera()->setClearColor(osg::Vec4f(0.2f, 0.2f, 0.4f, 1.0f)); view2->getCamera()->setProjectionMatrixAsPerspective( 30.0f, static_cast<double>(traits2->width)/static_cast<double>(traits2->height), 1.0, 1000.0); view2->getCamera()->setViewport(new osg::Viewport(0,0, traits2->width, traits2->height)); view2->getCamera()->setGraphicsContext(gc2); view2->setCameraManipulator(new osgGA::TrackballManipulator); } viewer->addView(mViewer); viewer->addView(view2); // Realize the Viewer viewer->realize(); }
5.将cOSG中的Render函数修改如下:
void cOSG::Render(void* ptr) { cOSG* osg = (cOSG*)ptr; osgViewer::CompositeViewer * viewer = osg->getViewer(); // You have two options for the main viewer loop // viewer->run() or // while(!viewer->done()) { viewer->frame(); } while(!viewer->done()) { osg->PreFrameUpdate(); viewer->frame(); osg->PostFrameUpdate(); //Sleep(10); // Use this command if you need to allow other processes to have cpu time } // For some reason this has to be here to avoid issue: // if you have multiple OSG windows up // and you exit one then all stop rendering AfxMessageBox("Exit Rendering Thread"); _endthread(); }主要也只是改动了一行代码,就是osgViewer::CompositeViewer * viewer = osg->getViewer();这一行代码。
6.修改完上述的地方后程序应该已经能正常启动了,但是需要注意的一点是现在这个程序的Viewer结构改变了,以前是一个osgViewer::Viewer对象,现在变成两个osgViewer::View对象,以及一个容纳这两个osgViewer::View对象的osgViewer::CompositeViewer对象,所以如果程序中如果有某些地方使用了程序的Viewer对象的地方都需要做一些修改,正好这个程序的CMFC_OSG_MDIView类中有一个函数OnKeyDown中使用了下面的代码:
mOSG->getViewer()->getEventQueue()->keyPress(nChar);需要将其替换成:
mOSG->getViewer()->getView(0)->getEventQueue()->keyPress(nChar);
在Visual Studio中,选择Debug | Exceptions菜单项,在弹出的对话框中,勾选所有的Win32 Exceptions,这样在Win32的异常抛出时,程序就会中断,这样就有机会在第一时间(异常处理前)看到自己的代码中发生了什么错误导致抛出异常,从而改正错误,消除程序中的隐患。
这个是修改后的工程的源码链接。