GetTriangle() public method

Gets the triangle vertex positions at a given index.
public GetTriangle ( int triangleIndex, Vector3 &v1, Vector3 &v2, Vector3 &v3 ) : void
triangleIndex int First index of a triangle's vertices in the index buffer.
v1 Vector3 First vertex of the triangle.
v2 Vector3 Second vertex of the triangle.
v3 Vector3 Third vertex of the triangle.
return void
        void ComputeShapeInformation(TransformableMeshData data, out ShapeDistributionInformation shapeInformation)
        {
            var indices = Resources.GetIntList();
            surfaceVertices.Clear();
            Toolbox.GetConvexHull(data.vertices, indices, surfaceVertices);
            for (int i = 0; i < surfaceVertices.count; i++)
            {
                AffineTransform.Transform(ref surfaceVertices.Elements[i], ref data.worldTransform, out surfaceVertices.Elements[i]);
            }
            shapeInformation.Center = new Vector3();

            if (solidity == MobileMeshSolidity.Solid)
            {

                //The following inertia tensor calculation assumes a closed mesh.

                shapeInformation.Volume = 0;
                for (int i = 0; i < data.indices.Length; i += 3)
                {
                    Vector3 v2, v3, v4;
                    data.GetTriangle(i, out v2, out v3, out v4);

                    //Determinant is 6 * volume.  It's signed, though; this is because the mesh isn't necessarily convex nor centered on the origin.
                    float tetrahedronVolume = v2.X * (v3.Y * v4.Z - v3.Z * v4.Y) -
                                              v3.X * (v2.Y * v4.Z - v2.Z * v4.Y) +
                                              v4.X * (v2.Y * v3.Z - v2.Z * v3.Y);

                    shapeInformation.Volume += tetrahedronVolume;
                    shapeInformation.Center += tetrahedronVolume * (v2 + v3 + v4);
                }
                shapeInformation.Center /= shapeInformation.Volume * 4;
                shapeInformation.Volume /= 6;
                shapeInformation.Volume = Math.Abs(shapeInformation.Volume);

                data.worldTransform.Translation -= shapeInformation.Center;

                //Source: Explicit Exact Formulas for the 3-D Tetrahedron Inertia Tensor in Terms of its Vertex Coordinates
                //http://www.scipub.org/fulltext/jms2/jms2118-11.pdf
                //x1, x2, x3, x4 are origin, triangle1, triangle2, triangle3
                //Looking to find inertia tensor matrix of the form
                // [  a  -b' -c' ]
                // [ -b'  b  -a' ]
                // [ -c' -a'  c  ]
                float a = 0, b = 0, c = 0, ao = 0, bo = 0, co = 0;

                float totalWeight = 0;
                for (int i = 0; i < data.indices.Length; i += 3)
                {
                    Vector3 v2, v3, v4;
                    data.GetTriangle(i, out v2, out v3, out v4);

                    //Determinant is 6 * volume.  It's signed, though; this is because the mesh isn't necessarily convex nor centered on the origin.
                    float tetrahedronVolume = v2.X * (v3.Y * v4.Z - v3.Z * v4.Y) -
                                              v3.X * (v2.Y * v4.Z - v2.Z * v4.Y) +
                                              v4.X * (v2.Y * v3.Z - v2.Z * v3.Y);

                    totalWeight += tetrahedronVolume;

                    a += tetrahedronVolume * (v2.Y * v2.Y + v2.Y * v3.Y + v3.Y * v3.Y + v2.Y * v4.Y + v3.Y * v4.Y + v4.Y * v4.Y +
                                              v2.Z * v2.Z + v2.Z * v3.Z + v3.Z * v3.Z + v2.Z * v4.Z + v3.Z * v4.Z + v4.Z * v4.Z);
                    b += tetrahedronVolume * (v2.X * v2.X + v2.X * v3.X + v3.X * v3.X + v2.X * v4.X + v3.X * v4.X + v4.X * v4.X +
                                              v2.Z * v2.Z + v2.Z * v3.Z + v3.Z * v3.Z + v2.Z * v4.Z + v3.Z * v4.Z + v4.Z * v4.Z);
                    c += tetrahedronVolume * (v2.X * v2.X + v2.X * v3.X + v3.X * v3.X + v2.X * v4.X + v3.X * v4.X + v4.X * v4.X +
                                              v2.Y * v2.Y + v2.Y * v3.Y + v3.Y * v3.Y + v2.Y * v4.Y + v3.Y * v4.Y + v4.Y * v4.Y);
                    ao += tetrahedronVolume * (2 * v2.Y * v2.Z + v3.Y * v2.Z + v4.Y * v2.Z + v2.Y * v3.Z + 2 * v3.Y * v3.Z + v4.Y * v3.Z + v2.Y * v4.Z + v3.Y * v4.Z + 2 * v4.Y * v4.Z);
                    bo += tetrahedronVolume * (2 * v2.X * v2.Z + v3.X * v2.Z + v4.X * v2.Z + v2.X * v3.Z + 2 * v3.X * v3.Z + v4.X * v3.Z + v2.X * v4.Z + v3.X * v4.Z + 2 * v4.X * v4.Z);
                    co += tetrahedronVolume * (2 * v2.X * v2.Y + v3.X * v2.Y + v4.X * v2.Y + v2.X * v3.Y + 2 * v3.X * v3.Y + v4.X * v3.Y + v2.X * v4.Y + v3.X * v4.Y + 2 * v4.X * v4.Y);
                }
                float density = 1 / totalWeight;
                float diagonalFactor = density / 10;
                float offFactor = -density / 20;
                a *= diagonalFactor;
                b *= diagonalFactor;
                c *= diagonalFactor;
                ao *= offFactor;
                bo *= offFactor;
                co *= offFactor;
                shapeInformation.VolumeDistribution = new Matrix3X3(a, bo, co,
                                                                    bo, b, ao,
                                                                    co, ao, c);


            }
            else
            {
                shapeInformation.Center = new Vector3();
                float totalWeight = 0;
                for (int i = 0; i < data.indices.Length; i += 3)
                { //Configure the inertia tensor to be local.
                    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);
                    float weight = cross.Length();
                    totalWeight += weight;

                    shapeInformation.Center += weight * (vA + vB + vC) / 3;


                }
                shapeInformation.Center /= totalWeight;
                shapeInformation.Volume = 0;


                data.worldTransform.Translation -= shapeInformation.Center;

                shapeInformation.VolumeDistribution = new Matrix3X3();
                for (int i = 0; i < data.indices.Length; i += 3)
                { //Configure the inertia tensor to be local.
                    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);
                    float weight = cross.Length();
                    totalWeight += weight;

                    Matrix3X3 innerProduct;
                    Matrix3X3.CreateScale(vA.LengthSquared(), out innerProduct);
                    Matrix3X3 outerProduct;
                    Matrix3X3.CreateOuterProduct(ref vA, ref vA, out outerProduct);
                    Matrix3X3 contribution;
                    Matrix3X3.Subtract(ref innerProduct, ref outerProduct, out contribution);
                    Matrix3X3.Multiply(ref contribution, weight, out contribution);
                    Matrix3X3.Add(ref shapeInformation.VolumeDistribution, ref contribution, out shapeInformation.VolumeDistribution);

                    Matrix3X3.CreateScale(vB.LengthSquared(), out innerProduct);
                    Matrix3X3.CreateOuterProduct(ref vB, ref vB, out outerProduct);
                    Matrix3X3.Subtract(ref innerProduct, ref outerProduct, out outerProduct);
                    Matrix3X3.Multiply(ref contribution, weight, out contribution);
                    Matrix3X3.Add(ref shapeInformation.VolumeDistribution, ref contribution, out shapeInformation.VolumeDistribution);

                    Matrix3X3.CreateScale(vC.LengthSquared(), out innerProduct);
                    Matrix3X3.CreateOuterProduct(ref vC, ref vC, out outerProduct);
                    Matrix3X3.Subtract(ref innerProduct, ref outerProduct, out contribution);
                    Matrix3X3.Multiply(ref contribution, weight, out contribution);
                    Matrix3X3.Add(ref shapeInformation.VolumeDistribution, ref contribution, out shapeInformation.VolumeDistribution);

                }
                Matrix3X3.Multiply(ref shapeInformation.VolumeDistribution, 1 / (6 * totalWeight), out shapeInformation.VolumeDistribution);
            }

            ////Configure the inertia tensor to be local.
            //Vector3 finalOffset = shapeInformation.Center;
            //Matrix3X3 finalInnerProduct;
            //Matrix3X3.CreateScale(finalOffset.LengthSquared(), out finalInnerProduct);
            //Matrix3X3 finalOuterProduct;
            //Matrix3X3.CreateOuterProduct(ref finalOffset, ref finalOffset, out finalOuterProduct);

            //Matrix3X3 finalContribution;
            //Matrix3X3.Subtract(ref finalInnerProduct, ref finalOuterProduct, out finalContribution);

            //Matrix3X3.Subtract(ref shapeInformation.VolumeDistribution, ref finalContribution, out shapeInformation.VolumeDistribution);
        }
