计算和应用摩擦力

3
我一直在研究如何施加摩擦力,但我遇到了一个难题,就是如何将摩擦力应用于速度(如果我正确计算了摩擦力的话)。
当我把球放在一个法线为(0,1,0)、当前速度为(2,0,0)的表面上时,我会将我的摩擦力计算为(0,-0.3,0)。然而,我不明白如何正确地将其应用于我的速度。如果我简单地减去它,那么我的速度将变为(2,-0.3,0),但是,难道不应该是使x分量更小吗?
这是我的当前代码,如果有人能看一下,我将非常感激。我知道还有一些优化需要做。
mTotalForces = D3DXVECTOR3(0.0f, 0.0f, 0.0f);

D3DXVECTOR3 vSurfaceNormalized;
D3DXVec3Normalize(&vSurfaceNormalized, &vSurfaceNormal);
D3DXVECTOR3 vFrictionForce(0.0f, 0.0f, 0.0f);

D3DXVECTOR3 forceAndVelocity = mTotalForces + m_vVelocity;
float fVelocityMagnitude = sqrt((forceAndVelocity.x * forceAndVelocity.x) + (forceAndVelocity.y * forceAndVelocity.y) + forceAndVelocity.z * (forceAndVelocity.z));
float fFrictionForceMagnitude = 0.0f;
float fFrictionForce = 0.0f;

if(fVelocityMagnitude == 0.0f)
{
    fFrictionForce = m_fStaticFrictionCoefficient;

    D3DXVECTOR3 vStaticFriction = -m_fStaticFrictionCoefficient * vSurfaceNormalized;
    vFrictionForce = vStaticFriction;
}
else if(fVelocityMagnitude > 0.0f)
{
    fFrictionForce = m_fKineticFrictionCoefficient;

    D3DXVECTOR3 vKineticFriction = -m_fKineticFrictionCoefficient * vSurfaceNormalized;
    vFrictionForce = vKineticFriction;
}


{
    float fFrictionForceMagnitude = abs(fFrictionForce * D3DXVec3Dot(&vSurfaceNormalized, &forceAndVelocity));

    if(fFrictionForceMagnitude > fVelocityMagnitude)
    {
        fFrictionForceMagnitude = 0.0f;
        m_vVelocity = D3DXVECTOR3(0.0f, 0.0f, 0.0f);
    }
    else
    {
        m_vVelocity -= vFrictionForce;
    }
}

在这个摩擦函数的开始处,我将总力归零,因为如果有摩擦,前面的力(重力)就不应该影响后面的速度。(是吧?)


如果你的球在x-z平面上的表面上沿x方向移动,为什么摩擦力会在y方向呢? - Oliver Charlesworth
你的物理知识有点偏差。看一下这个链接:http://hyperphysics.phy-astr.gsu.edu/hbase/frict2.html - Nope
@ Oli Charlesworth,这就是我试图弄清楚的问题...我同意,它应该在x方向上。 - mmurphy
3个回答

4
你的代码存在一些问题。因此,我将逐个解决这些问题,并回答你实际的问题。首先,
D3DXVECTOR3 forceAndVelocity = mTotalForces + m_vVelocity;

这是不正确的,因为力和速度在概念上非常不同。这体现在它们的不同单位上,所以它们不能相加。

float fVelocityMagnitude = sqrt((forceAndVelocity.x * forceAndVelocity.x) + ...

我相信您想要forceAndVelocity严格指速度。

我会将第一个if语句重写如下:

float fFrictionCoefficient = 0.0f;
if(fVelocityMagnitude == 0.0f)
{
    float fFrictionCoefficient = m_fStaticFrictionCoefficient;
}
else if(fVelocityMagnitude > 0.0f)
{
    float fFrictionCoefficient = m_fKineticFrictionCoefficient;
}

我放弃了向量计算,因为它们与法线平行而不是垂直。

摩擦力的大小是摩擦系数乘以法向力的大小,所以

float fFrictionForceMagnitude = fFrictionCoefficient 
                        * sqrt(D3DXVec3Dot(&vSurfaceNormal, &vSurfaceNormal));

在第二个if语句中,您再次比较力和速度,您要做的是确定何时可以克服静摩擦力。基本上,您需要确定所有其他力是否超过了摩擦力,因此需要将没有摩擦力的总力的大小与摩擦力的大小进行比较。因此,我会重新设计if块。
float fForceMagnitude = sqrt(D3DXVec3Dot(&mTotalForces, &mTotalForces));

if(fFrictionForceMagnitude > fForceMagnitude)
{
    float m_vVelocity = D3DXVECTOR3(0.0f, 0.0f, 0.0f);
}
else
{
    float mTotalForces -= fFrictionForceMagnitude * m_vVelocity / fVelocityMagnitude;
}

最后一行是你问题的答案。摩擦力与速度方向相反,因此它与你的速度方向相反,其中m_vVelocity / fVelocityMagnitude是规范化的速度。注意,这不会直接影响速度,而是影响你的速度。

D3DXVECTOR3 m_vVelocity = mTotalForces * time / mass;

这里的mass代表物体的质量;


我注意到的一个问题是,“fForceMagnitude”将始终为零。这是因为在函数顶部,总力已经减去了重力并且现在为零。其余部分非常有趣,大部分都很合理,但我想知道,你是从哪里学到的?你是否知道参考资料? - mmurphy
在垂直于重力方向的表面上,法向力完全被抵消(牛顿第三定律)。这是否意味着我根本不需要减去重力,而牛顿第三定律会自动完成? - mmurphy
我注意到当速度为(2.0, 0, 0),总力为(0, -9.8, 0)和法线为(0, 1, 0)时,第一次经过“mTotalForces”后的计算结果会变成类似于(-0.3, -9.8, 0)这样的值,这对我来说似乎是错误的。我之所以这么认为是因为如果有一个静摩擦力要施加,那么难道不应该没有重力作用吗?因为这样会导致物体开始穿透表面。 - mmurphy
抱歉向您提出两个问题,这似乎是阻碍我的最后一件事。您是否有任何进一步的建议? - mmurphy
抱歉,我正在搬家中,所以这个事情暂时被搁置了一段时间。我会尽量在今晚或明天回复您的。 - rcollyer
显示剩余6条评论

1
首先,你的摩擦力应该是切向于你的表面,沿着速度向量的方向。所以在你的情况下,你的力向量将是(-0.3,0,0)。然后你的摩擦力是一种力量,所以你不能像这样将它添加到速度中。你的力量执行影响速度的工作。这项工作随时间变化,并且实际上可能与你的速度成比例。

我该如何计算才能使力向量为(-0.3, 0, 0)? - mmurphy
我猜作为第一个近似,您可以说您的摩擦力不受速度影响。 您只需要选择一个与球的质量有意义的数字即可。 因为下一阶段是将摩擦对移动中的球的影响进行积分。 如果该摩擦力是唯一作用于球向运动方向的力(重力和表面反作用力相互抵消),则您的运动方程为m * a = F_{friction}。 因此,在您的时间步长dt内,您的速度变化为dv = F_f / m * dt。 合理吗? - FrenchKheldar

0

动态摩擦力始终平行于接触面,即垂直于法线,而不是沿着法线方向。


我该如何计算并应用它? - mmurphy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接