/// <summary> /// Computes a convex shape description for a ConvexHullShape. /// </summary> /// <param name="vertices">Vertices describing the convex hull shape.</param> /// <param name="collisionMargin">Collision margin of the shape.</param> /// <param name="center">Computed center of the convex hull shape. Used as the origin of the outputUniqueSurfaceVertices.</param> /// <param name="outputHullTriangleIndices">Computed list of indices into the input point set composing the triangulated surface of the convex hull. /// Each group of 3 indices represents a triangle on the surface of the hull.</param> /// <param name="outputUniqueSurfaceVertices">Computed nonredundant list of vertices composing the outer shell of the input point set. Recentered on the local origin.</param> /// <returns>Description required to define a convex shape.</returns> public static ConvexShapeDescription ComputeDescription(IList <Vector3> vertices, float collisionMargin, out Vector3 center, IList <int> outputHullTriangleIndices, IList <Vector3> outputUniqueSurfaceVertices) { if (outputHullTriangleIndices.Count != 0 || outputUniqueSurfaceVertices.Count != 0) { throw new ArgumentException("Output lists must start empty."); } ConvexShapeDescription description; ConvexHullHelper.GetConvexHull(vertices, outputHullTriangleIndices, outputUniqueSurfaceVertices); InertiaHelper.ComputeShapeDistribution(vertices, outputHullTriangleIndices, out center, out description.EntityShapeVolume.Volume, out description.EntityShapeVolume.VolumeDistribution); //Recenter the surface vertices. for (int i = 0; i < outputUniqueSurfaceVertices.Count; ++i) { outputUniqueSurfaceVertices[i] -= center; } description.MinimumRadius = InertiaHelper.ComputeMinimumRadius(vertices, outputHullTriangleIndices, ref center) + collisionMargin; description.MaximumRadius = ComputeMaximumRadius(outputUniqueSurfaceVertices, collisionMargin); description.CollisionMargin = collisionMargin; return(description); }
/// <summary> /// Computes and applies a convex shape description for this WrappedShape. /// </summary> /// <param name="center">Computed center of the shape before recentering.</param> public void UpdateConvexShapeInfo(out Vector3 center) { //Compute the volume distribution. var samples = CommonResources.GetVectorList(); if (samples.Capacity < InertiaHelper.SampleDirections.Length) { samples.Capacity = InertiaHelper.SampleDirections.Length; } samples.Count = InertiaHelper.SampleDirections.Length; for (int i = 0; i < InertiaHelper.SampleDirections.Length; ++i) { GetLocalExtremePoint(InertiaHelper.SampleDirections[i], out samples.Elements[i]); } var triangles = CommonResources.GetIntList(); ConvexHullHelper.GetConvexHull(samples, triangles); float volume; InertiaHelper.ComputeShapeDistribution(samples, triangles, out center, out volume, out volumeDistribution); Volume = volume; CommonResources.GiveBack(samples); CommonResources.GiveBack(triangles); //Now recenter the shape and compute the radii estimates. for (int i = 0; i < shapes.Count; i++) { shapes.WrappedList.Elements[i].Transform.Position -= center; } MinimumRadius = ComputeMinimumRadius(); MaximumRadius = ComputeMaximumRadius(); }
public static void GetShapeMeshData(EntityCollidable collidable, List <VertexPositionNormalTexture> vertices, List <ushort> indices) { var convexHullShape = collidable.Shape as ConvexHullShape; if (convexHullShape == null) { throw new ArgumentException("Wrong shape type."); } var hullTriangleVertices = new List <Vector3>(); var hullTriangleIndices = new List <int>(); ConvexHullHelper.GetConvexHull(convexHullShape.Vertices, hullTriangleIndices, hullTriangleVertices); //The hull triangle vertices are used as a dummy to get the unnecessary hull vertices, which are cleared afterwards. hullTriangleVertices.Clear(); foreach (int i in hullTriangleIndices) { hullTriangleVertices.Add(convexHullShape.Vertices[i]); } var toReturn = new VertexPositionNormalTexture[hullTriangleVertices.Count]; Vector3 normal; for (ushort i = 0; i < hullTriangleVertices.Count; i += 3) { normal = Vector3.Normalize(Vector3.Cross(hullTriangleVertices[i + 2] - hullTriangleVertices[i], hullTriangleVertices[i + 1] - hullTriangleVertices[i])); vertices.Add(new VertexPositionNormalTexture(MathConverter.Convert(hullTriangleVertices[i]), MathConverter.Convert(normal), new Microsoft.Xna.Framework.Vector2(0, 0))); vertices.Add(new VertexPositionNormalTexture(MathConverter.Convert(hullTriangleVertices[i + 1]), MathConverter.Convert(normal), new Microsoft.Xna.Framework.Vector2(1, 0))); vertices.Add(new VertexPositionNormalTexture(MathConverter.Convert(hullTriangleVertices[i + 2]), MathConverter.Convert(normal), new Microsoft.Xna.Framework.Vector2(0, 1))); indices.Add(i); indices.Add((ushort)(i + 1)); indices.Add((ushort)(i + 2)); } }
/// <summary> /// Computes a convex shape description for a TransformableShape and applies it. /// </summary> public void UpdateConvexShapeInfo() { //Compute the volume distribution. var samples = CommonResources.GetVectorList(); if (samples.Capacity < InertiaHelper.SampleDirections.Length) { samples.Capacity = InertiaHelper.SampleDirections.Length; } samples.Count = InertiaHelper.SampleDirections.Length; for (int i = 0; i < InertiaHelper.SampleDirections.Length; ++i) { shape.GetLocalExtremePointWithoutMargin(ref InertiaHelper.SampleDirections[i], out samples.Elements[i]); } var triangles = CommonResources.GetIntList(); ConvexHullHelper.GetConvexHull(samples, triangles); float volume; InertiaHelper.ComputeShapeDistribution(samples, triangles, out volume, out volumeDistribution); Volume = volume; //Estimate the minimum radius based on the surface mesh. MinimumRadius = InertiaHelper.ComputeMinimumRadius(samples, triangles, ref Toolbox.ZeroVector) + collisionMargin; MaximumRadius = ComputeMaximumRadius(); CommonResources.GiveBack(samples); CommonResources.GiveBack(triangles); }
/// <summary> /// Computes and applies a convex shape description for this MinkowskiSumShape. /// </summary> /// <returns>Description required to define a convex shape.</returns> public void UpdateConvexShapeInfo() { //Compute the volume distribution. var samples = CommonResources.GetVectorList(); if (samples.Capacity < InertiaHelper.SampleDirections.Length) { samples.Capacity = InertiaHelper.SampleDirections.Length; } samples.Count = InertiaHelper.SampleDirections.Length; for (int i = 0; i < InertiaHelper.SampleDirections.Length; ++i) { GetLocalExtremePoint(InertiaHelper.SampleDirections[i], out samples.Elements[i]); } var triangles = CommonResources.GetIntList(); ConvexHullHelper.GetConvexHull(samples, triangles); float volume; Vector3 center; InertiaHelper.ComputeShapeDistribution(samples, triangles, out center, out volume, out volumeDistribution); Volume = volume; //Recenter the shape. localOffset = -center; CommonResources.GiveBack(samples); CommonResources.GiveBack(triangles); //Compute the radii. float minRadius = 0, maxRadius = 0; for (int i = 0; i < shapes.Count; i++) { minRadius += shapes.WrappedList.Elements[i].CollisionShape.MinimumRadius; maxRadius += shapes.WrappedList.Elements[i].CollisionShape.MaximumRadius; } MinimumRadius = minRadius + collisionMargin; MaximumRadius = maxRadius + collisionMargin; }
public static void GetShapeMeshData(EntityCollidable collidable, List <VertexPositionNormalTexture> vertices, List <ushort> indices) { var shape = collidable.Shape as ConvexShape; if (shape == null) { throw new ArgumentException("Wrong shape type for this helper."); } var vertexPositions = new Vector3[SampleDirections.Length]; for (int i = 0; i < SampleDirections.Length; ++i) { shape.GetLocalExtremePoint(SampleDirections[i], out vertexPositions[i]); } var hullIndices = new RawList <int>(); ConvexHullHelper.GetConvexHull(vertexPositions, hullIndices); var hullTriangleVertices = new RawList <Vector3>(); foreach (int i in hullIndices) { hullTriangleVertices.Add(vertexPositions[i]); } for (ushort i = 0; i < hullTriangleVertices.Count; i += 3) { Vector3 normal = Vector3.Normalize(Vector3.Cross(hullTriangleVertices[i + 2] - hullTriangleVertices[i], hullTriangleVertices[i + 1] - hullTriangleVertices[i])); vertices.Add(new VertexPositionNormalTexture(MathConverter.Convert(hullTriangleVertices[i]), MathConverter.Convert(normal), new Microsoft.Xna.Framework.Vector2(0, 0))); vertices.Add(new VertexPositionNormalTexture(MathConverter.Convert(hullTriangleVertices[i + 1]), MathConverter.Convert(normal), new Microsoft.Xna.Framework.Vector2(1, 0))); vertices.Add(new VertexPositionNormalTexture(MathConverter.Convert(hullTriangleVertices[i + 2]), MathConverter.Convert(normal), new Microsoft.Xna.Framework.Vector2(0, 1))); indices.Add(i); indices.Add((ushort)(i + 1)); indices.Add((ushort)(i + 2)); } }
private void UpdateSurfaceVertices() { hullVertices.Clear(); if (Volume > 0) { ConvexHullHelper.GetConvexHull(triangleMesh.Data.vertices, hullVertices); var transformableData = triangleMesh.Data as TransformableMeshData; if (transformableData != null) { var transform = transformableData.worldTransform; for (int i = 0; i < hullVertices.Count; i++) { AffineTransform.Transform(ref hullVertices.Elements[i], ref transform, out hullVertices.Elements[i]); } } } else { hullVertices.Clear(); //A mobile mesh is allowed to have zero volume, so long as it isn't solid. //In this case, compute the bounding box of all points. BoundingBox box = new BoundingBox(); for (int i = 0; i < triangleMesh.Data.vertices.Length; i++) { Vector3 v; triangleMesh.Data.GetVertexPosition(i, out v); if (v.X > box.Max.X) { box.Max.X = v.X; } if (v.X < box.Min.X) { box.Min.X = v.X; } if (v.Y > box.Max.Y) { box.Max.Y = v.Y; } if (v.Y < box.Min.Y) { box.Min.Y = v.Y; } if (v.Z > box.Max.Z) { box.Max.Z = v.Z; } if (v.Z < box.Min.Z) { box.Min.Z = v.Z; } } //Add the corners. This will overestimate the size of the surface a bit. hullVertices.Add(box.Min); hullVertices.Add(box.Max); hullVertices.Add(new Vector3(box.Min.X, box.Min.Y, box.Max.Z)); hullVertices.Add(new Vector3(box.Min.X, box.Max.Y, box.Min.Z)); hullVertices.Add(new Vector3(box.Max.X, box.Min.Y, box.Min.Z)); hullVertices.Add(new Vector3(box.Min.X, box.Max.Y, box.Max.Z)); hullVertices.Add(new Vector3(box.Max.X, box.Max.Y, box.Min.Z)); hullVertices.Add(new Vector3(box.Max.X, box.Min.Y, box.Max.Z)); } }