Beispiel #2
0
        /// <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 > 0)
                    return shapeInformation;
                throw new ArgumentException("A solid mesh must have volume.");
            }
            shapeInformation.Center = new Vector3();
            shapeInformation.VolumeDistribution = new Matrix3x3();
            float totalWeight = 0;
            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);
                float weight = cross.Length();
                totalWeight += weight;

                float perVertexWeight = weight * (1f / 3f);
				Vector3 tmp;
				vA.Add2( ref vB, ref vC, out tmp );
                shapeInformation.Center.AddScaled( ref tmp, perVertexWeight, out shapeInformation.Center );

                //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.Mult( 1/totalWeight, out shapeInformation.Center );

            //The extra factor of 2 is used because the cross product length was twice the actual area.
            Matrix3x3.Multiply(ref shapeInformation.VolumeDistribution, 1 / (2 * totalWeight), out shapeInformation.VolumeDistribution);

            //Move the inertia tensor into position according to the center.
            Matrix3x3 additionalInertia;
            InertiaHelper.GetPointContribution(0.5f, ref Toolbox.ZeroVector, ref shapeInformation.Center, out additionalInertia);
            Matrix3x3.Subtract(ref shapeInformation.VolumeDistribution, ref additionalInertia, out shapeInformation.VolumeDistribution);

            shapeInformation.Volume = 0;


            return shapeInformation;
        }