예제 #1
0
            unsafe void PairTest(int workerIndex)
            {
                Debug.Assert(!disposed);
                int nextNodePairIndex;

                //To minimize the number of worker overlap lists, perform direct load balancing by manually grabbing the next indices.
                while ((nextNodePairIndex = Interlocked.Increment(ref NextNodePair)) < NodePairsToTest.Count)
                {
                    var overlap = NodePairsToTest[nextNodePairIndex];
                    if (overlap.A >= 0)
                    {
                        if (overlap.A == overlap.B)
                        {
                            //Same node.
                            Tree.GetOverlapsInNode2(Tree.nodes + overlap.A, ref WorkerOverlaps[workerIndex]);
                        }
                        else if (overlap.B >= 0)
                        {
                            //Different nodes.
                            Tree.GetOverlapsBetweenDifferentNodes2(Tree.nodes + overlap.A, Tree.nodes + overlap.B, ref WorkerOverlaps[workerIndex]);
                        }
                        else
                        {
                            //A is an internal node, B is a leaf.
                            var leafIndex = Tree.Encode(overlap.B);
                            var leaf      = Tree.leaves + leafIndex;
                            Tree.TestLeafAgainstNode2(leafIndex, ref (&Tree.nodes[leaf->NodeIndex].A)[leaf->ChildIndex], overlap.A, ref WorkerOverlaps[workerIndex]);
                        }
                    }
                    else
                    {
                        //A is a leaf, B is internal.
                        var leafIndex = Tree.Encode(overlap.A);
                        var leaf      = Tree.leaves + leafIndex;
                        Tree.TestLeafAgainstNode2(leafIndex, ref (&Tree.nodes[leaf->NodeIndex].A)[leaf->ChildIndex], overlap.B, ref WorkerOverlaps[workerIndex]);

                        //NOTE THAT WE DO NOT HANDLE THE CASE THAT BOTH A AND B ARE LEAVES HERE.
                        //The collection routine should take care of that, since it has more convenient access to bounding boxes and because a single test isn't worth an atomic increment.
                    }
                }
            }
예제 #2
0
            unsafe void RefitAndMark(int workerIndex)
            {
                int refitIndex;

                while ((refitIndex = Interlocked.Increment(ref RefitNodeIndex)) < RefitNodes.Count)
                {
                    var  nodeIndex = RefitNodes.Elements[refitIndex];
                    bool shouldUseMark;
                    if (nodeIndex < 0)
                    {
                        //Node was already marked as a wavefront. Should proceed with a RefitAndMeasure instead of RefitAndMark.
                        nodeIndex     = Tree.Encode(nodeIndex);
                        shouldUseMark = false;
                    }
                    else
                    {
                        shouldUseMark = true;
                    }

                    var node = Tree.nodes + nodeIndex;
                    Debug.Assert(node->Parent >= 0, "The root should not be marked for refit.");
                    var parent = Tree.nodes + node->Parent;
                    var boundingBoxInParent = &parent->A + node->IndexInParent;
                    if (shouldUseMark)
                    {
                        var costChange = Tree.RefitAndMark(nodeIndex, LeafCountThreshold, ref RefinementCandidates.Elements[workerIndex], ref *boundingBoxInParent);
                        node->LocalCostChange = costChange;
                    }
                    else
                    {
                        var costChange = Tree.RefitAndMeasure(nodeIndex, ref *boundingBoxInParent);
                        node->LocalCostChange = costChange;
                    }


                    //int foundLeafCount;
                    //Tree.Validate(RefitNodes.Elements[refitNodeIndex], node->Parent, node->IndexInParent, ref *boundingBoxInParent, out foundLeafCount);


                    //Walk up the tree.
                    node = parent;
                    while (true)
                    {
                        if (Interlocked.Decrement(ref node->RefineFlag) == 0)
                        {
                            //Compute the child contributions to this node's volume change.
                            var children = &node->ChildA;
                            node->LocalCostChange = 0;
                            for (int i = 0; i < node->ChildCount; ++i)
                            {
                                if (children[i] >= 0)
                                {
                                    var child = Tree.nodes + children[i];
                                    node->LocalCostChange += child->LocalCostChange;
                                    //Clear the refine flag (unioned).
                                    child->RefineFlag = 0;
                                }
                            }

                            //This thread is the last thread to visit this node, so it must handle this node.
                            //Merge all the child bounding boxes into one.
                            if (node->Parent < 0)
                            {
                                //Root node.
                                //Don't bother including the root's change in volume.
                                //Refinement can't change the root's bounds, so the fact that the world got bigger or smaller
                                //doesn't really have any bearing on how much refinement should be done.
                                //We do, however, need to divide by root volume so that we get the change in cost metric rather than volume.
                                var merged = new BoundingBox {
                                    Min = new Vector3(float.MaxValue), Max = new Vector3(float.MinValue)
                                };
                                var bounds = &node->A;
                                for (int i = 0; i < node->ChildCount; ++i)
                                {
                                    BoundingBox.Merge(ref bounds[i], ref merged, out merged);
                                }
                                var postmetric = ComputeBoundsMetric(ref merged);
                                if (postmetric > 1e-9f)
                                {
                                    RefitCostChange = node->LocalCostChange / postmetric;
                                }
                                else
                                {
                                    RefitCostChange = 0;
                                }
                                //Clear the root's refine flag (unioned).
                                node->RefineFlag = 0;
                                break;
                            }
                            else
                            {
                                parent = Tree.nodes + node->Parent;
                                boundingBoxInParent = &parent->A + node->IndexInParent;
                                var premetric           = ComputeBoundsMetric(ref *boundingBoxInParent);
                                *   boundingBoxInParent = new BoundingBox {
                                    Min = new Vector3(float.MaxValue), Max = new Vector3(float.MinValue)
                                };
                                var bounds = &node->A;
                                for (int i = 0; i < node->ChildCount; ++i)
                                {
                                    BoundingBox.Merge(ref bounds[i], ref *boundingBoxInParent, out *boundingBoxInParent);
                                }
                                var postmetric = ComputeBoundsMetric(ref *boundingBoxInParent);
                                node->LocalCostChange += postmetric - premetric;
                                node = parent;
                            }
                        }
                        else
                        {
                            //This thread wasn't the last to visit this node, so it should die. Some other thread will handle it later.
                            break;
                        }
                    }
                }
            }