示例#1
0
        internal static bool PolyhedronIntersectsLine(Polygon[] polygons, Vector3 lineStart, Vector3 lineEnd)
        {
            // Use two time values to represent the reduced line segment, at the start 0 represents lineStart and 1
            // represents lineEnd
            float timeStart = 0;
            float timeEnd   = 1f;

            Vector3 lineDelta = lineEnd - lineStart;

            for (int i = 0; i < polygons.Length; i++)
            {
                Plane plane = polygons[i].Plane;

                // Find the relation between the line and this polygon
                // Essentially we test the direction the line is moving in against the polygon's normal to see whether
                // the line is enterring or exiting through the polygon.

                float dot = Vector3.Dot(plane.normal, lineDelta);

                // Find the intersection time between the plane and the position
                // Note this essentially substitutes the line segment equation into the plane equation then makes t the
                // subject

                // Not sure why we have to flip time intersection's sign, probably to do with the pecularity of the way
                // Unity's Plane works
                float timeIntersection = -(Vector3.Dot(plane.normal, lineStart) + plane.distance) / dot;

                if (dot < 0) // Directions are opposing, must be enterring through the polygon
                {
                    if (timeIntersection > timeStart)
                    {
                        timeStart = timeIntersection;
                    }
                }
                else if (dot > 0) // Directions are similar, must be exiting through the polygon
                {
                    if (timeIntersection < timeEnd)
                    {
                        timeEnd = timeIntersection;
                    }
                }
                else // (dot == 0) directions are perpendicular, line is tangential to the polygon
                {
                    // Rather than just ignoring the perpendicular case, we instead test either of the points on the line
                    // against the plane, if it's outside the plane then the line is outside the polyhedron!
                    if (Polygon.ComparePointToPlane(lineStart, polygons[i].Plane) == Polygon.PointPlaneRelation.Behind)
                    {
                        return(false);
                    }
                }

                // No intersection has occurred
                if (timeEnd - timeStart <= 0)
                {
                    return(false);
                }
            }

            return(true);
        }
        public static bool SplitPolygonsByPlane(List <Polygon> polygons,        // Source polygons that will be split
                                                Plane splitPlane,
                                                bool excludeNewPolygons,        // Whether new polygons should be marked as excludeFromBuild
                                                out List <Polygon> polygonsFront,
                                                out List <Polygon> polygonsBack)
        {
            polygonsFront = new List <Polygon>();
            polygonsBack  = new List <Polygon>();

            // First of all make sure splitting actually needs to occur (we'll get bad issues if
            // we try splitting geometry when we don't need to)
            if (!PolygonsIntersectPlane(polygons, splitPlane))
            {
                return(false);
            }

            Material newMaterial = polygons[0].Material;

            // These are the vertices that will be used in the new caps
            List <Vertex> newVertices = new List <Vertex>();

            for (int polygonIndex = 0; polygonIndex < polygons.Count; polygonIndex++)
            {
                Polygon.PolygonPlaneRelation planeRelation = Polygon.TestPolygonAgainstPlane(polygons[polygonIndex], splitPlane);

                // Polygon has been found to span both sides of the plane, attempt to split into two pieces
                if (planeRelation == Polygon.PolygonPlaneRelation.Spanning)
                {
                    Polygon frontPolygon;
                    Polygon backPolygon;
                    Vertex  newVertex1;
                    Vertex  newVertex2;

                    // Attempt to split the polygon
                    if (Polygon.SplitPolygon(polygons[polygonIndex], out frontPolygon, out backPolygon, out newVertex1, out newVertex2, splitPlane))
                    {
                        // If the split algorithm was successful (produced two valid polygons) then add each polygon to
                        // their respective points and track the intersection points
                        polygonsFront.Add(frontPolygon);
                        polygonsBack.Add(backPolygon);

                        newVertices.Add(newVertex1);
                        newVertices.Add(newVertex2);

                        newMaterial = polygons[polygonIndex].Material;
                    }
                    else
                    {
                        // Two valid polygons weren't generated, so use the valid one
                        if (frontPolygon != null)
                        {
                            planeRelation = Polygon.PolygonPlaneRelation.InFront;
                        }
                        else if (backPolygon != null)
                        {
                            planeRelation = Polygon.PolygonPlaneRelation.Behind;
                        }
                        else
                        {
                            Debug.LogError("Polygon splitting has resulted in two zero area polygons. This is unhandled.");
                            //							Polygon.PolygonPlaneRelation secondplaneRelation = Polygon.TestPolygonAgainstPlane(polygons[polygonIndex], splitPlane);
                        }
                    }
                }

                // If the polygon is on one side of the plane or the other
                if (planeRelation != Polygon.PolygonPlaneRelation.Spanning)
                {
                    // Make sure any points that are coplanar on non-straddling polygons are still used in polygon
                    // construction
                    for (int vertexIndex = 0; vertexIndex < polygons[polygonIndex].Vertices.Length; vertexIndex++)
                    {
                        if (Polygon.ComparePointToPlane(polygons[polygonIndex].Vertices[vertexIndex].Position, splitPlane) == Polygon.PointPlaneRelation.On)
                        {
                            newVertices.Add(polygons[polygonIndex].Vertices[vertexIndex]);
                        }
                    }

                    if (planeRelation == Polygon.PolygonPlaneRelation.Behind)
                    {
                        polygonsBack.Add(polygons[polygonIndex]);
                    }
                    else
                    {
                        polygonsFront.Add(polygons[polygonIndex]);
                    }
                }
            }

            // If any splits occured or coplanar vertices are found. (For example if you're splitting a sphere at the
            // equator then no polygons will be split but there will be a bunch of coplanar vertices!)
            if (newVertices.Count > 0)
            {
                // HACK: This code is awful, because we end up with lots of duplicate vertices
                List <Vector3> positions = newVertices.Select(item => item.Position).ToList();

                Polygon newPolygon = PolygonFactory.ConstructPolygon(positions, true);

                // Assuming it was possible to create a polygon
                if (newPolygon != null)
                {
                    if (!MathHelper.PlaneEqualsLooser(newPolygon.Plane, splitPlane))
                    {
                        // Polygons are sometimes constructed facing the wrong way, possibly due to a winding order
                        // mismatch. If the two normals are opposite, flip the new polygon
                        if (Vector3.Dot(newPolygon.Plane.normal, splitPlane.normal) < -0.9f)
                        {
                            newPolygon.Flip();
                        }
                    }

                    newPolygon.ExcludeFromFinal = excludeNewPolygons;
                    newPolygon.Material         = newMaterial;

                    polygonsFront.Add(newPolygon);

                    newPolygon = newPolygon.DeepCopy();
                    newPolygon.Flip();

                    newPolygon.ExcludeFromFinal = excludeNewPolygons;
                    newPolygon.Material         = newMaterial;


                    if (newPolygon.Plane.normal == Vector3.zero)
                    {
                        Debug.LogError("Invalid Normal! Shouldn't be zero. This is unexpected since extraneous positions should have been removed!");
                        //						Polygon fooNewPolygon = PolygonFactory.ConstructPolygon(positions, true);
                    }

                    polygonsBack.Add(newPolygon);
                }
                return(true);
            }
            else
            {
                // It wasn't possible to create the polygon, for example the constructed polygon was too small
                // This could happen if you attempt to clip the tip off a long but thin brush, the plane-polyhedron test
                // would say they intersect but in reality the resulting polygon would be near zero area
                return(false);
            }
        }