在网上看了很多相关资料发现都是单个物体的Pick对于多物体进行World变换后的Pick则很少有讨论的。在dxsdk中也只有单个物体移动相机实现Pick的c++的代码。在此我用c#实现多物体Pick。
所谓Pick(拾取操作)就是通过鼠标选取3d空间中的几何图元(就像魔兽中选择英雄^_^)。
要实现多物体Pick需要实现以下几步:
1,通过鼠标在窗体中的位置获得拾取射线的方向矢量(RayDir)
首先将屏幕鼠标坐标映射到投影坐标空间(重剑兄台所说的1/2立方体)中,得到向量v:
Vector3 v;
v.X = ( float )(( 2.0f * mousePoint.X / this .Bounds.Width) - 1.0f ) / mPj.M11;
v.Y = - ( float )(( 2.0f * mousePoint.Y / this .Bounds.Height) - 1.0f ) / mPj.M22;
v.Z = 1.0f ;
再将其映射为视察坐标空间中的向量:
因为v=RayDir*ViewMatrix
所以要将视察矩阵进行你变换:
Matrix m = Matrix.Invert(mView);
由于v是向量所以要进行向量乘法得到RayDir:
vPickRayDir.Y = v.X * m.M12 + v.Y * m.M22 + v.Z * m.M32;
vPickRayDir.Z = v.X * m.M13 + v.Y * m.M23 + v.Z * m.M33;
2,获得摄像机位置坐标(RayOrig)作为射线起始点
这里要注意一点,视察矩阵的逆矩阵的第4行前三个数正好是视察点.所以有此的得到RayOrig:
vPickRayOrig.Y = m.M42;
vPickRayOrig.Z = m.M43;
以上两步只需在鼠标位置改变或视察矩阵改变的情况下刷新,(我是在MouseMove事件中刷新的)而下面的步骤需要在渲染时实时进行。
3,将投影空间中的RayDir向量和RayOrig坐标变换到世界空间
由于每个模型都有自己的世界矩阵(本例中用matrixList存储)
首先给出算法代码如下:
// 对vRayDir作向量变换
Vector3 vRayDir2;
vRayDir2.X = vRayDir.X * m.M11 + vRayDir.Y * m.M21 + vRayDir.Z * m.M31 ;
vRayDir2.Y = vRayDir.X * m.M12 + vRayDir.Y * m.M22 + vRayDir.Z * m.M32 ;
vRayDir2.Z = vRayDir.X * m.M13 + vRayDir.Y * m.M23 + vRayDir.Z * m.M33 ;
// 对vRayOrig作坐标变换
Vector3 vRayOrig2;
vRayOrig2.X = vRayOrig.X * m.M11 + vRayOrig.Y * m.M21 + vRayOrig.Z * m.M31 + m.M41;
vRayOrig2.Y = vRayOrig.X * m.M12 + vRayOrig.Y * m.M22 + vRayOrig.Z * m.M32 + m.M42;
vRayOrig2.Z = vRayOrig.X * m.M13 + vRayOrig.Y * m.M23 + vRayOrig.Z * m.M33 + m.M43;
以上代码应在Render函数或FrameMove函数中调用。当然以上只是为了方便说明,实际完全可以用Vector4.Transform()简化编程。应该注意的是vRayDir是一个向量所以用Vector4结构表示是W值应设置为0,而vRayOrig是一个坐标用Vector4结构表示是W值应设置为1。在获得了世界空间的vRayDir2和vRayOrig2后即可调用Mesh类的Intersect方法进行交叉检测,例如:meshList[i].Intersect(vRayOrig2, vRayDir2);
3,总结
对于射线与三角形交点的计算我将在以后的文章中继续讨论。
其实纵观整个Pick过程其实就是一系列逆变换,反过来看看也很简单,最初一个3D物体经过世界变换,得到在世界坐标空间的位置,在经过视察变换,得到在视察空间的坐标,最后在经过投影变换得到屏幕坐标。而鼠标本身给出的是一个屏幕坐标,就需要经过上述变换的逆过程得到鼠标指针在3D空间中的投影,既选取射线Ray(^_^)。
到此我们讨论了整个Pick过程,本文写的有些仓促,如需完整代码请于本人联系。
(^_^)QQ:253896246
Mail:whl0070179@163.com
参考文献:
Direct3D中实现图元的鼠标拾取BY 重剑,2004.5.28
Improved Ray Picking http://www.mvps.org/directx/articles/improved_ray_picking.htm
声明:
本文写作的目的是为了广大MDX学习者方便学习服务,文中算法为作者参考相关文献总结,作者无意把这些据为自己的成果,所有权原算法提出者所有(参阅参考文献)