예제 #1
0
        private static CollisionShape ExtractBox_Old(SubMesh subMesh)
        {
            if (DoLog)
            {
                Log("");
                Log(string.Format("Extracting box for submesh {0}", subMesh.Name));
            }
            MeshTriangle[] triangles = ExtractSubmeshTriangles(subMesh);
            int            count     = triangles.Length;

            Plane[] planesUnsorted = new Plane[6];
            int     planeCount     = 0;

            // Iterate through the triangles.  For each triangle,
            // determine the plane it belongs to, and find the plane
            // in the array of planes, or if it's not found, add it.
            for (int i = 0; i < count; i++)
            {
                MeshTriangle t     = triangles[i];
                bool         found = false;
                Plane        p     = new Plane(t.vertPos[0], t.vertPos[1], t.vertPos[2]);
                NormalizePlane(ref p);
                if (DoLog)
                {
                    Log(string.Format(" {0} => plane {1}", t.ToString(), p.ToString()));
                }
                for (int j = 0; j < planeCount; j++)
                {
                    Plane pj = planesUnsorted[j];
                    if (SamePlane(pj, p))
                    {
                        if (DoLog)
                        {
                            Log(string.Format(" plane {0} same as plane {1}", p.ToString(), pj.ToString()));
                        }
                        found = true;
                        break;
                    }
                }
                if (!found)
                {
                    if (planeCount < 6)
                    {
                        if (DoLog)
                        {
                            Log(string.Format(" plane[{0}] = plane {1}", planeCount, p.ToString()));
                        }
                        planesUnsorted[planeCount++] = p;
                    }
                    else
                    {
                        Debug.Assert(false,
                                     string.Format("In the definition of box {0}, more than 6 planes were found",
                                                   subMesh.Name));
                    }
                }
            }
            Debug.Assert(planeCount == 6,
                         string.Format("In the definition of box {0}, fewer than 6 planes were found",
                                       subMesh.Name));
            // Now recreate the planes array, making sure that
            // opposite faces are 3 planes apart
            Plane[] planes    = new Plane[6];
            bool[]  planeUsed = new bool[6];
            for (int i = 0; i < 6; i++)
            {
                planeUsed[i] = false;
            }
            int planePair = 0;

            for (int i = 0; i < 6; i++)
            {
                if (!planeUsed[i])
                {
                    Plane p1 = planesUnsorted[i];
                    planes[planePair] = p1;
                    planeUsed[i]      = true;
                    for (int j = 0; j < 6; j++)
                    {
                        Plane p2 = planesUnsorted[j];
                        if (!planeUsed[j] && !Orthogonal(p2, p1))
                        {
                            planes[3 + planePair++] = p2;
                            planeUsed[j]            = true;
                            break;
                        }
                    }
                }
            }
            Debug.Assert(planePair == 3, "Didn't find 3 pairs of parallel planes");
            // Make sure that the sequence of planes follows the
            // right-hand rule
            if (planes[0].Normal.Cross(planes[1].Normal).Dot(planes[3].Normal) < 0)
            {
                // Swap the first two plane pairs
                Plane p = planes[0];
                planes[0]     = planes[1];
                planes[1]     = p;
                p             = planes[0 + 3];
                planes[0 + 3] = planes[1 + 3];
                planes[1 + 3] = p;
                Debug.Assert(planes[0].Normal.Cross(planes[1].Normal).Dot(planes[3].Normal) > 0,
                             "Even after swapping, planes don't obey the right-hand rule");
            }
            // Now we have our 6 planes, sorted so that opposite
            // planes are 3 planes apart, and so they obey the
            // right-hand rule.  This guarantees that corners
            // correspond.  Find the 8 intersections that define the
            // corners.
            Vector3[] corners     = new Vector3[8];
            int       cornerCount = 0;

            for (int i = 0; i <= 3; i += 3)
            {
                Plane p1 = planes[i];
                for (int j = 1; j <= 4; j += 3)
                {
                    Plane p2 = planes[j];
                    for (int k = 2; k <= 5; k += 3)
                    {
                        Plane   p3     = planes[k];
                        Vector3 corner = -1 * ((p1.D * (p2.Normal.Cross(p3.Normal)) +
                                                p2.D * (p3.Normal.Cross(p1.Normal)) +
                                                p3.D * (p1.Normal.Cross(p2.Normal))) /
                                               p1.Normal.Dot(p2.Normal.Cross(p3.Normal)));
                        Debug.Assert(cornerCount < 8,
                                     string.Format("In the definition of box {0}, more than 8 corners were found",
                                                   subMesh.Name));
                        if (DoLog)
                        {
                            Log(string.Format("  corner#{0}: {1}", cornerCount, corner.ToString()));
                        }
                        corners[cornerCount++] = corner;
                    }
                }
            }
            Debug.Assert(cornerCount == 8,
                         string.Format("In the definition of box {0}, fewer than 8 corners were found",
                                       subMesh.Name));
            // We know that corners correspond.  Now find the center
            Vector3 center = (corners[0] + corners[7]) / 2;

            Debug.Assert((center - (corners[1] + corners[5]) / 2.0f).Length > geometryEpsilon ||
                         (center - (corners[2] + corners[6]) / 2.0f).Length > geometryEpsilon ||
                         (center - (corners[3] + corners[7]) / 2.0f).Length > geometryEpsilon,
                         string.Format("In the definition of box {0}, center definition {0} is not consistent",
                                       subMesh.Name, center.ToString()));
            // Find the extents
            Vector3 extents = new Vector3(Math.Abs((corners[1] - corners[0]).Length / 2.0f),
                                          Math.Abs((corners[3] - corners[1]).Length / 2.0f),
                                          Math.Abs((corners[4] - corners[0]).Length / 2.0f));

            if (DoLog)
            {
                Log(string.Format(" extents {0}", extents.ToString()));
            }
            // Find the axes
            Vector3[] axes = new Vector3[3] {
                (corners[1] - corners[0]).ToNormalized(),
                (corners[3] - corners[1]).ToNormalized(),
                (corners[4] - corners[0]).ToNormalized()
            };
            if (DoLog)
            {
                for (int i = 0; i < 3; i++)
                {
                    Log(string.Format(" axis[{0}] {1}", i, axes[i]));
                }
            }
            // Now, is it an obb or an aabb?  Figure out if the axes
            // point in the same direction as the basis vectors, and
            // if so, the order of the axes
            int[] mapping = new int[3] {
                -1, -1, -1
            };
            int foundMapping = 0;

            for (int i = 0; i < 3; i++)
            {
                for (int j = 0; j < 3; j++)
                {
                    if (axes[i].Cross(Primitives.UnitBasisVectors[j]).Length < geometryEpsilon)
                    {
                        mapping[i] = j;
                        foundMapping++;
                        break;
                    }
                }
            }
            CollisionShape shape;

            if (foundMapping == 3)
            {
                // It's an AABB, so build the min and max vectors, in
                // the order that matches the unit basis vector order
                Vector3 min = Vector3.Zero;
                Vector3 max = Vector3.Zero;
                for (int i = 0; i < 3; i++)
                {
                    float e = extents[i];
                    int   j = mapping[i];
                    min[j] = center[j] - e;
                    max[j] = center[j] + e;
                }
                shape = new CollisionAABB(min, max);
            }
            else
            {
                Vector3 ruleTest = axes[0].Cross(axes[1]);
                if (axes[2].Dot(ruleTest) < 0)
                {
                    axes[2] = -1 * axes[2];
                }
                // Return the OBB
                shape = new CollisionOBB(center, axes, extents);
            }
            if (DoLog)
            {
                Log(string.Format("Extraction result: {0}", shape));
            }
            return(shape);
        }