OGRE嵌入MFC(含源码)

来源:互联网 发布:mac打字不出现选字框 编辑:程序博客网 时间:2024/05/29 07:21

一、下载安装OGRE SDK

1、OGRE SDK下载地址:http://www.ogre3d.org/download/sdk

2、安装和普通的软件安装方式相同(默认安装到了盘,E:\OgreSDK_vc9_v1-8-1 )。

 

二、配置OGRE

    1、在环境变量中添加如下内容:

变量名:OGRE_HOME

变量值: E:\OgreSDK_vc9_v1-8-1(为SDK的路径)。

    2、创建一个基于单文档的MFC的应用程序(用于显示3D场景),然后对该工程进行配置:

    项目/属性/配置属性/调试:E:\OgreSDK_vc9_v1-8-1\bin\Debug(若程序运行出现找不到OgreMain_d.dll时添加)

项目/属性/ 配置属性/“C/C++”/附加包含目录:
    D:\OgreSDK_vc9_v1-8-1 \include
    E:\OgreSDK_vc9_v1-8-1\include\OGRE
    E:\OgreSDK_vc9_v1-8-1\boost

 

    项目/属性/ 配置属性/链接器/输入/附加依赖项:kernel32.lib user32.lib gdi32.lib winspool.lib shell32.lib ole32.lib oleaut32.lib uuid.lib comdlg32.lib advapi32.lib OgreMain_d.lib libboost_thread-vc90-mt-gd-1_49.lib libboost_date_time-vc90-mt-gd-1_49.lib OgreRTShaderSystem_d.lib OIS_d.lib 
    (主意:以上的libboost_thread-vc90-mt-gd-1_49.lib 和 libboost_date_time-vc90-mt-gd-1_49.lib名称可能因下载的版本不同而不同,打开目录OgreSDK_vc9_v1-8-1\boost\lib可查看其具体名称,然后将正确的名称写入依赖项目录)

    项目/属性/ 配置属性/链接器/常规/附加库目录:
    D:\OgreSDK_vc9_v1-8-1 \bin\debug  
    D:\OgreSDK_vc9_v1-8-1
 \bin\Release 
 
    D:\OgreSDK_vc9_v1-8-1
 \lib\debug
 
    D:\OgreSDK_vc9_v1-8-1 
\lib\Release
    D:\OgreSDK_vc9_v1-8-1
 \boost\lib  

