简短版本:
如何正确地将重力添加到物理更新?
详细版本:
我遇到的问题是,移动球体到平面的通用碰撞算法(在下面张贴以供参考)永远不会到达将要检测到未来碰撞的点。我相信这是因为我的物理更新。
我已将其设置为只有在确定将来会发生碰撞时,重力才会应用于对象。因此,在将重力应用于对象之前,首先进行碰撞检查。但是,由于始终假设从未有任何未来的碰撞,因此永远不会应用重力。想象一下具有
值的场景spherePosition = (0, 5, 0)
sphereVelocity = (2, 0, 0)
sphereRadius = 1
planeOrigin = (0, 0, 0)
planeNormal = (0, 1, 0)
这总是假设球体正在向平面移动parrelel。结果,永远不会施加重力。
我的更新相对简单,例如
mAcceleration = mTotalForces / mMass;
Vector3 translation = (mVelocity * fElapsedTime) + 0.5 * mAcceleration * pow(fElapsedTime, 2);
mVelocity += mAcceleration * fElapsedTime;
所以操作顺序大致是
int collisionResult = checkCollision(sphere, plane);
if(collisionResult == 2)
{
sphere.applyGravity(); // Just sets "mAcceleration" to (0, -9.81, 0). Which is then removed by my physics update.
}
sphere.update(timeSlice);
说完所有这些,我应该何时在物理更新循环中将重力应用于我的对象以及如何?如果我在碰撞检查之前应用它,那么在碰撞检查期间无关紧要,如果我之后要做,如果将来会发生碰撞,我应该如何调整更新?
碰撞检查参考:
int IntersectMovingSpherePlane(float sphereRadius, const Vector3& sphereCenter, const Vector3& sphereVelocity, const Vector3& planeNormal,
const Vector3& planeOrigin, float planeD, float &t, Vector3 &q)
{
// Compute distance of sphere center to plane
float dist = Vec3Dot(&planeNormal, &sphereCenter) - planeD;
if (fabs(dist) <= sphereRadius) {
// The sphere is already overlapping the plane. Set time of
// intersection to zero and q to sphere center
t = 0.0f;
q = sphereCenter;
return 0;
} else {
float denom = Vec3Dot(&planeNormal, &sphereVelocity);
if (denom * dist >= 0.0f) {
// No intersection as sphere moving parallel to or away from plane
return 1;
} else {
// Sphere is moving towards the plane
// Use +r in computations if sphere in front of plane, else -r
float r = dist > 0.0f ? sphereRadius : -sphereRadius;
t = (r - dist) / denom;
q = sphereCenter + t * sphereVelocity - sphereRadius * planeNormal;
return 2;
}
}
}
答案 0 :(得分:1)
这里最简单的方法是让重力成为mTotalForces
的一部分。
更物理化的方法是将重力作为单独的加速度。然后在最后加速度值后添加“mTotalForces / mMass”。
修改强>
Vector3 translation = (mVelocity * fElapsedTime) + 0.5 * mAcceleration * pow(fElapsedTime, 2);
在这里,你的代码似乎是为了统一运动。但是如果你想要在击中地面后停止球落下,那就不均匀了。
对于这种非均匀运动,通常我们只是细分时间范围并在非常短的时间内进行均匀计算,使运动可以被认为是均匀的,并忽略累积误差。
答案 1 :(得分:1)
向系统添加物理的正确方法是使用迭代过程,称为runge-kutta method(或牛顿,一阶runge-kutta)。
基本上,您的模型将具有质量随时间演变的粒子。你必须“塑造”的唯一事情是每个蜱上施加在每个粒子上的力。用它来计算加速度。
如果世界有重力,你必须说在每个粒子上,加速度是-g(向下指向负值,在这种情况下与质量无关)。
例如,第一个命令runge-kutta是:
newVelocity = oldVelocity + tickAcceleration*dt
newPosition = oldPosition + newVelocity*dt
其中dt是您选择勾选的时间步。
通常,为避免物体通过其他物体,您实际上并未计算新的*。您计算了一个建议的位置:
proposedVelocity = oldVelocity + tickAcceleration*dt
proposedPosition = oldPosition + proposedVelocity*dt
然后计算碰撞条件(您将每个粒子与其他粒子进行测试)。如果粒子碰撞,则应用碰撞方程(例如elastic collision),并相应地更新newPositions / velocity。如果它们没有发生碰撞,则使用建议的*值
更新新*newVelocity = proposedVelocity
newPosition = proposedPosition
编辑:
在1º近似值上,您使用哪一个碰撞无关紧要。然而,2º近似可能是首先计算建议的速度和位置。然后检查旧位置和新位置之间是否发生碰撞,并计算碰撞时间,我称之为dtCol。然后我们可以将时间步分为两部分:碰撞前,dtCol和碰撞后的dt-dtCol。第一部分是将拟议的数量设置为
proposedVelocityBeforeCollision = oldVelocity + tickAcceleration*dtCol
proposedPositionBeforeCollision = oldPosition + proposedVelocityBeforeCollision*dtCol
此数量正好在碰撞之前。您现在可以使用then然后使用碰撞方程式计算建议的VelocityAfterCollision(proposedPositionAfterCollision = proposedPosition)。
之后,您更新新的*数量:
newVelocity = proposedVelocityAfterCollision + tickAcceleration*(dt-dtCol)
newPosition = proposedPosition + newVelocity*(dt-dtCol)
请注意,此过程不会考虑多次碰撞。
希望这有帮助。