游戏开发论坛

 找回密码
 立即注册
搜索
查看: 2498|回复: 3

关于3D空间的碰撞问题

[复制链接]

16

主题

51

帖子

51

积分

注册会员

Rank: 2

积分
51
发表于 2004-7-3 09:21:00 | 显示全部楼层 |阅读模式
最近读了一些关于3D空间碰撞的文档,发现一个问题:虽然点碰撞的速度很快,也很好
现实,但总感觉不够精确,假设我们的角色是一个长方体,但被碰撞的物体比我们的角色小,则会出现被碰撞的物体从长方体的中间串过,而无法判断是否发生了碰撞,请问有没有好的处理方法?

2

主题

48

帖子

50

积分

注册会员

Rank: 2

积分
50
发表于 2004-7-5 14:59:00 | 显示全部楼层

Re:关于3D空间的碰撞问题

假如子弹是一个点,目标是一个长方体,可以用子弹在两?之间的连线跟目标作碰撞检测

3

主题

7

帖子

7

积分

新手上路

Rank: 1

积分
7
发表于 2004-7-5 18:30:00 | 显示全部楼层

Re:关于3D空间的碰撞问题

编写3D游戏时,最好用line和box,trangle进行碰撞,
尽量减少多点碰撞计算,以减少游戏计算开销。

19

主题

202

帖子

214

积分

中级会员

Rank: 3Rank: 3

积分
214
QQ
发表于 2004-7-5 21:43:00 | 显示全部楼层

Re:关于3D空间的碰撞问题

楼主说的问题很大程度上由于帧限制引起的

下面是一个关于2D刚体小球的碰撞检测以及碰撞响应的处理

因为是自己写的,不敢保证没有BUG,仅供参考

1、球体之间的相互碰撞检测(球的半径和质量均相等)

输入数据:(2D向量表示)
        球1的球心坐标
        球1的速度方向
        球1的速率
        球1的速度=球1的速度方向×球1的速率
        球2的球心坐标
        球2的速度方向
        球2的速率
        球2的速度=球2的速度方向×球2的速率

计算过程:
        球1与球2的相对速度 RelativeV = 球1的速度-球2的速度
        由球1的球心坐标与RelativeV的单位向量构成一个固定向量,表示由一点向某个方向的一条射线
        求球2的球心坐标与射线的距离
        如果所得的距离大于2倍半径,则两球不存在碰撞的可能性
        如果所得的距离小于等于2倍半径,则两球存在碰撞的可能性
       
        计算当前帧内的碰撞可能性
        为了增加计算精度,使用双循环,分离渲染层和逻辑层,渲染速度为33fps
       
        起始时间为 0        时间间隔为 t        把每帧切成30个时间片
        计算T 从0到30 之间是否存在一个点NewPosition与球2的球心坐标的距离小于或者等于2倍半径
       
        RV = RelativeV/30;
        V1'=V1/30;
        V2'=V2/30;
        while(T<=30){
                T+=t;
                NewPosition=Position1+RV*T;
                if(Distance(NewPosition, Position2)<=2*RADIUS){
                        // 计算在碰撞瞬间球1的球心坐标和球2的球心坐标
                        Pos1=Position1+V1'*T;
                        Pos2=Position2+V2'*T;
                        // 计算碰撞之后两个小球各自的速度
                        CollisionResponseBetweenSphere();
                        NewV1;        // 球1碰撞之后的速度
                        NewV2;        // 球2碰撞之后的速度
                        NV1 = NewV1/30;
                        NV2 = NewV2/30;
                        Pos1'=Pos1+NV1*(30-T);
                        Pos2'=Pos2+NV2*(30-T);
                }
        }

2、球体与平面的碰撞检测

在2D环境下,平面可以视为一条直线
输入数据:
        球的球心坐标 Position
        球的速度方向 Direction
        球的速率 Speed
        球的速度=球的速度方向×球的速率 Velocity = Direction*Speed
        线段的端点1的坐标 SP (Start Point)
        线段的端点2的坐标 EP (End Point)

