public static void ExtrudePolygonOld(Polygon sourcePolygon, out Polygon[] outputPolygons, out Quaternion rotation)
        {
            float extrusionDistance = 1;

            Polygon newPolygon = sourcePolygon.DeepCopy();

            newPolygon.UniqueIndex = -1;
            newPolygon.Flip();

            Vector3 normal = sourcePolygon.Plane.normal;

            Polygon oppositePolygon = sourcePolygon.DeepCopy();

            oppositePolygon.UniqueIndex = -1;

            Vertex[] vertices = oppositePolygon.Vertices;
            for (int i = 0; i < vertices.Length; i++)
            {
                vertices[i].Position += normal;
            }
            oppositePolygon.SetVertices(vertices);

            Polygon[] brushSides = new Polygon[sourcePolygon.Vertices.Length];

            for (int i = 0; i < newPolygon.Vertices.Length; i++)
            {
                Vertex vertex1 = newPolygon.Vertices[i].DeepCopy();
                Vertex vertex2 = newPolygon.Vertices[(i + 1) % newPolygon.Vertices.Length].DeepCopy();

                Vector2 uvDelta = vertex2.UV - vertex1.UV;

                float sourceDistance = Vector3.Distance(vertex1.Position, vertex2.Position);

                Vector2 rotatedUVDelta = uvDelta.Rotate(90) * (extrusionDistance / sourceDistance);

                Vertex vertex3 = vertex1.DeepCopy();
                vertex3.Position += normal * extrusionDistance;
                vertex3.UV       += rotatedUVDelta;

                Vertex vertex4 = vertex2.DeepCopy();
                vertex4.Position += normal * extrusionDistance;
                vertex4.UV       += rotatedUVDelta;

                Vertex[] newVertices = new Vertex[] { vertex1, vertex2, vertex4, vertex3 };

                brushSides[i] = new Polygon(newVertices, sourcePolygon.Material, false, false);
                brushSides[i].Flip();
                brushSides[i].ResetVertexNormals();
            }

            List <Polygon> polygons = new List <Polygon>();

            polygons.Add(newPolygon);
            polygons.Add(oppositePolygon);
            polygons.AddRange(brushSides);

            outputPolygons = polygons.ToArray();
            rotation       = Quaternion.identity;
        }
        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);
            }
        }
Example #3
0
        internal List <Polygon> ProvideSubtractChunks(List <BrushChunk> subtractChunks)
        {
            List <Polygon> damagedPolygons = new List <Polygon>();

            List <Polygon> addedPolygons = new List <Polygon>();

            // If this chunk knows about any split planes
//			if(splitPlanes.Count > 0)
            {
                // For each of the subtract chunks
                int subtractChunkCount = subtractChunks.Count;
                for (int chunkIndex = 0; chunkIndex < subtractChunkCount; chunkIndex++)
                {
                    int polygonCount = subtractChunks[chunkIndex].Polygons.Count;
                    // For each of the polygons within those subtract chunks
                    for (int j = 0; j < polygonCount; j++)
                    {
                        Polygon polygon = subtractChunks[chunkIndex].Polygons[j];

                        // Disregard any polygons that can't be displayed as final geometry
                        if (polygon.ExcludeFromFinal)
                        {
                            continue;
                        }

                        Plane polygonPlane = polygon.CachedPlaneTest;

                        // Determine if any of the split planes this chunk has been split against match any of those
                        // subtraction polygons
                        bool anyFound = false;


                        int   polygonsCount = polygons.Count;
                        Plane splitPlane;
                        for (int i = 0; i < polygonsCount; i++)
                        {
                            if (!polygons[i].ExcludeFromFinal)
                            {
                                continue;
                            }

                            splitPlane = polygons[i].CachedPlaneTest;

                            if (MathHelper.PlaneEqualsLooserWithFlip(polygonPlane, splitPlane))
                            {
                                anyFound = true;
                                break;
                            }
                        }

                        bool added = false;
                        if (anyFound)
                        {
                            // TODO: Is GetCenterPoint expensive?
                            Vector3 target = polygon.GetCenterPoint();
                            // If this brush chunk contains the subtraction polygon
                            // TODO: This is a heftly call a lot of the time, so see about optimising
                            if (GeometryHelper.PolyhedronContainsPointEpsilon3(this.polygons, target))
                            {
                                added = true;
                                // Duplicate the subtraction polygon
                                polygon = polygon.DeepCopy();


                                // Flip it, so that it can form outer geometry
                                polygon.Flip();
//
//
                                for (int i = 0; i < this.polygons.Count; i++)
                                {
                                    if (!this.polygons[i].ExcludeFromFinal && MathHelper.PlaneEqualsLooser(this.polygons[i].Plane, polygon.Plane))
                                    {
                                        if (!addedPolygons.Contains(this.polygons[i]))
                                        {
                                            //Debug.LogWarning("Removing duplicate from chunk " + this.uniqueID + " subtraction chunk " + subtractChunks[chunkIndex].UniqueID);
                                            polygons[i].ExcludeFromFinal = true;
                                        }
                                    }
                                }

                                // Add it to this brush chunk
                                polygons.Add(polygon);

                                addedPolygons.Add(polygon);
                            }
                        }

                        if (!added)
                        {
                            damagedPolygons.Add(polygon);
                        }
                    }
                }
            }

            return(damagedPolygons);
        }
