OSG在MFC多窗口的使用

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();

}

这是修改后的代码,相信也很容易理解,括号内的是另一个窗口的一些属性的设置,如果自己还有其他的一些需求,可以在这儿修改。需要注意的是将之前的mViewer对象替换成viewer,这是很明显的。

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的异常抛出时,程序就会中断,这样就有机会在第一时间(异常处理前)看到自己的代码中发生了什么错误导致抛出异常,从而改正错误,消除程序中的隐患。

这个是修改后的工程的源码链接。


你可能感兴趣的:(OSG在MFC多窗口的使用)