public void ApplyExternalForce(IRigidBody rigidBody, float timeStep) { Vector3 currentGravity; rigidBody.GetGravity(out currentGravity); Vector3 buoyancy; Vector3.Negate(ref currentGravity, out buoyancy); var volume = rigidBody.CollisionBounds.Volume; buoyancy *= (Density * volume); rigidBody.ApplyForce(ref buoyancy); // 抗力 (D: Drag) // // D = (1 / 2) * P * V^2 * S * Cd // // P: 流体の密度 (浮力で用いる流体の密度と同じなので、このクラスでは Density) // V: 物体と流体の相対速度 // S: 物体の代表面積 (ここでは簡易にするために衝突形状の全体の面積で代用) // Cd: 抗力係数 (算出が大変なようなので、このクラスでは任意の設定値として調整) Vector3 rigidBodyVelocity; rigidBody.GetVeclocity(out rigidBodyVelocity); // 相対速度 //var relativeVelocity = Velocity - rigidBodyVelocity; var relativeVelocity = rigidBodyVelocity - Velocity; // 相対速度の二乗 (速度ベクトルの大きさの二乗) var v2 = relativeVelocity.LengthSquared(); // 抗力 var drag = Density * v2 * rigidBody.CollisionBounds.SurfaceArea * DragCoefficient; // 抗力の方向 (単位ベクトル) var direction = Velocity; if (direction.LengthSquared() != 0) { direction.Normalize(); } var dragVector = direction * drag; rigidBody.ApplyForce(ref dragVector); }
public void ApplyExternalForce(IRigidBody rigidBody, float timeStep) { Vector3 velocity; rigidBody.GetVeclocity(out velocity); // 重力方向に対して衝突があるかどうかを判定します。 Vector3 gravity; character.RigidBody.GetGravity(out gravity); bool isStanding = character.CollisionBounds.IsCollidedForDirection(ref gravity); if (isStanding) { // 現在の速度から desiredVelocity までの速度の変化量。 var dv = desiredVelocity - velocity; // 時間 accelerationInterval で速度 dv に到達するために必要な加速度。 var acceleration = new Vector3(); acceleration.X = dv.X / accelerationInterval; acceleration.Y = dv.Y / accelerationInterval; acceleration.Z = dv.Z / accelerationInterval; // 加速度と質量によりかかる力。 var targetForce = rigidBody.Mass * acceleration; rigidBody.ApplyForce(targetForce); } else { if (!desiredVelocity.IsZero()) { // delta velocity var dv = desiredVelocity - velocity; // acceleration var acceleration = new Vector3(); acceleration.X = dv.X / accelerationInterval; acceleration.Z = dv.Z / accelerationInterval; // // 速度ベクトルが同じ方向であるほどに通常の加速度 // 反対方法であるほどに若干のブレーキをかける // Vector3 tryMoveVelocityUnit; Vector3Extension.NormalizeSafe(ref desiredVelocity, out tryMoveVelocityUnit); Vector3 currentVelocity = velocity; Vector3 currentVelocityUnit; Vector3Extension.NormalizeSafe(ref currentVelocity, out currentVelocityUnit); float dot; Vector3.Dot(ref tryMoveVelocityUnit, ref currentVelocityUnit, out dot); // // dot [-1, 1] -> factor [brake, 1] (brake < 1) // const float brake = 0.01f; // // dot の範囲を長さ 1 へ変更 // dot / (1 - (-1)) // それを factor の範囲の長さへ変更 // (dot / 2) * (1 - brake) // その原点を factor の中心へ移動 // (dot / 2) * (1 - brake) + (1 - (1 - brake) / 2) // ゆえに // (dot * (1 - brake) + (1 + brake)) / 2 // var factor = (dot * (1 - brake) + (1 + brake)) * 0.5f; var targetForce = rigidBody.Mass * acceleration * factor; // for jump if (0 < desiredVelocity.Y) { var accelerationY = (desiredVelocity.Y - velocity.Y) / accelerationInterval; targetForce.Y = rigidBody.Mass * accelerationY; } rigidBody.ApplyForce(targetForce); } } }