OSGのMFCマルチウィンドウでの使用

6582 ワード

OpenSceneGraphの例ではMFCでOSGをどのように使うか、コンソールでマルチビューマルチウィンドウレンダリングをどのように使うかという例もありますが、この2つの例を簡単に組み合わせるだけではプログラムに問題があります.細部の変化に注意しなければならないことがあります.ここに記録してください.主な修正手順は,OSGが持参した結合MFCの例で行った修正である.
1.cOSGに2つのメンバー変数を追加し、以前のデフォルトのmViewerオブジェクトのタイプを変更します.
	osg::ref_ptr<osgViewer::CompositeViewer> viewer ;

	osg::ref_ptr<osgViewer::View> view2;

        osgViewer::View* mViewer;

これにより、このプロジェクトにはosgViewer::CompositeViewerオブジェクト、2つのosgViewer::Viewクラスのオブジェクト(osgViewer::osgViewerではなくViewクラス)があります.
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();
}

主に1行のコードを変更しただけで、osgViewer::CompositeViewer*viewer=osg->getViewer();この行のコード.
6.上記の箇所を修正するとプログラムは正常に起動するはずですが、注意しなければならないのは、このプログラムのViewer構造が変更されたことです.以前はosgViewer::Viewerオブジェクトでしたが、今は2つのosgViewer::Viewオブジェクトと、この2つのosgViewer::Viewオブジェクトを収容するosgViewer::CompossiteViewerオブジェクトになりました.そのため、プログラムの中にプログラムのViewerオブジェクトを使用しているところがあれば、いくつかの修正が必要です.ちょうどこのプログラムのCMFC_OSG_MDIViewクラスの関数OnKeyDownでは、次のコードが使用されています.
  mOSG->getViewer()->getEventQueue()->keyPress(nChar);

次のように置き換える必要があります.
  mOSG->getViewer()->getView(0)->getEventQueue()->keyPress(nChar);

これでいいです.この機能を実現する過程で、プログラムが直接クラッシュし、何のヒントもないときにどうするかという小さなテクニックも身につけました.これはネットで見た方法で、発見は確かに役に立ちます.
Visual Studioでは、「Debug|Exceptions」メニュー項目を選択し、ポップアップ・ダイアログ・ボックスですべてのWin 32 Exceptionsをチェックします.これにより、Win 32の異常が投げ出されるとプログラムが中断し、自分のコードに何が起こったのかを最初の時間(異常処理前)に見て異常が投げ出され、エラーが修正され、プログラムの危険性がなくなります.
これは修正されたプロジェクトのソースリンクです.