/// <summary> /// Rescales a convex hull shape. /// </summary> /// <param name="shape">The shape.</param> /// <param name="scaleFactor">The scaling factor.</param> /// <returns>The new hull.</returns> public static ConvexHullShape Rescale(this ConvexHullShape shape, Vector3 scaleFactor) { ReadOnlyList <Vector3> verts = shape.Vertices; List <Vector3> newlist = new List <Vector3>(verts.Count); foreach (Vector3 vert in verts) { newlist.Add(vert * scaleFactor); } double len = scaleFactor.Length(); RawList <int> triangles = CommonResources.GetIntList(); ConvexHullHelper.GetConvexHull(newlist, triangles); InertiaHelper.ComputeShapeDistribution(newlist, triangles, out double volume, out Matrix3x3 volumeDistribution); ConvexShapeDescription csd = new ConvexShapeDescription() { CollisionMargin = shape.CollisionMargin, EntityShapeVolume = new BEPUphysics.CollisionShapes.EntityShapeVolumeDescription() { Volume = volume, VolumeDistribution = volumeDistribution }, MaximumRadius = shape.MaximumRadius * len, MinimumRadius = shape.MinimumRadius * len }; CommonResources.GiveBack(triangles); return(new ConvexHullShape(newlist, csd)); }
/// <summary> /// Recenters the triangle data and computes the volume distribution. /// </summary> /// <param name="data">Mesh data to analyze.</param> /// <returns>Computed center, volume, and volume distribution.</returns> private ShapeDistributionInformation ComputeVolumeDistribution(TransformableMeshData data) { //Compute the surface vertices of the shape. ShapeDistributionInformation shapeInformation; if (solidity == MobileMeshSolidity.Solid) { //The following inertia tensor calculation assumes a closed mesh. var transformedVertices = CommonResources.GetVectorList(); if (transformedVertices.Capacity < data.vertices.Length) { transformedVertices.Capacity = data.vertices.Length; } transformedVertices.Count = data.vertices.Length; for (int i = 0; i < data.vertices.Length; ++i) { data.GetVertexPosition(i, out transformedVertices.Elements[i]); } InertiaHelper.ComputeShapeDistribution(transformedVertices, data.indices, out shapeInformation.Center, out shapeInformation.Volume, out shapeInformation.VolumeDistribution); CommonResources.GiveBack(transformedVertices); if (shapeInformation.Volume > F64.C0) { return(shapeInformation); } throw new ArgumentException("A solid mesh must have volume."); } shapeInformation.Center = new Vector3(); shapeInformation.VolumeDistribution = new Matrix3x3(); Fix64 totalWeight = F64.C0; for (int i = 0; i < data.indices.Length; i += 3) { //Compute the center contribution. Vector3 vA, vB, vC; data.GetTriangle(i, out vA, out vB, out vC); Vector3 vAvB; Vector3 vAvC; Vector3.Subtract(ref vB, ref vA, out vAvB); Vector3.Subtract(ref vC, ref vA, out vAvC); Vector3 cross; Vector3.Cross(ref vAvB, ref vAvC, out cross); Fix64 weight = cross.Length(); totalWeight += weight; Fix64 perVertexWeight = weight * F64.OneThird; shapeInformation.Center += perVertexWeight * (vA + vB + vC); //Compute the inertia contribution of this triangle. //Approximate it using pointmasses positioned at the triangle vertices. //(There exists a direct solution, but this approximation will do plenty fine.) Matrix3x3 aContribution, bContribution, cContribution; InertiaHelper.GetPointContribution(perVertexWeight, ref Toolbox.ZeroVector, ref vA, out aContribution); InertiaHelper.GetPointContribution(perVertexWeight, ref Toolbox.ZeroVector, ref vB, out bContribution); InertiaHelper.GetPointContribution(perVertexWeight, ref Toolbox.ZeroVector, ref vC, out cContribution); Matrix3x3.Add(ref aContribution, ref shapeInformation.VolumeDistribution, out shapeInformation.VolumeDistribution); Matrix3x3.Add(ref bContribution, ref shapeInformation.VolumeDistribution, out shapeInformation.VolumeDistribution); Matrix3x3.Add(ref cContribution, ref shapeInformation.VolumeDistribution, out shapeInformation.VolumeDistribution); } shapeInformation.Center /= totalWeight; //The extra factor of 2 is used because the cross product length was twice the actual area. Matrix3x3.Multiply(ref shapeInformation.VolumeDistribution, F64.C1 / (F64.C2 * totalWeight), out shapeInformation.VolumeDistribution); //Move the inertia tensor into position according to the center. Matrix3x3 additionalInertia; InertiaHelper.GetPointContribution(F64.C0p5, ref Toolbox.ZeroVector, ref shapeInformation.Center, out additionalInertia); Matrix3x3.Subtract(ref shapeInformation.VolumeDistribution, ref additionalInertia, out shapeInformation.VolumeDistribution); shapeInformation.Volume = F64.C0; return(shapeInformation); }