三、程序的实现(假设创建的工程名为ogreMFC

    1、在视图类头文件ogreMFCView.h中添加:

    #include”Ogre.h

    #include”OgreConfigFile.h

    using namespace Ogre;

    将所有的#Define NEW DEBUG_NEW 注释掉替换成 #define OGRE_DEBUG_MEMORY_MANAGER 1

 
   此时,编译就可通过了。

    2、为视图类添加成员函数void SetupResource(),该函数主要用于OGRE资源的设置和加载。在成员函数中添加如下代码:

void COgreMFCView::SetupResource(void)

{

ConfigFile cf;

cf.load("resource_d.cfg");

ConfigFile::SectionIterator seci = cf.getSectionIterator();

String secName;

String typeName;

String archName;

while (seci.hasMoreElements())

{

secName = seci.peekNextKey();

ConfigFile::SettingsMultiMap *settings = seci.getNext();

ConfigFile::SettingsMultiMap::iterator i;

for (i = settings->begin(); i != settings->end(); ++i)

{

typeName = i->first;

archName = i->second;

ResourceGroupManager::getSingleton().addResourceLocation(archName,typeName,secName);

}

}

}

3、视图类中添加SetupConfig()函数,用来启用手动设置的部分

在头文件中添加:Root  m_pRoot;在构造函数中:m_pRoot = new Root("plugins_d.cfg"); 析构函数中:delete m_pRoot;

void COgreMFCView::SetupConfig(void)

{

RenderSystemList *rl = &const_cast<RenderSystemList&>(m_pRoot->getAvailableRenderers());//指向可用的渲染系统

RenderSystem * rSys = NULL;

RenderSystemList::iterator it = rl->begin();

//轮寻可用的Direct3D9渲染子系统,也可以使用openGL渲染子系统

while (it != rl->end())

{

if (-1 != (*it)->getName().find("Direct3D9"))

{

rSys = (RenderSystem*)(*it);

break;

}

++it;

}

rSys->setConfigOption("Full Screen","YES");

rSys->setConfigOption("VSync","No");

rSys->setConfigOption("Video Mode","640 x 480");

//rSys->setConfigOption("Colour Depth","32");

//rSys->setConfigOption("Display Frequency","60");

 

m_pRoot->setRenderSystem(rSys);//启用渲染子系统

}
 

4、视图类中添加成员函数CreateRanderWnd(),创建渲染窗口

添加视图类成员:RenderWindow *m_pWindow; 

void COgreMFCView::CreateRenderWnd(void)

{

m_pRoot->initialise(false);//false表示不要自动创建渲染窗口

NameValuePairList miscParams;

miscParams["externalWindowHandle"] = StringConverter::toString(m_hWnd);//手动创建渲染窗口,将视图句柄传入使其使用单文档视图窗口

CRect rt;

GetClientRect(&rt);//获取视图窗口大小

m_pWindow = m_pRoot->createRenderWindow("test",rt.Width(),rt.Height(),false,&miscParams);

}

5、添加成员函数void CreateSceneManager(),创建场景管理器

添加视图类成员:SceneManager  m_pSceneManager

//创建场景管理器

void COgreMFCView::CreateSceneManager(void)

{

m_pSceneMgr = m_pRoot->createSceneManager(ST_GENERIC,"ExampleSMInstance");//创建场景管理器

6、添加成员函数CreateCamera(),创建摄像机
 

视图类添加成员: Camera* m_pCamera;

//创建摄像机

void COgreMFCView::CreateCamera(void)

{

m_pCamera = m_pSceneMgr->createCamera("PlayerCam");//创建名为PlayerCam的摄像机

m_pCamera->setPosition(Vector3(0,400,500));//设置摄像机的位置

m_pCamera->lookAt(Vector3(0,400,0));//摄像机的方向

m_pCamera->setNearClipDistance(5);//位置5单位的近距离剪裁

}

7、添加成员函数void CreateViewPort(),设置视口

void COgreMFCView::CreateViewPort(void)

{

Viewport *vp = m_pWindow->addViewport(m_pCamera);//建立视口

vp->setBackgroundColour(ColourValue(255,0,0));//设置背景颜色为红色

m_pCamera->setAspectRatio(Real(vp->getActualWidth())/Real(vp->getActualHeight()));//设置摄影机的纵宽比

TextrueManager::getSingleton().setDefaultNumMipmaps(5);

8添加成员函数void LoadRecourse(),加载所有资源

void CChildView::loadResources()

{

    Ogre::ResourceGroupManager::getSingleton().initialiseAllResourceGroups();

}

9、创建场景

void COgreMFCView::CreateScene(void)

{

m_pSceneMgr->setAmbientLight(ColourValue(0.5,0.5,0.5));//设置环境光变暗

 

m_pSceneMgr->setSkyDome(false,"Examples/CloudySky",65);//天空穹,参数(是否启用天空穹,使用的材质脚本,天空穹的弯度:建议2~65,贴图的重复次数,与天空的距离,在其他对象渲染前还是渲染后,默认TRUE渲染前)

m_pSceneMgr->setSkyBox(true,"Examples/SpaceSkyBox");//天空盒,巨型立方体,参数(是否启用天空穹,使用的材质脚本,与天空的距离,在其他对象渲染前还是渲染后,默认TRUE渲染前)

Plane plane;

plane.d = 1000;

plane.normal = Vector3::NEGATIVE_UNIT_Y;

m_pSceneMgr->setSkyPlane(false,plane,"Examples/SpaceSkyPlane");//天空面,一个平面

 

Light *light = m_pSceneMgr->createLight("BuleLight");//创建光源1

light->setDiffuseColour(0,0,255);

light->setPosition(0,0,100);

 

light = m_pSceneMgr->createLight("GreenLight");//创建光源2

light->setDiffuseColour(255,0,0);

light->setPosition(0,0,-100);

 

}

10、添加成员函数CreateEntity(),创建实体
视图类添加成员:SceneNode *node1,*Node2;Entity *ent1,*ent2;并在构造函数中都初始化为NULL;

void COgreMFCView::CreateEntity(void)

{

ent1 = m_pSceneMgr->createEntity("sphere","ninja.mesh");

node1 = m_pSceneMgr->getRootSceneNode()->createChildSceneNode();

node1->translate(Vector3(0,0,0));//设置实体的位置

node1->attachObject(ent1);//将实体附在场景上

 

ent2 = m_pSceneMgr->createEntity("mikki","mikki.mesh");

node2 = m_pSceneMgr->getRootSceneNode()->createChildSceneNode();

node2->translate(Vector3(500,0,0));//设置实体的位置

node2->attachObject(ent2);//将实体附在场景上

}

11、添加成员函数CreateFloorPlane(void),创建地面

void COgreMFCView::CreateFloorPlane(void)

{

Entity * ent;

Plane p;

p.d = 0;//与天空的距离

p.normal = Vector3::UNIT_Y;

MeshManager::getSingleton().createPlane("cube.mesh",ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,p,2000,2000,1,1,true,1,5,5,Vector3::UNIT_Z);

ent = m_pSceneMgr->createEntity("floor","cube.mesh");

ent->setMaterialName("Examples/RustySteel");

m_pSceneMgr->getRootSceneNode()->attachObject(ent);//将实体附在场景上

12、添加成员函数VoidSetupMFC()将上面的函数执行启动3D画面

void COgreMFCView::SetupMFC(void)

{

SetupResource();

SetConfig();

CreateRanderWnd();

CreateSceneManager();

CreateCamera();

CreateViewPort();

InitAllResource();

CreateScene();

CreatePlane();

CreateEntity();

}

13、添加定时器消息

void COgreMFCView::OnTimer(UINT_PTR nIDEvent)

{

// TODO:在此添加消息处理程序代码和/或调用默认值

m_pRoot->renderOneFrame();

CView::OnTimer(nIDEvent);

}

14、在Ondraw()函数中设置计时器
添加视图类的成员:BOOL bHasInit;在构造函数中初始化为TRUE

// COgreMFCView绘制

 

void COgreMFCView::OnDraw(CDC* /*pDC*/)

{

COgreMFCDoc* pDoc = GetDocument();

ASSERT_VALID(pDoc);

if (!pDoc)

return;

 

// TODO:在此处为本机数据添加绘制代码

if (m_hasInit)

{

SetupMFC();

m_hasInit = FALSE;

}

SetTimer(1,30,NULL);

}

15、添加OnDestroy消息,用来摧毁计时器

void COgreMFCView::OnDestroy()

{

CView::OnDestroy();

KillTimer(1);

// TODO:在此处添加消息处理程序代码

}

16、添加Onsize()消息,用来改变窗口大小时更新重绘

void COgreMFCView::OnSize(UINT nType, int cx, int cy)

{

CView::OnSize(nType, cx, cy);

 

// TODO:在此处添加消息处理程序代码

if (m_pWindow)

{

CRect rt;

GetClientRect(&rt);

m_pWindow->windowMovedOrResized();

 

if (rt.Height() != 0 && m_pCamera != NULL)

{

m_pCamera->setNearClipDistance(Real(m_pWindow->getWidth())/Real(m_pWindow->getHeight()));

}

 

m_pCamera->yaw(Radian(0));

}

}
此时运行就可以出现如下效果了:

 
 

17、添加鼠标中键按下消息,获取中键点击时的点,用来旋转镜头。

视图类添加成员:CPoint m_lastPoint;   

void COgreMFCView::OnMButtonDown(UINT nFlags, CPoint point)

{

   // TODO: 在此添加消息处理程序代码和/或调用默认值

 

   m_lastPoint = point;

 

   CView::OnMButtonDown(nFlags, point);

}

18、添加鼠标移动消息OnMouseMove(),可以通过按住鼠标中键实现界面移动。
 

void COgreMFCView::OnMouseMove(UINT nFlags, CPoint point)

{

   // TODO: 在此添加消息处理程序代码和/或调用默认值

 

   if(nFlags & MK_MBUTTON)  

 

   {  

 

       CPoint mouseDiff = point - m_lastPoint;  

 

       m_lastPoint = point;  

 

 

 

       m_pCamera->yaw(Degree(mouseDiff.x) * 0.2);  

 

       m_pCamera->pitch(Degree(mouseDiff.y) * 0.2);  

 

   }

 

   CView::OnMouseMove(nFlags, point);

}
此时镜头就可以按着鼠标中键进行旋转了:

 

18、添加键盘响应消息,通过W、S、A、D控制镜头的向前、后、左、右移动。

void COgreMFCView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)

{

   // TODO: 在此添加消息处理程序代码和/或调用默认值

 

   Vector3 trans = Vector3::ZERO;

   switch (nChar)

   {

   case 'W': // 注意OnKeyDown()消息获取的按键字母总是大写

       trans.z -= 10;//向Z轴的负的方向移动10个像素单位

       m_pCamera->moveRelative(trans);

       break;

   case 'S':

       trans.z += 10;

       m_pCamera->moveRelative(trans);

       break;

   case 'A':

       trans.x -= 10;

       m_pCamera->moveRelative(trans);

       break;

   case 'D':

       trans.x += 10;

       m_pCamera->moveRelative(trans);

       break;

   default:

       break;

   }

   CView::OnKeyDown(nChar, nRepCnt, nFlags);

}

18、添加点选鼠标左键按下响应消息,实现鼠标点选(以包围盒的形式)

void COgreMFCView::OnLButtonDown(UINT nFlags, CPoint point)

{

      // TODO: 在此添加消息处理程序代码和/或调用默认值

 

      static BOOL pointEntity = TRUE;

      CRect rt;

      GetClientRect(&rt);

      RaySceneQuery *pRaySceneQuery = NULL;

      pRaySceneQuery = m_pSceneMgr->createRayQuery(Ray());//创建射线查询

 

      float sx = float(point.x)/float(rt.Width());

      float sy = float(point.y)/float(rt.Height());

 

      Ray mouseRay = m_pCamera->getCameraToViewportRay(sx,sy);//获取从视口点击点发射的射线

 

      pRaySceneQuery->setRay(mouseRay);

 

      pRaySceneQuery->setSortByDistance(true,1);//根据距离进行排序,并返回射线上离视口最近的1个实体

 

      RaySceneQueryResult &result = pRaySceneQuery->execute();//执行

 

      RaySceneQueryResult::iterator itr;

      for(itr = result.begin(); itr != result.end(); ++itr)

      {

             itr->movable->getParentSceneNode()->showBoundingBox(pointEntity);//将最近的实体显示包围盒

      }

 

      pointEntity = !pointEntity;

      m_pSceneMgr->destroyQuery(pRaySceneQuery);

 

      CView::OnLButtonDown(nFlags, point);

}

运行效果如下:

19、添加滚轮滚动消息OnMouseWheel(),实现滚轮缩放。

BOOL COgreMFCView::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt)

{

   // TODO: 在此添加消息处理程序代码和/或调用默认值

 

   Vector3 trans = Vector3::ZERO;

   if (zDelta > 0) //当滚轮向前滚动时,zDelte = 120,向后滚动zDelte = -120

   {

       trans.z -= 10;//向Z轴的负的方向移动10个像素单位

       m_pCamera->moveRelative(trans);

   }

   else

   {

       trans.z += 10;//向Z轴的负的方向移动10个像素单位

       m_pCamera->moveRelative(trans);

   }

 

   return CView::OnMouseWheel(nFlags, zDelta, pt);

}

效果如下:
 
 


19
、实现动画功能,添加一个动画成员函数,在视图.cpp添加全局的AnimationState *as = NULL;供监听类使用该类的成员。

void COgreMFCView::CreateAnimation(void)

{

   //首先使用sceneManager来创建一个animation,这里面同时指定动画的名字和帧的长度:

   Animation *pAnim = m_pSceneMgr->createAnimation("MyAnimation",Real(5));

 

   //设置该段动画的关键帧间帧的插值方式,Ogre主要提供两种插值方式:线性的和样条线的,样条线的更加平滑,绘制的是弧线:

   pAnim->setInterpolationMode(Animation::IM_SPLINE);

 

   //使用animation创建为每个要驱动的node创建一个track,比如这里我们只想让一个结点(node,比如它上面挂着摄像机)运动,就只为他创建一个track就行了,第一个参数是这个track的编号

   NodeAnimationTrack *pTrankOne = pAnim->createNodeTrack(0,node1);

 

   //对于每个track创建它的每个关键帧:

   TransformKeyFrame *pKeyFrame = NULL;

   pKeyFrame = pTrankOne->createNodeKeyFrame(0);//设置该帧的时间点 

   pKeyFrame->setTranslate(Vector3(0,0,0));//设置该帧处这个结点的位置和其他几何状态 

 

   pKeyFrame = pTrankOne->createNodeKeyFrame(1);

   pKeyFrame->setTranslate(Vector3(100,50,0));

 

   pKeyFrame = pTrankOne->createNodeKeyFrame(2);

   pKeyFrame->setTranslate(Vector3(200,100,0));

 

   pKeyFrame = pTrankOne->createNodeKeyFrame(3);

   pKeyFrame->setTranslate(Vector3(300,50,0));

 

   pKeyFrame = pTrankOne->createNodeKeyFrame(4);

   pKeyFrame->setTranslate(Vector3(400,0,0));

 

   //至此这段结点动画就算编完了,下面你需要为他创建一个实例,才能播放,也就是创建一个AnimationState: 

   //将声明放在VIEW.CPP文件的开头作为全局变量供下面的类使用AnimationState *as;

   as = m_pSceneMgr->createAnimationState("MyAnimation ");//注意此处的名称和创建动画时的名称保持一致

 

   as->setLoop(true);

 

   as->setEnabled(true);

 

}

然后创建一个帧监听类的派生类来重写frameStart()函数,创建MyFrameListener.h和MyFrameListener.cpp文件,导入到该工程之中:

头文件MyFrameListener .h

#ifndef _MYFRAME_

#define _MYFRAME_

#include "OgreFrameListener.h"

#include "ExampleFrameListener.h"

 

class MyFrameListener:public FrameListener

{

public:

   virtual bool frameStarted(const FrameEvent &evt);

};

#endif

 

源文件MyFrameListener.cpp

#include "stdafx.h"

#include "MyFrameListener.h"

#include "OgreAnimationState.h"

 

extern AnimationState *as;

 

bool MyFrameListener::frameStarted(const FrameEvent &evt)

{

   if(NULL != as)

   {

       as->addTime(evt.timeSinceLastFrame);

   }

 

   return true;

}

最后,在构造函数中创建关联监听类对象
m_pRoot->addFrameListener(new MyFrameListener);

添加鼠标右键按下消息OnRButtonDown (),调用上面的动画生成函数。

void COgreMFCView::OnRButtonDown(UINT nFlags, CPoint point)

{

   // TODO: 在此添加消息处理程序代码和/或调用默认值

 

   CreateAnimation();

   CView::OnRButtonDown(nFlags, point);

}


此时运行点击右键动画效果就可以显现了,如下:
 

20
、为实体动态加载、卸载材质。
添加视图的成员函数ChangeMaterial ()

void COgreMFCView::ChangeMaterial(void)

{

      //方法一

      MaterialPtr planeMaterial = MaterialManager::getSingleton().getByName("Examples/Ninja");

      planeMaterial->getBestTechnique(0)->setLightingEnabled(true);

      planeMaterial->getBestTechnique(0)->getPass(0)->setDiffuse(0.0, 0.0, 0.0, 0.5);

      planeMaterial->getBestTechnique(0)->getPass(0)->setSpecular(0.5, 0.0, 0.0, 0);

      planeMaterial->getBestTechnique(0)->getPass(0)->createTextureUnitState("MRAMOR6X6.jpg");

 

      //方法二

      ent2->getSubEntity(0)->getMaterial()->getBestTechnique(0)->getPass(0)->removeTextureUnitState(0);//卸载当前实体纹理

      ent2->getSubEntity(0)->getMaterial()->getBestTechnique(0)->setLightingEnabled(true);

      ent2->getSubEntity(0)->getMaterial()->getBestTechnique(0)->getPass(0)->setDiffuse(0.0, 0.0, 0.0, 0.5);

      ent2->getSubEntity(0)->getMaterial()->getBestTechnique(0)->getPass(0)->setSpecular(0.5, 0.0, 0.0, 0);

 ent2->getSubEntity(0)->getMaterial()->getBestTechnique(0)->getPass(0)->createTextureUnitState("NMStripes.png");//纹理贴图设置为另一张图片

      

}

OnKeyDown()消息函数中添加case分支用来按C键调用材质加/卸载函数:

case 'C':

             ChangeMaterial();

             break;

执行按C键效果如下: