关于台球(刚体)碰撞物理模型的编写方案

来源:互联网 发布:idc 大型网络架构 编辑:程序博客网 时间:2024/04/28 22:28
只能提供初步了

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-1);
   Pos2=Position2+V2'*(T-1);
   // 计算碰撞之后两个小球各自的速度
   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;
 // Step1
 // 线段相交的快速排斥实验
 xMax=max(SP.x, EP.x);
 xMin=min(SP.x, EP.x);
 yMax=max(SP.y, EP.y);
 yMin=min(SP.y, EP.y);
 if((P1.x>=xMin&&P1.x<=xMax)&&(P1.y>=yMin&&P1.y<=yMax))
  flag1=true;
 else
  flag1=false;
 if((P2.x>=xMin&&P2.x<=xMax)&&(P2.y>=yMin&&P2.y<=yMax))
  flag2=true;
 else
  flag2=false;
 if(flag1||flag2)
  // 快速排斥实验成立
  step1=true;
 else
  continue; // 排斥实验失败,碰撞不会发生
 // Step2
 // 线段相交的跨立实验
 if((P1-SP)×(EP-SP)*(EP-SP)×(P2-SP)>=0){
  // 碰撞会发生, 计算碰撞点M
  // 分情况:
  // 1、两条线段的斜率均存在
  // 由碰撞点既在线段P1P2上又在线段SE上,得到一个方程组
  // (M-P1)×(P2-P1)=0
  // (M-SP)×(EP-SP)=0
  M.x = ((P1×P2)*(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

原创粉丝点击