示例#1
0
    /// <summary>
    /// Chooses a split polygon by scoring the polygon choices.
    ///
    /// This algorithm is approximately O(N**2), so it's likely to take a while.
    ///
    /// This method runs as a coroutine so should be run until completion.
    /// </summary>
    /// <param name="polygons">The polygons to choose from</param>
    /// <param name="result">The resulting split polygon, along with classifications for other polygons in relation.</param>
    /// <returns></returns>
    private static IEnumerator ChooseSplitPolygonBestChoice(List <Polygon> polygons, ChooseSplitPolygonResult result)
    {
        int bestChoiceScore = int.MaxValue;

        foreach (var p1 in polygons)
        {
            if (p1.Used)
            {
                continue;
            }

            ChooseSplitPolygonResult potentialResult = new ChooseSplitPolygonResult(p1);
            potentialResult.Classify(polygons);

            int frontfaces = potentialResult.Front.Count - 1; // -1 because p1 is included.
            int backfaces  = potentialResult.Back.Count;
            int splits     = potentialResult.Spanning.Count;

            int score = Math.Abs(frontfaces - backfaces) + (splits * 8);

            if (score < bestChoiceScore)
            {
                bestChoiceScore = score;
                result.Assign(potentialResult);
            }

            yield return(null);
        }
    }
示例#2
0
    /// <summary>
    /// Chooses a split polygon at random (non-deterministic). Also classifies
    /// the rest of the polygons by whether they are in front, behind, spanning, or coincident.
    ///
    /// This runs as a coroutine, however, this specific version only iterates once.
    /// </summary>
    /// <param name="polygons">The polygons to choose from</param>
    /// <param name="result">The resulting polygons and polygon classification</param>
    /// <returns></returns>
    private static IEnumerator ChooseSplitPolygonRandom(List <Polygon> polygons, ChooseSplitPolygonResult result)
    {
        int index = Random.Range(0, polygons.Count);

        result.Assign(new ChooseSplitPolygonResult(polygons[index]));
        result.Classify(polygons);
        yield return(null);
    }
示例#3
0
 /// <summary>
 /// Copies the field values from another instance.
 /// </summary>
 /// <param name="cp"></param>
 public void Assign(ChooseSplitPolygonResult cp)
 {
     this.Polygon    = cp.Polygon;
     this.Front      = cp.Front;
     this.Back       = cp.Back;
     this.Spanning   = cp.Spanning;
     this.Coincident = cp.Coincident;
 }
示例#4
0
    /// <summary>
    /// Builds each node of the tree
    /// </summary>
    /// <param name="polygons"></param>
    /// <param name="convexNodes">A list to add convex leaf nodes to.</param>
    /// <param name="settings"></param>
    /// <returns></returns>
    private IEnumerator BuildTree(List <Polygon> polygons, List <SolidLeafBSPTree> convexNodes, BuildSettings settings)
    {
        ChooseSplitPolygonResult result = new ChooseSplitPolygonResult();

        if (settings.HighQuality)
        {
            var it = ChooseSplitPolygonBestChoice(polygons, result);
            while (it.MoveNext())
            {
                yield return(null);
            }
        }
        else
        {
            var it = ChooseSplitPolygonRandom(polygons, result);
            while (it.MoveNext())
            {
                yield return(null);
            }
        }

        var splitPolygon = result.Polygon;

        splitPolygon.MarkUsed();

        this.Plane = splitPolygon.Plane;

        //Classify the coincident polygons to either the front of back list.
        foreach (var polygon in result.Coincident)
        {
            var dp = Vector3.Dot(splitPolygon.Plane.normal, polygon.Plane.normal);
            if (dp > 0)
            {
                result.Front.Add(polygon);
            }
            else
            {
                result.Back.Add(polygon);
            }
        }

        //Split the spanning polygons and add them to front/back list.
        foreach (var polygon in result.Spanning)
        {
            var faces = SplitPolygon(polygon, Plane);
            result.Front.Add(faces.First());
            result.Back.Add(faces.Last());
        }

        //check if all frontfaces are used
        bool allUsed = result.Front.Count > 0 && result.Front.All(ff => ff.Used);

        if (allUsed)
        {
            this.Polygons     = result.Front;
            this.IsConvexLeaf = true;
            convexNodes.Add(this);
        }
        else
        {
            if (result.Front.Count > 0)
            {
                FrontTree = new SolidLeafBSPTree();
                var it = FrontTree.BuildTree(result.Front, convexNodes, settings);
                while (it.MoveNext())
                {
                    yield return(null);
                }
            }

            if (result.Back.Count > 0)
            {
                BackTree = new SolidLeafBSPTree();
                var it = BackTree.BuildTree(result.Back, convexNodes, settings);
                while (it.MoveNext())
                {
                    yield return(null);
                }
            }
        }
    }