??xml version="1.0" encoding="utf-8" standalone="yes"?> 谢伟?nbsp; feiyurainy@163.com 转蝲h明出?/p>
很早以前想写一些关?span>OGRE的文章了Q一直没Z?/span> 理解一个渲染引擎,我觉得最重要的是先抓住了它的L构,它的ȝQ渲染流E,不然的话Q一个引擎几万行Q甚臛_十万行的代码Q光是打开solutionp吓你一跳了Q?/span>OGRE也有十几万行的代码量Q我一开始看它的时候也是无从下手,感觉代码太多了,不知道从哪开始看好,q个class看看Q那?/span>class看看Q由于对整个引擎没有一个清晰的认识Q看q了也印象不深,所以,最后,q是军_先找出它的主U,了解它的渲染程Q这h能有机地把各个部分联pv来?/span> q篇短文也是?/span>OGRE的主要渲染流E的一个介l,可能对一?/span>class不会太多地去介绍具体的实现细节。我所用的代码都是取自?/span>OGRE的最新的CVS版本?/span> 读者最好对OGRE有一定的了解Q至得看懂它的exampleQ不然可能一些东西理解v来比较困难。对D3DQ?/span>OPENGL有一定了解更好?/span> 如果你看q?/span>D3D SDK中带的例子,你一定知道一个比较简单的3DE序要运行v来,臛_都会涉及以下的几部分Q?/span> 首先是数据的来源Q包括顶Ҏ(gu)据,U理数据{,q些数据可以从文件中dQ也可以在程序运行时生成?/span> 接下来,我们会徏立顶点缓冲区把顶点保存v来,建立texture对象来表C?/span>textureQ对点l成的物体设|它在世界坐标系下的坐标Q设|摄像机的位|,视点Q设|?/span>viewport的位|和大小Q然后就可以在渲染@环中开始调用渲染操作了Q经q了front buffer?/span>back buffer的交换,我们p在屏q上看到3D囑Ş了,伪代码如下: setupVertexBuffer setWorldTransform setCamera setProjectionTransform setViewport beginFrame setTexture drawObject endFrame 以下是渲染一个物体的主要步骤Q在我看来,q就?/span>3DE序的主U,同样道理Q无Z多复杂的渲染引擎Q都得实Cq的q些步骤Q其他的一些效果如阴媄Q光照等Q都是附着在这条主U上的,所以,如果你能在你所研究的渲染引擎上也清晰地看到q条ȝQ可能对你深入地研究它会大有帮助Q下面,我们׃h扑ֈOGRE中的q条ȝ?/span> OGRE的渲染@环都是v源于Root::renderOneFrameQ这个函数在OGRE自带?/span>example中是不会昑ּ调用的,因ؓexample都调用了Root::startRenderingQ由startRendering来调?/span>renderOneFrameQ如果你?/span>OGRE来写真正的游戏,或者编辑器Q你可能需要在的消息主循环中调?/span>renderOneFrame了,思义Q这个函数就是对整个OGREq行一帧的更新Q包括动画,渲染状态的改变Q渲?/span>api的调用等Q在q个函数中,会包括了我们上述伪代码的几乎全部内容Q所以是本文的重Ҏ(gu)在?/span> q入renderOneFrameQ可以看到头两?/span>fire函数Q这U函数在OGRE中经常出玎ͼ一般都?/span>fire…start?/span>fire…end一起出现的Q在q些函数中,可能会处理一些用戯定义的操作,?/span>_fireFrameStarted׃Ҏ(gu)以的frameListenerq行处理Q这?/span>fire函数可以暂时不用理会Ql看_updateAllRenderTargetsQ在q个函数中,会委zֽ前所用的rendererҎ(gu)有创建出来的render targetq行updateQ?/span>render target也就是渲染的目的圎ͼ一般会有两U,一U是render textureQ一U是render bufferQ接着q入RenderSystem::_updateAllRenderTargetsQ可以看到在render system中,对创建出来的render target是用RenderTargetPriorityMap来保存的Q以便按照一定的序来对render targetq行updateQ因为在渲染物体?/span>render bufferӞ一般会用到之前渲染好的render textureQ所?/span>render texture形式?/span>render target需要在render buffer之前q行更新?/span> q入render target?/span>updateQ可以看刎ͼ它仍然把update操作l箋传递下去,调用所有挂在这?/span>render target上的viewport?/span>update?/span> Viewport其实是定义?/span>render target上的一块要q行更新的区域,所以一?/span>render target是可以挂多个viewport的,以实现多人对战时分屏Q或者是Mȝ效果Q可以把OGRE中的viewport看成是保?/span>camera?/span>rendertargetq两者的l合Q把viewport中所定义?/span>camera所看到的场景内Ҏ(gu)染到viewport所定义?/span>render target的区域里?/span> Viewportq有一个重要信息是ZOrderQ可以看?/span>RenderTarget中的ViewportList带有一个比较函敎ͼ所以在RenderTarget::update中,ZOrder小的,先被渲染,所以,如果两个viewport所定义的区域互盔R叠了Q而且ZOrder又不一P最l的效果是ZOrder的viewport的内容会?/span>ZOrder大的viewport的内Ҏ(gu)覆盖?/span> l箋q入Viewport::updateQ就像前面所_它调用它所引用?/span>camera来渲染整个场景,而在Camera::_renderScene中,是调?/span>SceneManager::_renderScene(Camera* camera, Viewport* vp, bool includeOverlays)?/span>SceneManager::_renderScene里就是具体的渲染程了。从函数名称q有参数也可以看出来Q这个函数的作用是利用所指定?/span>camera?/span>viewportQ来把场景中的内Ҏ(gu)染到viewport所指定?/span>render target的某块区域中。根?/span>cameraQ我们可以定?/span>view matrixQ?/span>projection matrixQ还可以q行视锥剔除Q只渲染看得见的物体。注意,我们q里只看标准?/span>SceneManager的方法,不看BspSceneManagerzcȝҎ(gu)Q而且Q我们会抛开跟主U无关的内容Q如?/span>shadow?/span>setupQ骨骼动ȝ播放Q?/span>shader参数的传递等Q因为我们只注重渲染的主程?/span> ?/span>SceneManager::_renderScene中所应看的第一个重要函数是_updateSceneGraphQ?/span>OGRE对场景的l织是通过节点?wi)来l织的,一个节点,你可以看成是I间中的某些变换的组合,如位|,~放Q旋转等Q这些变换,会作用到挂接在这些节点上的具体的物体的信息,也就是说Q节点保存了world transformQ对具体的物体,如一个hQ在I间中的定位Q都是通过操作节点来完成的。同时节点还保存了一个世界坐标的AABBQ这?/span>AABB能容Ux有它所挂接的物体的大小Q主要是用于视锥裁减的,如果当前摄像机看不见某个节点?/span>AABBQ那么说明摄像机看不见节Ҏ(gu)挂接的所有物体,所以在渲染时可以对q个节点视而不见?/span> _updateSceneGraph的内部处理比较繁琐,我们只需知道Q经q了_updateSceneGraphQ场景节Ҏ(gu)(wi)中的每个节点都经q了更新Q包括位|,~放Q和方位Q还有节点的包围盒?/span> l箋回到SceneManager::_renderSceneQ接下来要看的是setViewportQ它会调用具体的renderer?/span>setviewport的操作,讄viewport中所挂接?/span>render target为当前所要渲染的目标Q?/span>viewport中的区域为当前所要渲染的目标中的区域?/span> 接下来要到OGRE渲染程中的一个重要的概念Q?/span>Render Queue。这个东西实在内Ҏ(gu)较多Q还是以后有Z单独提出来说吧,你可以简单把它想成是一个容器,里面的元素就?/span>renderableQ每?/span>renderable可以看成是每ơ调?/span>drawprimitive函数所渲染的物体,可以是一个模型,也可以是模型的一部分。在RenderQueue中,它会按材质来分组q些renderableQ还会对renderableq行排序?/span> 在每一ơ调?/span>SceneManager::_renderSceneӞ都会调用SceneManager::prepareRenderQueue来清?/span>RenderQueueQ然后再调用SceneManager::__findVisibleObjects来把当前摄像机所能看见的物体都加入到RenderQueue中?/span> SceneManager::__findVisibleObjects是一个递归的处理过E,它从场景的根节点开始,先检查摄像机是否能看见这个节点的包围盒(包围盒在_updateSceneGraph时已l计好了)Q如果看不见Q那么这个节点,q有它的子节炚w不用了。如果能看见Q再挂在这个节点上的所?/span>MovableObjectQ如果当前所的MovableObject是可见的Q就会调用它?/span>_updateRenderQueueҎ(gu)Q一般在q个Ҏ(gu)里就可以把和q个MovableObject相关?/span>renderable送入RenderQueue了?/span> q里要说?/span>MovableObjectQ?/span>MovableObject主要是用于表C场景中L的物体,?/span>EntityQ顾名思义Q能Ud的物体,不过它的“能移?#8221;q个能力是要通过SceneNode来实现的Q所?/span>MovableObject来能昄出来Q首先得先挂接在某个场景节点上,通过场景节点来定位。你可以控制MovableObject的一些属性,如某?/span>MovableObject是否要显C,是否要隐藏,都可以通过MovableObject::setVisibleҎ(gu)来实现?/span> 完该节点上?/span>MovableObject之后Q就l箋调用所有子节点?/span>_findVisibleObjectsҎ(gu)Q一直递归下去。这Pp把场景中所有要渲染?/span>renderable所加入?/span>RenderQueue中了?/span> xQ我们就拥有了要渲染的物体的信息了,接下来就是对q些物体q行渲染了,你会发现?/span>D3D?/span>OpenGL的代码很cM的调用: mDestRenderSystem->clearFrameBuffer mDestRenderSystem->_beginFrame mDestRenderSystem->_setProjectionMatrix mDestRenderSystem->_setViewMatrix _renderVisibleObjects(); mDestRenderSystem->_endFrame(); q些api的作用和D3D中的cM调用的作用都差不多,q里再说一?/span>_renderVisibleObjects()Q在q个函数中,会对RenderQueue中的每个renderableq行渲染Q用的是visitor模式来遍历操作每?/span>renderableQ最l在SceneManager::renderSingleObject中取出每?/span>renderable所保存的顶点,索引Q世界矩늭信息Q来q行渲染。这其中q包括了查找该renderable最q的光源{操作,比较复杂?/span> 到这里,SceneManager::_renderScene的流E基本走完了Q也是_OGRE一帧中的渲染流E差不多也结束了Q你应该也发玎ͼq个程跟你?/span>D3D写一个简单程序的程基本是一L(fng)Q在q个程的基上,再去看具体的实现Q如怎么栯|纹理,怎么栯用你熟?zhn)?/span>D3D?/span>OpenGL?/span>API来渲染物体,应该会简单得多?/span> ?/span>OGRE的渲染流E的大概介绍到这里也l束了,很多l节都没涉及Q以后有Z再写吧?/span>
posted on 2007-05-22 10:59 hitmaen 阅读(762) 评论(2) ~辑 收藏 引用 所属分c? Ogre
Ogre是一个跨操作pȝq_的开?D引擎Q既支持DirectXQ也支持使用OpenGLQ支持可替换的场景管理算法(BSP, OCTQ。ؓOgre提供q些灉|可扩展性的基础之一是光向插件的设计?br>
很多常用的Y件大都提供了插g接口Q用以扩展应用程序设计者最初未惛_的功能,比较常见的譬如PhotoShop的o镜,After Effect中的各种插gQ最有名的比如shineQ,3dMax的插件譬如渲染器Q魔兽世界的辅助插g{等?br>
通常Q插件本w通常也需要实C应用E序所需要的必要接口Q从而得插件可以被应用E序加蝲执行。此外,插g的实C需要由d用程序提供一些接口apiQ通过q些接口Q插件可以对d用程序的功能q行调用?br>
插g可以是动态链接库Qwin32q_上ؓDLL文gQ,也可以是以脚本的形式提供的,比如兽世界中的插g是使用lua~写的,插g也可能是某种应用E序自定义的文gQ只要该应用E序提供了创cL件的Ҏ(gu)q实现解析、执行功能即可。(不同的实现Ş式各有利弊,具体需要参考插件及应用E序所处的q行环境q行取舍Q?br>
采用插g的一个巨大的好处Q以及很多应用程序中使用插g的主要目的就是,我们可以在不需要改动应用程序本w的情况下扩展应用程序的功能?br>
在Ogre中,插g被用来提供渲染子pȝQRenderSystemQ,不同cd的图形API被封装在不同的渲染子pȝ的视U当中,Ogre默认提供了DX和OpenGL的实玎ͼ甚至Q如果我们乐意,甚至可以只用l点函数实现一套纯软g的渲染子pȝ提供lOgre使用。以此ؓ例,用简单的形式来展CU实现大概类g下面q样Q?br>
class RenderSystem
{
// … operations that a render system need to support
};
// In DX_RenderSystem.dll (in plugin dx rendersystem )
class DX_RenderSystem : public RenderSystem
{
// … implementation & override of the operations from RenderSystem using DirectX
};
// In GL_RenderSystem.dll (in plugin openGL rendersystem)
class GL_RenderSystem : public RenderSystem
{
// … implementation & override of the operations from RenderSystem using OpenGL
};
// …. We could implement any other rendersystem as we like
在引擎的内部QOgreMainQ,插g在初始化的时候,一个渲染子pȝ的实例创建出来(可能是DX_RenderSystemQ也可能?nbsp;GL_RenderSystemQ也可能是其他)Qƈ之挂接到OgreMain的Root对象当中。此后,OgreMain中的Root所有的渲染操作也就可以通过该接口访问插件中创徏的渲染子pȝ了?br>
本文接下来分析Ogre是如何实现插件的Q以及插件是如何与OgreMaind擎进行配合的?br>
事实上,想编写一个插件是很简单的Q我们只需要约定几个接口,插g这些接口实CQ主应用E序通过某种机制Q配|文?/span>/遍历某个目录Q加载插Ӟq查找接口在插g中是否被实现了,如果实现了,则调用之卛_?br>
一个简单的例子如下Q?br>
// in xx.dll
__declspec(dllexport) extern “C” // __declspec(dllexport)告知~译器需要将该函数导?br>
// extern “C” 告知~译器不要对函数做C++名字重整
const char* GetPluginName(void)
{
return “Test Plugin”;
}
// in application
HMODULE hInst = LoadLibrary(”xx.dll”);
if (!hInst) return;
typedef const char* (*GetPluginNameFunc)(void);
GetPluginNameFunc pFunc = GetProcAddress(hInst, “GetPluginName”);
if (!pFunc) return;
const char* szPluginName = pFunc();
// … do other things
事实上,在C语言里,我们可以通过q种方式Q约定一套需要实现的接口Q交l插件实现即可。在q里Q插件的功能都是在dll中实现的Q我们需要加?nbsp;dllQ保存句柄,q在插g卸蝲的时候释攄应的资源。在C++中,我们昄可以做的更好一点,比如dll模块相关的功能以及资源封装v来:
class DynLib
{
public:
bool Load(const char* szPluginPath);
void* GetProcAddress(const char* szProcName);
private:
HMODULE m_hInst;
};
bool DynLib::Load(const char* szPluginPath)
{
m_hInst = LoadLibrary(szPluginPath);
return m_hInst != NULL;
}
void* DynLib::GetProcAddress(const char* szProcName)
{
return ::GetProcAddress(m_hInst, szProcName);
}
q样一来,我们有了一个DLL的简单封装?br>
但是一个dll里未必只能有一个插Ӟ假若我们单的把插件接口设计ؓ一套C导出函数Q我们就不得不面对这U局限。经典的做法依旧是抽象,Ogre中定义了一个插件接口,每一个实C插g接口的实例都代表了一个插Ӟ如下Q?br>
class Plugin
{
public:
virtual const String& getName() = 0;
virtual void install() = 0;
virtual void initialize() = 0;
virtual void shutdown() = 0;
virtual void uninstall() = 0;
};
Ogre的每一个插仉需要实C上接口。该接口提供的功能包括:
install 插g被加载时调用?br>
initialize 插g被初始化时调用?br>
shutdown 插g被反初始化时调用?br>
uninstall 插g被卸载时调用?br>
不过Q单有这个接口,插gq是无法工作。插件中q需要提供两个约定的C导出函数。这个稍后再说?br>
Ogre在Root对象中统一理插gQ因此Root对象提供了以下与插g相关的接口:
class Root
{
// …
void loadPlugin(const String& pluginName);
void unloadPlugin(const String& pluginName);
void installPlugin(Plugin* plugin);
void uninstallPlugin(Plugin* plugin);
// 以及对应的处理多个插件的接口
// …
};
当loadPlugin函数被调用时QOgre加载该插g的dllQ从中查扑ƈ调用名ؓdllStartPlugin的导出函数?br>
对应的,当unloadPlugin函数被调用时QOgre从该dll中调用dllStopPlugin函数。ƈ该dll卸蝲?br>
每个插g在实现的时候,都必L供上q的两个C导出函数。其中,dllStartPlugin负责创徏插g实例Qƈ调用 Root::installPluginQ将创徏好的插g指针传递给Root对象。在q里QdllStartPlugin实际可以创徏多个插g实例Qƈ依次调用Root::installPluginQ这h们就可以在一个DLL中包含多个插件了。在dllStopPluginӞ则需要调?nbsp;Root::uninstallPluginQƈ插件DLL中创建的plugin实例释放掉?br>
一个典型的dllStartPlugin的实现像q样Q?br>
class D3D9Plugin : public Plugin
{
//…
};
D3D9Plugin* plugin;
__declspec(dllexport) extern “C”
void dllStrartPlugin(void)
{
plugin = new D3D9Plugin();
Root::getSingleton().installPlugin(plugin);
}
__declspec(dllexport) extern “C”
void dllStopPlugin(void)
{
Root::getSingleton().uninstallPlugin(plugin);
delete plugin;
}
Root::getSingleton().installPlugin(plugin)会负责调用插件的install以及initialise操作Qƈ插件的指针存放hQ以备卸载时使用?br>
Plugin::install以及Plugin::initialise则分别负责创建OgreMain提供扩展功能接口的实例,以及创建好的对象挂载到应用E序当中?br>
一个典型的Plugin的行为像q样Q?br>
void BspSceneManagerPlugin::install()
{
mBspFactory = new BspSceneManagerFactory();
}
void BspSceneManagerPlugin::initialise()
{
Root::getSingleton().addSceneManagerFactory(mBspFactory);
}
其中QBspSceneManagerFactory是承自OgreMain中的SceneManagerFactory的派生类?br>
( class BspSceneManagerFactory : public SceneManagerFactory {…} )
通过场景管理器工厂d到Root对象当中Q插件动态的其功能dCOgreMain当中?br>
PS: SceneManagerFactory是一个用于创建SceneManager的工厂。SceneManager则是被用于场景管理的理器。具体的 SceneManager也根据算法不同而不同,Ogre自带提供了两U类型的场景理法插gQBsp以及Octree(实现了两个对应的插gQ分别是 Plugin_BSPSceneManager以及Plugin_OctreeSceneManager)?br>
通过上述方式QOgreMain核心引擎q不需要关心场景管理算法的具体实现Q不需要关心渲染子pȝ的具体实玎ͼ不需要关心粒子系l的具体实现Q等{。一切这些扩展性的功能都通过插g实现Qƈ在加载时动态挂载到OgreMain当中Q供OgreMain的引擎核心用?br>
使用插g时几个需要注意的地方Q?br>
1Q?nbsp; 调用插gDLLҎ(gu)创徏的对象需要交由插件DLL释放。(因ؓ不同的链接单元可能具有不同的内存理上下文环境,此处的new与彼处的new在语义上未必{同Q?br>
2Q?nbsp; 调用插gDLLҎ(gu)获取的插件内对象的引用或指针Q在插gDLL卸蝲之后是无效的,必须保证不再使用。(比较Ҏ(gu)引发问题的一个典型例子是从插件中传递回一个引用计数字W串Q当DLL被卸载后Q字W串内指向实际数据的指针已经无效Q但是在该对象析构时Q仍需要访问该指针Q?/span>
]]>
]]>
?
通情况下Q我们用单一的摄像机Q实现第一人称或者第三hUͼ有时我们用多个摄像机在单一的窗口中切换视角Q比如从W一人称切换到第三hU视角(游戏中屡
见不鲜)Q而画中画会同时展现W一人称和第三hUͼ或者第三hUCW三人称Q,也就是说同时存在不同的观察点Q这需要多H口多摄像机分别q行渲染?br>
用Ogre实现Md能是件比较容易的事情Q首先,搭徏一个普通的场景Q关于这斚w的工?a >www.ogre3d.org/wiki里有详细的教E,不赘qC?br>
下面q入关键部分?br>
在Ogre里摄像机Camera和视口Viewport是一一对应的关p,普通情况下包含一个摄像机对应一个视口,我们只要d摄像机和与之对应的视口就O(jin)K了!
我的H口c里是这样配|Ogre的,基本和教E示例里的一栗?br>
{
mRoot = new Root();
// 讄资源
setupResources();
// 配置渲染H口
bool carryOn = configure();
if (!carryOn)
return false;
// 创徏场景理?/span>
chooseSceneManager();
// 创徏摄像?/span>
createCamera();
// 创徏视口
createViewports();
// 讄~省 mipmap {
TextureManager::getSingleton().setDefaultNumMipmaps(5);
// 创徏所有资源监听器Qؓ了加载屏q)
createResourceListener();
// 加蝲资源
loadResources();
// 创徏场景
createScene();
// 创徏帧监听器
createFrameListener();
return true;
}
其中Q?span style="color: #000000;">createCamera(); // 创徏摄像?/span> ?createViewports(); // 创徏视口 是我们需要关心的?br>
createCamera()Q?/span>
{
// ȝ口摄像机
mCamera_1 = mSceneMgr->createCamera("Cam_1");
mCamera_1->setPosition(Vector3(0,0,300));
mCamera_1->lookAt(Vector3(0,0,-300));
mCamera_1->setNearClipDistance(5);
// ML像机
mCamera_2 = mSceneMgr->createCamera("Cam_2");
mCamera_2->setPosition(Vector3(100,100,300));
mCamera_2->lookAt(Vector3(-100,-100,-300));
mCamera_2->setNearClipDistance(5);
}
createViewports()Q?br>
{
// ȝ?/span>
Viewport* vp_1 = mWindow->addViewport( mCamera_1 );
vp_1->setBackgroundColour( ColourValue(0,0,0) );
mCamera_1->setAspectRatio(
Real( vp_1->getActualWidth() ) / Real( vp_1->getActualHeight() ) );
// M?/span>
Viewport* vp_2 = mWindow->addViewport( mCamera_2, 1, 0.7, 0.05, 0.25, 0.25 );
vp_2->setBackgroundColour( ColourValue(0,0,0) );
vp_2->setOverlaysEnabled(false);
mCamera_2->setAspectRatio(
Real( vp_2->getActualWidth() ) / Real(vp_2->getActualHeight() ) );
}
?/span>addViewport中我们控制画中画视口在主H口中的位置和大(注意q里??的取D_cM于脓(chung)囑֝标)
q样实C下图所C效果的一半了?br>
是不是很P如果q一步设计成Q当触发某一事g时将Mȝ口动态的弹出Q那更酷了Q有兴趣的可以试一试:P
如图所C,我另外还利用了CEGUIl画中画H口加了个边框,q且带了一个combobox用来控制更多摄像Z间的切换QCEGUI是用脚本来定义界面的Q实C比较单。有关CEGUI部分的介l,在ogre wiki上有更详l的教程?br>
#end
评论
# re: [ 试验 ] 用Ogre实现M?[ 截图 ]
2007-05-22 16:14
万连?/a>
# re: [ 试验 ] 用Ogre实现M?[ 截图 ]
2007-05-22 19:05
hitmaen
@万连?
鹰眼是什么?不是指小地图Q玩一玩跑跑卡丁R明白我说的ML什么了 回复 更多评论
]]>
?span lang="EN-US">Ogre1.2.5版本中,通过?span lang="EN-US">Ogre官方论坛的开发者讨论实COverlay的中文显C,当初的实现非常的怪异Q具体的实现可以参见Ogre官方论坛?span lang="EN-US">
随着Ogre的更斎ͼ现在Ogre已经发布?span lang="EN-US">1.4.7Q?span lang="EN-US">1.4pd版本有一个重要的改进Q就是加入了UTFStringQ这?span lang="EN-US">Ogre中文昄予以很大的帮助。ؓ了便于演C,我直接?span lang="EN-US">Ogre自带?span lang="EN-US">OverlayQ也是大家熟?zhn)?span lang="EN-US">DebugOverlayQ测试工E我选择Demo_ParticleFXQ选择其他的也没有关系。现在编译它Q运行后得到下图Q?span lang="EN-US">
囄最左下角显C的是英文DebugOverlayQ接下来我们的Q务就是把它编E中文的Q?span lang="EN-US">^_^?span lang="EN-US">
Overlay中文化操作步骤如?span lang="EN-US">
1. 打开OgreSDK\media\packs\ OgreCore.zip?span lang="EN-US">
2. 打开C:\WINDOWS\FontsQ把simhei.ttfd?span lang="EN-US">OgreCore.zipQ(什么,没有simhei.ttfq个文gQ那p其他的中?span lang="EN-US">ttf字体吧)?span lang="EN-US">
3. 打开OgreCore.zip中的Ogre.fontdefQ里面有BlueHighwayq个字体定义块,在他的下面添加我们的SimHeiQ?span lang="EN-US">code_points里面的一大堆数字看不明白没关p,随后文章会解释?span lang="EN-US">
SimHei
{
type truetype
source simhei.ttf
size 16
resolution 96
code_points
33-166 24403-24403 21069-21069 24103-24103 36895-36895 29575-29575
24179-24179 22343-22343 26368-26368 39640-39640 20302-20302 19977-19977
35282-35282 24418-24418 25968-25968 37327-37327 25209-25209 27425-27425
}
4. 打开OgreCore.zip中的OgreDebugPanel.overlayQ把BlueHighway全部替换?span lang="EN-US">SimHeiQ我们要使用中文字体了,嘿嘿?span lang="EN-US">
5. 修改完成后,保所做的修改已经保存?span lang="EN-US">OgreCore.zip?span lang="EN-US">
6. q入Ogre解决Ҏ(gu)Q打开文gExampleFrameListener.hQ把54-59行的代码替换如下Q?span lang="EN-US">
static String currFps = "Current FPS: ";
static String avgFps = "Average FPS: ";
static String bestFps = "Best FPS: ";
static String worstFps = "Worst FPS: ";
static String tris = "Triangle Count: ";
static String batches = "Batch Count: ";
static DisplayString currFps = L"当前帧速率: ";
static DisplayString avgFps = L"q_帧速率: ";
static DisplayString bestFps = L"最高速率: ";
static DisplayString worstFps = L"最低速率: ";
static DisplayString tris = L"三角形数?span lang="EN-US">: ";
static DisplayString batches = L"Ҏ(gu): ";
7. 最后重新编译工E,下面是我q行的截图,是不是已l显CZ文了Q?span lang="EN-US">^_^?span lang="EN-US">
现在再来看看SimHei中的code_points是如何生成的Q这个可以参考我上次写的q篇文章http://www.cnblogs.com/gogoplayer/archive/2008/05/09/1189795.htmlQ至此,实现Overlay中文昄?/span>
转蝲h明出处:
作者:gogoplayer
E-mail : gogoplayer@163.com
QQ : 78939328
本文由 自由骑士W志 译整理,版权属于OgreTeam。{载请包含本行信息?/span>
q个工具包包含了一些对Ogre资源文gq行操作的预处理命o行工兗?/span>
它包?/span>OgreXMLConveter, OgreMeshUpgrade, OgreMaterialUpgrade?/span>MeshMagick?/span>
(zhn)可以在q里获得?/span>WindowsV
.[OgreXMLConveter]
OgreXML转换器能够将 .mesh 模型|格文g ?/span> .skeleton 骨骼文g ?/span>XML格式转换Zq制格式Q同时可以将其二q制格式转换?/span>XML格式。它同时也允怽在将XML格式转换Zq制格式时设|?/span>LOD层信息?/span>
如果你的Ogre脚本资源中原本用的是XML格式文g的话Q那么本工具则是Ogreq行时必ȝ。所以你能够?/span>OgreSource包的Tools/XMLConverter中找到它?/span>
使用Ҏ(gu)Q?/span>
OgreXMLConverter 操作选项 源文件\?/span> 目标文g路径
有用的操作选项包括Q?/font>
-i = 控制与命令行?/span>
-l nLODNum = 指定?/span>LOD层 ( 该项仅在XML格式转换?/span>Mesh格式时有?/span> )
-d nLODDis = 指定LOD层间的距离增幅 ( 该项仅在XML格式转换?/span>Mesh格式时有?/span> )
-p nLODPer = 指定每两U?/span>LOD层之间三角面减少癑ֈ?/span> ( 该项仅在XML格式转换?/span>Mesh格式时有?/span> )
-f nLODNum = 指定两LOD层之间的固定点减少?/span> ( 该项仅在XML格式转换?/span>Mesh格式时有?/span> )
-e = 关闭模版阴媄?/span>edge?/span> ( 当用模版阴影时该项才有?/span> )
-r = 关闭Ogre推荐的顶点缓冲区格式?/span>
-t = 为法U脓(chung)囄成切U信?/span> ( 当用法U脓(chung)图时该项才有?/span> )
-o = 关闭冗余关键桢和q动轨迹的剔?/span>
-d3d = 优先使用D3Dq行颜色格式的填?/span> ( ?/span>Windowsq_中默认该开?/span> )
-gl = 优先使用GLq行颜色格式的填?/span> ( 在非Windowsq_中默认该开?/span> )
-E endian = 讄endian模式Q可以选择big, little ?/span> native ( 默认?/span>native )
-q = 轻量模式Q减输出?/span>
-log filename = Log文g名称。(默认?/span>OgreXMLConverter.logQ?/span>
.[OgreMeshUpgrade]
q个工具能够你的Q何老版本的 .mesh 文g更新到当前版本的 .mesh 文g?/span>
你可以在Ogre.log文g中得?/span>.mesh文g的版本信息。一般来_Ogre可以q行老版本的.mesh文gQ但是性能上会有一些差别。如果你更新?/span>Ogre的其他部分,你尽量应当将.mesh文g更新为同L(fng)版本?/span>
使用Ҏ(gu)Q?/span>
OgreMeshUpgrate 操作选项 源文件\?/span> 目标文g路径
有用的操作选项包括Q?/font>
-i = 控制与命令行?/span>
-l nLODNum = 指定?/span>LOD层 ( 该项仅在XML格式转换?/span>Mesh格式时有?/span> )
-d nLODDis = 指定LOD层间的距离增幅 ( 该项仅在XML格式转换?/span>Mesh格式时有?/span> )
-p nLODPer = 指定每两U?/span>LOD层之间三角面减少癑ֈ?/span> ( 该项仅在XML格式转换?/span>Mesh格式时有?/span> )
-f nLODNum = 指定两LOD层之间的固定点减少?/span> ( 该项仅在XML格式转换?/span>Mesh格式时有?/span> )
-e = 关闭模版阴媄?/span>edge?/span>
-r = 关闭Ogre推荐的顶点缓冲区格式?/span>
-t = 为法U脓(chung)囄成切U信?/span>
-d3d = 转换?/span>D3D颜色格式
-gl = 转换?/span>GL颜色格式
-srcd3d = 老版本的mesh文g?/span>D3D颜色格式
-srcgl = 老版本的mesh文g?/span>GL颜色格式
-E endian = 讄endian模式Q可以选择big, little ?/span> native ( 默认?/span>native )
注意Q?/span>
q个工具现在允许你自定义重组你的mesh|格文g的顶Ҏ(gu)式?/span>
如果你想更新
q个工具能够你的Q何老版本的 .material 材质文g更新到当前版本的 .material 材质文g?/span>
值得注意的是q个自动更新是不会加入一些新的脚本语法功能的Q这么说你可能不好理解。(例子Q?/span> “scene_blend add”q句可能会被更新?/span>”scene_blend one one”Q因?/span>”add”的底层实际上是”scene_blend one one”Q自动更C一些高U语法更Cؓ比较直接底层的语法)
另外Q这个工具仅?/span>
使用Ҏ(gu)Q?/span>
OgreMaterialUpgrade 源文件\?/span> 目标文g路径
Copyright 2007 by Daniel Wickert
q个工具是对mesh文g?/span>skeleton文gq行一些处理的工具?/span>
大致包括以下功能Q?/font>
Info = 输出mesh的信息?/span>
Meshmerge = 多?/span>mesh合ƈZ?/span>mesh文g
rename = 重命?/span>mesh?/span>skeleton的不同元?/span>
transform = 旋{Q羃放一?/span>mesh
使用方式Q?/span>
MeshMagick –help=工具?/span> 可以获得更多相关信息?/span>
1Q除MeshMagick该工具外Q其他三U工P使用方式都可以是Q将源资源文件拖拽到工具?/span>exe图标上。因为更新程序会源文g覆盖Q所以推荐做下备份后再更新?/span>
2Q?zhn)可以写批处理文g对其q行使用。格式即Z面的使用方式?/span>
举例Q新Z个文本文?/span>test.txt
~辑内容?/span> OgreMeshUpgrate –d3d –l 4 –d 500 –p 30 E:\Ogre\Media\TestSrc.xml F:\Temp\TestDest.mesh
修改文本后缀名ؓtest.bat
该批处理文件与OgreMeshUpgrate.exe攄同一目录下,q行
则会自动?/span>E:\Ogre\Media\TestSrc.xml文g转换?/span>F:\Temp\TestDest.mesh文gQ同时开启了4?/span>LodQ?/span>Lod间距?/span>500象素Q每一U间面数差距?/span>30%
3Q?/span>OgreMeshUpgrate工具推荐使用automatic自动模式点格式Q效率会比较高,q且省去不少ȝ?/span>
4Q?/span>MeshMagick工具不推荐用。本w功能有限,而且长期无hl护Q对新的mesh支持不好?/span>
原创 韩D
http://www.hjpdiy.com
Ogre采用?wi)桩理场景中的各?元素"(摄像机、灯光、物体等)Q所有的东西都挂??上,不在"?上的东西不会被渲染?br> Ogre::SceneManager是"?的管理者,Ogre::SceneNode是从SceneManager中创建的Q当然BSP?*?wi)的理也和q两个类有关Q这暂时不讨论)?/p>
AABB(轴对齐包围盒)
q个东西是碰撞检的基础Q怎么L起JJYY呢)Q和它类似的q有OBB(有向包围?Q由于OBB创徏复杂Q所以Ogre采用了AABB?/p>
最单的撞:
?br>
qOgre::SceneNode::_getWorldAABB()可以取得q个叶子节点的AABB(Ogre::AxisAlignedBox)Q?br>
Ogre::AxisAlignedBox装了对AABB的支持,该类的成员函数Ogre::AxisAlignedBox::intersects
()可以判断一个AABB?球体、点、面以及其他?的相交情况(撞情况Q?/p>
m_SphereNode?wi)的叶子Q挂了一??
m_CubeNode?wi)的叶子Q挂了一?正方?
AxisAlignedBox spbox=m_SphereNode->_getWorldAABB();
AxisAlignedBox cbbox=m_CubeNode->_getWorldAABB();
if(spbox.intersects(cbbox))
{
//怺
}
区域查询Q?/p>
单的讲就是,查询某一区域中有什么东西,分ؓAABB、球体、面查询?/p>
//创徏一个球体查询,q里?00是m_SphereNode挂着的那个球体的半径
SphereSceneQuery * pQuery=m_SceneMgr->createSphereQuery(Sphere(m_SphereNode->getPosition(),100));
//执行q个查询
SceneQueryResult QResult=pQuery->execute();
//遍历查询列表扑և范围内的物体
for (std::list<MovableObject*>::iterator iter = QResult.movables.begin(); iter != QResult.movables.end();++iter)
{
MovableObject* pObject=static_cast<MovableObject*>(*iter);
if(pObject)
{
if(pObject->getMovableType()=="Entity")
{
Entity* ent = static_cast<Entity*>(pObject);
//q里化了操作Q由于只有一?球体"和一?正方?Q?br>
//所以只判断了球体和正方体的怺
if(ent->getName()=="cube")
{
//改变位置防止物体重叠
vtl=-vtl;
m_SphereNode->translate(vtl);
break;
}
}
}
}
怺查询
遍历所有的对象Q找C对一对的怺物体Q废话呀Q相交当然至两个物体)?/p>
//创徏怺?br>
IntersectionSceneQuery* pISQuery=m_SceneMgr->createIntersectionQuery();
//执行查询
IntersectionSceneQueryResult QResult=pISQuery->execute();
//遍历查询列表扑և两个怺的物?br>
for (SceneQueryMovableIntersectionList::iterator iter = QResult.movables2movables.begin();
iter != QResult.movables2movables.end();++iter)
{
SceneQueryMovableObjectPair pObject=static_cast<SceneQueryMovableObjectPair>(*iter);
//if(pObject)
{
String strFirst=pObject.first->getName();
String strSecond=pObject.second->getName();
//下面加入你自q两个物体怺判断代码Q或者简单的用AABB的判断方法,
}
}
p={0,x0,y0,z0}
q= {cos(α/ 2) , sina(α/ 2) Nx, sin(α/ 2)Ny, sin(α/ 2)Nz } (N为单位向?
pl果 =q*p*q-1
在数学上Q?span>quaternion表示复数w+xi+yj+zkQ其?/span>i,j,k都是虚数单位,而复C?span>(叉乘)的几何意义实际上是对复数进行旋转。这也是OGREZ么要用quaternion的原?比Matrix更快h节省I间),Ҏ(gu)单的二维复数p= x + yi来说Q和另一?/span>q = ( conαQ?/span>sinα)怹Q则表示?/span>p沉K时针方向旋?#945;Q?/span>p’ = pq ,q是2D旋{.
如果要表C?D旋{,需?D复数?于是有?四元?,q=w+ix+jy+kz (i,j,k都是虚数)
其中j,j,k关系如下:
i2 = j2 = k2 = -1
i * j = k = -j * i
j * k = i = -k * j
k * i = j = -i * k
四元数加?
q1 + q2 = (w1+w2) + (x1+x2) i + (y1+y2) j + (z1+z2) k
四元C?
q1 * q2 =
(w1*w2 - x1*x2 - y1*y2 - z1*z2) +
(w1*x2 + x1*w2 + y1*z2 - z1*y2) i +
(w1*y2 - x1*z2 + y1*w2 + z1*x1) j +
(w1*z2 + x1*y2 - y1*x2 + z1*w2) k
OGRE源代码里q样定义乘法:
Quaternion Quaternion::operator* (const Quaternion& rkQ) const
{
// cases p*q != q*p.
return Quaternion
(
w * rkQ.w - x * rkQ.x - y * rkQ.y - z * rkQ.z,
w * rkQ.x + x * rkQ.w + y * rkQ.z - z * rkQ.y,
w * rkQ.y + y * rkQ.w + z * rkQ.x - x * rkQ.z,
w * rkQ.z + z * rkQ.w + x * rkQ.y - y * rkQ.x
);
}
目录[隐藏] |
本代码ؓWin32q_上OGRE 3D囑Ş引擎各版本中文输入所使用。代码中可能存在不完善的地方Q如有问题可以到论坛交流?
下蝲q接Qfor OGRE 3D 1.4.0RC1 Q?
下蝲q接Qfor OGRE 3D 1.2.5Q?
~译q行。就O(jin)K了?/p>
关于layout文g:
一开始我只是单的把配|文件中?Quit"改了"退?,l果q行报错了, LOG文g昄?
Exception: ExpatParser::parseXMLFile - XML Parsing error 'not well-formed (invalid token)' at line 7 |
查了? 原来文g格式也要Ҏ(gu)UTF-8格式?呵呵
本文由 自由骑士W志 译整理,版权属于OgreTeam。{载请包含本行信息?/span>
q个工具包包含了一些对Ogre资源文gq行操作的预处理命o行工兗?/span>
它包?/span>OgreXMLConveter, OgreMeshUpgrade, OgreMaterialUpgrade?/span>MeshMagick?/span>
(zhn)可以在q里获得?/span>WindowsV
.[OgreXMLConveter]
OgreXML转换器能够将 .mesh 模型|格文g ?/span> .skeleton 骨骼文g ?/span>XML格式转换Zq制格式Q同时可以将其二q制格式转换?/span>XML格式。它同时也允怽在将XML格式转换Zq制格式时设|?/span>LOD层信息?/span>
如果你的Ogre脚本资源中原本用的是XML格式文g的话Q那么本工具则是Ogreq行时必ȝ。所以你能够?/span>OgreSource包的Tools/XMLConverter中找到它?/span>
使用Ҏ(gu)Q?/span>
OgreXMLConverter 操作选项 源文件\?/span> 目标文g路径
有用的操作选项包括Q?/font>
-i = 控制与命令行?/span>
-l nLODNum = 指定?/span>LOD层 ( 该项仅在XML格式转换?/span>Mesh格式时有?/span> )
-d nLODDis = 指定LOD层间的距离增幅 ( 该项仅在XML格式转换?/span>Mesh格式时有?/span> )
-p nLODPer = 指定每两U?/span>LOD层之间三角面减少癑ֈ?/span> ( 该项仅在XML格式转换?/span>Mesh格式时有?/span> )
-f nLODNum = 指定两LOD层之间的固定点减少?/span> ( 该项仅在XML格式转换?/span>Mesh格式时有?/span> )
-e = 关闭模版阴媄?/span>edge?/span> ( 当用模版阴影时该项才有?/span> )
-r = 关闭Ogre推荐的顶点缓冲区格式?/span>
-t = 为法U脓(chung)囄成切U信?/span> ( 当用法U脓(chung)图时该项才有?/span> )
-o = 关闭冗余关键和q动轨迹的剔?/span>
-d3d = 优先使用D3Dq行颜色格式的填?/span> ( ?/span>Windowsq_中默认该开?/span> )
-gl = 优先使用GLq行颜色格式的填?/span> ( 在非Windowsq_中默认该开?/span> )
-E endian = 讄endian模式Q可以选择big, little ?/span> native ( 默认?/span>native )
-q = 轻量模式Q减输出?/span>
-log filename = Log文g名称。(默认?/span>OgreXMLConverter.logQ?/span>
.[OgreMeshUpgrade]
q个工具能够你的Q何老版本的 .mesh 文g更新到当前版本的 .mesh 文g?/span>
你可以在Ogre.log文g中得?/span>.mesh文g的版本信息。一般来_Ogre可以q行老版本的.mesh文gQ但是性能上会有一些差别。如果你更新?/span>Ogre的其他部分,你尽量应当将.mesh文g更新为同L(fng)版本?/span>
使用Ҏ(gu)Q?/span>
OgreMeshUpgrate 操作选项 源文件\?/span> 目标文g路径
有用的操作选项包括Q?/font>
-i = 控制与命令行?/span>
-l nLODNum = 指定?/span>LOD层 ( 该项仅在XML格式转换?/span>Mesh格式时有?/span> )
-d nLODDis = 指定LOD层间的距离增幅 ( 该项仅在XML格式转换?/span>Mesh格式时有?/span> )
-p nLODPer = 指定每两U?/span>LOD层之间三角面减少癑ֈ?/span> ( 该项仅在XML格式转换?/span>Mesh格式时有?/span> )
-f nLODNum = 指定两LOD层之间的固定点减少?/span> ( 该项仅在XML格式转换?/span>Mesh格式时有?/span> )
-e = 关闭模版阴媄?/span>edge?/span>
-r = 关闭Ogre推荐的顶点缓冲区格式?/span>
-t = 为法U脓(chung)囄成切U信?/span>
-d3d = 转换?/span>D3D颜色格式
-gl = 转换?/span>GL颜色格式
-srcd3d = 老版本的mesh文g?/span>D3D颜色格式
-srcgl = 老版本的mesh文g?/span>GL颜色格式
-E endian = 讄endian模式Q可以选择big, little ?/span> native ( 默认?/span>native )
注意Q?/span>
q个工具现在允许你自定义重组你的mesh|格文g的顶Ҏ(gu)式?/span>
如果你想更新
q个工具能够你的Q何老版本的 .material 材质文g更新到当前版本的 .material 材质文g?/span>
值得注意的是q个自动更新是不会加入一些新的脚本语法功能的Q这么说你可能不好理解。(例子Q?/span> “scene_blend add”q句可能会被更新?/span>”scene_blend one one”Q因?/span>”add”的底层实际上是”scene_blend one one”Q自动更C一些高U语法更Cؓ比较直接底层的语法)
另外Q这个工具仅?/span>
使用Ҏ(gu)Q?/span>
OgreMaterialUpgrade 源文件\?/span> 目标文g路径
Copyright 2007 by Daniel Wickert
q个工具是对mesh文g?/span>skeleton文gq行一些处理的工具?/span>
大致包括以下功能Q?/font>
Info = 输出mesh的信息?/span>
Meshmerge = 多?/span>mesh合ƈZ?/span>mesh文g
rename = 重命?/span>mesh?/span>skeleton的不同元?/span>
transform = 旋{Q羃放一?/span>mesh
使用方式Q?/span>
MeshMagick –help=工具?/span> 可以获得更多相关信息?/span>
1Q除MeshMagick该工具外Q其他三U工P使用方式都可以是Q将源资源文件拖拽到工具?/span>exe图标上。因为更新程序会源文g覆盖Q所以推荐做下备份后再更新?/span>
2Q?zhn)可以写批处理文g对其q行使用。格式即Z面的使用方式?/span>
举例Q新Z个文本文?/span>test.txt
~辑内容?/span> OgreMeshUpgrate –d3d –l 4 –d 500 –p 30 E:\Ogre\Media\TestSrc.xml F:\Temp\TestDest.mesh
修改文本后缀名ؓtest.bat
该批处理文件与OgreMeshUpgrate.exe攄同一目录下,q行
则会自动?/span>E:\Ogre\Media\TestSrc.xml文g转换?/span>F:\Temp\TestDest.mesh文gQ同时开启了4?/span>LodQ?/span>Lod间距?/span>500象素Q每一U间面数差距?/span>30%
3Q?/span>OgreMeshUpgrate工具推荐使用automatic自动模式点格式Q效率会比较高,q且省去不少ȝ?/span>
4Q?/span>MeshMagick工具不推荐用。本w功能有限,而且长期无hl护Q对新的mesh支持不好?/span>
游戏主要用到了几个引擎,物理引擎QPhysicsX SDK
模型的导?/strong>
OGRE有自q3D模型格式Q?mesh格式Q。导出可以直接出OGRE官方|站下蝲导出插g。不q导出插件有好些Bug。对于徏模方式的不同导出也不同,Maya的导出插件不能导出非闭的曲面,?dsMax可以Q所以可以通过它导?mesh?/p>
另外Q在物理引擎中要表现_的碰撞,最好能得到模型的网格结构,x型的炚w信息Q而不是用单的规则形式来包裏V我们的游戏中地囄的是前者,而R辆道L(fng)用的是后者?/p>
但PhysicsXq不支持.mesh。所以我们是通过导出插g导出?mesh.xml格式文g中读取点面信息(仅此Q,再写到自定义的二q制文g格式中,为物理引擎用?/p>
OGRE?/strong>PhysicsX之间的耦合
PhysicsX和OGRE场景理比较cMQ都有对应的cR一个可以移动的物体Q在OGRE中可以用SceneNode实现Qƈ加入到场景管? 中,在PhysicsX中则可以用NxActor对应。NxActor中PhysicsX中的一个物理单位,它可以把一个物体用单的几个规则几何形状? 裹v来,所以的重力、碰撞等物理作用都作用在NxActor中,q生相应的物理反应。得到相应的物理数据之后Q再通过讄SceneNode相应属性, 可以实现逼真的物理效果?/p>
事实上,地图场景也是作ؓ普通的3D物体来实现?/p>
而OGRE与PhysicsX之间的映ƈ不是对于每一个物体进行映封装实现。而是把这两部分封装成独立的两个模块,但这两部分中所有的物体都是 一一对应的。在ȝ序中Q再把从PhysicsX部分计算出的l果Q传递给OGRE部分Q进行绘制。这样也为网l的加入提供了好的嵌入点。因为只要服务端 q行全部物理q算Q再把运的l果发给客户端OGREq行渲染?/p>
OGRE中的frameStated(const FrameEvent &evt)作ؓE序的主U程Q在其中调用
m_NxScene->simulate(evt.timeSinceLastFrame); // m_NxScene, instance of (NxScene*)
m_NxScene->flushStream();
m_NxScene->fetchResults(NX_RIGID_BODY_FINISHED);
再把q算的物理结果给OGREl制?/p>
q样OGRE与PhysicsXl合在一P而两者的内部实现是互不媄响的Q可以独立编E,只要处理好两者物体的一一对应关系?/p>
地图场景的实?/strong>
对于OGRE来说有专门的室外地图场景理。但是由于其高度囑־隑֯入到PhysicsX中,除非通过建模时得到点面信息,但在具体操作中很隑ց? 高度图与|格炚w信息的一致。我们还试过在程序初始化旉过OGRE的Ray取得地图上M*N个点的坐标,l成2*M*N个三角Ş面片Q用到物理引擎 中,q似的实现物理地图。但q种实现所有的三角形在XZq面上的投媄都是一L(fng)Q面片太可能不_Q太多又会增加不必要的开销Qȝ来说不够理想?/p>
PhysicsX中也有专门用于处理地囑֜景的NxActorQ可以在创徏NxActor前通过
terrainDesc.heightFieldVerticalAxis = NX_Y; // terrainDesc is a NxTriangleMeshDes
// Default: NX_NOT_HEIGHTFIELD
terrainDesc.heightFieldVerticalExtent =
q行讄。这样可以大大的提高效率。这本来应该是一个理想的做法。但׃我们建模时模型导出有些误差的原因Q会出现某些面片为垂_物理撞的效? 在这些地方过于激烈,表现在屏q上是车会H然被撞得飞h很高。我们试了很久都没找到合适的模型导出Ҏ(gu)避免q一现象。所以只有所地图场景也作Z个普 通的NxActorq行处理Q这P虽然克服不了建模导出时的q个问题Q但也不易被玩家发觉?/p>
q样Q地囑֜景就有了实现的方法了Q在OGRE中作为普通的.mesh对待Q创建SceneNode和EntityQ在PhysicsX中,作ؓ普通的NxActor对待Q只是用NxCookingq行处理Q具体没ȝIӞ可能是ؓ了提高性能?/p>
车辆的实?/strong>
车辆的实现是本游戏的重点?/p>
当然也分OGRE和PhysicsX两部分实现?/p>
OGRE部分q包括视角即QCameraQ,而其他诸如a量,道具之类的与车辆本n无关的这里不做描q。一辆R的主要结构如下:
q样状态间的{换即为:
׃只能到是哪个NxActorQ而R辆对应的c(q里NxVehicleQ是自己装的,里面包含一个NxActorQ所以得到哪? NxVehicle可以充分利用NxActor中的一个public成员void* userData的作用,让它指向它所在的NxVehicle对象QthisQ即可?/p>
CEGUI的实?/strong>
引用Lzx一D:
“利用OGRE引擎和CEGUIq行了基本的场景和GUI布局q行了编写?/p>
CEGUId2DGUI布局的配|文Ӟq个文g是用xml来编写的。这样可以将E序~写和UI的设计相对分开Q得程序设计和UI工设计可以更好的分开。读取后?D场景中进行绘制?#8221;
q个实际与游戏过E部分是独立的。由于时间紧q,我们q没q行很好的封装实玎ͼ只在一呛_写在c(class CuteCarFrameListener : public ExampleFrameListener, public MouseMotionListener, public MouseListenerQ中?/p>
q部分具体不是我做的Q也没去l究。而且是在|络加入p|后做的,所以ƈ没考虑|络斚w的接口,q里便不详述了?/p>
另外Q小地图和R速表的实C是这部分内容?/p>
地囑֮现先贴一张赛道图Q在从物理引擎得到R辆的位置Q算出在地图上的相当位置Q百分比Q,映射昄到小地图上即可?/p>
车速表则更单,d速度Q画个图可?/p>
玩家视角Camera的实?/strong>
在R辆实C已有描述Q这里只是一U实现方案?/p>
只创Z个Camera对象Q注意它不能被多个SceneNode来attachQ所以{换视角时Q要先detatch。这个当时探索了好些旉Q不q都是Ogre基本知识Q做hq是单的Q不说Ş?/p>
提一下,在实际R辆行CQh的视U跟随通常会比车辆转弯的动作稍晚一点点Q这里就加了一个缓Ԍ也就是每ơ看到的东西都是30帧之前的场景Q以实现更好的效果。这个通过一个链表(数组Q就很容易实现?/p>
另外车辆左右摆动Ӟ人的视角是不会跟着左右摆的Q虽然现实中可能会一些,但在游戏中会lhq于晃动的感觉,q里把左右摆动L了,也就是Camera向上向量始终与y轴^Ӟq通过一些数学运便可,说实话,我是凑出来了Q花好长旉?/p>
声音的实?/strong>
也不是我做的Q同学Lzx做的Q引用一D:
“音频模块支持3D和非3D的播放模式。考虑到播放时多次读音频文件会提高音频模块的CPU占用率而媄响游戏进行,所以针对一个音频文Ӟ每次把音频文件全部读取到~存中而不是多ơ读取,每次d一部分。这是个用内存换CPU效率的选择?#8221;
声音的加入,对原先的E序基本无媄响。因Z用的DirectSound和上面这些基本算独立QLzx装得也相当不错。声x放时自动会开U程Q对游戏其它模块无Q何媄响?/p>
有关|络引擎加入p|
原计划网l引擎采用RakNetQ也装了一些东西,也提供了不错的接口。但׃当初游戏的整体设计不充分Q游戏框架设计成一个Ogre作ؓȝ E,而网l部分需要单独开辟一个线E来q行数据传输和处理,如果q在一个线E里面,会ɾU程dQ数据传送相当缓慢,甚至不成功,D游戏的无法l? ׃旉的关p,框架更新旉不Q只好放弃这块,做成单机版?/p>
׃|络引擎需要额外的U程和缓Ԍ而OGREq不提供q种功能。最好的办法是创Z个主U程Q而把OGRE中@环作Z个子U程来处理。但q样做,原先我们装的系l是不能够支持,大量改变代码Q时间已不够Q所以无奈只好放弃?/p>
在网l上q_֊太少Q一开始不够重视也是个原因啊。而事实上我们对于|络上的~程毫无l验?/p>
贴些游戏截图Q美工还?/strong>PP
后话
调试qOGRE提供的Log好了Q不能一步步q行调试。还有一个好办法是生成.map文gQ再Ҏ(gu)windows中出错提C框中通常提示q行? 哪个虚拟地址出错Q在.map文g中找Z码的具体出错行。这实际上对于已l给玩家使用的程序根据玩家获得的出错信息找Bug很有帮助
windows2000QVS2005~译NxOgre
环境Q?span lang="EN-US">windows2000Qvs2005Qc++Qteam suiteQ,.net1.0
主要内容
1. vs2005 sp1
2. ogre1.40:
3 PhsyX2.62
4. NxOgre
5 ~译NxOgre tutorials
1. vs2005 sp1
1.1 查看自己的vs2005是否已经安装了sp1?o:p>
a) 在IDE里选择“帮助->关于Visual Studio 2005”菜单,查看一下,认SP1列ؓ其中一个安装的产品Q?o:p>
b) 在IDE里选择“文g->新项?#8221;菜单,查看一下,认VS 2005 Web应用目模型选项(是内|于SP1中的)被安装了Q而且是v作用的:
Q引?a target="_blank">http://www.shengfang.org/blog/in ... a2aaf8dc91169701875Q?o:p>
1.2 sp1的下?o:p>
Q引?a target="_blank">http://hi.baidu.com/yongfa365/bl ... e5b57fcb80c484.htmlQ?o:p>
VS2005 SP1英文正式版下载地址 431M http://download.microsoft.com/do ... B926601-X86-ENU.exe
VS2005 SP1中文正式版下载地址 440M
http://download.microsoft.com/do ... B926604-X86-CHS.exe
1.3 sp1的安装注意事?o:p>
1.安装旉会非帔RQ如果机器配|不是很高的话需?个小Ӟ一般的话也需?个小时左x以请耐心{待?o:p>
2.安装前检查你的c盘是否有大于3G的空余空_因ؓ安装的时候会释放很多临时文g在c盘,如果不能保证大于3g的话可能会发生异帔R误,不过我在安装的时候没有占?Gq么恐怖,不过也v码占用了1G多的I间?o:p>
Qsp1下蝲到的那个盘分区Q最好空间也要大一些)
3.如果你以前安装过web application projectQ在安装vs2005 sp1以前请先把他卸蝲Q不然不能成功安装vs2005 sp1
4.vs2005sp1的补丁包是把你机器上所有单独装qvs2005的版本的补丁都打?如果机器上装了Visual Web Developer Express和Visual Studio team sutie,那么他就要运行安装补丁两?
Q引?a target="_blank">http://www.cnblogs.com/ltp/archive/2007/02/25/656562.htmlQ?o:p>
1.4 安装sp1
?a target="_blank">http://www.cnblogs.com/ltp/archive/2007/02/25/656562.html【文1】中有vs2005 sp1安装的一般方法?o:p>
可是Q?.我的机器是windows2000Q找不到“软g限制{略”?.执行【文1】中?bat文g时出错-Q无法将相应的键值导入注册表?o:p>
解决Ҏ(gu)是手动导入注册表键|
* "开?Q?#8220;q行”Q》键入regeditQ回车)?o:p>
* 扑ֈHKEY_LOCAL_MACHINE\Software\Policies\Microsoft\Windows\Installer
* 在其下面建立一:名称QMaxPatchCacheSizeQ类型:REG_DWORDQ数据|0
现在执行批处理文件来安装
假设下蝲的sp1存放在目录dir下,
1Q?在dir目录下徏立a.bat文g?o:p>
2Q?用记事本打开a.batQ把下列的代码复制进去,保存Q关闭?o:p>
regedit export HKEY_LOCAL_MACHINE\Software\Policies\Microsoft\Windows\Installer installer.reg
regedit add
HKEY_LOCAL_MACHINE\Software\Policies\Microsoft\Windows\Installer /v
MaxPatchCacheSize /t REG_DWORD /d 0 /f
net stop msiserver
start /wait VS80sp1-KB926604-X86-CHS.exe
//Q本行是注释Q不要拷贝)VS80sp1-KB926604-X86-CHS.exe是下载的中文sp1文g的名U。如果下载英文的sp1Q需作相应的替换
regedit delete HKEY_LOCAL_MACHINE\Software\Policies\Microsoft\Windows\Installer /v MaxPatchCacheSize /f
regedit import installer.reg
net stop msiserver
3Q?双击执行a.bat。虽然在我的window2000上仍旧会有几个错误。但可以无视之?sp1开始安装了?o:p>
cpu1.7GQ内?56M。安装时间近3时Qc盘占?G?o:p>
安装NxOgre基本是按照官方的安装步骤Q?a target="_blank">http://nxogre.org/Installing
2. ogre1.40:
在这里下载以下两个包http://www.ogre3d.org/index.php? ... =412&Itemid=132
ogre-win32-v1-4-0.zipQ解压羃到H:\ProgramFiles\Ogre\ogrenewQ?o:p>
OgreDependencies_VC8SP1_Eihort_20070323.zipQ解压羃到H:\ProgramFiles\Ogre\ogrenew下)
~译ogre.sln利通过
注意Q要有够的盘I间来编译ogre的源代码Q我选择批编译-》全部。编译完成后Qogrenew目录竟然?.59GQ!Q?.obj *.ncb *.sbr *.idb *.pdb *.dep文g占了3.47GQ?o:p>
3 PhsyX2.62
可以参照官方的步?a target="_blank">http://nxogre.org/Installing
4. NxOgre
4.1 下蝲NxOgre
NxOgre.0.4.RC3.zipQ可以在官方http://nxogre.org下蝲Q?o:p>
NxOgre.0.4.RC3.tutorials.zipQ可以在官方http://nxogre.org下蝲Q?o:p>
NxOgrePatch-ForEihort-VS8SP1.zipQdownload from http://www.ogre3d.org/phpBB2addons/viewtopic.php?t=3505Q?o:p>
4.2 解压~?o:p>
三个包全部解压羃到H:\ProgramFiles\Ogre\NxOgre
4.3 讄环境变量
NXOGRE_DIR=H:\ProgramFiles\Ogre\NxOgre
OGRE_HOME=H:\ProgramFiles\Ogre\ogrenew\OgreMain;H:\ProgramFiles\Ogre\ogrenew
(OGRE_HOME的D|的可能有问题。因为编译NxOgre tutorials时提C找不到ogre.h)
PHYSX_DIR=H:\Program Files\AGEIA Technologies\AGEIA PhysX SDK\v2.6.2
4.4 ~译NxOgre
打开H:\ProgramFiles\Ogre\NxOgre\NxOgre.VC8.sln
可能是前面的OGRE_HOME讄的不对,所以需要加入ogre的目录才能编译通过
在属性->c/c++Q?gt;inlude目录?#8220;最前面”加入“H:\ProgramFiles\Ogre\ogrenew\OgreMain\include”~译ok
在属?>链接Q?gt;库目?#8220;最?#8221;加入"H:\ProgramFiles\Ogre\ogrenew\lib"
5 ~译NxOgre tutorials
5.1
打开H:\ProgramFiles\Ogre\NxOgre\tutorials\NxOgreTutorials.sln
可能是前面的OGRE_HOME讄的不对,所以需要加入ogre的目录才能编译通过
在属性->c/c++Q?gt;inlude目录里后面附?o:p>
H:\ProgramFiles\Ogre\ogrenew\OgreMain\include;
H:\ProgramFiles\Ogre\ogrenew\Dependencies\include
在属?>链接Q?gt;库目?#8220;最?#8221;附加
H:\ProgramFiles\Ogre\ogrenew\lib;
H:\ProgramFiles\Ogre\ogrenew\Dependencies\lib\Release
5.2 修改源文?o:p>
引自http://www.ogre3d.org/phpBB2addons/viewtopic.php?t=3508
?01.cpp文g和其目Z。其他同?o:p>
1.如果提示“error C2039: 'relX' : is not a member of 'OIS::MouseState' ”
需要用ms.X.rel替换ms.relX
如果提示“error C2039: 'relY' : is not a member of 'OIS::MouseState' ”
需要用ms.X.rel替换ms.relY
如果提示“error C2039: 'relZ' : is not a member of 'OIS::MouseState' ”
需要用ms.Z.rel替换ms.relZ
2.如果提示MSVCRT.lib(crtexe.obj) : error LNK2019: unresolved
external symbol _main referenced in function ___tmainCRTStartup
Release/nxTutorial101.exe : fatal error LNK1120: 1 unresolved externals
一个可行的解决Ҏ(gu)Q?o:p>
a.先将tutorialApplicationEihort.h中的q段代码注释?o:p>
#ifdef _CONSOLE
#define TUTORIAL_VOIDMAIN \
int main(int argc, char *argv[]) {\
...
}
#else
#define TUTORIAL_VOIDMAIN \
INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE, LPSTR strCmdLine, INT ) {\
...
}
#endif
b.a中所说的main函数或winmain函数拯?01.cpp末尾?o:p>
3.可能q需要注释掉main或WinMain函数中的SET_TERM_HANDLER;
4.注释?01.cpp末尾的TUTORIAL_VOIDMAIN
其他问题可以?span lang="EN-US">NxOgre论坛咨询Q?o:p>
http://www.ogre3d.org/phpBB2addo ... 5649a7b87f21b4a057b