《Fluid Engine Development》 学习笔记2-基礎 (3)

碰撞在物理模拟乃至物理引擎领域都是一个非常复杂的问题,《Fluid Engine Development》对于这一块并没有进行深入,碰撞检测只是简单检测碰撞点是否在几何表面的内部,以及碰撞点,粒子的中心间的距离是否小于粒子的半径。

至于碰撞的处理,主要是改变粒子的速度,和把粒子修正到正确的位置。

粒子的正确位置为碰撞点+碰撞点法线 * 粒子半径,也就是紧贴碰撞面表面的位置

至于粒子的速度,这里把粒子相对碰撞面的速度拆解切向速度和法向速度

经过碰撞,法向速度变更为 \(- R V_{n}\) (R是恢复系数,Vn是法向速度)

切向速度变更为 \(max\left( 1 - u \frac{\left|\Delta V_{n}\right|}{V_{t}} \right) V_{t}\)

切向速度的变更大家或许会有疑惑,这里列出推导过程

假定\(\Delta V_{n} = V_{n}^{new} - V_{n} = (- R - 1)V_{n}\)

已知\(\Delta V_{t} = a_{t}\Delta t = F_{f}/m \Delta t = u F_{n}/m \Delta t\)

又上类推得\(\Delta V_{n} = a_{n}\Delta t = F_{n}/m \Delta t\)

所以\(\Delta V_{t} = u \Delta V_{n}\)

因为新切向速度必然小于原速度,所以\(\Delta V_{t} = min(u\Delta V_{n},V_{t})\)

可得 \(V_{t}^{new} =max\left( 1 - u \frac{\left|\Delta V_{n}\right|}{V_{t}} \right) V_{t}\)

具体代码实现如下

struct ColliderQueryResult final { double distance; Vector3D point; Vector3D normal; Vector3D velocity; }; void CalfFluidEngine::Collider3::ResolveCollision( double radius, double restitutionCoefficient, Vector3D * position, Vector3D * velocity) { ColliderQueryResult res; getClosestPoint(_surface, *position, &res); if (isPenetrating(res, *position, radius)) { Vector3D targetNormal = res.normal; Vector3D targetPoint = res.point + radius * targetNormal; Vector3D colliderVelAtTargetPoint = res.velocity; Vector3D relativeVel = *velocity - colliderVelAtTargetPoint; double normalDotRelativeVel = Vector3D::Dot(targetNormal, relativeVel); Vector3D relativeVelN = normalDotRelativeVel * targetNormal; Vector3D relativeVelT = relativeVel - relativeVelN; if (normalDotRelativeVel < 0.0) { Vector3D deltaRelativeVelN = (-restitutionCoefficient - 1.0) * relativeVelN; relativeVelN *= -restitutionCoefficient; // Apply friction to the tangential component of the velocity // From Bridson et al., Robust Treatment of Collisions, Contact and // Friction for Cloth Animation, 2002 // if (relativeVelT.SquareMagnitude() > 0.0) { double frictionScale = std::max( 1.0 - _frictionCoeffient * deltaRelativeVelN.Magnitude() / relativeVelT.Magnitude(), 0.0); relativeVelT *= frictionScale; } *velocity = relativeVelN + relativeVelT + colliderVelAtTargetPoint; } *position = targetPoint; } } bool CalfFluidEngine::Collider3::isPenetrating( const ColliderQueryResult & colliderPoint, const Vector3D & position, double radius) { return _surface->IsInside(position) || colliderPoint.distance < radius; } 粒子发射器

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zyddgj.html