试验性物理引擎(续)

今天主要记录一些跟物理性质关系比较大的细节问题,有时候细节问题是很重要的,很多bug就在这些问题里。

首先一个,reflash函数内部的处理次序问题,究竟是先算速度,还是先算力
 1void CBall::reflash()
 2{
 3    velocity.positivation();
 4    /*
 5    if(velocity.degree > maxVelocity)
 6    {
 7        velocity.degree = maxVelocity;
 8    }
 9    */

10    /*
11    else if(velocity.degree < 0.01)
12    {
13        velocity.degree = 0;
14    }
15    */

16    if(velocity.degree > 0)
17    {
18        CVector griftForce(velocity.x * (-1), velocity.y * (-1), 1);
19        griftForce = griftForce * (gravity * Qgrift * Qgroundgrift);
20        griftForce.degree += velocity.degree * velocity.degree / 1000;
21        //force = force + griftForce;
22        velocity.degree -= griftForce.degree/gravity;
23        if(velocity.degree < 0)
24        {
25            velocity.degree = 0;
26        }

27    }

28    if(fabs(force.degree) > 0)
29    {
30        velocity = velocity + force/gravity;
31    }
    
32    velocity.positivation();
33    if(velocity.degree > maxVelocity)
34    {
35        velocity.degree = maxVelocity;
36    }

37    velocity.standarlization();
38    double tx = x;
39    x += velocity.degree * velocity.x;
40    y += velocity.degree * velocity.y;
41    force.reset();
42}
这是最新版的ball->reflash函数。是经过了几次轮回尝试得来的。来之不易啊。。。
在这里,每一帧先算摩擦,然后是受力,最后才是速度。这样,每一帧结束后,球所保存的速度就是当前速度。上一个版本忘了怎样的顺序,出了个当速度很小的时候(应该是受力平衡而且运动很慢的时候),每一帧结束后速度总为0,但又总是能动的错误。

接下来是一个关于重叠的问题。
计算机是离散的,只能模拟连续,这是问题的根源。
举个例子,当在某一帧里,两球的距离为2,但径向的相对速度为8的时候,你应该怎样判断?假如判断为不碰,下一帧两球将会有6个像素的重叠区域,判为碰,两球其实还没碰到。
问题提出来了,我的解法是,当距离小于径向相对速度的一半判为碰。否则不碰。原因比较简单,也比较复杂,反正用起来是不错。
当然需要一个重叠的修正函数,参考水王的话“重叠的时候,用一种看起来正常的方法分开就可以了”,于是,我就直接把两个球的坐标重置。往径向位移一点就行了,根据重叠的程度。在运动中,这是看不出来的重置。

还有问题,是两球相对速度为0时候的碰撞。严格说这不算碰撞,但这里有一个力传递的概念。假如不管这个力,如果某球在下一帧受到作用力,在碰撞检测的时候,两球无速度,但到刷新的时候,速度出现了!就会产生一个重叠至穿越的bug。也许会说把刷新和碰撞检测的顺序调换,没试过,从逻辑上讲,我觉得行不太通,说不明白。

说实话,穿越这个bug我到现在还没能完全修正。由于出现几率较小,还是放着先吧。

再来一个细节,牵引力的问题。
把代码贴出来就行了。
void CBall::tract(CVector d)
{
    
if(fabs(velocity.degree) > 0)
    
{
        CVector rg 
= velocity & d;
        d.degree 
= (1 + rg.degree / velocity.degree) * gravity * Qgrift * Qgroundgrift;
    }

    
else
    
{
        d.degree 
= gravity * Qgrift * Qgroundgrift;
    }

    push(d);
}
看到了,不是单纯的使用摩擦力推进就可以。要先把牵引力方向的摩擦力中和掉。。

posted on 2009-03-10 16:22 whitech 阅读(168) 评论(0)  编辑 收藏 引用


只有注册用户登录后才能发表评论。
【推荐】超50万行VC++源码: 大型组态工控、电力仿真CAD与GIS源码库
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理


<2009年3月>
22232425262728
1234567
891011121314
15161718192021
22232425262728
2930311234

导航

统计

常用链接

留言簿(1)

随笔档案

搜索

最新评论

阅读排行榜

评论排行榜