Tags: Ogre

RockyRay第一个Demo即将完成

之前由于准备考研复试、毕业答辩和吃散伙饭忙活了好一阵子,现在总算是有点喘息的时间来做点其他事情了。这第一件事情就是继续RockyRay的开发。貌似我以前还没有在blog中提到过RockyRay。

所谓RockyRay是我和小强精力过剩蛋疼无聊的时候满怀着拯救世界解放他人并把爱与和平带给全人类的信念做的一个RPG游戏。恩恩,这也是小强的毕设。因为明天就是小强答辩的日子,结果他在deadline到之前终于完成了第一个场景模型、男主角的模型,以及一些设定图和其他一些CG。第一个游戏场景的Demo已经编译出来,不过还没有打包。明天我就会把整个Demo打包提供下载。整个程序使用Ogre+OgreMax+OpenAL+LuaPlus+Boost,从三月份开始弄到现在(其实中间有将近2个月没有更新)。


感兴趣的童鞋可以先在下面的网址看看小强为RockyRay做的一些2D作品:

http://code.google.com/p/rockyray/



探险

看!灰机!

主角们

排排站,吃果果

OgreOpcode碰撞检测使用概述


OgreOpcode几乎是不使用物理引擎时Ogre下的唯一选择,但是这个天杀的库文档实在是太少了,约等于没有。下面把这两天使用它的经验整理一下。

下载&编译

OgreOpcode没有任何Release,获取它的唯一办法是从SVN中下载源代码进行编译,SVN地址如下:
https://ogreconglo.svn.sourceforge.net/svnroot/ogreconglo/ogreopcode/trunk
在script文件夹找到自己用的编译器的项目文件,直接编译就可以了。需要注意的是,SVN中的exmples是无法正确编译的–这些例子运行所需要的一些文件没有在SVN里面!另外就是doc目录中的Doxygen配置文件中居然用的是绝对路径,不经修改是无法运行的。此外我在使用VS2005的时候发现,它的项目文件中少包含了一个叫OgreCapsuleMeshCollisionShape.cpp的文件,导致编译无法通过。需要自己把它加到OgreOpcode项目中才可以编译成功。另外在项目的“生成后事件”中会执行一个拷贝的命令,但是在svn的文件夹结构中目标文件夹是不存在的!这也会导致编译失败。
实在是被这个项目的维护人员打败了…这么多纰漏…
我知道是个人都会觉得从svn里面编译很麻烦,所以我吧它编译好了上传上来了,点这里下载ogreopcodebin。里面包括编译好的debug和release版的dll。

使用

要使用OgreOpcode,基本上可以分为这么几步:

  1. 创建一个Manager
  2. 创建一个Context
  3. 加入参加碰撞的物体
  4. 碰撞检测

初始化

    // 创建Manager。这个Manager使用Singleton实现
    CollisionManager* mCollisionMgr = new CollisionManager(sceneMgr);
    // 创建context 不同的context中可以添加不同的物体,发生不同的碰撞关系
    mCollisionContext = mCollisionMgr->createContext( "test" );

    // 创建碰撞类,并且设置不同类型之间碰撞的检测方式
    mCollisionMgr->addCollClass("charactor");
    mCollisionMgr->addCollClass("scene");
    // COLLTYPE_QUICK 表示两个charactor之间的碰撞使用简单的球体进行检测
    mCollisionMgr->addCollType("charactor", "charactor", COLLTYPE_QUICK);
    // COLLTYPE_IGNORE 表示忽略场景物体之间的碰撞
    mCollisionMgr->addCollType("scene", "scene", COLLTYPE_IGNORE);
    // COLLTYPE_EXACT 表示计算charactor和scene碰撞时的所有交点
    mCollisionMgr->addCollType("charactor", "scene", COLLTYPE_EXACT);

加入物体

