OGRE嵌入MFC(含源码)

一、下载安装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键效果如下:


 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值