예제 #1
0
        public override void Invalidate(bool polygonsChanged)
        {
            ////////////////////////////////////////////////////////////////////
            // a little hack to detect the user manually resizing the bounds. //
            // we use this to automatically add steps for barnaby.            //
            // it's probably good to build a more 'official' way to detect    //
            // user scaling events in compound brushes sometime.              //
            if (m_LastKnownExtents != localBounds.extents)                    //
            {                                                                 //
                // undo any position movement.                                //
                transform.localPosition = m_LastKnownPosition;                //
            }                                                                 //
            ////////////////////////////////////////////////////////////////////
            Bounds csgBounds = new Bounds();

            // nothing to do except copy csg information to our child brushes.
            if (!isDirty)
            {
                for (int i = 0; i < BrushCount; i++)
                {
                    generatedBrushes[i].Mode         = this.Mode;
                    generatedBrushes[i].IsNoCSG      = this.IsNoCSG;
                    generatedBrushes[i].IsVisible    = this.IsVisible;
                    generatedBrushes[i].HasCollision = this.HasCollision;
                    generatedBrushes[i].Invalidate(true);
                    csgBounds.Encapsulate(generatedBrushes[i].GetBounds());
                }
                // apply the generated csg bounds.
                localBounds         = csgBounds;
                m_LastKnownExtents  = localBounds.extents;
                m_LastKnownPosition = transform.localPosition;
                return;
            }

            base.Invalidate(polygonsChanged);
            isDirty = false;

            // build the polygons from the project.
            if (m_LastBuiltPolygons == null)
            {
                m_LastBuiltPolygons = BuildConvexPolygons();
            }

            // iterate through the brushes we received:
            int brushCount = BrushCount;

            // force nocsg when creating a flat polygon sheet as sabrecsg doesn't support it.
            if (extrudeMode == ExtrudeMode.CreatePolygon)
            {
                this.IsNoCSG = true;
            }

            for (int i = 0; i < brushCount; i++)
            {
                // copy our csg information to our child brushes.
                generatedBrushes[i].Mode         = this.Mode;
                generatedBrushes[i].IsNoCSG      = this.IsNoCSG;
                generatedBrushes[i].IsVisible    = this.IsVisible;
                generatedBrushes[i].HasCollision = this.HasCollision;

                // local variables.
                Quaternion rot;
                Polygon[]  outputPolygons;

                switch (extrudeMode)
                {
                // generate a flat 2d polygon.
                case ExtrudeMode.CreatePolygon:
                    GenerateNormals(m_LastBuiltPolygons[i]);
                    GenerateUvCoordinates(m_LastBuiltPolygons[i], false);
                    Polygon poly1 = m_LastBuiltPolygons[i].DeepCopy();
                    poly1.Flip();
                    generatedBrushes[i].SetPolygons(new Polygon[] { poly1 });
                    break;

                // generate 3d cube-ish shapes that revolve around the pivot.
                case ExtrudeMode.RevolveShape:
                    int labpIndex = i % m_LastBuiltPolygons.Count;

                    Polygon poly2 = m_LastBuiltPolygons[labpIndex].DeepCopy();
                    poly2.Flip();
                    GenerateUvCoordinates(poly2, false);
                    foreach (Vertex v in poly2.Vertices)
                    {
                        float step = 360.0f / project.revolve360;
                        v.Position = RotatePointAroundPivot(v.Position, new Vector3(((project.revolveDistance / 8.0f) * project.extrudeScale.x) + ((project.revolveRadius * project.extrudeScale.x) / 8.0f), 0.0f, 0.0f), new Vector3(0.0f, (project.revolveDirection ? 0 : 180) + ((i / m_LastBuiltPolygons.Count) * step), 0.0f));
                    }
                    Polygon nextPoly = m_LastBuiltPolygons[labpIndex].DeepCopy();
                    nextPoly.Flip();
                    foreach (Vertex v in nextPoly.Vertices)
                    {
                        float step = 360.0f / project.revolve360;
                        v.Position = RotatePointAroundPivot(v.Position, new Vector3(((project.revolveDistance / 8.0f) * project.extrudeScale.x) + ((project.revolveRadius * project.extrudeScale.x) / 8.0f), 0.0f, 0.0f), new Vector3(0.0f, (project.revolveDirection ? 0 : 180) + (((i / m_LastBuiltPolygons.Count) * step) + step), 0.0f));
                    }
                    GenerateNormals(poly2);
                    List <Polygon> polygons = new List <Polygon>()
                    {
                        poly2
                    };
                    List <Vertex> backPolyVertices = new List <Vertex>();
                    Edge[]        myEdges          = poly2.GetEdges();
                    Edge[]        nextEdges        = nextPoly.GetEdges();
                    for (int j = 0; j < myEdges.Length; j++)
                    {
                        Edge myEdge   = myEdges[j];
                        Edge nextEdge = nextEdges[j];

                        Polygon newPoly = new Polygon(new Vertex[] {
                            new Vertex(myEdge.Vertex1.Position, Vector3.zero, Vector2.zero),
                            new Vertex(nextEdge.Vertex1.Position, Vector3.zero, Vector2.zero),
                            new Vertex(nextEdge.Vertex2.Position, Vector3.zero, Vector2.zero),
                            new Vertex(myEdge.Vertex2.Position, Vector3.zero, Vector2.zero),
                        }, null, false, false);

                        backPolyVertices.Add(nextEdge.Vertex1);
                        GenerateNormals(newPoly);
                        if (newPoly.Plane.normal == Vector3.zero)
                        {
                            continue;                                           // discard single line, can happen in the center of the shape.
                        }
                        GenerateUvCoordinates(newPoly, false);
                        polygons.Add(newPoly);
                    }

                    Polygon backPoly = new Polygon(backPolyVertices.ToArray(), null, false, false);

                    backPoly.Flip();
                    GenerateNormals(backPoly);
                    GenerateUvCoordinates(backPoly, false);
                    polygons.Add(backPoly);

                    generatedBrushes[i].SetPolygons(polygons.ToArray());
                    break;

                // generate a 3d cube-ish shape.
                case ExtrudeMode.ExtrudeShape:
                    GenerateNormals(m_LastBuiltPolygons[i]);
                    SurfaceUtility.ExtrudePolygon(m_LastBuiltPolygons[i], project.extrudeDepth, out outputPolygons, out rot);
                    foreach (Polygon poly in outputPolygons)
                    {
                        GenerateUvCoordinates(poly, false);
                    }
                    generatedBrushes[i].SetPolygons(outputPolygons);
                    break;

                // generate a 3d cone-ish shape.
                case ExtrudeMode.ExtrudePoint:
                    GenerateNormals(m_LastBuiltPolygons[i]);
                    ExtrudePolygonToPoint(m_LastBuiltPolygons[i], project.extrudeDepth, new Vector2((project.globalPivot.position.x * project.extrudeScale.x) / 8.0f, -(project.globalPivot.position.y * project.extrudeScale.y) / 8.0f), out outputPolygons, out rot);
                    foreach (Polygon poly in outputPolygons)
                    {
                        GenerateUvCoordinates(poly, false);
                    }
                    generatedBrushes[i].SetPolygons(outputPolygons);
                    break;

                // generate a 3d trapezoid-ish shape.
                case ExtrudeMode.ExtrudeBevel:
                    GenerateNormals(m_LastBuiltPolygons[i]);
                    ExtrudePolygonBevel(m_LastBuiltPolygons[i], project.extrudeDepth, project.extrudeClipDepth / project.extrudeDepth, new Vector2((project.globalPivot.position.x * project.extrudeScale.x) / 8.0f, -(project.globalPivot.position.y * project.extrudeScale.y) / 8.0f), out outputPolygons, out rot);
                    foreach (Polygon poly in outputPolygons)
                    {
                        GenerateUvCoordinates(poly, false);
                    }
                    generatedBrushes[i].SetPolygons(outputPolygons);
                    break;
                }

                generatedBrushes[i].Invalidate(true);
                csgBounds.Encapsulate(generatedBrushes[i].GetBounds());
            }

            // apply the generated csg bounds.
            localBounds         = csgBounds;
            m_LastKnownExtents  = localBounds.extents;
            m_LastKnownPosition = transform.localPosition;
        }
