转载自:http://www.cnblogs.com/Yuri/archive/2007/07/28/834227.html
我的碰撞检测树就是一BVH树,和标准的AABB碰撞检测树相比,AABB树是2叉树,我的树的节点数是不定的。
两种建树过程如下:
我的树可能不如AABB树平衡,可能性能稍差。
注:
碰撞检测树一般在物体定坐标系下建立出来
可以根据情况,为不同节点选择不同类型的包围体,使得包围体包围得最紧凑
碰撞检测:
一个几何图形vs树
按深度优先或广度优先遍历树,对于非最末级节点,判断几何图形是否和节点包围体相交,如果相交那么继续遍历它的子节点。对于最末级节点,还要进行几何图形和最末节点所对应的三角形求交。这样,遍历完一次即可找到所有碰撞。
注:
1.碰撞检测需检测出碰撞点,碰撞法向量,和刺穿深度
2.球和三角形碰撞:
以下过程按顺序执行,一旦相交就return,停止和这个三角形继续检测:
(1).判断球心与三角面垂直且过三边的平面的位置关系,如果被包围,那么直接判断球心到三角面所在平面距离是否<=半径
(2).根据(1)的结果,如果球心在哪条边外,那么试着和那条线段求交
(3).判断球心到三角形某顶点距离<=半径
3.球和棱、点碰撞,碰撞法向量为那个面在碰撞点的切平面的法向量
4.通过更精确的包围体测试,会遍历更少节点,但更精确的包围体测试一般会花更多时间。
树vs树
对于一对节点,判断两个节点的包围体是否相交。如果相交,那么测试它们的子节点包围体是否相交。
如果有一个节点是最末级节点,它对应着一个三角形,另一个是一个非最末级节点,那么问题转化为上面“一个几何图形vs树”。
如果两个节点都是最末级节点,那么进行三角形求交。
注:
对于刚体,它们会转动,转动了的AABB可以用AABB加上一个刚体变换矩阵表示。也可懒一些,直接把树放入全局坐标系下,更新树。
树的更新:
如果物体不是刚体,可能会形变,这就需要更新树。一般自下而上的更新树。先根据最末级节点对应的三角形,更新最末级节点。然后一级一级更新上面的节点,使它们的包围体包住子节点。
以后安排(先把想法记下来)
物体破裂 :
将物体网格表示成一张无向图(不用邻接矩阵表示),在压强足够大的地方细化网格,细化出的部分作为图的一部分,然后从压强足够大的几个顶点遍历图。遍历时根据物体物理材质选择图的边(第一条边应选择最和切向量正交的),将其并入断裂线,必要时就细化网格,直到这条线首尾封闭。这样做是因为不同材质的物体,其断裂口有的光滑,有的粗糙,甚至有尖刺。这样应该能生成一条满意的断裂线。然后取出子图,成为分裂出的物体的网格的一部分。不过断口的填充就暂无想法了……
脚本:
设想了一种托管脚本。先写好脚本,经过编译器将其编译为自定的较低级中间语言,或者直接IL代码。运行前加载时,对其进行JIT编译,除了.Net的JIT以外,还有自己的一些,当然肯定是自己先处理后再交给.Net……这样脚本最终就是本机代码,执行速度比解释型的快,而且异常也不用一下一下的考虑。
一开始编译为直接IL代码时,不能直接转为它的字节码,而是自己规定的字节码,但其指令还是一一对应的(就是把IL代码用2进制形式表示了一下)。这主要是因为代码中有一些东西,还不能直接转为标准的IL字节码
最终应该可以构建复杂的物体,比如一个人,由Joint、刚体(骨骼和关节)和柔体(头发和肥膘)组成。他做个什么动作要是碰到了什么倒是自然能模拟出来。不过他的行走,怎么维持重心不好说,我的想法是对已做好的动画解析,将其数值微分,最后算出各部分的作用力……维持重心不管他用那些肌肉,维持重心的力 应该包括在里面……
以前有外国人拟做过类似的东西,第六届全国中小学电脑制作活动上还有即将得一得奖的抄过——botz,一个2D质点弹簧系统模拟程序,它的欧拉法积分不严密(或者说就不是),碰撞检测就和边界检查了一下,但是要注意他的“肌肉”思想,质点弹簧系统组成机器人,然后肌肉伸缩运动,我这个应该和那个在这一点有着类似之处。更接近一点的东西就是Dr.Jan Bender的那些机器人了。
当然稍微遥远的东西别想得太多,毕竟还有不少东西未完成……
Broad-phase碰撞检测
Sweep and Prune:
1.将物体的AABB分离到三个坐标轴上。得到若干个区间。
2.根据区间的终点坐标由小到大排序。
3.逐个遍历排序结果,当遇到一个区间的起始点的时候,就将这个区间放到一个列表中;当遇到一个区间的终点时,就将这个区间从列表中清除。
当在列表中存在区间,而又遇到一个新区间的起始点时,则遇到的区间与列表中的所有区间重叠。
4.如果一对物体在三个坐标轴上的区间都重叠,那么他们的AABB相叠。
Mid-phase碰撞检测
碰撞检测树就是将要碰撞的网格分离成多个部分,并将这些部分按树的结构组织起来。我的碰撞检测树就是一BVH树,和标准的AABB碰撞检测树相比,AABB树是2叉树,我的树的节点数是不定的。
两种建树过程如下:
AABB: 1.计算三角形集合的AABB包围体 | 我的碰撞检测树: 1.计算三角形集合的包围体 2.计算三角形集合的几何重心,将几何重心视为原点,按三个坐标平面将三角形集合分成8部分 3.穿过这个坐标平面的三角形按中点分配到平面一侧,如果中点还在平面上,随便分配 4.如果有的部分中没三角形,那么去掉它。如果只有一部分且这部分包含多个三角形,强行随便的将这部分分成多部分(防止死递归)。 5.将分出的n部分作为子节点继续分割(步骤1),直到分出的部分只有一个三角形 |
包围体有: |
包围球 |
碰撞检测树一般在物体定坐标系下建立出来
可以根据情况,为不同节点选择不同类型的包围体,使得包围体包围得最紧凑
碰撞检测:
一个几何图形vs树
按深度优先或广度优先遍历树,对于非最末级节点,判断几何图形是否和节点包围体相交,如果相交那么继续遍历它的子节点。对于最末级节点,还要进行几何图形和最末节点所对应的三角形求交。这样,遍历完一次即可找到所有碰撞。
注:
1.碰撞检测需检测出碰撞点,碰撞法向量,和刺穿深度
2.球和三角形碰撞:
以下过程按顺序执行,一旦相交就return,停止和这个三角形继续检测:
(1).判断球心与三角面垂直且过三边的平面的位置关系,如果被包围,那么直接判断球心到三角面所在平面距离是否<=半径
(2).根据(1)的结果,如果球心在哪条边外,那么试着和那条线段求交
(3).判断球心到三角形某顶点距离<=半径
3.球和棱、点碰撞,碰撞法向量为那个面在碰撞点的切平面的法向量
4.通过更精确的包围体测试,会遍历更少节点,但更精确的包围体测试一般会花更多时间。
树vs树
对于一对节点,判断两个节点的包围体是否相交。如果相交,那么测试它们的子节点包围体是否相交。
如果有一个节点是最末级节点,它对应着一个三角形,另一个是一个非最末级节点,那么问题转化为上面“一个几何图形vs树”。
如果两个节点都是最末级节点,那么进行三角形求交。
注:
对于刚体,它们会转动,转动了的AABB可以用AABB加上一个刚体变换矩阵表示。也可懒一些,直接把树放入全局坐标系下,更新树。
树的更新:
如果物体不是刚体,可能会形变,这就需要更新树。一般自下而上的更新树。先根据最末级节点对应的三角形,更新最末级节点。然后一级一级更新上面的节点,使它们的包围体包住子节点。
以后安排(先把想法记下来)
物体破裂 :
将物体网格表示成一张无向图(不用邻接矩阵表示),在压强足够大的地方细化网格,细化出的部分作为图的一部分,然后从压强足够大的几个顶点遍历图。遍历时根据物体物理材质选择图的边(第一条边应选择最和切向量正交的),将其并入断裂线,必要时就细化网格,直到这条线首尾封闭。这样做是因为不同材质的物体,其断裂口有的光滑,有的粗糙,甚至有尖刺。这样应该能生成一条满意的断裂线。然后取出子图,成为分裂出的物体的网格的一部分。不过断口的填充就暂无想法了……
脚本:
设想了一种托管脚本。先写好脚本,经过编译器将其编译为自定的较低级中间语言,或者直接IL代码。运行前加载时,对其进行JIT编译,除了.Net的JIT以外,还有自己的一些,当然肯定是自己先处理后再交给.Net……这样脚本最终就是本机代码,执行速度比解释型的快,而且异常也不用一下一下的考虑。
一开始编译为直接IL代码时,不能直接转为它的字节码,而是自己规定的字节码,但其指令还是一一对应的(就是把IL代码用2进制形式表示了一下)。这主要是因为代码中有一些东西,还不能直接转为标准的IL字节码
最终应该可以构建复杂的物体,比如一个人,由Joint、刚体(骨骼和关节)和柔体(头发和肥膘)组成。他做个什么动作要是碰到了什么倒是自然能模拟出来。不过他的行走,怎么维持重心不好说,我的想法是对已做好的动画解析,将其数值微分,最后算出各部分的作用力……维持重心不管他用那些肌肉,维持重心的力 应该包括在里面……
以前有外国人拟做过类似的东西,第六届全国中小学电脑制作活动上还有即将得一得奖的抄过——botz,一个2D质点弹簧系统模拟程序,它的欧拉法积分不严密(或者说就不是),碰撞检测就和边界检查了一下,但是要注意他的“肌肉”思想,质点弹簧系统组成机器人,然后肌肉伸缩运动,我这个应该和那个在这一点有着类似之处。更接近一点的东西就是Dr.Jan Bender的那些机器人了。
当然稍微遥远的东西别想得太多,毕竟还有不少东西未完成……