当前位置: 首页 > 知识库问答 >
问题:

刚体模拟摩擦

易昌翰
2023-03-14

我目前正在做一个三维刚体模拟程序。我目前已经设法使刚体碰撞地板和弹跳正确地利用冲力。然而,我的问题是,一旦他们反弹,他们不断地加速,尽管使用摩擦矢量试图减缓他们。

Rvector fDirection(m_Bodies[i].Vel.x,0.0,m_Bodies[i].Vel.z);
Rvector relativeVelocities = m_Bodies[i].Vel - floorVelocity;
fDirection.normalize();


Real impulse = -(1+e) * (Rvector::dotProduct(relativeVelocities,floorNormal)) 
/ (1/m_Bodies[i].mass + floorMass);
Rvector friction = fDirection*mu*gravity.length()*m_Bodies[i].mass;

Rvector collision_forces = Rvector(0,1,0)*impulse;
collision_forces += friction ;

m_Bodies[i].Vel += (collision_forces/m_Bodies[i].mass);

谢谢

编辑:这里是集成代码。

void RigidBodySimulation::eulerIntegration(float dTime)
{
    Rvector newVel;
    Rvector newPos;
    Rvector zero(0.0, 0.0, 0.0);
    Real one_over_mass;
    Rvector accel;
    for( unsigned int i = 0 ; i < m_Bodies.size(); i++)
    {   
        one_over_mass = 1/m_Bodies[i].mass;
        newVel = m_Bodies[i].Vel + m_Bodies[i].force*one_over_mass*dTime;
        newPos = m_Bodies[i].Pos + m_Bodies[i].Vel*dTime;
        accel = m_Bodies[i].force / m_Bodies[i].mass;
        m_Bodies[i].acceleration = accel;
        m_Bodies[i].newPos = newPos;  
        m_Bodies[i].Vel = newVel;
        m_Bodies[i].Pos = newPos;
    }
}

共有1个答案

靳彦
2023-03-14

我不得不说,这是一段非常糟糕的代码,我已经做了10多年了。你应该得到一本关于动力学的基本教科书(像Hibbeler那样)。

Real impulse = -(1+e) * (Rvector::dotProduct(relativeVelocities,floorNormal))
               / (1/m_Bodies[i].mass + floorMass);

这个方程式看起来像是在计算撞击的恢复冲量(尽管计算是错误的)。首先,你必须明白,冲动和力不是一回事。冲量是力在一定时间间隔上的积分。在撞击过程中,你可以假设这段时间非常小,这就是为什么你会执行瞬时速度变化。这就是为什么你应该指定积分代码与碰撞计算无关,因为它在那一瞬间是绕过的,或者至少,如果你做基于冲量的计算,它应该是绕过的。实际计算应该是这样的:

Real momentum_before = Rvector::dotProduct(m_Bodies[i].Vel * m_Bodies[i].mass + floorVelocity * floorMass, floorNormal);
Real rel_vel_after = -e * Rvector::dotProduct(relativeVelocities,floorNormal);
// conservation of momentum in normal direction gives this:
Real body_vel_after = (momentum_before + floorMass * rel_vel_after) / (m_Bodies[i].mass + floorMass);
Real floor_vel_after = body_vel_after - rel_vel_after;

这实际上简化为一行,如下所示:

Real body_vel_after = ( (m_Bodies[i].mass - e * floorMass) * Rvector::dotProduct(m_Bodies[i].Vel, floorNormal)
                      + (1.0 + e) * floorMass * Rvector::dotProduct(floorVelocity, floorNormal) 
                      ) / (m_Bodies[i].mass + floorMass);
Real body_rel_vel_after = -e * Rvector::dotProduct(relativeVelocities, floorNormal);
Real body_vel_after = Rvector::dotProduct(floorVelocity, floorNormal) + body_rel_vel_after;
Real impulse = m_Bodies[i].mass * (body_vel_after - Rvector::dotProduct(m_Bodies[i].Vel, floorNormal));

现在,因为恢复冲量是法向力在撞击的小时间段内的积分,所以撞击过程中摩擦产生的冲量可以从恢复冲量中计算出来。摩擦力等于“mu”乘以法向力,即ff=mu*fn,这也适用于冲量,即if=mu*in。因此,您可以直接计算:

