MFC(VS2010) + OGRE 环境搭建

    文章参考了《Ogre嵌入MFC傻瓜完全教程》(http://blog.csdn.net/guoyk1990/article/details/25915065)和Ogre官方网站上的示例(http://www.ogre3d.org/tikiwiki/tiki-index.php?page=Setting+Up+An+Application+-+Visual+Studio&structure=Development)。实际操作过程中出现了一些问题,故将全部工作完整地记录下来,以备不时之需,也给广大朋友一个参考。记住:即便是“傻瓜完全教程”,也不可能完全照搬。

一、准备工作

        本人的配置Windows7 64位系统、VS2010(32位)、OgreSDK_vc10_v1-8-1      

       下载OGRESDK:http://www.ogre3d.org/download/sdk  ,并运行 安装到 D盘根目录。

二、环境变量配置

        官方示例中采用cmd命令进行配置,本人不善于这种方式,操作起来没有安全感。故采用更直观的方式:

        在用户变量和系统变量中均新建一项 OGRE_HOME 值为:D:\OgreSDK_vc10_v1-8-1

        在path中添加一项:%OGRE_HOME%

       

        本人最初仅仅是在系统变量中新建了该项,但在运动程序时,发现配置并没有成功,干脆两种变量都加,问题解决了。

        配置好环境变量之后要重启电脑。

三、建立MFC单文档应用程序

       1. 工程名称:OgreTest2,配置如下:

2. 项目属性配置

进入属性页,选择“所有配置”,

配置属性—>常规

输出目录:bin\$(Configuration)\

中间目录:obj\$(Configuration)\

mfc的使用:使用标准 Windows 库

字符集:使用多字节字符集

       

配置属性—>调试

命令:  $(OGRE_HOME)\Bin\$(Configuration)\$(ProjectName).exe

工作目录: $(OGRE_HOME)\Bin\$(Configuration)


配置属性—>C/C++—>常规

附加包含目录

$(OGRE_HOME)\include
$(OGRE_HOME)\include\OIS
$(OGRE_HOME)\include\OGRE
$(OGRE_HOME)\Samples\Common\include
$(OGRE_HOME)\boost


配置属性—>C/C++—>预处理器

预处理器定义

添加一项:_AFXDLL


配置属性—>链接器—>常规

附加目录库:

$(OGRE_HOME)\lib\$(Configuration)
$(OGRE_HOME)\boost\lib


配置 切换为“Debug”:


配置属性—>链接器—>输入

附加依赖项:

OgreMain_d.lib
OIS_d.lib


配置 再切换为“Release”:

配置属性—>链接器—>输入

附加依赖项:

OgreMain.lib
OIS.lib


至此,完成配置工作,在分别在DEBUG和RELEASE模式下,点击生成命令,成功!


四、渲染场景至MFC窗口


1. 项目->添加类->C++类


      添加的类名为“CMyOgreApp”,源代码如下:

头文件

#pragma once
#include "ogre.h"
#include "OgreConfigFile.h"
#include "OgreFrameListener.h"
#include "OgreStringConverter.h"
#include "OIS.h"

#include <SdkTrays.h>
#include <SdkCameraMan.h>
#include "MyFrameListener.h"
using namespace Ogre;
class CMyOgreApp
{
public:
	CMyOgreApp(void);
	~CMyOgreApp(void);

	Ogre::Root* getRoot(void) const {return mRoot;}
	Ogre::Camera* getCamera(void) const {return mCamera;}
	Ogre::SceneNode* getCamNode(void) const {return mCamNode;}
	Ogre::SceneManager* getSceneManager(void) const {return mSceneMgr;}
	Ogre::RenderWindow* getRenderWindow(void) const {return mWindow;}

	bool go(CRect rt, HWND hWnd);
	void createRoot(void);
	void setupResources(void);
	void setupRenderSystem(void);
	void createRenderWindow(HWND m_hWnd, int width, int height);
	int initializeResourceGroups(void);
	void chooseSceneManager(void);
	void createCamera(void);
	void createViewport(void);
	void createScene(void);
	void createFrameListener(void);
	class CMyFrameListener* mListener;

private:
	Ogre::Root* mRoot;
	Ogre::RenderWindow* mWindow;            
	Ogre::SceneManager* mSceneMgr;
	Ogre::Camera* mCamera;
	Ogre::SceneNode* mCamNode;
	OgreBites::SdkCameraMan* mCameraMan;     // basic camera controller
	Ogre::Light* light;
};


源文件

#include "StdAfx.h"
#include "MyOgreApp.h"


CMyOgreApp::CMyOgreApp(void)
{
}


CMyOgreApp::~CMyOgreApp(void)
{
}


bool CMyOgreApp::go(CRect rt, HWND hWnd)
{
	createRoot();
	setupResources();
	setupRenderSystem();
	createRenderWindow(hWnd, rt.Width(), rt.Height());
	chooseSceneManager();
	createCamera();
	createViewport();
	initializeResourceGroups();
	createScene();
	createFrameListener();	//创建侦听
	return true;
}


void CMyOgreApp::createRoot(void)
{
//	mRoot = new Ogre::Root("plugins_d.cfg");		//debug模式用
	//已将plugins_d.cfg文件名改成了plugins.cfg,这样一来,无论是DEBUG还是RELEASE模式,都不用修改代码
	mRoot = new Ogre::Root("plugins.cfg");			//release模式用
}


void CMyOgreApp::setupResources(void)
{
	// Load resource paths from config file
	Ogre::ConfigFile cf;
//	cf.load("resources_d.cfg");		//debug模式用
	//已将plugins_d.cfg文件名改成了plugins.cfg,这样一来,无论是DEBUG还是RELEASE模式,都不用修改代码
	cf.load("resources.cfg");		//release模式用

	// Go through all sections & settings in the file
	Ogre::ConfigFile::SectionIterator seci = cf.getSectionIterator();

	Ogre::String secName, typeName, archName;
	while (seci.hasMoreElements())
	{
		secName = seci.peekNextKey();
		Ogre::ConfigFile::SettingsMultiMap *settings = seci.getNext();
		Ogre::ConfigFile::SettingsMultiMap::iterator i;
		for (i = settings->begin(); i != settings->end(); ++i)
		{
			typeName = i->first;
			archName = i->second;
			Ogre::ResourceGroupManager::getSingleton().addResourceLocation(
				archName, typeName, secName);
		}
	}
}

void CMyOgreApp::setupRenderSystem(void)
{
//	mRoot->showConfigDialog();
//	mRoot->restoreConfig();
	//if (!mRoot->restoreConfig() && !mRoot->showConfigDialog())
	//	throw Ogre::Exception(1, "未选择渲染系统","setupRenderSystem()");

	RenderSystemList* rl = &const_cast<RenderSystemList&>(mRoot->getAvailableRenderers());
	RenderSystem* rSys = NULL;
	RenderSystemList::iterator it = rl->begin();
	while (it!=rl->end())
	{
		if (-1 != (*it)->getName().find("OpenGL Rendering Subsystem"))
	//	if (-1 != (*it)->getName().find("Direct3D9 Rendering Subsystem"))
		{
			rSys = (RenderSystem*)(*it);
			break;
		}
		++it;
	}
	rSys->setConfigOption("Full Screen","Yes");
	rSys->setConfigOption("VSync","No");
	mRoot->setRenderSystem(rSys);
}


void CMyOgreApp::createRenderWindow(HWND m_hWnd, int width, int height)
{
	mRoot->initialise(false);//禁止ogre创建新的渲染窗口,而使用MFC的窗口
	NameValuePairList misc;
	misc["externalWindowHandle"] = StringConverter::toString((int)m_hWnd); 
	mWindow = mRoot->createRenderWindow("OgreRenderWindow", width, height, false, &misc);
}


int CMyOgreApp::initializeResourceGroups(void)
{
	TextureManager::getSingleton().setDefaultNumMipmaps(5);
	ResourceGroupManager::getSingleton().initialiseAllResourceGroups();
	return 0;
}


void CMyOgreApp::chooseSceneManager(void)
{
	mSceneMgr = mRoot->createSceneManager(ST_EXTERIOR_CLOSE);
}


void CMyOgreApp::createCamera(void)
{
	// Create the camera
	mCamera = mSceneMgr->createCamera("PlayerCam");

	// Position it at 500 in Z direction
	mCamera->setPosition(Ogre::Vector3(0,0,80));
	// Look back along -Z
	mCamera->lookAt(Ogre::Vector3(0,0,-300));
	mCamera->setNearClipDistance(5);
	mCameraMan = new OgreBites::SdkCameraMan(mCamera);   // create a default camera controller
}


void CMyOgreApp::createViewport(void)
{
	// Create one viewport, entire window
	Viewport* vp = mWindow->addViewport(mCamera);
	vp->setBackgroundColour(ColourValue(0,0,0));
	// Alter the camera aspect ratio to match the viewport
	mCamera->setAspectRatio(Real(vp->getActualWidth()) / Real(vp->getActualHeight()));
}


void CMyOgreApp::createScene(void)
{

	//添加背景
	mSceneMgr->setSkyDome(true, "Examples/CloudySky",6, 8);

	Ogre::Entity* ogreHead = mSceneMgr->createEntity("Head", "ogrehead.mesh");

	Ogre::SceneNode* headNode = mSceneMgr->getRootSceneNode()->createChildSceneNode();
	headNode->attachObject(ogreHead);

	// Set ambient light
	mSceneMgr->setAmbientLight(Ogre::ColourValue(0.5, 0.5, 0.5));

	// Create a light
	Ogre::Light* l = mSceneMgr->createLight("MainLight");
	l->setPosition(20,80,50);
}

//创建帧监听
void CMyOgreApp::createFrameListener(void)
{
	mListener= new CMyFrameListener(mWindow, mCamera, mSceneMgr, light);
	mRoot->addFrameListener(mListener);
}


2. 在View类的头文件中包含CMyOgreApp 的头文件

#include "MyOgreApp.h"


并声明两个变量

public:
	// ogre主类
	CMyOgreApp m_ogreApp;
	// 初次渲染
	bool m_firstDraw;


3. 在View类的构造函数中将m_firstDraw 初始化为  true。

4. 在View类的OnDraw函数中添加下如下代码

void COgreTest2View::OnDraw(CDC* /*pDC*/)
{
	COgreTest2Doc* pDoc = GetDocument();
	ASSERT_VALID(pDoc);
	if (!pDoc)
		return;

	// TODO: 在此处为本机数据添加绘制代码
	//Ogre渲染
	try {
		if(m_firstDraw)
		{
			m_firstDraw = false;
			CRect   rect;
			GetClientRect(&rect);
			m_ogreApp.go(rect,m_hWnd);//传入MFC主窗口句柄
			SetTimer(1,20,0);
		}

		m_ogreApp.getRoot()->renderOneFrame();
	} catch( Ogre::Exception& e ) {
#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
		MessageBox(  e.getFullDescription().c_str(), "An exception has occured!", MB_OK | MB_ICONERROR | MB_TASKMODAL);
#else
		std::cerr << "An exception has occured: " <<
			e.getFullDescription().c_str() << std::endl;
#endif
	}
}


5. 添加WM_TIMER和WM_ERASEBKGND消息处理函数,代码分别如下 :

void COgreTest2View::OnTimer(UINT_PTR nIDEvent)
{
	// TODO: 在此添加消息处理程序代码和/或调用默认值
	if (1 == nIDEvent)
	{
		m_ogreApp.getRoot()->renderOneFrame();
	}
	CView::OnTimer(nIDEvent);
}

BOOL COgreTest2View::OnEraseBkgnd(CDC* pDC)
{
	// TODO: 在此添加消息处理程序代码和/或调用默认值
	return TRUE;
}


五、添加事件处理方法,实现人机交互


1. 添加一个帧监听类:CMyFrameListener,代码如下:

头文件

#pragma once
#include "ogre.h"
#include "OgreConfigFile.h"
#include "OgreFrameListener.h"
#include "OgreStringConverter.h"
#include "OIS.h"

#include "MyOgreApp.h"
#include <OISEvents.h>
#include <OISInputManager.h>
#include <OISKeyboard.h>
#include <OISMouse.h>

#include <SdkTrays.h>
#include <SdkCameraMan.h>
using namespace Ogre;
class CMyFrameListener: public FrameListener, public OIS::MouseListener,public Ogre::WindowEventListener, public OIS::KeyListener
{
public:
	CMyFrameListener(RenderWindow* win, Camera* cam, SceneManager *sceneMgr, Light* light);
	~CMyFrameListener(void);
	bool frameRenderingQueued(const Ogre::FrameEvent& evt);
	bool mouseMoved(const OIS::MouseEvent &e);
	bool mousePressed(const OIS::MouseEvent &e, OIS::MouseButtonID id); 
	bool mouseReleased(const OIS::MouseEvent &e, OIS::MouseButtonID id);
	bool keyPressed(const OIS::KeyEvent &e);
	bool keyReleased(const OIS::KeyEvent &e);

protected:

	Ogre::SceneManager *mSceneMgr;//场景管理器
	Ogre::SceneNode* mCamNode;//摄像机节点
	Ogre::Camera* mCamera;//摄像机
	Ogre::RenderWindow* mWindow;//渲染窗口
	Ogre::Light* light;//灯光

	OIS::Keyboard* mKeyboard;//键盘         
	OIS::Mouse* mMouse;      //鼠标    
	OIS::InputManager* mInputManager;//输入管理器 

//	OgreBites::SdkTrayManager* mTrayMgr;
	OgreBites::SdkCameraMan* mCameraMan;     // basic camera controller
	bool mRBtdown;
};


源文件

#include "StdAfx.h"
#include "MyFrameListener.h"

CMyFrameListener::CMyFrameListener(RenderWindow* win, Camera* cam, SceneManager *sceneMgr, Light *l): mMouse(0), 
	mKeyboard(0), mInputManager(0), mWindow(win), mCamera(cam), light(l)
{
	mRBtdown = false;
	mCamNode=cam->getParentSceneNode();
	mSceneMgr = sceneMgr;


	size_t windowHnd = 0;
	std::ostringstream windowHndStr;
	OIS::ParamList pl;


	mCameraMan = new OgreBites::SdkCameraMan(mCamera);  


	windowHnd = (size_t )AfxGetMainWnd()->GetSafeHwnd(); // 这里这个窗口句柄就是传入的MFC主窗口
	windowHndStr << windowHnd;
	// OIS的窗口必须要顶层窗口,所以只有传MFC的主窗口给他,传view就不行
	pl.insert(std::make_pair(std::string("WINDOW"), windowHndStr.str()));


	// 设置鼠标显示和非游戏独占,这样鼠标可以显示在屏幕上并可以移动到窗口外
	pl.insert(std::make_pair(std::string("w32_mouse"), std::string("DISCL_FOREGROUND" )));
	pl.insert(std::make_pair(std::string("w32_mouse"), std::string("DISCL_NONEXCLUSIVE")));
	// 键盘非游戏独占
	pl.insert(std::make_pair(std::string("w32_keyboard"), std::string("DISCL_FOREGROUND")));
	pl.insert(std::make_pair(std::string("w32_keyboard"), std::string("DISCL_NONEXCLUSIVE")));
	mInputManager = OIS::InputManager::createInputSystem(pl);


	mKeyboard = static_cast<OIS::Keyboard*>(mInputManager->createInputObject( OIS::OISKeyboard, true ));
	mMouse = static_cast<OIS::Mouse*>(mInputManager->createInputObject( OIS::OISMouse, true ));


	mMouse->setEventCallback(this);
	mKeyboard->setEventCallback(this);
}




CMyFrameListener::~CMyFrameListener(void)
{
	mInputManager->destroyInputObject(mMouse);
	mInputManager->destroyInputObject(mKeyboard);
	OIS::InputManager::destroyInputSystem(mInputManager);
	mInputManager = 0;
}




bool CMyFrameListener::frameRenderingQueued(const Ogre::FrameEvent& e){


	mMouse->capture();
	mKeyboard->capture();
	mCameraMan->frameRenderingQueued(e); 
	return true;
}


bool CMyFrameListener::mouseMoved(const OIS::MouseEvent &e)
{
	if (mRBtdown)
	{
		mCameraMan->injectMouseMove(e);
	}
	
	return true;
}


bool CMyFrameListener::mousePressed(const OIS::MouseEvent &e, OIS::MouseButtonID id)
{
//	mCameraMan->injectMouseDown(e, id);
	if (id == OIS::MB_Right)
	{
		mRBtdown = true;
	}
	
	return true;
}


bool CMyFrameListener::mouseReleased(const OIS::MouseEvent &e, OIS::MouseButtonID id)
{


//	mCameraMan->injectMouseUp(e, id);
	if (id == OIS::MB_Right)
	{
		mRBtdown = false;
	}
	return true;
}
//键盘响应
bool CMyFrameListener::keyPressed(const OIS::KeyEvent &e)
{
	
	mCameraMan->injectKeyDown(e);


	return true;
}


bool CMyFrameListener::keyReleased(const OIS::KeyEvent &e)
{
	 mCameraMan->injectKeyUp(e);
	return true;
}



2. 为了实现监听与响应,需要修改CMyOgreApp类,而这些工作在上面贴出的代码中已经完成了,这里再简单说明一下:

在CMyOgreApp类的头文件中包含监听类

#include "MyFrameListener.h"

声明一个CMyFrameListener类的变量

class CMyFrameListener* mListener; 

声明一个函数,函数的实现已在上面的代码中贴出来了

void createFrameListener(void); 

在go()函数中调用createFrameListener()


3. 需要特别指出的是setupRenderSystem()函数的修改,本项目默认以OpenGL进行渲染,所以省略了渲染选择对话框

代码如下:

void CMyOgreApp::setupRenderSystem(void)
{
	RenderSystemList* rl = &const_cast<RenderSystemList&>(mRoot->getAvailableRenderers());
	RenderSystem* rSys = NULL;
	RenderSystemList::iterator it = rl->begin();
	while (it!=rl->end())
	{
		if (-1 != (*it)->getName().find("OpenGL Rendering Subsystem"))
	//	if (-1 != (*it)->getName().find("Direct3D9 Rendering Subsystem"))
		{
			rSys = (RenderSystem*)(*it);
			break;
		}
		++it;
	}
	rSys->setConfigOption("Full Screen","Yes");
	rSys->setConfigOption("VSync","No");
	mRoot->setRenderSystem(rSys);
}

如果想要弹出渲染选择对话框,则代码可以修改为如下:

void CMyOgreApp::setupRenderSystem(void)
{
	mRoot->showConfigDialog();
}

4. 为了保证在DEBUG和RELEASE模式下,程序都可以正确运行,本人将D:\OgreSDK_vc10_v1-8-1\bin\debug文件夹中的两个文件的名称改了:

plugins_d.cfg 改成了 plugins.cfg

resources_d.cfg 改成了 resources.cfg


至此,全部工作就完成了,生成并运行。














       







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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值