反引力/anti-gravity?我需要更改重力算法的哪些元素才能反转它?
Reverse gravity / anti-gravity? What elements of a gravitational force algorithm do i need to change for reversing it?
我想反转我的重力算法以产生多个物体相互作用的“过去”位置。通过 运行 在一组物体上多次使用算法来产生未来的位置是微不足道的,但将其反转以写出物体先前位置的位置让我很困惑。我不想存储过去的位置,因为这是确定性的,所以应该可以以某种方式 运行 向后算法,但我不确定如何。
在代码段element
中,循环中从universe
开始测试的每个主体,tick
是增量时间。
function forces(other) {
if (element === other) {
return;
}
var distancePoint = element.point.sub(other.point);
var normal = Math.sqrt(100.0 + distancePoint.lengthSq());
var mag = GravatationalConstant /
Math.pow(normal, 3);
var distPointMulOtherMass = distancePoint
.mul(mag * other.mass);
element.acceleration = element.acceleration.sub(distPointMulOtherMass);
other.acceleration = other
.acceleration
.add(distancePoint
.mul(mag * element.mass)
);
}
element.acceleration = new Point(0,0,0,0);
universe.forEach(forces);
element.velocity = element.velocity.add(element.acceleration.mul(ticks));
element.point = element.point.add(element.velocity.mul(0.5 * ticks));
我尝试发送一个负的刻度以及负的引力常数,但是它为“过去”产生的位置似乎并没有遵循元素在真实过去所做的事情。
我对物理了解不多,但我想知道是否可以做一些小改动来逆转这个算法。
更新
感谢 Graeme Niedermayer,我已将重力算法更新为平方反比定律并使用负时间生成过去的位置!
function forces(other) {
if (element === other) {
return;
}
var distancePoint = element.point.sub(other.point);
const forceElementMass = GravatationalConstant * element.mass * other.mass /
Math.pow(element.mass,2)
const forceOtherMass = GravatationalConstant * element.mass * other.mass /
Math.pow(other.mass,2)
element.acceleration = element.acceleration
.sub(distancePoint.mul(forceOtherMass))
other.acceleration = other.acceleration
.add(distancePoint.mul(forceElementMass))
}
const ticks = forwards ? dt : -dt;
element.acceleration = new Point(0,0,0,0);
universe.forEach(forces);
element.velocity = element.velocity.add(element.acceleration.mul(ticks));
element.point = element.point.add(element.velocity.mul(0.5 * ticks));
轮廓圆圈位于当前位置,“过去”位置是其他逐渐淡出至零不透明度的位置。
更新 2
意识到我在更新 1 中使用了错误的方程式(两个力常数使用相同的质量 object)。我查看了更多示例并更新了代码,但现在我不确定我应该在哪里添加增量时间 ticks
,目前正向设置为 1,向后设置为 -1。下面是一张图像,如果我将加速度乘以 ticks
,然后再将其添加到每一帧的速度 body.velocity = body.velocity.add(body.acceleration.mul(ticks))
,或者如果我使其中一个质量为负值 const force = G * body.mass * (forward ? other.mass : -other.mass) / d ** 2
。
如您所见,绿色 body 的“过去”位置(红色轮廓)移至左侧和上方。我希望让它们看起来“跟随”当前位置,但我不确定如何反转或反转等式以显示“过去”位置,基本上如果 body 正朝相反的方向行进。有办法吗?
在下一张图片中,我将速度乘以增量时间 ticks
,然后将其添加到位置 body.point = body.point.add(body.velocity.mul(ticks))
,这导致与 body 行进的记录路径类似的路径(通过将每个位置写入数组并在这些位置之间画一条线)但它略有偏离。此解决方案与我在更新 1 中看到的类似。这“几乎”正确是否有原因?
下面的代码没有任何反转位置的添加。
function forces(other, ticks) {
if (body === other) {
return;
}
// Calculate direction of force
var distanceVector = other.point.sub(body.point)
// Distance between objects
var d = distanceVector.mag()
// Normalize vector (distance doesn't matter here, we just want this vector for direction)
const forceNormalized = distanceVector.normalized()
// Calculate gravitational force magnitude
const G = 6.674
const force = G * body.mass * other.mass / d ** 2
// Get force vector --> magnitude * direction
const magDirection = forceNormalized.mul(force)
const f = magDirection.div(body.mass)
body.acceleration = body.acceleration.add(f)
}
body.acceleration = body.acceleration.mul(0)
universe.forEach(body => forces(body, ticks))
body.velocity = body.velocity.add(body.acceleration)
body.point = body.point.add(body.velocity)
更新 3
我最终删除了负质量和速度乘以滴答声,只是颠倒了加速度应用于位置的方式:
if (forward) {
universe.forEach(body => forces(body, ticks));
body.velocity = body.velocity.add(body.acceleration)
body.point = body.point.add(body.velocity)
} else {
body.point = body.point.sub(body.velocity)
universe.forEach(body => forces(body, ticks));
body.velocity = body.velocity.sub(body.acceleration)
}
导致能够从当前位置及时向前和向后生成位置。在图像中,它显示为“过去”位置遵循当前位置的记录轨迹。
为了在“过去”中生成一个步骤,它从当前位置减去当前速度,将其置于它所在的最后一个位置。接下来它通过检查来自其他物体的力获得加速度,然后减去新的来自速度的加速度(使用负质量会做同样的事情)所以“过去”的下一个位置将是正确的。
你应该可以把其中一个群众变成负数。
负时间不起作用的原因是因为你隐式使用欧拉方法。欧拉法在使用负步时不稳定。
另外你使用的物理学也有点奇怪。重力通常是一个平方定律。
我想反转我的重力算法以产生多个物体相互作用的“过去”位置。通过 运行 在一组物体上多次使用算法来产生未来的位置是微不足道的,但将其反转以写出物体先前位置的位置让我很困惑。我不想存储过去的位置,因为这是确定性的,所以应该可以以某种方式 运行 向后算法,但我不确定如何。
在代码段element
中,循环中从universe
开始测试的每个主体,tick
是增量时间。
function forces(other) {
if (element === other) {
return;
}
var distancePoint = element.point.sub(other.point);
var normal = Math.sqrt(100.0 + distancePoint.lengthSq());
var mag = GravatationalConstant /
Math.pow(normal, 3);
var distPointMulOtherMass = distancePoint
.mul(mag * other.mass);
element.acceleration = element.acceleration.sub(distPointMulOtherMass);
other.acceleration = other
.acceleration
.add(distancePoint
.mul(mag * element.mass)
);
}
element.acceleration = new Point(0,0,0,0);
universe.forEach(forces);
element.velocity = element.velocity.add(element.acceleration.mul(ticks));
element.point = element.point.add(element.velocity.mul(0.5 * ticks));
我尝试发送一个负的刻度以及负的引力常数,但是它为“过去”产生的位置似乎并没有遵循元素在真实过去所做的事情。
我对物理了解不多,但我想知道是否可以做一些小改动来逆转这个算法。
更新
感谢 Graeme Niedermayer,我已将重力算法更新为平方反比定律并使用负时间生成过去的位置!
function forces(other) {
if (element === other) {
return;
}
var distancePoint = element.point.sub(other.point);
const forceElementMass = GravatationalConstant * element.mass * other.mass /
Math.pow(element.mass,2)
const forceOtherMass = GravatationalConstant * element.mass * other.mass /
Math.pow(other.mass,2)
element.acceleration = element.acceleration
.sub(distancePoint.mul(forceOtherMass))
other.acceleration = other.acceleration
.add(distancePoint.mul(forceElementMass))
}
const ticks = forwards ? dt : -dt;
element.acceleration = new Point(0,0,0,0);
universe.forEach(forces);
element.velocity = element.velocity.add(element.acceleration.mul(ticks));
element.point = element.point.add(element.velocity.mul(0.5 * ticks));
轮廓圆圈位于当前位置,“过去”位置是其他逐渐淡出至零不透明度的位置。
更新 2
意识到我在更新 1 中使用了错误的方程式(两个力常数使用相同的质量 object)。我查看了更多示例并更新了代码,但现在我不确定我应该在哪里添加增量时间 ticks
,目前正向设置为 1,向后设置为 -1。下面是一张图像,如果我将加速度乘以 ticks
,然后再将其添加到每一帧的速度 body.velocity = body.velocity.add(body.acceleration.mul(ticks))
,或者如果我使其中一个质量为负值 const force = G * body.mass * (forward ? other.mass : -other.mass) / d ** 2
。
如您所见,绿色 body 的“过去”位置(红色轮廓)移至左侧和上方。我希望让它们看起来“跟随”当前位置,但我不确定如何反转或反转等式以显示“过去”位置,基本上如果 body 正朝相反的方向行进。有办法吗?
在下一张图片中,我将速度乘以增量时间 ticks
,然后将其添加到位置 body.point = body.point.add(body.velocity.mul(ticks))
,这导致与 body 行进的记录路径类似的路径(通过将每个位置写入数组并在这些位置之间画一条线)但它略有偏离。此解决方案与我在更新 1 中看到的类似。这“几乎”正确是否有原因?
下面的代码没有任何反转位置的添加。
function forces(other, ticks) {
if (body === other) {
return;
}
// Calculate direction of force
var distanceVector = other.point.sub(body.point)
// Distance between objects
var d = distanceVector.mag()
// Normalize vector (distance doesn't matter here, we just want this vector for direction)
const forceNormalized = distanceVector.normalized()
// Calculate gravitational force magnitude
const G = 6.674
const force = G * body.mass * other.mass / d ** 2
// Get force vector --> magnitude * direction
const magDirection = forceNormalized.mul(force)
const f = magDirection.div(body.mass)
body.acceleration = body.acceleration.add(f)
}
body.acceleration = body.acceleration.mul(0)
universe.forEach(body => forces(body, ticks))
body.velocity = body.velocity.add(body.acceleration)
body.point = body.point.add(body.velocity)
更新 3
我最终删除了负质量和速度乘以滴答声,只是颠倒了加速度应用于位置的方式:
if (forward) {
universe.forEach(body => forces(body, ticks));
body.velocity = body.velocity.add(body.acceleration)
body.point = body.point.add(body.velocity)
} else {
body.point = body.point.sub(body.velocity)
universe.forEach(body => forces(body, ticks));
body.velocity = body.velocity.sub(body.acceleration)
}
导致能够从当前位置及时向前和向后生成位置。在图像中,它显示为“过去”位置遵循当前位置的记录轨迹。
为了在“过去”中生成一个步骤,它从当前位置减去当前速度,将其置于它所在的最后一个位置。接下来它通过检查来自其他物体的力获得加速度,然后减去新的来自速度的加速度(使用负质量会做同样的事情)所以“过去”的下一个位置将是正确的。
你应该可以把其中一个群众变成负数。
负时间不起作用的原因是因为你隐式使用欧拉方法。欧拉法在使用负步时不稳定。
另外你使用的物理学也有点奇怪。重力通常是一个平方定律。