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