OgreOpcode中的物体主要有以下几种:Box, Capsule, Sphere, Terrain, Mesh, Entity, Ptr,调用CollisionManager::createXXXXCollisionShape函数来创建。从函这些物体的名称大体上可以才到它的用法。其中Ptr是从一个三角形数组中得到一个碰撞物体的形状。

    // 根据一个entity的网格模型信息来创建碰撞形状
    EntityCollisionShape *shape = CollisionManager::getSingletonPtr()->
        createEntityCollisionShape(ent->getName());
    // 制定该shape所关联的entity
    shape->load(ent);
    // 创建一个碰撞物体
    CollisionObject* pCollisionObject = mCollisionContext->createObject( ent->getName() );
    // 设置该物体的类型,这里应该是第一步中设置的"charactor","scene"之一
    pCollisionObject->setCollClass( type.c_str() );
    // 设置object的形状
    pCollisionObject->setShape( shape );
    pCollisionObject->setForcedUpdate(forceupdate);
    // 把这个object加到我们创建的CollisionContext中去
    mCollisionContext->addObject( pCollisionObject );

其他设置

在每一帧都需要调用CollisionContext::Collide(time)来更新状态,否则是无法检测到碰撞的。

另外在所有物体都已经添加到CollisionContext中了以后需要调用一次CollisionContext::reset()。

碰撞检测

OgreOpcode中的碰撞检测包括射线(rayCheck)、球体(sphereCheck)、移动球体(sweptSphereCheck)三种方式。rayCheck就是传入一个Ray对象,检查射线上有没有和其他物体相交。sphereCheck则是创建一个虚拟的球体,检查这个球体有没有碰撞。sweptSphereCheck则是创建一个虚拟球体,并且让它沿着某个方向移动,检查在这个过程中是否有交点。

下面给出一个rayCheck的例子:

    Ogre::Ray ray(Vector(0,30,0), Vector(0,-1,0));
    Ogre::Real dist = 100;
    std::vector vectorList;
    CollisionPair** collisionPair = NULL;
    if( mCollisionContext->rayCheck(ray, dist ,
            COLLTYPE_EXACT, COLLTYPE_ALWAYS_EXACT, collisionPair ) > 0)
    {
        int count= mCollisionContext->getNumCollisions();
        for( int i = 0; i < count; i ++ )
        {
            vectorList.push_back( collisionPair [i]->contact );
        }
    }

其他

其实OgreOpcode的接口并不是那么那么的复杂,但是没有文档使得使用它变成了一个比较头疼的事情。官方网站也仅仅是一个并不活跃的论坛,让人很是怀疑这个库是不是值得去深入学习。其它的碰撞检测库如GIMPACT虽然文档上好很多,但是却没有Ogre下的wrapper。说不是什么时候我心血来潮了就会写一个这样的wrapper?

被OgreOpcode折磨中

用了很长时间的开源软件,大多是时候都用的是开发时间很长很成熟的代码。这次因为要在Ogre里面作碰撞检测,但是又不想用物理引擎这么重量级的东西,所以选择了OgreOpcode。但是没有想到的是,整个项目没有任何Release,没有文档,论坛里面门可罗雀,运行Doxygen生成的还是没有多少有价值的东西。想看看samples里面是怎么做的,但是缺少场景、模型等文件,不能运行…
google搜索OgreOpcode,唯一有价值的东西还是Azure在blog里面写的一个很简略的介绍,其他的基本上都是转载的这个。

这真的是Ogre引擎下用的最广泛的碰撞检测库么…?

OgreMax使用经验

对于Ogre的3ds max导出插件目前只用过oFusion和OgreMax,其中oFusion免费版因为有功能限制几乎没法儿用来做真正的开发。所以大部分时间就是用oFusion在3ds max中的即时预览功能,然后用OgreMax来做真正的导出。

自定义数据

使用OgreMax很重要的一点就是导出自定义数据。要做到这一点首先需要自己写一个xml文档来说明自定义数据的类型,在OgreMax文档的"Custom User Data Types"页面中有很详细的例子,比如下面是我正在做的项目中截出来的一段:

<userDataTypes>
<class name="charactor" displayName="角色 " usage="private">
<data name="name" displayName="名称 " type="string"/>
<data name="wayname" displayName="路径名 " type="string"/>
<data name="meshname" displayName="模型名称 " type="string"/>
<data name="common_skeleton" displayName="公用骨骼 " type="bool" defaultValue="true"/>
</class>
</userDataTypes>

在OgreMax->Object Settings->User Data中载入以后就可以在type中选择"角色"类型了,并且会按照xml中定义的数据显示。

导出以后在.scene文件中会有类似如下的xml块:

