lii's profile童言无忌PhotosBlogListsMore Tools Help

Blog


    7/30/2009

    Ogre 3D引擎笔记 [3D engine]

    注意,原文 blog 上有恶意代码,通过 google reader 可以安全阅读。

    http://narita1982.bokee.com/6715000.html

    Ogre 3D引擎 笔记~2:键盘&鼠标响应

    最近看2D又看不下去了,继续看Ogre解闷。事隔一年了,真快。可惜3D功力还没见长>_<翻了下旧帐,发现自己去 年写得东西竟然有点看不懂了,暴汗,赶紧拾起来看看。

    刚觉得程序真是一件令人郁闷的东西,语言和语言之间的经验是没有办法共享的,会了一个,另一个语言能做的东西这个却做不了。放眼望去竟是不会的东 西。超有挫折感。不过后来翻了翻原先的代码,或者别人的教程,倒是发觉理解能力变强了,代码看看就知道和学过的东西哪些是共通的,哪些是特殊的。嘿嘿,没 白写那些代码。

    开始看Ogre的键盘&鼠标,之前很晕的东西,现在发现其实还好啦(也可能和英语逐渐能一目十行有关-_-)

    Ogre有Buffer Input和Unbuffer Input两种,其实这两种Wiki上的教程都过时了,新的Ogre,OIS已经遭淘汰了,所以Wiki的代码是调不通的。

    现在想想FrameListener无非就如同MFC的OnTimer,数据变化的处理都在之中进行。

    Buffer Input 是在发生输入响应事件的时候进行,而UnBuffer Input则是在FrameListener里进行。就如同Buffer Input是响应WM_MOUSEMOVE,WM_KEYDOWN一样,而Unbuffer Input则是在OnTimer里检测是否有键盘等事件。

    具体的(以下现在都没有了,说说思想吧):

    ExampleFrameListener有成员变量mMouse和mKeyboard。

    UnBuffer Input在FrameListener里调用mMouse->Catch(),或mKeyboard->Catch()来 检测消息。然后if来处理。

    Buffer Input是要继承OIS::MouseListener和OIS::KeyListener,这两个类有纯虚函数KeyPressed()和 KeyReleased()遗迹MousePressed()和MouseListener()。有处理内容的话,就重载这些纯虚函数就可以了。

    目前的做法是要用到CEGUI,所以Wiki的Basic Tutorial 5和6是不用看地。


    http://narita1982.bokee.com/6728107.html

    OgreNewt~1:如果不能 动->Collision Tree

    吐血啊,吐血……
    想着“老天爷,你快让我搞定,我好去睡觉了!”,终于搞定了,老天爷真是赏脸。

    查了下,有个老外和我犯了一样的错误,他花了5个小时发现的,让他狂吐;我比他吐得更厉害。心碎。

    原话:I don't get it at all. It took me 5 hours to discover I had to use mNewtonWorld->setWorldSize(vector, vector) before anything would be updated.

    就是说:必须调用SetWorldSize()设置世界大小,引擎才会更新。body会掉到最低处就不动了。奇怪的是,demo里没有 设置,却能更新,真是害人啊。

    本来想用Newton的,后来发现最大的问题是,Newton用旋转和位移,而Ogre却用translate(),yaw(), pitch() 和roll()来旋转和位移。鉴于偶数学太差,搞不定Matrix就作罢。

    设置没什么难的,Newton比Ode好的地方在于Newton文档齐全,教程齐全,整合了OpenGl因此Domo可以看到效果,编 译了lib和dll。OgreNewt和OgreOde一样,也需要自己编译lib,BasicFrameListener因为新版的Ogre输入部分的 改动,要作一些修改。

    -----------------------------------------------

    OgreNewt封装得很好,Newton的Collisiton Tree只是一个框架,而OgreNewt的Collision Tree部分真的是很容易,它通过节点读取entity的mesh模型,然后读取面加入到Newton的CollisionTree里,太傻瓜了吧?一点 都没有进步…… 原代码部分可以好好看下,看看怎么读Ogre的mesh模型。

    http://narita1982.bokee.com/6730470.html

    Ogre 3D引擎 笔记~3:摄像机绕定点转动->Overlay->RayQuery

    不是很难的东西,不过想不到的话绝对可以让人吐血。

    Ogre里面的转动都是自转的,所以不要改什么yaw,roll, pitch,rotate或者TS_WORLD,TS_PARENT了,即使计算部分全部自己作,它还是会傻傻地绕自己的轴转动。

    看了兔子也会编游戏的月亮绕太阳公转的教程,才恍然大悟。如果公转是要转太阳,而不是月亮地。将月亮的节点绑到太阳的节点下面,月亮和太阳节点的距 离是一定的,这样当太阳自传的时候,月亮就会跟着转了。

    摄像机也同理。

    当需要摄像机规位的时候,也不要自己想怎么rotate回去。只要将绑定摄像机的节点removeAndDestroy(),然后重新绑定就好。

    用Overlay把导航条的雏形作好了。Ogre真得太脚本化了,一点技术含量也没有。
    参照ExampleFrameListener写吧。Overlay的布局,字体设置,以及图片都用txt文件设置。可以在pack文件夹里把 OgreCore解压缩看看。

    不过不晓得Overlay动态处理图片的能力怎么样,有待研究。

    用Ogre的射线查询(RayQuery)在导航板加入了显示高度的部分。有一点点飞行游戏的雏形了。活活~

    RayQuery的教程还是满多的。Ogre wiki上的教程还满不错。http://www.ogre3d.org/wiki/index.php/Intermediate_Tutorial_2

    具体的太都,就不写了吧 =P

    http://narita1982.bokee.com/6732119.html

    Ogre 3D引擎 笔记~4:玩转RibbonTrail

    想作跟踪弹的尾迹?方法之一就是求助于RibbonTrail。




    RibbonTrail的Demo(就是两条光绕头转动的那个)代码和注释的误导性太大。如果照抄的话,是很难作出想要的效果地。

    代码其实分为几个部分:公告板(Billboard,就是永远朝向镜头的贴图)是用来作光线头部的贴图的,绑定Light是为了照到别的物体上有明暗效 果,而RibbonTrail是用来作轨迹的。

    那一段给节点加入Track的部分完全是误导>_<,动画的部分完全不需要。 RibbonTrail的轨迹是不需要绑定若干节点的。RibbonTrail只需要绑定两个节点,一个头,一个尾。而头必须绑定在移动的节点上,用 RibbonTrail的addNode()绑定;尾则随便建一个SceneNode,用SceneNode的attachObject()绑定,这个节 点的父节点会自动设置为头部,所以如果设置位移的话不要设置成世界位移。

    RibbonTrail的maxElement越多,setTrailLength()越大;渐变效果越明显,最终效果也就越真实。

    另外RibbonTrail的材质是一条高1pixel,宽128pixel的图。实际上白色的部分才是表示光线的部分。

    嘿嘿,RibbonTrail可以作出一些很酷的效果哦。

    http://narita1982.bokee.com/6733505.html

    Ogre 3D引擎 笔记~5 :碰撞检测

    终于搞定了,郁闷,我得提高发现问题的速度>_<

    物体间的碰撞检测我用的是OgreNewt(一个开源的物理引擎)。但是我不太在乎物理定律,因为作出精确的行为是需要满强的物理功底的。我只是需 要用到它的碰撞检测,如何初始化等就不说了,只说下问题。

    Ogre的SceneNode和OgreNewt的body是绑定的。可以用SceneNode的位置设置body的位置,或者相反。但是不要用前 者,除非初始化的时候。因为不用物理规则设定body位置的话,那么碰撞就不起作用了(多么2)。

    设置body的位置和方向有几种方法,setVelocity,setForce, setTorque,setOmega;分别是设置速度,受力,力矩,和角速度;因为对物理定律不熟悉,所以超级厌恶受力和力矩。所以搞一 个伪物理行为取而代之:因为对物体的实际旋转没有兴趣(比如受到撞击木块会翻滚),所以只用SetVelocity调整body的位置;而用 SceneNode来计算旋转方向。

    具体……掠过……

    注意虽然body和SceneNode是绑定的,实际上body位置或者SceneNode位置改变都是不影响到对方,必须自己改变另一个的位置。 改变SceneNode的位置比较正宗的方法是用Callback,OgreNewt可以设置各种各样的Callback函数,程序会自动在某种情况发生 的时候调用它们。改变位置就可以用

    body->setCustomTransformCallback(customTransformCallback); 

    /*定义*/

    void CRider::customTransformCallback(OgreNewt::Body* me, const Ogre::Quaternion& orient, const Ogre::Vector3& pos )
    {
    /*获取和body绑定的指针,用body->setUserData()设定*/
     SceneNode* node=(CRider*)me->getUserData();
     node->setPosition(pos);
    }

    具体……掠过……

    这里的callback虽然不需要传参数,但是实际上它的参数数量和形式已经是定义好的。另外,函数必须是静态的。

    主要问题已经解决,我的程序因为未知原因出现了一件超级恶的事,就是body走着走着就不动了,虽然速度设置的没有错误,我想可能是物理定律发威 了。搞了好久,终于发现不动的时候TransformCallback也不会被调用了,果然是物理定律发威了。Newton会将不动的物体永久打入冷宫, 好像锁定一样,实际上是不再计算它。

    然后发现有一个setAutoactiveCallback(),试验了一下,发现在不动的时候程序会不断调用这个callback。于是写了一个 callback如下。

    void CRider::customAutoActiveCallback(OgreNewt::Body* me, unsigned int state)
    {
         me->unFreeze();
    }

    终于大功告成~~~~~~