计算过程:
        求线段的法向量 Normal
        计算球的速度方向与线段法向量的点积 Dot,判断球与线段是否平行
        如果Dot为0,表示两个向量互相垂直,即球的运动方向与线段平行,不存在碰撞的可能性
        如果Dot不为 0,表示球体与线段存在碰撞的可能
       
        计算当前帧内的碰撞的可能性
       
        由球心的当前坐标与经过一帧之后球心的坐标构成一条线段 P1P2
        由线段的StartPoint和EndPoint构成一条线段SE
        计算P1P2与SE是否相交
        如果不相交,则在当前帧内,球体与线段不会碰撞
        如果相交,则在当前帧内,球体与线段发生碰撞

        P1=Position;
        P2=Position+Velocity;
       
        // 线段相交的跨立实验
        if((EP-SP)×(P1-SP)*(EP-SP)×(P2-SP)<0)
                flag1 = true;
        else
                flag1 = false;

        if((P2-P1)×(SP-P1)*(P2-P1)×(EP-P1)<0)
                flag2 = true;
        else
                flag2 = false;

        if(flag1&&flag2){
                // 碰撞会发生, 计算碰撞点M
                // 分情况:
                // 1、两条线段的斜率均存在
                // 由碰撞点既在线段P1P2上又在线段SE上,得到一个方程组
                // (M-P1)×(P2-P1)=0
                // (M-SP)×(EP-SP)=0
                M.x = ((P1&#2152)*(EP.x-SP.x)-(SP×EP)*(P2.x-P1.x))/((EP-SP)×(P2-P1));
                M.y = ((P1×P2)*(EP.y-SP.y)-(SP×EP)*(P2.y-P1.y))/((EP-SP)×(P2-P1));
                // 2、线段SE与x轴平行
                // M.y为SP.y
                // (M-P1)×(P2-P1)=0
                M.y = SP.y;
                M.x = ((P1×P2)*(EP.x-SP.x)-(SP×EP)*(P2.x-P1.x))/((EP-SP)×(P2-P1));
                // 3、线段SE与y轴平行
                // M.x为SP.x
                // (M-P1)×(P2-P1)=0
                M.x = SP.x;
                M.y = ((P1×P2)*(EP.y-SP.y)-(SP×EP)*(P2.y-P1.y))/((EP-SP)×(P2-P1));
                // 计算碰撞之后球体的速度
                CollisionResponseBetweenEdge();
                NewVelocity;
                NewPos = M+NewVelocity*(Distance(M, P2)/Distance(P1, P2));
        }
        else
                continue;

3、球体之间的碰撞处理CollisionResponseBetweenSphere();

输入数据:
        球1的球心坐标位置 Position1
        球1的速度方向 Direction1
        球1的速率 Speed1
        球1的速度=球1的速度方向×球1的速率 Velocity1=Direction1×Speed1
        球2的球心坐标位置 Position2
        球2的速度方向 Direction2
        球2的速率 Speed2
        球2的速度=球2的速度方向×球2的速率 Velocity2=Direction2×Speed2

计算目的:
        得到两个小球碰撞之后的新速度

计算过程:
        计算两球体碰撞时的法向量
                Normal=(Position2-Position1).Unit()
        计算两球体碰撞前的初速度
        将x-y坐标系统中的速度转换到n-t坐标系统中
                球1在n轴上的速度 V1n = Normal*(Normal dot Velocity1)
                球1在t轴上的速度 V1t = Velocity1-V1n
                球2在n轴上的速度 V2n = Normal*(-Normal dot Velocity2)
                球2在t轴上的速度 V2t = Velocity2-V2n
        计算两球体在碰撞之后的法线方向新速度
                NewV1n = ((V1n*m1)+(V2n*m2)-(V1n-V2n)*m2)/(m1+m2)
                NewV2n = ((V1n*m1)+(V2n*m2)-(V2n-V1n)*m1)/(m1+m2)
        假设m1=m2=1,则有:
                NewV1n = (V1n+V2n-(V1n-V2n))/2 = V2n
                NewV2n = (V1n+V2n-(V2n-V1n))/2 = V1n
        计算两球体在碰撞之后的切线方向新速度
                NewV1t = V1t
                NewV2t = V2t
        计算两球体碰撞之后的最终速度
                NewVelocity1 = NewV1n+NewV1t
                NewVelocity2 = NewV2n+NewV2t

4、球体与平面的碰撞处理
CollisionResponseBetweenEdge();

输入数据:
        球体的球心坐标位置 Position
        球体的速度方向 Direction
        球体的速率 Speed
        球体的速度 = 球体的速度方向×球体的速率 Velocity = Direction×Speed
        平面的法向量 Normal

计算过程
        计算法线方向的向量 N = (-Velocity*Normal)*Normal
        计算球体碰撞之后新的速度
                NewVelocity = 2*N+Velocity

数学理论:
矢量叉积P1(x1,y1) P2(x2,y2)  P1×P2=x1*y2-x2*y1
矢量点积P1(x1,y1) P2(x2,y2)  P1*P2 =x1*x2+y1*y2
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

作品发布|文章投稿|广告合作|关于本站|游戏开发论坛 ( 闽ICP备17032699号-3 )

GMT+8, 2025-8-12 23:45

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表