Real friction_impulse = mu * fabs(impulse);

但那只是摩擦冲量的大小。其方向与相对切向速度相反,即:

Rvector tangent_rel_vel = relativeVelocities - Rvector::dotProduct(relativeVelocities, floorNormal) * floorNormal;

它的方向是:

Rvector dir_rel_vel = tangent_rel_vel;
dir_rel_vel.normalize();
Rvector tangent_rel_vel_after = tangent_rel_vel - dir_rel_vel * friction_impulse / m_Bodies[i].mass;
Real tang_rel_vel_change = friction_impulse / mBodies[i].mass;
Rvector tangent_rel_vel_after = tangent_rel_vel - dir_rel_vel * tang_rel_vel_change;

if ( tang_rel_vel_change > tangent_rel_vel.length() ) 
    tangent_rel_vel_after = Rvector(0.0, 0.0, 0.0);   // stop relative motion.

此时,你所需要做的就是将两个最终的速度结合起来:

m_Bodies[i].Vel = floorVelocity + tangent_rel_vel_after + body_rel_vel_after * floorNormal;

至少,对于这个非常简单的问题(无限大的地板质量)来说,就是这样。在现实中,这种基于脉冲的方法变得越来越难处理,因为你把事情复杂化了:两个有限质量的物体,多个物体,以及实际的刚体动力学(因为你在这里只是做粒子动力学)。这种基于脉冲的方法很少见到,除了简单的校园里的球在地板上弹跳的例子。顺便说一句,你不应该把它叫做“刚体”模拟器,因为你实际上是在做一个粒子动力学(而三维刚体动力学要比这个复杂得多)。还有,你的积分法很糟糕,但那是完全不同的故事。

 类似资料:
  • 流氓和静态刚体 一般当我们创建一个刚体并将它添加到空间上后,空间就开始对之进行模拟,包括了对刚体位置、速度、受力以及重力影响等的模拟。没被添加到空间(没有被模拟)的刚体我们把它称之为流氓刚体。流氓刚体最重要的用途就是用来当作静态刚体,但是你仍然可以使用它来实现如移动平台这样的直接受控物体。 内存管理函数 cpBody *cpBodyAlloc(void) cpBody *cpBodyInit(cp

  • 刚体是组成物理世界的基本对象,可以让一个节点受到物理影响并产生反应。该组件在使用 Builtin 物理引擎时无效。 点击 属性检查器 下方的 添加组件 -> 物理组件 -> Rigid Body 3D,即可添加刚体组件到节点上。 刚体属性 属性 功能说明 Mass 刚体的质量 Linear Damping 线性阻尼,用于减小刚体的线性速率,值越大物体移动越慢 Angular Damping 角阻尼

  • 刚体是组成物理世界的基本对象,你可以将刚体想象成一个你不能看到(绘制)也不能摸到(碰撞)的带有属性的物体。 刚体属性 质量 刚体的质量是通过碰撞组件的 密度 与 大小 自动计算得到的。 当你需要计算物体应该受到多大的力时可能需要使用到这个属性。 var mass = rigidbody.getMass(); 移动速度 // 获取移动速度 var velocity = rigidbody.line

  • 获取刚体组件 TypeScript的代码示例:const rigidBody = this.getComponent(RigidBody); 刚体类型 刚体一般分为三种类型,static,dynamic,kinematic. static,表示静态刚体,犹如质量巨大无比的石头,具体为质量为0的,或者只有碰撞组件的物理元素。 dynamic,表示动力学刚体,能够受到力的作用,具体为质量大于0并且is

  • 如何模拟AsNoTracking方法? 在下面的示例中,DbContext已经注入到服务类中,如果我从GetOrderedProducts方法中移除AsNoTracking扩展方法,它可以正常工作,但是with AsNoTracking测试失败,因为它返回null。我还试图模拟AsNoTracking以返回正确的值,但它不起作用。

  • 我有一个模型类和一个控制器。我在post man的正文中发布json类型的数据。但每次我都会收到一个不受支持的媒体类型415错误。这是我的模型课: 我的控制器是: 我已经用HttpServletRequest代替@RequestBody,它起到了作用。但为什么在我使用@RequestBody时它不工作呢? 这是邮递员的快照。这是邮递员请求的图片 这是请求中使用的标题的屏幕截图