我想建立我自己的2D迷你物理引擎,它将包括(现在)僵硬的身体和约束(关节,接触,弹簧......)。当我开始一个时间步,当一般阶段是:宽相,窄相(碰撞检测和接触生成),分辨率(约束求解器),以及我试图弄清楚阶段的正确顺序是什么。整合 - 希望你能告诉我正确的顺序。
我对每个阶段也有一般性问题:
窄相 - 当我发现碰撞时,我需要在发现碰撞后将物体分开,或者只是在分辨阶段对它们的速度施加冲动?
如果我对某些身体使用CCD(连续碰撞检测),那么如果我发现快速移动的物体A与其他物体B发生碰撞(对物体A最早),并且我发现物体B在物体碰撞物体A之前,它会与其他物体C碰撞,在我找到他的第一次碰撞后,我是否需要回到物体A并寻找其他碰撞?
如果我在我的引擎中使用Contact Solver(在约束求解器中,我将为每次碰撞生成一个A Contact约束,然后我将在解析阶段解决所有问题,或者我将在解决后立即解决每个联系人他们发现他们处于狭窄的阶段?
分辨率 - 使用constaints Solver进行分辨率阶段是否合适?如果通过解决一个约束我将解决其他约束或制定更多约束怎么办? (如果解决了其他约束或制作更多约束,我是否需要在每个约束求解后进行检查?
积分 - 这是我收集所有信息(冲动,力......)并将它们整合到速度而不是用我选择的积分方法定位的部分?
对于我的物理引擎来说,一个辛辣的euler集成就足够了吗?
我也在许多物理引擎中看到过,比如box2D,他们使用迭代,让我选择这里的频率(注意我可以改变迭代次数(10)和频率(60.0 Hz)):
这个变量意味着什么?迭代是我在每一帧中回忆起物理更新(上面的所有阶段)的次数,或者它只是回想起一个阶段,如狭窄阶段或类似的东西?而频率变量让我选择一秒钟内会有多少帧?如果我想请你纠正我。
上面的所有问题让我从学习堆栈中学习,因为它的基础知识,而且我没有找到一个可以在一个清洁和平稳的前进中解释这个东西的地方
非常感谢能够阅读所有这些内容的人,尤其是那些也会帮助我解决所有问题的人:)
阶段的顺序并不那么重要。是的,他们互相混乱,但任何失效都可以通过调整常数来纠正......
load(file,ini,stream...),save(file,ini,stream...)
draw(screen or render context),update(dt),bool colide(object)
,等...
及时你会看到你需要添加的内容......现在它们将是空的(而不是你需要编写的绘图......)。您还可以准备一些常见的物理变量(也可以是虚拟的),如位置,速度,温度......load(filename)
...加载所有对象
draw(...)
...绘制所有物体......1-100 ms
。对于非常快速的模拟,您可以在每次定时器调用时执行N
迭代。这就是计数和频率的含义。其中频率是定时器调用速度,你的迭代循环被调用,count(N
)是时间步长dt
分区所以如果N=10
和f=60Hz
它意味着你每10
秒迭代1/60
次数所以它与N=1 f=600Hz
相同但至少在Windows计时器中分辨率是1 ms
而不是非常精确的以太。所以100 Hz
以上的频率是不可靠的。如果你想更加精确,你可以通过PerformanceCounter
或RDTSC
或任何足够精确的时间API来测量时间。
您可以使用D'Alembert原理(简单积分)模拟运动,其余用已知方程计算(不知道您想要模拟的所有内容)。例如,看这里simple mass points gravity simulation in 3D (C++)
如果您的代码写得很好,您可以并行化迭代循环,但您必须记住,它可以创建一些麻烦,如双碰撞反应等在这里得到的想法是我的模拟之一的样子的例子
它使用了我在这里写的所有东西,此外它还使用了一个特殊的类,用于弹簧或关节等键。这是它的样子:
struct _bond
{
physics_point *pnt0,*pnt1;
double l0,l1;
int _beg0,_end0;
int _beg1,_end1;
List<int> depend0,depend1;
int _computed;
_bond() {}
_bond(_bond& a) { *this=a; }
~_bond() {}
_bond* operator = (const _bond *a) { *this=*a; return this; }
//_bond* operator = (const _bond &a) { ...copy... return this; }
};
List<_bond> bnds;
我可以用这背后的东西覆盖整本书,但我太懒了,而且这个网站也不适合这个,所以匆忙重要的是每个债券都有它的开始和结束对象指针(pnt0,pnt1
)并且在计算期间填充依赖项列表(depend0,depend1
)。
depend0
来自pnt0
方面的所有后续债券depend1
来自pnt1
方面的所有后续债券。然后在每次迭代期间,递归地更新所有债券以匹配债券/碰撞条件,只有当它们都这样做时,才立即为所有债券更新头寸。
_computed flag
只是宣布这种关系是正常的(条件得到满足)。其余的只是临时变量,以减轻递归堆/堆栈丢弃的负担