<![CDATA[
<player>
<name>DefaultPlayer</name>
<wayname></wayname>
<common_skeleton>true</common_skeleton>
<meshname>robot</meshname>
</player>
]]>

上面这一段CDATA可能包含在一个Entity或者Node节点中,具体取决与你在OgreMax中的设置。

物体属性设置

前面也提到了,在OgreMax->Object Settings中可以对导出物体的属性进行设置。这里介绍一下其中比较重要的一些选项。

General

  • Type 这一项决定了导出物体在.scene文件中的类型。最常用的是Entity/Mesh,这个类型在导出以后会生成一个node以及挂载在该node上面的entity,同时会把3ds
    max中的该物体导出为一个.mesh文件。然后就比较常用的就是Empty,这种类型会导出为一个没有挂任何东西的node。比如说我用一个box来代表NPC出现的位置,那么这个box就可以设置为Empty类型。
  • Rendering 在这里设置物体的可见性、渲染顺序、shader参数等等

Node Animation

在这里设置物体的Node动画,即位置、旋转、缩放上的动画。物体模型本身变化的动画在Mesh Animation中设置。具体的用法还没有仔细研究。

User Data

自己游戏所需要的自定义数据就在这里设置了。点Configure…按钮添加上面所说的userdatatypes.xml文件以后,User Data Class中就会出现自定义的数据类型。这样就可以直接把3ds
max作为一个关卡编辑器来使用了。虽说还是没有专门的编辑器那么方便,不过大多数情况下还是够用了。

Mesh

Mesh Name和Skeleton Name可以制定输出的模型和骨骼的文件名,如果不指定的话则会以3ds max中物体的名字命名。

Mesh Animation

这里用来设置顶点动画或骨骼动画。可以把整个场景中物体的任意某一段动画制定某个名字以供程序调用。点击Add..会弹出Animation Settings窗口。通常其中的Track类型已经设置好了,骨骼动画是Physicue,
定点动画是Morph。只需要制定动作的起始帧号就可以了。要注意的是一个场景中某个物体的骨骼动画只能导出为一个skeleton文件,如果你需要把不同的动作导出为不同的动画的话,需要把骨骼动画保存为不同的max文件然后飞别导出。

自定义文件的读取

OgreMax提供了从3ds max中导出为.scene文件的机制,然是我们还是缺一个读取它的程序。虽然OgreMax中自带了一个Viewer程序,但是要处理自定义数据显然还是得自己动手写一个。这里可以参考Ogre
Wiki中的一个.scene文件读取程序的例子,在它的基础上进行修改:

http://www.ogre3d.org/wiki/index.php/New_DotScene_Loader

但是这个程序在很多地方都只是写了一个函数名而没有实现,并且对场景文件的处理和OgreMax导出的格式还是有所区别,需要自己进行大量修改。这里附上我自己的场景读取程序:SceneLoader

Ogre在运行时绑定骨骼

通常一个骨骼动画用的模型用插件从建模软件里面导出的时候都会绑定所用的骨骼,但是有的时候需要在运行时动态的绑定骨骼。比如说我有很多个不同的角色模型,但是他们都共用走路、跳跃的骨骼动画,那么就可以在把这些模型载入以后再制定他们使用的骨骼。

Ogre的官方文档几乎没有提及具体应该怎么做,在Ogre的wiki和论坛中搜索了半天,发现有好些人都有这样的问题,但是都没有一个明确的解决方法。最后反而是在一个中文博客的留言里面发现了实现的方法:
* 假设我有一个角色char01.mesh,以及它所用的几个骨骼动画,比如说sit.skeleton, attack.skeleton,并且char01.mesh默认绑定了一个idle.skeleton
* 和通常一样载入char01.mesh,得到一个Entity*指针ent
* 进行如下操作

SkeletonInstance* oldSkel = ent->getSkeleton();
oldSkel->addLinkedSkeletonAnimationSource("sit.skeleton");
ent->refreshAvailableAnimationState()

这样就搞定了

缺胳膊少腿的Ogre

