- 概览
- OSG读取OSGB模型并显示
- MFC视图显示OSGB模型
概览
OSG提供了一个浏览三维模型的视图osgViewer::Viewer
,将.osg或.osgb文件通过osgDB::readNodeFile()
读进来后用osgViewer::Viewer::setSceneData()
添加到视图中,接着调用osgViewer::Viewer::run()
即可开一个新的窗口显示。
MFC提供了C++软件程序框架,可以显示单个或多个窗口、对话框,并提供了文件、路径选择的接口,可以用来开发基础的OSGB浏览软件。将MFC视图的窗口句柄传递给osgViewer
,并设置一些运行过程的控制,即可实现在MFC中使用OSG自带的视图显示OSGB模型。
OSG读取OSGB模型并显示
以下代码实现的功能:拖动一个.osgb文件到exe文件上,即可打开一个全屏的视图显示OSGB模型。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| #include<osgViewer/Viewer> #include<osgDB/ReadFile>
int main(int argc, char* argv[]) { if (argc != 2) return 1; const std::string indexFilePath = argv[1]; std::cout << indexFilePath << std::endl; const std::string dirPath = indexFilePath.substr(0, indexFilePath.find_last_of('\\'));
auto opts = new osgDB::Options(); opts->setDatabasePath(dirPath); const osg::ref_ptr<osg::Node> node = osgDB::readNodeFile(indexFilePath, opts);
node->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF | osg::StateAttribute::OVERRIDE);
osg::Group* group = dynamic_cast<osg::Group*>(node.get()); for (size_t i = 0; i < group->getNumChildren(); i++) { osg::PagedLOD* plod = dynamic_cast<osg::PagedLOD*>(group->getChild(i)); plod->setDatabasePath(dirPath + plod->getDatabasePath()); std::cout << dirPath + plod->getDatabasePath() << std::endl; }
osgViewer::Viewer viewer; viewer.setSceneData(node); viewer.setUpViewOnSingleScreen(1); return viewer.run(); }
|
MFC视图显示OSGB模型
首先新建一个类:
COsgbViewer.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| #pragma once #include <string> #include <osgViewer/Viewer>
class COsgbViewer { public: COsgbViewer(HWND hWnd); ~COsgbViewer();
void InitOsgb(std::string filepath);
osg::ref_ptr<osgViewer::Viewer> GetViewer() const;
static void Render(void*);
private: HWND m_hWnd; osg::ref_ptr<osgViewer::Viewer> m_lpViewer; };
|
COsgbViewer.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86
| #include "COsgbViewer.h" #include <osgViewer/api/Win32/GraphicsWindowWin32> #include <osgDB/ReadFile> #include <osgGA/TrackballManipulator>
COsgbViewer::COsgbViewer(HWND hWnd) { this->m_hWnd = hWnd; }
COsgbViewer::~COsgbViewer() { }
void COsgbViewer::InitOsgb(std::string filepath) { std::replace(filepath.begin(), filepath.end(), '/', '\\'); const std::string dirPath = filepath.substr(0, filepath.find_last_of('\\')); auto opts = new osgDB::Options(); opts->setDatabasePath(dirPath); const osg::ref_ptr<osg::Node> node = osgDB::readNodeFile(filepath, opts);
if (node == nullptr) return;
node->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF | osg::StateAttribute::OVERRIDE);
osg::Group* group = dynamic_cast<osg::Group*>(node.get()); for (size_t i = 0; i < group->getNumChildren(); i++) { osg::PagedLOD* plod = dynamic_cast<osg::PagedLOD*>(group->getChild(i)); plod->setDatabasePath(dirPath + plod->getDatabasePath()); }
RECT m_rect; ::GetWindowRect(m_hWnd, &m_rect);
osg::ref_ptr<osg::GraphicsContext::Traits> traits = new osg::GraphicsContext::Traits(); osg::ref_ptr<osg::Referenced> windata = new osgViewer::GraphicsWindowWin32::WindowData(m_hWnd);
traits->x = 0; traits->y = 0; traits->width = m_rect.right - m_rect.left; traits->height = m_rect.bottom - m_rect.top; traits->windowDecoration = true; traits->doubleBuffer = true; traits->overrideRedirect = false; traits->sharedContext = 0; traits->setInheritedWindowPixelFormat = true; traits->inheritedWindowData = windata;
m_lpViewer = new osgViewer::Viewer; osg::ref_ptr<osg::Camera> camera = m_lpViewer->getCamera(); camera->setGraphicsContext(osg::GraphicsContext::createGraphicsContext(traits)); camera->setViewport(new osg::Viewport(0, 0, traits->width, traits->height)); m_lpViewer->setCamera(camera);
m_lpViewer->setCameraManipulator(new osgGA::TrackballManipulator);
m_lpViewer->setSceneData(node); m_lpViewer->realize(); m_lpViewer->getCamera()->setComputeNearFarMode(osg::CullSettings::COMPUTE_NEAR_FAR_USING_PRIMITIVES); }
osg::ref_ptr<osgViewer::Viewer> COsgbViewer::GetViewer() const { return this->m_lpViewer; }
void COsgbViewer::Render(void* ptr) { const auto self = (COsgbViewer*)ptr; const auto viewer = self->GetViewer(); while (!viewer->done()) { viewer->frame(); } _endthread(); }
|
接着在MFC的view类(继承自CView,命名为:CBigViewerView
)中添加成员变量:
1 2
| private: COsgbViewer* m_lpOsgbViewer;
|
接着重载虚函数OnInitialUpdate
和三个消息响应函数:
OnInitialUpdate:加载模型文件后开一个线程处理渲染过程,在这里提供文件路径
1 2 3 4 5 6 7 8
| void CBigViewerView::OnInitialUpdate() { CView::OnInitialUpdate();
m_lpOsgbViewer->InitOsgb("D:\\codes\\C++\\reconstruct-engine\\DJI_202207281718_006_1area04125cmc_1-2\\model-osgb\\Model.osgb"); _beginthread(&COsgbViewer::Render, 0, m_lpOsgbViewer); }
|
OnCreate:视图类创建时先进行初始化,将窗口句柄给到自定义的viewer类中
1 2 3 4 5 6 7 8 9 10
| int CBigViewerView::OnCreate(LPCREATESTRUCT lpCreateStruct) { if (CView::OnCreate(lpCreateStruct) == -1) return -1;
m_lpOsgbViewer = new COsgbViewer(m_hWnd);
return 0; }
|
OnEraseBkgnd:好像没啥用?无论是单文档还是多文档都无法触发
1 2 3 4 5 6 7
| BOOL CBigViewerView::OnEraseBkgnd(CDC* pDC) { if (m_lpOsgbViewer) return FALSE;
return CView::OnEraseBkgnd(pDC); }
|
OnDestroy:退出时注销OSG视图类
1 2 3 4 5 6 7 8 9 10
| void CBigViewerView::OnDestroy() { CView::OnDestroy();
if (m_lpOsgbViewer) { delete m_lpOsgbViewer; } }
|