注意工程类型应与下载的OSG库类型一样,我这里是Release版OSG库,生成Release版程序没问题,但是Debug版有错误,如需要生成Debug版程序,需要下载Debug版OSGbinary。
OSGbinary版库(OpenSceneGraph3.0.1forVS2010-X86-32bi)下载OSGbinary版下载 (已经编译好的lib,不用自己编译,直接使用即可)
需要自己增加两个环境变量,OSG_FILE_PATH 指定OSG 程序读取图形和模型文件时的搜索路径。如果环境变量为空或者没有设置,OSG 在读取图形和
模型文件时只搜索当前的目录。
1、项目名称3DVision
选择字符集为多字符集
2、第一步:修改doc类
public:
//从属性面板上把建立新文档操作删除掉,因为不需要建立新文档,什么时候都不会需要这个功能
//virtual BOOL OnNewDocument();
protected:
//定义一个文件名称,用来存放用来读取的模型文件
CString m_csFileName;
public: //类向导重载OnOpenDocument函数,
virtual BOOL OnOpenDocument(LPCTSTR lpszPathName);
添加函数GetFileName专门用来获得文件名
CString GetFileName() const{ return m_csFileName;};
// CMy3DVisionDoc 构造/析构
CMy3DVisionDoc::CMy3DVisionDoc()
{
// 定义一个默认打开文件
m_csFileName="cow.osg";
}
删除掉重载的新建文档函数
//BOOL CMy3DVisionDoc::OnNewDocument()
//{
//
// if (!CDocument::OnNewDocument())
// return FALSE;
//
// // TODO: 在此添加重新初始化代码
// // (SDI 文档将重用该文档)
//
// return TRUE;
//}
新加的打开文档映射
BOOL CMy3DVisionDoc::OnOpenDocument(LPCTSTR lpszPathName)
{
//打开时,把文件名传入m_csFileName.
m_csFileName=lpszPathName;
if (!CDocument::OnOpenDocument(lpszPathName))
return FALSE;
return TRUE;
}
附加依赖性lib
OpenThreads.lib
osg.lib
osgDB.lib
osgFX.lib
osgGA.lib
osgManipulator.lib
osgParticle.lib
osgShadow.lib
osgSim.lib
osgTerrain.lib
osgText.lib
osgUtil.lib
osgViewer.lib
osg.lib
osgDB.lib
osgFX.lib
osgGA.lib
osgManipulator.lib
osgParticle.lib
osgShadow.lib
osgSim.lib
osgTerrain.lib
osgText.lib
osgUtil.lib
osgViewer.lib
在当前项目下新建包含文件和库文件目录
第二步:添加OSG核心处理类
CorsOSG.h
#pragma once
#include <osgViewer/Viewer>
#include <osgViewer/ViewerEventHandlers>
#include <osgViewer/api/Win32/GraphicsWindowWin32>
/*********osgGA =osg GUI ACTION 图形界面交互库*****************/
#include <osgGA/TrackballManipulator>
#include <osgGA/KeySwitchMatrixManipulator>
#include <osgDB/DatabasePager>
#include <osgDB/Registry>
#include <osgDB/ReadFile>
#include <osgDB/WriteFile>
#include <osgUtil/Optimizer>
#include <string>
/************************************************************************/
/* OSG核心类,在这里执行MFC对OSG的大部分的管理功能 */
/************************************************************************/
class CCoreOSG
{
public:
// CCoreOSG(void);
~CCoreOSG(void);
// 构造函数获取上一级窗口句柄
CCoreOSG(HWND hWnd);
// 初始化OSG,参数filename为需要加入的模型
void InitOSG(std::string filename);
// 初始化操作器
void InitManipulators(void);
// 初始化场景
void InitSceneGraph(void);
// 初始化相机配置
void InitCameraConfig(void);
// 建立窗口
void SetupWindow(void);
// 建立相机
void SetupCamera(void);
// 每帧绘制前整理
void PreFrameUpdate(void);
// 每帧绘制后处理
void PostFrameUpdate(void);
// SetDone
void Done(bool value)
{
mDone=value;
}
// getDone
bool Done(void)
{
return mDone;
}
// 渲染,注意这里是静态的,可启用为全局线程
static void Render(void* ptr);
// 使用一个名称为filename的模型代替当前场景中的所有模型
void ReplaceSceneData(std::string filename);
// osgViewer::Viewer* GetViewer(void);
private:
bool mDone;
std::string m_ModelName;
HWND m_hWnd;
osgViewer::Viewer* mViewer;
osg::ref_ptr<osg::Group> mRoot;
// osg::ref_ptr<osg::Node> m_Node;
public:
osg::ref_ptr<osg::Node> mModel;
private:
osg::ref_ptr<osgGA::TrackballManipulator> trackball;
osg::ref_ptr<osgGA::KeySwitchMatrixManipulator> keyswitchManipulator;
public:
osgViewer::Viewer* GetViewer(void)
{
return mViewer;
}
};
CoreOSG.cpp
#include "StdAfx.h"
#include "CoreOSG.h"
// 构造函数获取上一级窗口句柄
CCoreOSG::CCoreOSG(HWND hWnd):m_hWnd(hWnd)
{
}
CCoreOSG::~CCoreOSG()
{
mViewer->setDone(true);
Sleep(1000);
mViewer->stopThreading();
delete mViewer;
}
void CCoreOSG::InitOSG(std::string modelname)
{
//存储取到的模型文件名称
m_ModelName = modelname;
// 初始化OSG的不同部分
InitManipulators();
InitSceneGraph();
InitCameraConfig();
}
void CCoreOSG::InitManipulators(void)
{
/*
//创建一个trackball操作器
trackball = new osgGA::TrackballManipulator();
//创建一个KEY切换
keyswitchManipulator = new osgGA::KeySwitchMatrixManipulator;
// 加入KEY切换
keyswitchManipulator->addMatrixManipulator( '1', "Trackball", trackball.get());
//选择一个
keyswitchManipulator->selectMatrixManipulator(0);// 0是索引值*/
//创建一个trackball操作器
trackball = new osgGA::TrackballManipulator();
//创建一个KEY切换
keyswitchManipulator = new osgGA::KeySwitchMatrixManipulator;
// 加入KEY切换
keyswitchManipulator->addMatrixManipulator( '1', "Trackball", trackball.get());
//选择一个
keyswitchManipulator->selectMatrixManipulator(0);// 0是索引值
}
void CCoreOSG::InitSceneGraph(void)
{
//初始化组
mRoot = new osg::Group;
//读取模型
mModel = osgDB::readNodeFile(m_ModelName);
// 优化模型
osgUtil::Optimizer optimizer;
optimizer.optimize(mModel.get());
optimizer.reset();
//把模型加入到场景中
mRoot->addChild(mModel.get());
}
void CCoreOSG::InitCameraConfig(void)
{
// 局部变量存放窗口矩形
RECT rect;
// 创建一个viewer
mViewer = new osgViewer::Viewer();
// 加入一个statshandler
mViewer->addEventHandler(new osgViewer::StatsHandler);
// 得到当前窗口矩形
::GetWindowRect(m_hWnd, &rect);
// 初始化图形描述
osg::ref_ptr<osg::GraphicsContext::Traits> traits = new osg::GraphicsContext::Traits;
// 初始化窗口变量,为OSG所用
osg::ref_ptr<osg::Referenced> windata = new osgViewer::GraphicsWindowWin32::WindowData(m_hWnd);
// 设置一些参数
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;
// 创建图形上下文
osg::GraphicsContext* gc = osg::GraphicsContext::createGraphicsContext(traits.get());
// 初始化一个相机
osg::ref_ptr<osg::Camera> camera = new osg::Camera;
camera->setGraphicsContext(gc);
//相机视口设置
camera->setViewport(new osg::Viewport(traits->x, traits->y, traits->width, traits->height));
// 添加相机到VIEWER
mViewer->addSlave(camera.get());
// 添加操作器到VIEWER
mViewer->setCameraManipulator(keyswitchManipulator.get());
//设置数据
mViewer->setSceneData(mRoot.get());
// 实现VIEWER
mViewer->realize();
}
// 建立窗口
void CCoreOSG::SetupWindow(void)
{
}
// 建立相机
void CCoreOSG::SetupCamera(void)
{
}
void CCoreOSG::PreFrameUpdate(void)
{
// 帧前操作可在这里做一下
}
void CCoreOSG::PostFrameUpdate(void)
{
// 帧后操作可在这里做一下
}
// 渲染,注意这里是静态的,可启用为全局线程
void CCoreOSG::Render(void* ptr)
{
CCoreOSG* osg=(CCoreOSG*)ptr;
osgViewer::Viewer* viewer=osg->GetViewer();
//可以这样
// view->run() or
// while(!viewer->done()){viewer->frame();}
// viewer->run();
//也可以这样,建议这样
while (!viewer->done())
{
osg->PreFrameUpdate();
viewer->frame();
osg->PostFrameUpdate();
//Sleep(10);//让其他程序也占用CPU,放出MS
}
//退出了程序,弹出个对话框说一下
AfxMessageBox("线程退出");
_endthread();
}
void CCoreOSG::ReplaceSceneData(std::string filename)
{
//移掉mRoot中所有的数据,这些数据将会被自动释放掉,不用手动处理
mRoot->removeChildren(0, mRoot->getNumChildren());
//加入要置换的模型
mModel = osgDB::readNodeFile(filename);
//优化
osgUtil::Optimizer optimizer;
optimizer.optimize(mModel.get());
optimizer.reset();
//添加孩子
mRoot->addChild(mModel.get());
}
第三步:在view类中处理OSG
// 3DVisionView.h : CMy3DVisionView 类的接口
//
#pragma once
#include "CoreOSG.h"
添加类CCoreOSG
protected:
// 添加类CCoreOSG
CCoreOSG* mOSG;
// 线程句柄
HANDLE mThreadHandle;
// 用于文件计数
int iFileNum;
添加下列函数
public:
// 重写以下类型函数
virtual void OnInitialUpdate();
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
afx_msg void OnDestroy();
afx_msg BOOL OnEraseBkgnd(CDC* pDC);
afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags);
构造函数
// CMy3DVisionView 构造/析构
CMy3DVisionView::CMy3DVisionView()
: mOSG(NULL)
, iFileNum(0)
{
// TODO: 在此处添加构造代码
iFileNum=1;
}
如果多字符集
void CMy3DVisionView::OnInitialUpdate()
{
//在这里控制一下打开文件的操作
CView::OnInitialUpdate();
if(iFileNum ==1)
{
//第一次打开默认飞机文件
iFileNum ++ ;
CString csFileName = GetDocument() ->GetFileName() ;
mOSG ->InitOSG(csFileName.GetString()) ;
mThreadHandle = (HANDLE)_beginthread(&CCoreOSG::Render, 0, mOSG) ;
}
else
{
//后续打开,直接替掉模型就可以了
iFileNum ++ ;
CString csFileName = GetDocument() ->GetFileName() ;
mOSG ->ReplaceSceneData(csFileName.GetString()) ;
}
}
如果选的是Unicode字符集上面的CString类型需要转换。
int CMy3DVisionView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CView::OnCreate(lpCreateStruct) == -1)
return -1;
// TODO: 在此添加您专用的创建代码
mOSG=new CCoreOSG(m_hWnd);
//return 0;
return 1;
}
void CMy3DVisionView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
mOSG->GetViewer()->getEventQueue()->keyPress(nChar);
if (nChar==VK_ESCAPE)
{
GetParent()->SendMessage(WM_CLOSE);
}
// CView::OnKeyDown(nChar, nRepCnt, nFlags);
}
void CMy3DVisionView::OnDestroy()
{
if (mOSG!=0)
{
delete mOSG;
}
WaitForSingleObject(mThreadHandle,1000);
CView::OnDestroy();
}