예제 #2
0
        public override void Invalidate(bool polygonsChanged)
        {
            ////////////////////////////////////////////////////////////////////
            // a little hack to detect the user manually resizing the bounds. //
            // we use this to automatically add steps for barnaby.            //
            // it's probably good to build a more 'official' way to detect    //
            // user scaling events in compound brushes sometime.              //
            if (m_LastKnownExtents != localBounds.extents)                    //
            {                                                                 //
                // undo any position movement.                                //
                transform.localPosition = m_LastKnownPosition;                //
            }                                                                 //
            ////////////////////////////////////////////////////////////////////
            Bounds csgBounds = new Bounds();

            // force nocsg when creating a flat polygon sheet as sabrecsg doesn't support it.
            if (extrudeMode == ExtrudeMode.CreatePolygon)
            {
                this.IsNoCSG = true;
            }

            // force nocsg when revolving with a sloped spiral as there are non-planar polygons.
            if (extrudeMode == ExtrudeMode.RevolveShape && project.revolveSpiralSloped && project.globalPivot.position.y != 0)
            {
                this.IsNoCSG = true;
            }

            // nothing to do except copy csg information to our child brushes.
            if (!isDirty)
            {
                for (int i = 0; i < BrushCount; i++)
                {
                    generatedBrushes[i].Mode         = this.Mode;
                    generatedBrushes[i].IsNoCSG      = this.IsNoCSG;
                    generatedBrushes[i].IsVisible    = this.IsVisible;
                    generatedBrushes[i].HasCollision = this.HasCollision;
                    generatedBrushes[i].Invalidate(true);
                    csgBounds.Encapsulate(generatedBrushes[i].GetBounds());
                }
                // apply the generated csg bounds.
                localBounds         = csgBounds;
                m_LastKnownExtents  = localBounds.extents;
                m_LastKnownPosition = transform.localPosition;
                return;
            }

            base.Invalidate(polygonsChanged);
            isDirty = false;

            // build the polygons from the project.
            if (m_LastBuiltPolygons == null)
            {
                m_LastBuiltPolygons = BuildConvexPolygons();
            }

            // iterate through the brushes we received:
            int brushCount = BrushCount;

            for (int i = 0; i < brushCount; i++)
            {
                // copy our csg information to our child brushes.
                generatedBrushes[i].Mode         = this.Mode;
                generatedBrushes[i].IsNoCSG      = this.IsNoCSG;
                generatedBrushes[i].IsVisible    = this.IsVisible;
                generatedBrushes[i].HasCollision = this.HasCollision;

                // local variables.
                Quaternion rot;
                Polygon[]  outputPolygons;

                switch (extrudeMode)
                {
                // generate a flat 2d polygon.
                case ExtrudeMode.CreatePolygon:
                    GenerateNormals(m_LastBuiltPolygons[i]);
                    GenerateUvCoordinates(m_LastBuiltPolygons[i], false);
                    Polygon poly1 = m_LastBuiltPolygons[i].DeepCopy();
                    poly1.Flip();
                    generatedBrushes[i].SetPolygons(new Polygon[] { poly1 });
                    break;

                // generate 3d cube-ish shapes that revolve around the pivot and spirals up or down.
                case ExtrudeMode.RevolveShape:
                    float spiralHeight = ((((project.globalPivot.position.y * project.extrudeScale.y) / 8.0f) * (i / m_LastBuiltPolygons.Count)) / project.revolve360) * (project.revolve360 / project.revolveSteps);
                    float spiralStep   = ((((project.globalPivot.position.y * project.extrudeScale.y) / 8.0f)) / project.revolve360) * (project.revolve360 / project.revolveSteps);
                    int   labpIndex    = i % m_LastBuiltPolygons.Count;

                    Polygon poly2 = m_LastBuiltPolygons[labpIndex].DeepCopy();
                    poly2.Flip();
                    GenerateUvCoordinates(poly2, false);
                    foreach (Vertex v in poly2.Vertices)
                    {
                        float step = 360.0f / project.revolve360;
                        v.Position = new Vector3(0, -spiralHeight, 0) + RotatePointAroundPivot(v.Position, new Vector3(((project.revolveDistance / 8.0f) * project.extrudeScale.x) + ((project.revolveRadius * project.extrudeScale.x) / 8.0f), 0.0f, 0.0f), new Vector3(0.0f, ((i / m_LastBuiltPolygons.Count) * step), 0.0f));
                    }
                    GenerateNormals(poly2);

                    Polygon nextPoly = m_LastBuiltPolygons[labpIndex].DeepCopy();
                    nextPoly.Flip();
                    foreach (Vertex v in nextPoly.Vertices)
                    {
                        float step = 360.0f / project.revolve360;
                        v.Position = new Vector3(0, -spiralHeight - (project.revolveSpiralSloped ? spiralStep : 0), 0) + RotatePointAroundPivot(v.Position, new Vector3(((project.revolveDistance / 8.0f) * project.extrudeScale.x) + ((project.revolveRadius * project.extrudeScale.x) / 8.0f), 0.0f, 0.0f), new Vector3(0.0f, (((i / m_LastBuiltPolygons.Count) * step) + step), 0.0f));
                    }
                    List <Polygon> polygons = new List <Polygon>()
                    {
                        poly2
                    };
                    List <Vertex> backPolyVertices = new List <Vertex>();
                    Edge[]        myEdges          = poly2.GetEdges();
                    Edge[]        nextEdges        = nextPoly.GetEdges();
                    for (int j = 0; j < myEdges.Length; j++)
                    {
                        Edge myEdge   = myEdges[j];
                        Edge nextEdge = nextEdges[j];

                        Polygon newPoly = new Polygon(new Vertex[] {
                            new Vertex(myEdge.Vertex1.Position, Vector3.zero, Vector2.zero),
                            new Vertex(nextEdge.Vertex1.Position, Vector3.zero, Vector2.zero),
                            new Vertex(nextEdge.Vertex2.Position, Vector3.zero, Vector2.zero),
                            new Vertex(myEdge.Vertex2.Position, Vector3.zero, Vector2.zero),
                        }, null, false, false);

                        backPolyVertices.Add(nextEdge.Vertex1);
                        GenerateNormals(newPoly);
                        if (newPoly.Plane.normal == Vector3.zero)
                        {
                            continue;                                           // discard single line, can happen in the center of the shape.
                        }
                        GenerateUvCoordinates(newPoly, false);
                        polygons.Add(newPoly);
                    }

                    Polygon backPoly = new Polygon(backPolyVertices.ToArray(), null, false, false);

                    backPoly.Flip();
                    GenerateNormals(backPoly);
                    GenerateUvCoordinates(backPoly, false);
                    polygons.Add(backPoly);

                    generatedBrushes[i].SetPolygons(polygons.ToArray());
                    break;

                // generate a 3d cube-ish shape.
                case ExtrudeMode.ExtrudeShape:
                    GenerateNormals(m_LastBuiltPolygons[i]);
                    SurfaceUtility.ExtrudePolygon(m_LastBuiltPolygons[i], project.extrudeDepth, out outputPolygons, out rot);
                    foreach (Polygon poly in outputPolygons)
                    {
                        GenerateUvCoordinates(poly, false);
                    }
                    generatedBrushes[i].SetPolygons(outputPolygons);
                    break;

                // generate a 3d cone-ish shape.
                case ExtrudeMode.ExtrudePoint:
                    GenerateNormals(m_LastBuiltPolygons[i]);
                    ExtrudePolygonToPoint(m_LastBuiltPolygons[i], project.extrudeDepth, new Vector2((project.globalPivot.position.x * project.extrudeScale.x) / 8.0f, -(project.globalPivot.position.y * project.extrudeScale.y) / 8.0f), out outputPolygons, out rot);
                    foreach (Polygon poly in outputPolygons)
                    {
                        GenerateUvCoordinates(poly, false);
                    }
                    generatedBrushes[i].SetPolygons(outputPolygons);
                    break;

                // generate a 3d trapezoid-ish shape.
                case ExtrudeMode.ExtrudeBevel:
                    GenerateNormals(m_LastBuiltPolygons[i]);
                    ExtrudePolygonBevel(m_LastBuiltPolygons[i], project.extrudeDepth, project.extrudeClipDepth / project.extrudeDepth, new Vector2((project.globalPivot.position.x * project.extrudeScale.x) / 8.0f, -(project.globalPivot.position.y * project.extrudeScale.y) / 8.0f), out outputPolygons, out rot);
                    foreach (Polygon poly in outputPolygons)
                    {
                        GenerateUvCoordinates(poly, false);
                    }
                    generatedBrushes[i].SetPolygons(outputPolygons);
                    break;
                }

                // we invalidate every brush after hidden surface removal.
            }

            // we exclude hidden faces automatically.
            // this step will automatically optimize NoCSG output the same way additive brushes would have.
            // it also excludes a couple faces that CSG doesn't exclude due to floating point precision errors.
            // the latter is especially noticable with complex revolved shapes.

            // compare each brush to another brush:
            for (int i = 0; i < brushCount; i++)
            {
                for (int j = 0; j < brushCount; j++)
                {
                    // can't check for hidden faces on the same brush.
                    if (i == j)
                    {
                        continue;
                    }

                    // compare each polygon on brush i to each polygon on brush j:
                    foreach (Polygon pa in generatedBrushes[i].GetPolygons())
                    {
                        foreach (Polygon pb in generatedBrushes[j].GetPolygons())
                        {
                            // check they both have this polygon:
                            bool identical = true;
                            foreach (Vertex va in pa.Vertices)
                            {
                                if (!pb.Vertices.Any(vb => vb.Position == va.Position))
                                {
                                    identical = false;
                                    break;
                                }
                            }
                            // identical polygons on both brushes means it can be excluded:
                            if (identical)
                            {
                                pa.UserExcludeFromFinal = true;
                                pb.UserExcludeFromFinal = true;
                            }
                        }
                    }
                }

                // invalidate every brush.
                generatedBrushes[i].Invalidate(true);
                csgBounds.Encapsulate(generatedBrushes[i].GetBounds());
            }

            // apply the generated csg bounds.
            localBounds         = csgBounds;
            m_LastKnownExtents  = localBounds.extents;
            m_LastKnownPosition = transform.localPosition;
            // update the generated name in the hierarchy.
            UpdateGeneratedHierarchyName();
        }