Exemplo n.º 1
0
    private BVHNode BuildNodeRecursively(NodeSpec spec, int depth)
    {
        // 节点只有一个图元的时候没必要再继续分割
        if (spec.numRef <= MIN_LEAF_SIZE || depth >= MAX_DEPTH)
        {
            return(CreatLeaf(spec));
        }

        // 挑选使用object split还是spatial split
        float        leafSAH      = spec.bounds.Area * spec.numRef;
        float        nodeSAH      = spec.bounds.Area * 0.125f;//spec.Bounds.Area * 2; // 节点遍历的固定开销,2是个经验值(不一定是最好的)
        ObjectSplit  objectSplit  = FindObjectSplit(spec, nodeSAH);
        SpatialSplit spatialSplit = SpatialSplit.New();

        if (depth < MAX_SPATIAL_DEPTH)
        {
            var overlap = objectSplit.leftBounds;
            overlap.Intersect(objectSplit.rightBounds);

            if (overlap.Area >= _minOverlap)
            {
                spatialSplit = FindSpatialSplit(spec, nodeSAH);
            }
        }

        // 叶节点胜出,不论是Object还是Spatial slpit,分割后的
        float minSAH = Mathf.Min(Mathf.Min(leafSAH, objectSplit.sah), spatialSplit.sah);

        if (minSAH == leafSAH && spec.numRef <= MAX_LEAF_SIZE)
        {
            return(CreatLeaf(spec));
        }

        // spatial split胜出,尝试执行spatial split
        NodeSpec left  = NodeSpec.New();
        NodeSpec right = NodeSpec.New();

        if (minSAH == spatialSplit.sah)
        {
            PerformSpatialSplit(ref left, ref right, spec, spatialSplit);
        }

        // objcet split胜出,或spatial split并未取得实质性进展,执行object split
        if (left.numRef == 0 || right.numRef == 0)
        {
            PerformObjectSplit(ref left, ref right, spec, objectSplit);
        }

        _numDuplicates += left.numRef + right.numRef - spec.numRef;

        // 由于后文取下标的方式,一定是先右后左
        var rightNode = BuildNodeRecursively(right, depth + 1);
        var leftNode  = BuildNodeRecursively(left, depth + 1);

        return(new InnerNode(spec.bounds, leftNode, rightNode));
    }
Exemplo n.º 2
0
    private ObjectSplit FindObjectSplit(NodeSpec spec, float nodeSAH)
    {
        ObjectSplit split  = ObjectSplit.New();
        int         refIdx = _refStack.Count - spec.numRef; // CreateLeaf以后_refStack发生了变化

        for (byte dim = 0; dim < 3; dim++)
        {
            _refComparer.sortDim = dim;
            _refStack.Sort(refIdx, spec.numRef, _refComparer);

            // 从右到左,记录每一种可能的分割后,处在“右边”包围盒的
            AABB rightBounds = AABB.New();

            for (int i = spec.numRef - 1; i > 0; i--)
            {
                rightBounds.Union(_refStack[refIdx + i].bounds);
                _rightBounds[i - 1] = rightBounds; // 每一个都记录下来,后面才能比较
            }

            // 从左到右尝试分割,比较计算得到最佳SAH
            AABB leftBounds = AABB.New();
            for (int i = 1; i < spec.numRef; i++)
            {
                leftBounds.Union(_refStack[refIdx + i - 1].bounds);
                float sah = nodeSAH + leftBounds.Area * i /*左边有i个图元*/ + _rightBounds[i - 1].Area * (spec.numRef - i);
                if (sah < split.sah)
                {
                    split.sah         = sah;
                    split.dim         = dim;
                    split.numLeft     = i;
                    split.leftBounds  = leftBounds;
                    split.rightBounds = _rightBounds[i - 1];
                }
            }
        }

        return(split);
    }
Exemplo n.º 3
0
    private void PerformObjectSplit(ref NodeSpec left, ref NodeSpec right, NodeSpec spec, ObjectSplit split)
    {
        int refIdx = _refStack.Count - spec.numRef;

        _refComparer.sortDim = split.dim;
        _refStack.Sort(refIdx, spec.numRef, _refComparer);

        left.numRef  = split.numLeft;
        left.bounds  = split.leftBounds;
        right.numRef = spec.numRef - split.numLeft;
        right.bounds = split.rightBounds;
    }