Exemple #1
0
        /// <inheritdoc/>
        public override void Apply(RigidBody body)
        {
            if (body == null)
            {
                throw new ArgumentNullException("body", "Rigid body in area of effect must not be null.");
            }

            // Get BuoyancyData. If necessary create new data.
            BuoyancyData data = body.BuoyancyData;

            if (data == null)
            {
                Prepare(body);
                data = body.BuoyancyData;
            }

            // Compute size of volume that is in the water and the center of the submerged volume.
            Vector3 centerOfSubmergedVolume;
            float   submergedVolume = GetSubmergedVolume(body.Scale, body.Pose, data.Mesh, out centerOfSubmergedVolume);

            if (submergedVolume > 0)
            {
                // The up force.
                Vector3 buoyancyForce = (Density * submergedVolume * Gravity) * Surface.Normal;

                // The total volume of the body.
                float totalVolume = data.Volume * body.Scale.X * body.Scale.Y * body.Scale.Z;

                // The fraction of the total mass that is under the water (assuming constant density).
                float submergedMass = body.MassFrame.Mass * submergedVolume / totalVolume;

                // Compute linear drag.
                Vector3 centerLinearVelocity = body.GetVelocityOfWorldPoint(centerOfSubmergedVolume);
                Vector3 dragForce            = (submergedMass * LinearDrag) * (Velocity - centerLinearVelocity);

                // Apply up force and linear drag force.
                Vector3 totalForce = buoyancyForce + dragForce;
                AddForce(body, totalForce, centerOfSubmergedVolume);

                // Apply torque for angular drag.
                // body.Length is proportional to the unscaled shape. Apply scaling to get a new
                // proportional value for the scaled shape.
                float   length        = data.Length * 1.0f / 3.0f * (body.Scale.X + body.Scale.Y + body.Scale.Z);
                float   lengthSquared = length * length;
                Vector3 dragTorque    = (-submergedMass * AngularDrag * lengthSquared) * body.AngularVelocity;
                AddTorque(body, dragTorque);
            }
        }
Exemple #2
0
        /// <summary>
        /// Prepares the specified rigid body for the buoyancy effect.
        /// </summary>
        /// <param name="body">The rigid body.</param>
        /// <remarks>
        /// <para>
        /// This method is automatically called for each body that touches the water. It computes
        /// additional information per rigid body that is needed for the buoyancy effect.
        /// </para>
        /// <para>
        /// To prepare the rigid bodies ahead of time, this method can be called manually - but this
        /// is not required. It is sufficient to call this method once per rigid body, then the body
        /// is prepared for all buoyancy effect instances.
        /// </para>
        /// </remarks>
        /// <exception cref="ArgumentNullException">
        /// <paramref name="body"/> is <see langword="null"/>.
        /// </exception>
        public static void Prepare(RigidBody body)
        {
            // Must be called once per shape not really per body - but we keep this info internal in
            // case we make changes in the future, like per-body buoyancy settings.

            if (body == null)
            {
                throw new ArgumentNullException("body");
            }

            Shape shape = body.Shape;

            // Try to use existing data for the same shape.
            var simulation = body.Simulation;

            if (simulation != null)
            {
                int numberOfRigidBodies = simulation.RigidBodies.Count;
                for (int i = 0; i < numberOfRigidBodies; i++)
                {
                    var otherBody = simulation.RigidBodies[i];
                    if (otherBody.Shape == shape && otherBody.BuoyancyData != null)
                    {
                        body.BuoyancyData = otherBody.BuoyancyData;
                        return;
                    }
                }
            }

            BuoyancyData data = new BuoyancyData();

            data.Mesh   = shape.GetMesh(0.01f, 4);
            data.Volume = data.Mesh.GetVolume();
            data.Length = shape.GetAabb(Pose.Identity).Extent.LargestComponent;

            body.BuoyancyData = data;
        }