Example #4
0
        private void CreateBrush(List <Vector3> positions)
        {
            Polygon sourcePolygon = PolygonFactory.ConstructPolygon(positions, true);

            // Early out if it wasn't possible to create the polygon
            if (sourcePolygon == null)
            {
                return;
            }

            if (activePolygon != null)
            {
                for (int i = 0; i < sourcePolygon.Vertices.Length; i++)
                {
                    Vector2 newUV = GeometryHelper.GetUVForPosition(activePolygon, sourcePolygon.Vertices[i].Position);
                    sourcePolygon.Vertices[i].UV = newUV;
                }
            }

            Vector3 planeNormal = GetActivePlane().normal;

            //			Debug.Log(Vector3.Dot(sourcePolygon.Plane.normal, planeNormal));

            // Flip the polygon if the winding order is wrong
            if (Vector3.Dot(sourcePolygon.Plane.normal, planeNormal) < 0)
            {
                sourcePolygon.Flip();

                // Need to flip the UVs across the U (X) direction
                for (int i = 0; i < sourcePolygon.Vertices.Length; i++)
                {
                    Vector2 uv = sourcePolygon.Vertices[i].UV;
                    uv.x = 1 - uv.x;
                    sourcePolygon.Vertices[i].UV = uv;
                }
            }

            float   extrusionDistance = 1;
            Vector3 positionOffset    = Vector3.zero;

            if (selectingHeight)
            {
                extrusionDistance = prismHeight;
            }
            else
            {
                if (activePolygon != null && activeBrush != null)
                {
                    extrusionDistance = activeBrush.CalculateExtentsInAxis(planeNormal);
                }
                else
                {
                    Brush lastSelectedBrush = csgModel.LastSelectedBrush;
                    if (lastSelectedBrush != null)
                    {
                        Bounds lastSelectedBrushBounds = lastSelectedBrush.GetBoundsTransformed();

                        for (int i = 0; i < 3; i++)
                        {
                            if (!planeNormal[i].EqualsWithEpsilon(0))
                            {
                                if (lastSelectedBrushBounds.size[i] != 0)
                                {
                                    extrusionDistance = lastSelectedBrushBounds.size[i];

                                    if (planeNormal[i] > 0)
                                    {
                                        positionOffset[i] = lastSelectedBrushBounds.center[i] - lastSelectedBrushBounds.extents[i];
                                    }
                                    else
                                    {
                                        positionOffset[i] = lastSelectedBrushBounds.center[i] + lastSelectedBrushBounds.extents[i];
                                    }
                                }
                            }
                        }
                    }
                }

                // Subtractions should go through
                if (csgMode == CSGMode.Subtract)
                {
                    sourcePolygon.Flip();
                }
            }

            Quaternion rotation;

            Polygon[] polygons;
            SurfaceUtility.ExtrudePolygon(sourcePolygon, extrusionDistance, out polygons, out rotation);

            GameObject newObject = csgModel.CreateCustomBrush(polygons);

            PrimitiveBrush newBrush = newObject.GetComponent <PrimitiveBrush>();

            newObject.transform.rotation  = rotation;
            newObject.transform.position += positionOffset;

            if (activePolygon != null &&
                activePolygon.Material != csgModel.GetDefaultMaterial())
            {
                for (int i = 0; i < polygons.Length; i++)
                {
                    polygons[i].Material = activePolygon.Material;
                }
            }
            // Finally give the new brush the other set of polygons
            newBrush.SetPolygons(polygons, true);

            newBrush.Mode = csgMode;

            newBrush.ResetPivot();

            // Use this brush as the basis for drawing the next brush
            csgModel.SetLastSelectedBrush(newBrush);

            Undo.RegisterCreatedObjectUndo(newObject, "Draw Brush");
        }
        public static void ExtrudePolygon(Polygon sourcePolygon, out Polygon[] outputPolygons, out Quaternion rotation)
        {
            float extrusionDistance = 1;

            Polygon basePolygon = sourcePolygon.DeepCopy();

            basePolygon.UniqueIndex = -1;

            rotation = Quaternion.LookRotation(basePolygon.Plane.normal);
            Quaternion cancellingRotation = Quaternion.Inverse(rotation);

            Vertex[] vertices = basePolygon.Vertices;
//			Vector3 offsetPosition = vertices[0].Position;

            for (int i = 0; i < vertices.Length; i++)
            {
//				vertices[i].Position -= offsetPosition;
                vertices[i].Position = cancellingRotation * vertices[i].Position;

                vertices[i].Normal = cancellingRotation * vertices[i].Normal;
            }

//			Vector3 newOffsetPosition = vertices[0].Position;
//			Vector3 delta = newOffsetPosition - offsetPosition;
//			for (int i = 0; i < vertices.Length; i++)
//			{
//				vertices[i].Position += delta;
//			}

            basePolygon.SetVertices(vertices);

            Vector3 normal          = basePolygon.Plane.normal;
            Polygon oppositePolygon = basePolygon.DeepCopy();

            oppositePolygon.UniqueIndex = -1;

            basePolygon.Flip();

            vertices = oppositePolygon.Vertices;
            for (int i = 0; i < vertices.Length; i++)
            {
                vertices[i].Position += normal;
            }
            oppositePolygon.SetVertices(vertices);

            Polygon[] brushSides = new Polygon[sourcePolygon.Vertices.Length];

            for (int i = 0; i < basePolygon.Vertices.Length; i++)
            {
                Vertex vertex1 = basePolygon.Vertices[i].DeepCopy();
                Vertex vertex2 = basePolygon.Vertices[(i + 1) % basePolygon.Vertices.Length].DeepCopy();

                Vector2 uvDelta = vertex2.UV - vertex1.UV;

                float sourceDistance = Vector3.Distance(vertex1.Position, vertex2.Position);

                Vector2 rotatedUVDelta = uvDelta.Rotate(90) * (extrusionDistance / sourceDistance);

                Vertex vertex3 = vertex1.DeepCopy();
                vertex3.Position += normal * extrusionDistance;
                vertex3.UV       += rotatedUVDelta;

                Vertex vertex4 = vertex2.DeepCopy();
                vertex4.Position += normal * extrusionDistance;
                vertex4.UV       += rotatedUVDelta;

                Vertex[] newVertices = new Vertex[] { vertex1, vertex2, vertex4, vertex3 };

                brushSides[i] = new Polygon(newVertices, sourcePolygon.Material, false, false);
                brushSides[i].Flip();
                brushSides[i].ResetVertexNormals();
            }

            List <Polygon> polygons = new List <Polygon>();

            polygons.Add(basePolygon);
            polygons.Add(oppositePolygon);
            polygons.AddRange(brushSides);

            outputPolygons = polygons.ToArray();
        }
