在物理计算中表示无穷大
Representing infinity in physics calculations
我目前正在编写一些函数来处理 C++ 中的弹性碰撞。我在处理移动物体与不动物体碰撞时遇到了绊脚石,因为计算要求不动物体具有无限大的质量。
我知道 std::numeric_limits
提供 infinity()
但我不确定它在这种情况下是否完全有用,因为据我所知,这只是可能的最大数量在浮点表示中。在下面的代码中,如果 aabb_obj
的质量等于 std::numeric_limits<double>::max()
,那么使用它的每个计算似乎都会导致 std::numeric_limits<double>::max()
或 0
.
double t;
if (intersect_moving_circle_aabb(circle_obj, aabb_obj, t))
{
circle_obj->position += circle_obj->velocity * t;
vec2 closest_point;
closest_pt_point_aabb(circle_obj->position, aabb_obj, closest_point);
vec2 n = (closest_point - circle_obj->position).normalized();
double a = dot_product(circle_obj->velocity, n);
double p = (2.0 * a) / (circle_obj->mass + aabb_obj->mass);
circle_obj->velocity = circle_obj->velocity - p * aabb_obj->mass * n;
}
这是一款游戏,因此结果不需要 100% 物理准确,只需 'good enough'。在此类计算中表示无穷大的推荐方法是什么?我只是选择一个任意高的数字吗?
as far as I'm aware, this is just the max number possible in the floating point representation.
当然可以,因为 IEEE 浮点数不能表示任何大于无穷大的值。同时,这是真正的无限,您可以放心使用它。
如果我是你,我会在我的代码中明确说明某些对象是不可移动的。就像这样,不是将值插入到一个通用公式中 应该 阻止某些对象移动,而是对两个可移动对象碰撞与可移动和不可移动对象碰撞具有不同的执行分支。
此外,如果准确性不是一个大问题,请使用 float
s 而不是 double
s。 :)
对于 IEEE 浮点数,硬件已经对两个无穷大以及非数字值 (NAN) 进行了特殊处理。他们遵守正常的数学规则:
1/0 = +inf
+inf + x = +inf
-inf + +inf = NAN
x/+inf = 0
0*+inf = NAN
...
现在您可以检查您的代码,看看如果您为其中一个群众插入 +inf
会发生什么:这将产生一个值 p = 0
,并且在下面的行中 [=13] =] 将产生 0
如果 aabb_obj->mass
是有限的,或者 NAN
如果它是无限的。后一种情况是您需要避免的,因为 NAN
将通过其他操作传播,产生 circle_obj->velocity = NAN
.
问题中的代码应该计算圆形移动物体与不可移动的 AABB 物体碰撞时的回弹速度。理论上,一个完全不动的物体应该具有无限大的质量,但可以看出,用浮点数表示会导致计算产生 (NaN, NaN) 的矢量。
最后我选择了对无限质量的显式检查,这简化了代码。
不动的物体不能从碰撞中获得动量,并且由于 Conservation of Momentum 移动的物体不能失去任何动量。这意味着两个物体的质量与计算无关,因为移动物体的速度大小不会改变,只会改变方向。
理解这一点使我能够将代码简化为简单地反映关于碰撞法线的速度矢量:
double t;
if (aabb_obj->mass == std::numeric_limits<double>::infinity()
&& intersect_moving_circle_aabb(circle_obj, aabb_obj, t))
{
circle_obj->position += circle_obj->velocity * t;
vec2 closest_point;
closest_pt_point_aabb(circle_obj->position, aabb_obj, closest_point);
vec2 n = (closest_point - circle_obj->position).normalized();
circle_obj->velocity = circle_obj->velocity - 2.0 * dot_product(circle_obj->velocity, n) * n;
}
我目前正在编写一些函数来处理 C++ 中的弹性碰撞。我在处理移动物体与不动物体碰撞时遇到了绊脚石,因为计算要求不动物体具有无限大的质量。
我知道 std::numeric_limits
提供 infinity()
但我不确定它在这种情况下是否完全有用,因为据我所知,这只是可能的最大数量在浮点表示中。在下面的代码中,如果 aabb_obj
的质量等于 std::numeric_limits<double>::max()
,那么使用它的每个计算似乎都会导致 std::numeric_limits<double>::max()
或 0
.
double t;
if (intersect_moving_circle_aabb(circle_obj, aabb_obj, t))
{
circle_obj->position += circle_obj->velocity * t;
vec2 closest_point;
closest_pt_point_aabb(circle_obj->position, aabb_obj, closest_point);
vec2 n = (closest_point - circle_obj->position).normalized();
double a = dot_product(circle_obj->velocity, n);
double p = (2.0 * a) / (circle_obj->mass + aabb_obj->mass);
circle_obj->velocity = circle_obj->velocity - p * aabb_obj->mass * n;
}
这是一款游戏,因此结果不需要 100% 物理准确,只需 'good enough'。在此类计算中表示无穷大的推荐方法是什么?我只是选择一个任意高的数字吗?
as far as I'm aware, this is just the max number possible in the floating point representation.
当然可以,因为 IEEE 浮点数不能表示任何大于无穷大的值。同时,这是真正的无限,您可以放心使用它。
如果我是你,我会在我的代码中明确说明某些对象是不可移动的。就像这样,不是将值插入到一个通用公式中 应该 阻止某些对象移动,而是对两个可移动对象碰撞与可移动和不可移动对象碰撞具有不同的执行分支。
此外,如果准确性不是一个大问题,请使用 float
s 而不是 double
s。 :)
对于 IEEE 浮点数,硬件已经对两个无穷大以及非数字值 (NAN) 进行了特殊处理。他们遵守正常的数学规则:
1/0 = +inf
+inf + x = +inf
-inf + +inf = NAN
x/+inf = 0
0*+inf = NAN
...
现在您可以检查您的代码,看看如果您为其中一个群众插入 +inf
会发生什么:这将产生一个值 p = 0
,并且在下面的行中 [=13] =] 将产生 0
如果 aabb_obj->mass
是有限的,或者 NAN
如果它是无限的。后一种情况是您需要避免的,因为 NAN
将通过其他操作传播,产生 circle_obj->velocity = NAN
.
问题中的代码应该计算圆形移动物体与不可移动的 AABB 物体碰撞时的回弹速度。理论上,一个完全不动的物体应该具有无限大的质量,但可以看出,用浮点数表示会导致计算产生 (NaN, NaN) 的矢量。
最后我选择了对无限质量的显式检查,这简化了代码。
不动的物体不能从碰撞中获得动量,并且由于 Conservation of Momentum 移动的物体不能失去任何动量。这意味着两个物体的质量与计算无关,因为移动物体的速度大小不会改变,只会改变方向。
理解这一点使我能够将代码简化为简单地反映关于碰撞法线的速度矢量:
double t;
if (aabb_obj->mass == std::numeric_limits<double>::infinity()
&& intersect_moving_circle_aabb(circle_obj, aabb_obj, t))
{
circle_obj->position += circle_obj->velocity * t;
vec2 closest_point;
closest_pt_point_aabb(circle_obj->position, aabb_obj, closest_point);
vec2 n = (closest_point - circle_obj->position).normalized();
circle_obj->velocity = circle_obj->velocity - 2.0 * dot_product(circle_obj->velocity, n) * n;
}