void GetBuoyancyInformation(EntityCollidable collidable, out float submergedVolume, out Vector3 submergedCenter) { BoundingBox entityBoundingBox; RigidTransform localTransform; RigidTransform.MultiplyByInverse(ref collidable.worldTransform, ref surfaceTransform, out localTransform); collidable.Shape.GetBoundingBox(ref localTransform, out entityBoundingBox); if (entityBoundingBox.Min.Y > 0) { //Fish out of the water. Don't need to do raycast tests on objects not at the boundary. submergedVolume = 0; submergedCenter = collidable.worldTransform.Position; return; } if (entityBoundingBox.Max.Y < 0) { submergedVolume = collidable.entity.CollisionInformation.Shape.Volume; submergedCenter = collidable.worldTransform.Position; return; } Vector3 origin, xSpacing, zSpacing; float perColumnArea; GetSamplingOrigin(ref entityBoundingBox, out xSpacing, out zSpacing, out perColumnArea, out origin); float boundingBoxHeight = entityBoundingBox.Max.Y - entityBoundingBox.Min.Y; float maxLength = -entityBoundingBox.Min.Y; submergedCenter = new Vector3(); submergedVolume = 0; for (int i = 0; i < samplePointsPerDimension; i++) { for (int j = 0; j < samplePointsPerDimension; j++) { Vector3 columnVolumeCenter; float submergedHeight; if ((submergedHeight = GetSubmergedHeight(collidable, maxLength, boundingBoxHeight, ref origin, ref xSpacing, ref zSpacing, i, j, out columnVolumeCenter)) > 0) { float columnVolume = submergedHeight * perColumnArea; Vector3.Multiply(ref columnVolumeCenter, columnVolume, out columnVolumeCenter); Vector3.Add(ref columnVolumeCenter, ref submergedCenter, out submergedCenter); submergedVolume += columnVolume; } } } Vector3.Divide(ref submergedCenter, submergedVolume, out submergedCenter); //Pull the submerged center into world space before applying the force. RigidTransform.Transform(ref submergedCenter, ref surfaceTransform, out submergedCenter); }