Example #6
0
        /// <summary>
        /// Creates a brush by extruding a supplied polygon by a specified extrusion distance.
        /// </summary>
        /// <param name="sourcePolygon">Source polygon, typically transformed into world space.</param>
        /// <param name="extrusionDistance">Extrusion distance, this is the height (or depth) of the created geometry perpendicular to the source polygon.</param>
        /// <param name="outputPolygons">Output brush polygons.</param>
        /// <param name="rotation">The rotation to be supplied to the new brush transform.</param>
        public static void ExtrudePolygon(Polygon sourcePolygon, float extrusionDistance, out Polygon[] outputPolygons, out Quaternion rotation)
        {
            bool flipped = false;

            if (extrusionDistance < 0)
            {
                sourcePolygon.Flip();
                extrusionDistance = -extrusionDistance;
                flipped           = true;
            }

            // Create base polygon
            Polygon basePolygon = sourcePolygon.DeepCopy();

            basePolygon.UniqueIndex = -1;

            rotation = Quaternion.LookRotation(basePolygon.Plane.normal);
            Quaternion cancellingRotation = Quaternion.Inverse(rotation);

            Vertex[] vertices = basePolygon.Vertices;

            for (int i = 0; i < vertices.Length; i++)
            {
                vertices[i].Position = cancellingRotation * vertices[i].Position;

                vertices[i].Normal = cancellingRotation * vertices[i].Normal;
            }

            basePolygon.SetVertices(vertices);

            // Create the opposite polygon by duplicating the base polygon, offsetting and flipping
            Vector3 normal          = basePolygon.Plane.normal;
            Polygon oppositePolygon = basePolygon.DeepCopy();

            oppositePolygon.UniqueIndex = -1;

            basePolygon.Flip();

            vertices = oppositePolygon.Vertices;
            for (int i = 0; i < vertices.Length; i++)
            {
                vertices[i].Position += normal * extrusionDistance;
//				vertices[i].UV.x *= -1; // Flip UVs
            }
            oppositePolygon.SetVertices(vertices);

            // Now create each of the brush side polygons
            Polygon[] brushSides = new Polygon[sourcePolygon.Vertices.Length];

            for (int i = 0; i < basePolygon.Vertices.Length; i++)
            {
                Vertex vertex1 = basePolygon.Vertices[i].DeepCopy();
                Vertex vertex2 = basePolygon.Vertices[(i + 1) % basePolygon.Vertices.Length].DeepCopy();

                // Create new UVs for the sides, otherwise we'll get distortion

                float sourceDistance = Vector3.Distance(vertex1.Position, vertex2.Position);
                float uvDistance     = Vector2.Distance(vertex1.UV, vertex2.UV);

                float uvScale = sourceDistance / uvDistance;

                vertex1.UV = Vector2.zero;
                if (flipped)
                {
                    vertex2.UV = new Vector2(-sourceDistance / uvScale, 0);
                }
                else
                {
                    vertex2.UV = new Vector2(sourceDistance / uvScale, 0);
                }

                Vector2 uvDelta = vertex2.UV - vertex1.UV;

                Vector2 rotatedUVDelta = uvDelta.Rotate(90) * (extrusionDistance / sourceDistance);

                Vertex vertex3 = vertex1.DeepCopy();
                vertex3.Position += normal * extrusionDistance;
                vertex3.UV       += rotatedUVDelta;

                Vertex vertex4 = vertex2.DeepCopy();
                vertex4.Position += normal * extrusionDistance;
                vertex4.UV       += rotatedUVDelta;

                Vertex[] newVertices = new Vertex[] { vertex1, vertex2, vertex4, vertex3 };

                brushSides[i] = new Polygon(newVertices, sourcePolygon.Material, false, false);
                brushSides[i].Flip();
                brushSides[i].ResetVertexNormals();
            }

            List <Polygon> polygons = new List <Polygon>();

            polygons.Add(basePolygon);
            polygons.Add(oppositePolygon);
            polygons.AddRange(brushSides);

            outputPolygons = polygons.ToArray();
        }