这个问题有一个主要的问题,和一个次要问题。 我相信,我是正确的,从我的研究两个问题,但不能同时使用。
对于我的物理循环,我做的第一件事是应用重力我TotalForce
一个刚体对象。 然后我检查使用我的碰撞TotalForce
和我的Velocity
。 我TotalForce
被重置为(0, 0, 0)
每个物理循环后,虽然我会保持我的velocity
。
我所熟悉的只使用速度时做运动球体和平面静态之间的碰撞检测。 但是,如果我有其他的之外势力velocity
,比如重力? 我把其他部队进入TotalForces
(现在我只有重力)。 为了弥补的是,当我确定该领域目前不重叠的飞机上,我做
Vector3 forces = (sphereTotalForces + sphereVelocity);
Vector3 forcesDT = forces * fElapsedTime;
float denom = Vec3Dot(&plane->GetNormal(), &forces);
然而,这可能是对我怎么想是假设静养接触问题。 我以为休息接触被计算
denom * dist == 0.0f
其中dist
是
float dist = Vec3Dot(&plane->GetNormal(), &spherePosition) - plane->d;
(作为参考,显而易见denom * dist > 0.0f
意味着球体移动远离所述平面)
然而,这绝不是真实的。 即使有似乎是“休息接触”。 这是由于我的forces
计算上述总是具有至少-9.8(我的重力)的.Y。 向的平面内移动以正常的时,当(0,1,0)将产生AY的denom
的-9.8。
我的问题是
1)我是不是正确计算休息接触,我如何与我的头两个代码段提到?
如果是这样,
2)如何使我的“其他部队”,比如重力可以用吗? 是我使用的TotalForces
不正确的?
作为参考,我的时间步长
mAcceleration = mTotalForces / mMass;
mVelocity += mAcceleration * fElapsedTime;
Vector3 translation = (mVelocity * fElapsedTime);
编辑
因为似乎有些建议的更改会改变我的碰撞代码,这是我如何检测我的碰撞状态
if(fabs(dist) <= sphereRadius)
{ // There already is a collision }
else
{
Vector3 forces = (sphereTotalForces + sphereVelocity);
float denom = Vec3Dot(&plane->GetNormal(), &forces);
// Resting contact
if(dist == 0) { }
// Sphere is moving away from plane
else if(denom * dist > 0.0f) { }
// There will eventually be a collision
else
{
float fIntersectionTime = (sphereRadius - dist) / denom;
float r;
if(dist > 0.0f)
r = sphereRadius;
else
r = -sphereRadius;
Vector3 collisionPosition = spherePosition + fIntersectionTime * sphereVelocity - r * planeNormal;
}
}
Answer 1:
您应该使用if(fabs(dist) < 0.0001f) { /* collided */ }
这是acocunt浮点精度。 你肯定不会得到最多的角度或接触一个确切的0.0F。
值dist
如果为负,其实你需要身体的情况下,移回到平面上表面的实际金额它穿过平面。 sphere.position = sphere.position - plane.Normal * fabs(dist);
一旦已经移动回至表面,则可以选择,使其在大约正常的平面相反的方向反弹; 或者只是停留在飞机上。
parallel_vec = Vec3.dot(plane.normal, -sphere.velocity);
perpendicular_vec = sphere.velocity - parallel_vec;
bounce_velocity = parallel - perpendicular_vec;
你不能一味做totalforce = external_force + velocity
,除非一切都有单位质量。
编辑 :
- 完全定义在三维空间中的飞机,你的平面结构应该存储平面向量和在飞机上的一个点。 http://en.wikipedia.org/wiki/Plane_(geometry )。
Vector3 planeToSphere = sphere.point - plane.point;
float dist = Vector3.dot(plane.normal, planeToSphere) - plane.radius;
if(dist < 0) { // collided. }
我建议你先多学习数学,如果这是你不知道的部分。
注:对不起,格式化搞砸了......我不能将其标记为代码块。
编辑2:根据我对你的代码的理解,无论你是严重或正如我前面提到命名变量,你需要修改你的数学和物理理论。 这条线没有做任何有用的东西。
float denom = Vec3Dot(&plane->GetNormal(), &forces);
一个在任何时刻,在球上的力可以在任何方向都无关行进的方向。 所以基本上DENOM计算在平面方向的力的大小,但不能告诉你球是否会击中飞机。 例如重力是向下的,但是球可以具有向上速度和命中上方的平面。 就这样,你需要Vec3Dot(plane.normal, velocity)
来代替。
另外,马克Phariss和格哈德·鲍威尔已经给你线性运动的物理方程,你可以使用这些直接计算未来的位置,速度和影响的时间。
例如s = 0.5 * (u + v) * t;
给未来的时间t后的位移。 比较从平面距离位移,你会得到球是否会击中飞机。 如此反复,我建议你读了http://en.wikipedia.org/wiki/Linear_motion和简单的东西先然后http://en.wikipedia.org/wiki/Kinematics 。
另一种方法,如果你希望或不承担任何其他力量作用于球,然后你做一个光线/撞机试验找到时刻t它会打击飞机,在这种情况下,读取HTTP:// EN .wikipedia.org /维基/线路plane_intersection 。
Answer 2:
总是会有-9.8y球体上的重力。 在悬挂球的情况下,这将导致向下的加速度(净力是非零)。 在球体上休息的平面的情况下,这将导致在平面上施加球体的法向力。 如果飞机是完全水平在休息球体此法向力会完全+ 9.8y这将完全消除重力。 对于静止在非水平面上的球体的法向力是9.8y * cos(angle)
(角度为-90和+90度之间)。
事情变得更加复杂,当一个移动球击中一个平面的法向力将取决于速度和平面/球的材料特性。 根据你的应用需求,你既可以忽略这或尝试用正常的力量了一些东西,看看它是如何工作的。
为了您的具体问题:
- 我相信,接触更准确地说只是当
dist == 0.0f
,这是球体和平面正在接触。 我假设你的碰撞考虑到了球体可移动过去的平面上按任何物理时间步帐户。 - 现在,你似乎没有被提上从当他们正在接触面球体任何正常的力量。 我会通过接触检查(做这个
dist == 0.0f
),如果属实将法向力的领域。 在落球的简单情况下到(-90和+90度之间的角度)的近水平面这纯粹是sphereTotalForces += Vector3D(0, 9.8 * cos(angle), 0)
编辑:
从这里你的方程dist
根据问题和代码(未给出)的详细信息,计算从球面到平面边缘的距离可能不正确。 假设你的飞机经过原点正确的公式是:
dist = Vec3Dot(&spherePosition, &plane->GetNormal()) - sphereRadius;
这是与您的公式,如果plane->d == sphereRadius
。 请注意,如果飞机不是在原点,然后使用:
D3DXVECTOR3 vecTemp(spherePosition - pointOnPlane);
dist = Vec3Dot(&vecTemp, &plane->GetNormal()) - sphereRadius;
Answer 3:
解决这个问题的确切解决方案涉及到一些相当严肃的数学。 如果你想要一个近似解我强烈建议分阶段开发它。
1)确保你的SIM卡不工作重心。 球必须穿过空间,并且具有与成角度的摩擦表面的非弹性(或部分弹性的)碰撞。
2)引入重力。 这将改变的弹道从直线条抛物线,并引入滑动 ,但不会有冲突太大的影响。
3)引入的静态和动摩擦(独立地)。 这些将改变滑动的动力。 不要担心摩擦碰撞现在。
4)给出的球角速度和转动惯量。 这是一个很大的进步。 确保您可以将扭矩给它,并得到现实的角加速度。 注意纺纱质量可反直觉的是现实的行为。
5)尝试滑动球沿着一个水平表面,在重力作用下。 如果你做的一切权利,其角速度将逐渐增加,其线速度逐渐降低,直至其断裂成卷。 实验给球一些初始旋转(“画”,“跟随”或“英语”)。
6)尝试是相同的,但在一个倾斜面。 这是一个相对较小的步骤。
如果到了这一步,你将有一个非常现实的SIM卡。 不要试图跳过任何步骤,你只给自己头痛。
Answer 4:
解答您的物理问题:
f = mg + other_f; // m = mass, g = gravity (9.8)
a = f / m; // a = acceleration
v = u + at; // v = new speed, u = old speed, t = delta time
s = 0.5 * (u + v) *t;
当你有一个碰撞,你改变的速度都为0(或V和U = - (U * 0.7),如果你想让它反弹)。
因为速度= 0时,球静止不动。
如果是2D或3D,则只需改变速度在正常的表面的方向为0,并保持平行的速度是相同的。 这将导致球滚动的表面上。
你必须,如果切割表面的球移动到表面。 您可以碰撞距离少量(例如0.001),以确保它仍然停留。
http://www.physicsforidiots.com/dynamics.html#vuat
编辑:
讷河是游戏引擎设计的惊人的来源:下面是关于碰撞检测页具有很好的描述: http://nehe.gamedev.net/tutorial/collision_detection/17005/
编辑2:(从讷河)
double DotProduct=direction.dot(plane._Normal); // Dot Product Between Plane Normal And Ray Direction
Dsc=(plane._Normal.dot(plane._Position-position))/DotProduct; // Find Distance To Collision Point
Tc= Dsc*T / Dst
Collision point= Start + Velocity*Tc
Answer 5:
我建议以后,要看看艾琳卡托的文章(的Box2D的作者)和格伦·费德勒文章,以及。 重力是一个强劲的加速和产生强烈的力量。 这是很容易有因为浮动不精确,变时间步和欧拉积分,非常迅速的故障模拟。 在平面球的repositionning情况下,它开始巴里本身传递的平面是强制性的,我发现自己说,这是更好地做到这一点只有当球的速度是在反对正常的平面(这可以比较面对3D渲染扑杀:不考虑backfaced平面)。
此外,大多数的物理引擎空闲机构停止模拟,并在移动的同时下降,只有当大多数游戏中从来没有采取重力考虑。 他们使用“导航网格”,并自定义系统,只要他们肯定模拟OBJET仍然坚持它的“地面”。
我不知道一个完美无瑕的物理模拟器在那里,总会有一个集成爆炸,错过碰撞(寻找“sweeped碰撞”)......它需要大量的实证精细的调整的。
此外,我建议你找“冲动”,这是一种方法,以避免手动调整速度在遇到碰撞时。
也看看到“每个计算机科学家应该知道浮点什么”
运气好的话,你进入了一个雷场进行数值计算机科学,随机未理解的,手指咬面积:)
Answer 6:
对于更高的保真度(不会解决你的主要问题),我想你的时间步改变
mAcceleration = mTotalForces / mMass;
Vector3 translation = (mVelocity * fElapsedTime) + 0.5 * mAcceleration * pow(fElapsedTime, 2);
mVelocity += mAcceleration * fElapsedTime;
你提到的领域是一个刚体; 你是不是也建模平面刚性? 如果是的话,你就必须在接触与完全弹性碰撞的那一刻无限点力而不势头一些明确的耗散。
力和速度不能被求和(不兼容的单位); 如果你只是想运动学模型,你可以不顾质量只用加速度和速度工作。
假定球被简单地拖放到一个水平面上完全非弹性碰撞(没有反弹),你可以做[NB,我真的不知道C语法,所以这将是Python化]
mAcceleration = if isContacting then (0, 0, 0) else (0, -9.8, 0)
如果增加一些弹性(比如一半势头守恒)碰撞,它会更喜欢
mAcceleration = (0, -9.8, 0) + if isContacting then (0, 4.9, 0)
文章来源: Determining Resting contact between sphere and plane when using external forces