本文主要内容是关于拾取机理的探讨,我在自己引擎中的每个Mesh类中加入了拾取机制,当物体打开拾取开关时,就会响应拾取,同时绘制一个辅助的外接体,被拾取到时,物体进行一个简单的绕自身Y轴自转的动作。
(我将鼠标投影矩阵进行了改写,在原基础上调节成了屏幕中心为原点,这样可以减少坐标系转换时的运算量,鼠标系统我使用了自己定义的DXInput系统,所以可以这么做。)
附一些截图:
(不要在意某些细节)
关于拾取的机理,龙书上已经讲的非常详细了,但是有一些关键点没讲到。在网上可以搜到一些关于长方体外接体拾取的探讨。讲的都不甚详细,而且效率不够高。不能用于实际使用。(事实上龙书已经擦边式的把所有知识都将给我们了)
我想了一下,找到了一个相对快速、容易掌握的办法:
拾取最核心的部分,就是拾取射线的确定,这里稍微提一下,我们假定屏幕上直接显示的,是距离摄像头距离为1.0f的表面,并不是(-1.0f, 1.0f)的那个表面。所以要根据这个表面进行计算。机智的筒子们稍微用点数学知识很快就可以写出来了。
新增射线结构体 struct rayLine{ D3DXVECTOR3 pos, dir;},所求射线为 pickRayLine。
通过乘一系列的矩阵,求出世界坐标系内的拾取射线方程,然后进入我们今天的课题:(本文只讨论普适情况)
假设2D空间的射线为 ray(rX, rY);
在讨论3D空间之前,首先讨论2D空间的内容,如上草图所示,如果要判断射线是否穿过多变形,首先要确定两条边界线,OA、OC。方法如下:
对OA、OB、OC、OD做单位化处理,然后求出新的节点 mMin=(x, y,),mMax =(a, b, c); mMin中存储的是四顶点的三分量中的最小值。
(pickRayLine也需要做单位化处理。)
那么当射线满足下列条件时,射线穿过多边形:
if( rX > x && rX < a )
if( rY > y && rY < b )
// 穿过矩形
好了,2D空间的情况到此分析完毕,现在我们来转到3D空间,长方体,急需要多算几个顶点、多一个分量就可以了。
现在转到我们的程序中,如果要实现上述算法,有两种方案,1.拾取射线和物体的交互在世界空间内进行;2.拾取射线转换到物体空间内进行。
使用方法1时,我们需要在建立一个物体的时候,额外占用一部分空间建立一个长方体外接体顶点数组,然后对所有顶点进行世界坐标系转换,一共需要变换8个顶点。真是一个费空间费时间的方法啊,果断抛弃!
来看方法2,我们仅需要把做一步转换 —— 射线转换到物体局部坐标系中,而且,不需要使用额外空间存储外接体,你没看错,仅需要一个像龙书示例所使用的两个变量 mMin、mMax即可。具体方法我就不再多提了。相信对于头脑聪明的筒子你来说,这都不是事了。
OK....
*********************************************
补充知识
物体的拾取是件非常耗时的工作,所以尽可能减少拾取操作。场景的加载应该是逐级加载的,使用额外的线程进行后台加载。逐级的加载、删除物体。这是第一道关卡,然后物体内部加一个active变量,如果物体与player点的距离达不到要求,应该不参与拾取。这是第二关。
*********************************************
好了,本文到此结束吧。明天开始做一个小游戏玩玩,记得网上有一个是男人就点100下,用自己的这个渣渣引擎实现以下试试吧。