DirectX11 With Windows SDK--18 使用DirectXCollision库进行碰
原文:
DirectX11 With Windows SDK--18 使用DirectXCollision库进行碰撞检测
前言在DirectX SDK中,碰撞检测的相关函数位于xnacollision.h中。但是现在,前面所实现的相关函数都已经转移到Windows SDK的DirectXCollision.h中,并且处于名称空间DirectX内。这里面主要包含了四种包围盒(Bounding Volumes),并且是以类的形式实现的:
除此之外里面还包含有三角形(射线)与其余物体的碰撞检测。 后续的项目将会使用该碰撞库。 DirectX11 With Windows SDK完整目录 Github项目源码 欢迎加入QQ群: 727623616 可以一起探讨DX11,以及有什么问题也可以在这里汇报。 常见包围盒包围球(Bounding Box)一个球体只需要使用圆心坐标和半径就可以表示。结构体的一部分如下: struct BoundingSphere { XMFLOAT3 Center; // 球体中心坐标 float Radius; // 球体半径 // 构造函数 BoundingSphere() : Center(0,0),Radius( 1.f ) {} XM_CONSTEXPR BoundingSphere(const XMFLOAT3& center,float radius ) : Center(center),Radius(radius) {} BoundingSphere(const BoundingSphere& sp ) : Center(sp.Center),Radius(sp.Radius) {} // ... // 静态创建方法 static void CreateMerged(BoundingSphere& Out,const BoundingSphere& S1,const BoundingSphere& S2 ); static void CreateFromBoundingBox(BoundingSphere& Out,const BoundingBox& box ); static void CreateFromBoundingBox(BoundingSphere& Out,const BoundingOrientedBox& box ); static void CreateFromPoints(BoundingSphere& Out,size_t Count,const XMFLOAT3* pPoints,size_t Stride); static void CreateFromFrustum(BoundingSphere& Out,const BoundingFrustum& fr ); }; 其中
然后还需要着重说明一下 参数 参数 参数 下面是一个使用示例: struct VertexPosNormalTex { XMFLOAT3 pos; XMFLOAT3 normal; XMFLOAT3 tex; }; VertexPosNormalTex vertices[20]; // 省略初始化操作... BoundingSphere sphere; BoundingSphere::CreateFromPoints(sphere,20,&vertices[0].pos,sizeof(VertexPosNormalTex)); 轴对齐包围盒(Axis-aligned bounding box)一个物体若拥有AABB盒,那AABB盒的六个面都会和物体紧紧贴靠在一起。它可以用两个点描述:Vmax和Vmin。其中Vmax的含义是:分别取物体所有顶点中x,y,z分量下的最大值以构成该顶点。Vmin的含义则是:分别取物体所有顶点中x,z分量下的最小值以构成该顶点。 获取了这两个点后,我们就可以用另一种表述方式:中心位置C和一个3D向量E,E的每个分量的含义为中心位置到该分量对应轴的两个面的距离(距离是相等的)。 该碰撞库使用的则是第二种表述方式,但也支持用第一种方式来构建。结构体的一部分如下: struct BoundingBox { static const size_t CORNER_COUNT = 8; // 边界点数目 XMFLOAT3 Center; // 盒中心点 XMFLOAT3 Extents; // 中心点到每个面的距离 // 构造函数 BoundingBox() : Center(0,Extents( 1.f,1.f,1.f ) {} XM_CONSTEXPR BoundingBox(const XMFLOAT3& center,const XMFLOAT3& extents) : Center(center),Extents(extents) {} BoundingBox(const BoundingBox& box) : Center(box.Center),Extents(box.Extents) {} // ... // 静态创建方法 static void CreateMerged(BoundingBox& Out,const BoundingBox& b1,const BoundingBox& b2 ); static void CreateFromSphere(BoundingBox& Out,const BoundingSphere& sh ); static void XM_CALLCONV CreateFromPoints(BoundingBox& Out,FXMVECTOR pt1,FXMVECTOR pt2 ); static void CreateFromPoints(BoundingBox& Out,size_t Stride ); };
有向包围盒(Oriented bounding box)对某些物体来说,在经过一系列变换后它的包围盒也需要随之改变。但例如一些默认情况下宽度、深度值比高度大得多的物体,比如飞机、书本等,经过变换后它的AABB盒可能会变得特别大,暴露了许多空余的位置,从而不能很好地将物体包住。 因为AABB盒的边界是轴对齐的,没有办法记录旋转属性。这时候我们可以考虑使用OBB盒,除了包含AABB盒应当记录的信息外,它还记录了旋转相关的信息。结构体部分如下: struct BoundingOrientedBox { static const size_t CORNER_COUNT = 8; // 边界点数目 XMFLOAT3 Center; // 盒中心点 XMFLOAT3 Extents; // 中心点到每个面的距离 XMFLOAT4 Orientation; // 单位旋转四元数(物体->世界) // 构造函数 BoundingOrientedBox() : Center(0,1.f ),Orientation(0,1.f ) {} XM_CONSTEXPR BoundingOrientedBox(const XMFLOAT3& _Center,const XMFLOAT3& _Extents,const XMFLOAT4& _Orientation) : Center(_Center),Extents(_Extents),Orientation(_Orientation) {} BoundingOrientedBox(const BoundingOrientedBox& box) : Center(box.Center),Extents(box.Extents),Orientation(box.Orientation) {} // ... // 静态创建方法 static void CreateFromBoundingBox(BoundingOrientedBox& Out,const BoundingBox& box ); static void CreateFromPoints(BoundingOrientedBox& Out,size_t Stride ); }; 其中 包围视锥体(Bounding Frustum)为了描述一个视锥体,一种方式是以数学的形式指定视锥体的六个边界平面:左/右平面,顶/底平面,近/远平面。这里假定六个视锥体平面是朝向内部的。 虽然我们可以用六个4D平面向量来存储一个视锥体,但这还是有更节省空间的表示方法。 首先在物体坐标系中,取摄像头的位置为原点,正前方观察方向为Z轴,右方向为X轴,上方向为Y轴,这样就可以得到右(左)平面投影到zOx平面下的直线斜率为X/Z(-X/Z),以及上(下)平面投影到zOy平面下的直线斜率为Y/Z(-Y/Z)。同时也可以得到近(远)平面到原点的距离,也即是对应的Z值。 然后使用一个3D位置向量和单位旋转四元数来表示视锥体在世界中的位置和朝向。这样我们也可以描述一个视锥体了。 下面展示了视锥体包围盒结构体的部分内容: struct BoundingFrustum { static const size_t CORNER_COUNT = 8; XMFLOAT3 Origin; // 摄像机在世界中的位置,物体坐标系下默认会设为(0.0f,0.0f,0.0f) XMFLOAT4 Orientation; // 单位旋转四元数 float RightSlope; // 右平面投影到zOx平面的直线斜率+X/Z float LeftSlope; // 左平面投影到zOx平面的直线斜率-X/Z float TopSlope; // 上平面投影到zOy平面的直线斜率+Y/Z float BottomSlope; // 下平面投影到zOy平面的直线斜率-Y/Z float Near,Far; // Z值对应近(远)平面到摄像机物体坐标系原点的距离 // 构造函数 BoundingFrustum() : Origin(0,1.f),RightSlope( 1.f ),LeftSlope( -1.f ),TopSlope( 1.f ),BottomSlope( -1.f ),Near(0),Far( 1.f ) {} XM_CONSTEXPR BoundingFrustum(const XMFLOAT3& _Origin,const XMFLOAT4& _Orientation,float _RightSlope,float _LeftSlope,float _TopSlope,float _BottomSlope,float _Near,float _Far) : Origin(_Origin),Orientation(_Orientation),RightSlope(_RightSlope),LeftSlope(_LeftSlope),TopSlope(_TopSlope),BottomSlope(_BottomSlope),Near(_Near),Far(_Far) {} BoundingFrustum(const BoundingFrustum& fr) : Origin(fr.Origin),Orientation(fr.Orientation),RightSlope(fr.RightSlope),LeftSlope(fr.LeftSlope),TopSlope(fr.TopSlope),BottomSlope(fr.BottomSlope),Near(fr.Near),Far(fr.Far) {} BoundingFrustum(CXMMATRIX Projection) { CreateFromMatrix( *this,Projection ); } // ... // 静态创建方法 static void XM_CALLCONV CreateFromMatrix(BoundingFrustum& Out,FXMMATRIX Projection); } 通常情况下,我们会通过传递投影矩阵来创建一个包围视锥体,而不是直接指定上面的这些信息。 包围盒的相交、包含、碰撞检测及变换包围盒与平面的相交检测对于包围盒与平面的相交检测,返回结果使用了枚举类型 enum PlaneIntersectionType { FRONT = 0,// 包围盒在平面的正面区域 INTERSECTING = 1,// 包围盒与平面有相交 BACK = 2,// 包围盒在平面的背面区域 }; 上面提到的四种包围盒都具有重载方法Intersects用于检测该包围盒与平面的相交情况: PlaneIntersectionType XM_CALLCONV Intersects(FXMVECTOR Plane) const; 正/背面的判定取决于一开始平面法向量的设定。比如一个中心在原点,棱长为2的正方体,与平面-z+2=0(对应4D平面向量(0.0f,-1.0f,2.0f),平面法向量(0.0f,-1.0f) )的相交结果为:物体在平面的正面区域。 包围盒与包围盒的包含检测对于两个包围盒的包含检测,返回结果使用了枚举类型 enum ContainmentType { DISJOINT = 0,// 两个包围盒相互分离 INTERSECTS = 1,// 两个包围盒有相交 CONTAINS = 2,// 两个包围盒存在包含关系 }; 这四种包围盒相互之间都有对应的方法来测试: ContainmentType Contains(const BoundingSphere& sp) const; ContainmentType Contains(const BoundingBox& box) const; ContainmentType Contains(const BoundingOrientedBox& box) const; ContainmentType Contains(const BoundingFrustum& fr) const; 包围盒与包围盒的碰撞检测如果我们只需要检查两个包围盒之间是否发生碰撞(相交和包含都算),则可以使用下面的这些方法。四种包围盒相互之间都能进行碰撞测试: bool Intersects(const BoundingSphere& sh) const; bool Intersects(const BoundingBox& box) const; bool Intersects(const BoundingOrientedBox& box) const; bool Intersects(const BoundingFrustum& fr) const; 包围盒的变换四种包围盒都包含下面两个方法,一个是任意矩阵的变换,另一个是构造世界矩阵的变换(这里用 void XM_CALLCONV Transform(BoundingVolume& Out,FXMMATRIX M ) const; void XM_CALLCONV Transform(BoundingVolume& Out,float Scale,FXMVECTOR Rotation,FXMVECTOR Translation) const; 要注意的是,第一个参数都是用于输出变换后的包围盒, 包围盒的其它方法获取包围盒的八个顶点除了包围球外的其它包围盒都拥有方法 void GetCorners(XMFLOAT3* Corners) const; 这里要求传递的参数 获取包围视锥体的六个平面
void GetPlanes(XMVECTOR* NearPlane,XMVECTOR* FarPlane,XMVECTOR* RightPlane,XMVECTOR* LeftPlane,XMVECTOR* TopPlane,XMVECTOR* BottomPlane) const; 包围视锥体在检测是否包含某一包围盒的时候内部会调用待测包围盒的 ContainmentType XM_CALLCONV ContainedBy(FXMVECTOR Plane0,FXMVECTOR Plane1,FXMVECTOR Plane2,GXMVECTOR Plane3,HXMVECTOR Plane4,HXMVECTOR Plane5 ) const; // Test frustum against six planes (see BoundingFrustum::GetPlanes) 三角形、射线三角形的表示需要用到三个坐标点向量,而射线的表示则需要一个 射线(三角形)与非包围盒的相交检测下面这三个常用的方法都在名称空间 namespace TriangleTests { bool XM_CALLCONV Intersects(FXMVECTOR Origin,FXMVECTOR Direction,FXMVECTOR V0,GXMVECTOR V1,HXMVECTOR V2,float& Dist ); // 射线与三角形的相交检测 bool XM_CALLCONV Intersects(FXMVECTOR A0,FXMVECTOR A1,FXMVECTOR A2,GXMVECTOR B0,HXMVECTOR B1,HXMVECTOR B2 ); // 三角形与三角形的相交检测 PlaneIntersectionType XM_CALLCONV Intersects(FXMVECTOR V0,FXMVECTOR V1,FXMVECTOR V2,GXMVECTOR Plane ); // 平面与三角形的相交检测 // 忽略... }; 其中 射线(三角形)与包围盒的相交检测四种包围盒都包含了下面的两个方法: bool XM_CALLCONV Intersects(FXMVECTOR Origin,float& Dist) const; // 射线与包围盒的相交检测 bool XM_CALLCONV Intersects(FXMVECTOR V0,FXMVECTOR V2) const; // 三角形与包围盒的相交检测 演示程序关于碰撞检测库的演示可以在下面的链接找到,这里就没有必要再写一个演示程序了: DirectX SDK Samples 下载(克隆)到本地后找到Collision文件夹,选择合适的解决方案打开并编译运行即可。这里我选择的是Collision_Desktop_2017_Win10.sln。成功运行的话效果如下: DirectX11 With Windows SDK完整目录 Github项目源码 欢迎加入QQ群: 727623616 可以一起探讨DX11,以及有什么问题也可以在这里汇报。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
- windows – event.getFile().getFileName()返回带有PrimeFa
- windows-8 – 在MetroStyle应用程序中使用COM对象
- windows – 如何在GoSublime的命令shell中退出“go run”?
- windows – 如何删除本地管理员权限?
- disk-image – 如何在Windows 7 WinPE中安装ISO映像?
- Windows窗体错误解析VB.NET
- windows-installer – Windows Installer总是说“正在安装另
- .net – 在发布时突然没有复制引用的程序集(DLL)
- 在Windows下编译适用于PHP 5.2.12及5.2.13的eAccelerator.d
- 与在NTFS上存储数百万个文件相关的性能