Ogre算是目前最成功的一个开源引擎,引擎功能不差,也有不少项目都是使用它在作为渲染引擎。不过这段时间用Ogre做游戏还是发现了它的不少弱点。
最麻烦的一点就是Ogre只是提供一个渲染的程序库,而开发用的工具基本上没有什么像样的东西。用了几个从建模软件里面导出模型用的插件,结果功能强大一些如oFusion的居然卖价比Photoshop还贵,其它的插件倒是能用,但是却都或多或少有这样那样的问题。专门的关卡编辑器之类的东西则更是没有了。Ogre的官方wiki上面有一些类似与Ogre IDE之类的项目,但是都已经很长时间没有更新了,有的连官方网站都已经失效了。

不过Ogre在主页上就已经说得很清楚,它是一个图形渲染引擎,不是游戏引擎。不知道这是作者为自己开脱还是他打算专注于提升引擎。另外一个选择就是使用基于Ogre开发的游戏引擎。不过现在看来这样的项目规模都比较小,网站也很简陋。反正我是不敢把自己的项目架在这样的质量不清不楚的东西上面。

最近花了很多时间实现自定义的关卡格式。主要就是在OgreMax导出的.scene文件夹中加入自己的数据,然后用自己的XML解析程序把数据从里面读出来。现在可以在3ds max里面创建关卡时指定游戏用的路点和角色了。不过作为一个典型的想把一切都纳入自己掌控之中的C++使用者,我总是很郁闷自己的程序得依赖OgreMax的导出插件,而又不想花时间去研究3ds max插件的写法(自己是不是有点太贪婪了?)。OgreMax的作者在论坛上面发了一篇帖子说支持Ogre 1.6的插件正在开发中,不知道什么时候会出来。

另外一个工作就是在游戏里面集成了LuaPlus,比想象中的要容易。没写多少代码就完成了脚本和游戏函数之间互相调用的功能。其它的选择像LuaBind因为要使用庞大的Boost,而我不希望编译自己的程序得下载一个和我的程序差不多大的库,放弃使用了(放弃它的另外一个原因是因为LuaBind大量使用了模板编程,这会让本来就已经很慢了的项目编译变得更加让人无法忍受)。毕竟对于脚本我的要求就是能够很容易的实现Lua和C++的相互调用就行了,所以其它的也不是很重要。

然后考察了一下物理引擎。之前曾经参加的一个开源游戏项目中,PM曾经对几个物理引擎进行了一个性能的测试。具体数字机不清楚了,只记得ODE, Newton之类的性能都差不多,而Physix即使是在没有物理加速的情况下仍然是大幅领先几个开源引擎。但是Physix一个比较郁闷的地方是它不是免费提供源代码。它现在只提供Windows, Red Hat, Debian的SDK。如果说想要在其它Linux下编译的话得话50美刀买它的源代码。源代码的许可协议没有仔细读,还不知道是不是能和开源项目一块儿发布。看来只能放弃Physix了。

研究Ogre引擎ing

还好一开始就对于Ogre引擎配套的东西没有抱太大希望,后来证实果然很多都是些不成熟的东西。
首先遇到的问题就是3ds max插件的问题。刚开始在OgreWiki里面看到介绍,感觉是最强大的一个就下载下来用了。好用倒是好用,只是把代码都已经放到svn里面了以后才发现关键功能是要收费的。我得花上比Photoshop还贵的价格才能让oFusion导出自定义数据。囧rz 这感觉就好象小沈阳被赵本山忽悠了一顿饭一样。
之后用了OgreMax,功能上除了不能像oFusion一样在3ds Max中即时预览以外,其他似乎都差不多。然后参照Ogre官方wiki上面的文章写了一个Loader。现在算是凑合能用了。似乎现在Ogre的工具都还没有更新到1.6版上面来,OgreMax和oFusion都还只是声称支持1.4版。好在1.6版向下兼容,这些工具都还可以正常运行。

然后就是CEGUI。现在大致算是明白它是怎么用的了,只是自己制作皮肤的工作量实在是有点大。官方提供的仅有的两个工具–用来制作layerout和图表映射的两个工具–实在是非常简陋,和习惯了Visual Studio, Eclipse之类的完善工具的我来造成了不小的有点心理落差。看来以后做GUI少不了让美工手工对XML文件进行修修补补什么的。

项目在google code上面注册到现在过了6天,每天边玩边学ogre,现在基本能够正常创建简单场景 感觉进度还是可以接受。