Пример #1
0
        public static Dictionary <long, BuildStats> FindBuildStatsPerPlayer()
        {
            Dictionary <long, BuildStats> stats = new Dictionary <long, BuildStats>();

            foreach (MyEntity entity in MyEntities.GetEntities())
            {
                if (!(entity is MyCubeGrid grid))
                {
                    continue;
                }

                foreach (var block in grid.GetBlocks())
                {
                    long buildBy = block.BuiltBy;

                    if (!stats.TryGetValue(buildBy, out BuildStats statsForPlayer))
                    {
                        statsForPlayer = new BuildStats();
                        stats.Add(buildBy, statsForPlayer);
                    }

                    statsForPlayer.BlockCount++;
                    statsForPlayer.PcuCount += BlockUtils.GetPcu(block);
                }
            }

            return(stats);
        }
Пример #2
0
        public void build <T>(List <T> primitives, uint leafSize = 3, bool printStats = false) where T : IModel
        {
            if (primitives.Count == 0)
            {
                init_empty();
                return;
            }

            buildData dat;

            dat.maxPrims  = (int)leafSize;
            dat.numPrims  = (uint)primitives.Count;
            dat.indices   = new uint[dat.numPrims];
            dat.primBound = new AxisAlignedBox[dat.numPrims];
            bounds        = primitives[0].getBounds();
            for (int i = 0; i < dat.numPrims; ++i)
            {
                dat.indices[i]   = (uint)i;
                dat.primBound[i] = primitives[i].getBounds();
                bounds.merge(dat.primBound[i]);
            }
            List <uint> tempTree = new List <uint>();
            BuildStats  stats    = new BuildStats();

            buildHierarchy(tempTree, dat, stats);

            objects = new uint[dat.numPrims];
            for (int i = 0; i < dat.numPrims; ++i)
            {
                objects[i] = dat.indices[i];
            }

            tree = tempTree.ToArray();
        }
Пример #3
0
        public async Task <ActionResult> Stats(bool pr = false)
        {
            var util      = Factory.Create <BuildCounterEntity>(_storageAccount.CreateCloudTableClient(), TableNames.CounterBuilds);
            var map       = new Dictionary <DateTimeKey, BuildStats>();
            var endDate   = DateTimeOffset.UtcNow;
            var startDate = endDate.AddDays(-7);

            foreach (var entity in await util.QueryAsync(startDate: startDate, endDate: endDate))
            {
                BuildStats stats;
                var        date = util.GetDateTimeKey(entity);
                if (!map.TryGetValue(date, out stats))
                {
                    stats     = new BuildStats(date.DateTime);
                    map[date] = stats;
                }

                stats.BuildSucceededCount += entity.CommitSucceededCount;
                stats.BuildFailedCount    += entity.CommitFailedCount;

                if (pr)
                {
                    stats.BuildSucceededCount += entity.PullRequestSucceededCount;
                    stats.BuildFailedCount    += entity.PullRequestFailedCount;
                }
            }

            var model = new BuildStatsModel(map.Values.OrderBy(x => x.Date).ToList(), pr);

            return(View(viewName: "Stats", model: model));
        }
Пример #4
0
        public void build <T>(List <T> primitives, GetBounds <T> getBounds, uint leafSize = 3, bool printStats = false)
        {
            if (primitives.Count == 0)
            {
                init_empty();
                return;
            }

            buildData dat;

            dat.maxPrims  = (int)leafSize;
            dat.numPrims  = (uint)primitives.Count;
            dat.indices   = new uint[dat.numPrims];
            dat.primBound = new AxisAlignedBox[dat.numPrims];
            getBounds(primitives[0], out bounds);
            for (int i = 0; i < dat.numPrims; ++i)
            {
                dat.primBound[i] = AxisAlignedBox.NaN;
                dat.indices[i]   = (uint)i;
                getBounds(primitives[i], out dat.primBound[i]);
                bounds.merge(dat.primBound[i]);
            }
            List <uint> tempTree = new List <uint>();
            BuildStats  stats    = new BuildStats();

            buildHierarchy(tempTree, dat, stats);

            for (int i = 0; i < dat.numPrims; ++i)
            {
                objects.Add(dat.indices[i]);
            }
            tree = tempTree;
        }
        public void build(PrimitiveList primitives)
        {
            this.primitives = primitives;
            int n = primitives.getNumPrimitives();

            UI.printDetailed(UI.Module.ACCEL, "Getting bounding box ...");
            bounds  = primitives.getWorldBounds(null);
            objects = new int[n];
            for (int i = 0; i < n; i++)
            {
                objects[i] = i;
            }
            UI.printDetailed(UI.Module.ACCEL, "Creating tree ...");
            int        initialSize = 3 * (2 * 6 * n + 1);
            List <int> tempTree    = new List <int>((initialSize + 3) / 4);
            BuildStats stats       = new BuildStats();
            Timer      t           = new Timer();

            t.start();
            buildHierarchy(tempTree, objects, stats);
            t.end();
            UI.printDetailed(UI.Module.ACCEL, "Trimming tree ...");
            tree = tempTree.ToArray();
            // display stats
            stats.printStats();
            UI.printDetailed(UI.Module.ACCEL, "  * Creation time:  {0}", t);
            UI.printDetailed(UI.Module.ACCEL, "  * Usage of init:  {0,9:0.00}%", (double)(100 * tree.Length) / initialSize);
            UI.printDetailed(UI.Module.ACCEL, "  * Tree memory:    {0}", Memory.SizeOf(tree));
            UI.printDetailed(UI.Module.ACCEL, "  * Indices memory: {0}", Memory.SizeOf(objects));
        }
 public void build(PrimitiveList primitives)
 {
     this.primitives = primitives;
     int n = primitives.getNumPrimitives();
     UI.printDetailed(UI.Module.ACCEL, "Getting bounding box ...");
     bounds = primitives.getWorldBounds(null);
     objects = new int[n];
     for (int i = 0; i < n; i++)
         objects[i] = i;
     UI.printDetailed(UI.Module.ACCEL, "Creating tree ...");
     int initialSize = 3 * (2 * 6 * n + 1);
     List<int> tempTree = new List<int>((initialSize + 3) / 4);
     BuildStats stats = new BuildStats();
     Timer t = new Timer();
     t.start();
     buildHierarchy(tempTree, objects, stats);
     t.end();
     UI.printDetailed(UI.Module.ACCEL, "Trimming tree ...");
     tree = tempTree.ToArray();
     // display stats
     stats.printStats();
     UI.printDetailed(UI.Module.ACCEL, "  * Creation time:  %s", t);
     UI.printDetailed(UI.Module.ACCEL, "  * Usage of init:  %3d%%", 100 * tree.Length / initialSize);
     UI.printDetailed(UI.Module.ACCEL, "  * Tree memory:    %s", Memory.SizeOf(tree));
     UI.printDetailed(UI.Module.ACCEL, "  * Indices memory: %s", Memory.SizeOf(objects));
 }
Пример #7
0
        void BuildHierarchy(List <uint> tempTree, buildData dat, BuildStats stats)
        {
            // create space for the first node
            tempTree.Add(3u << 30); // dummy leaf
            tempTree.Add(0);
            tempTree.Add(0);

            // seed bbox
            AABound gridBox = new();

            gridBox.lo = bounds.Lo;
            gridBox.hi = bounds.Hi;
            AABound nodeBox = gridBox;

            // seed subdivide function
            Subdivide(0, (int)(dat.numPrims - 1), tempTree, dat, gridBox, nodeBox, 0, 1, stats);
        }
Пример #8
0
 private void buildHierarchy(List <int> tempTree, int[] indices, BuildStats stats)
 {
     // create space for the first node
     tempTree.Add(3 << 30); // dummy leaf
     tempTree.Add(0);
     tempTree.Add(0);
     if (objects.Length == 0)
     {
         return;
     }
     // seed bbox
     float[] gridBox = { bounds.getMinimum().x, bounds.getMaximum().x,
                         bounds.getMinimum().y, bounds.getMaximum().y,
                         bounds.getMinimum().z, bounds.getMaximum().z };
     float[] nodeBox = { bounds.getMinimum().x, bounds.getMaximum().x,
                         bounds.getMinimum().y, bounds.getMaximum().y,
                         bounds.getMinimum().z, bounds.getMaximum().z };
     // seed subdivide function
     subdivide(0, objects.Length - 1, tempTree, indices, gridBox, nodeBox, 0, 1, stats);
 }
Пример #9
0
 public BuildContext()
 {
     Stats = new BuildStats();
     Env = new BuildEnvironment(this);
     ProbedPaths = new ConcurrentBag<string>();
 }
Пример #10
0
        private void buildTree(float minx, float maxx, float miny, float maxy, float minz, float maxz, BuildTask task, int depth, List <int> tempTree, int offset, List <int> tempList, BuildStats stats)
        {
            // get node bounding box extents
            if (task.numObjects > maxPrims && depth < MAX_DEPTH)
            {
                float dx = maxx - minx;
                float dy = maxy - miny;
                float dz = maxz - minz;
                // search for best possible split
                float bestCost = INTERSECT_COST * task.numObjects;
                int   bestAxis = -1;
                int   bestOffsetStart = -1;
                int   bestOffsetEnd = -1;
                float bestSplit = 0;
                bool  bestPlanarLeft = false;
                int   bnl = 0, bnr = 0;
                // inverse area of the bounding box (factor of 2 ommitted)
                float area       = (dx * dy + dy * dz + dz * dx);
                float ISECT_COST = INTERSECT_COST / area;
                // setup counts for each axis
                int[] nl = { 0, 0, 0 };
                int[] nr = { task.numObjects, task.numObjects, task.numObjects };
                // setup bounds for each axis
                float[] dp      = { dy *dz, dz *dx, dx *dy };
                float[] ds      = { dy + dz, dz + dx, dx + dy };
                float[] nodeMin = { minx, miny, minz };
                float[] nodeMax = { maxx, maxy, maxz };
                // search for best cost
                int    nSplits = task.n;
                long[] splits  = task.splits;
                byte[] lrtable = task.leftRightTable;
                for (int i = 0; i < nSplits;)
                {
                    // extract current split
                    long  ptr   = splits[i];
                    float split = unpackSplit(ptr);
                    int   axis  = unpackAxis(ptr);
                    // mark current position
                    int currentOffset = i;
                    // count number of primitives start/stopping/lying on the
                    // current plane
                    int  pClosed = 0, pPlanar = 0, pOpened = 0;
                    long ptrMasked = (long)((ulong)ptr & (~((ulong)TYPE_MASK) & 0xFFFFFFFFF0000000L));
                    long ptrClosed = ptrMasked | CLOSED;
                    long ptrPlanar = ptrMasked | PLANAR;
                    long ptrOpened = ptrMasked | OPENED;
                    while (i < nSplits && ((ulong)splits[i] & 0xFFFFFFFFF0000000L) == (ulong)ptrClosed)
                    {
                        int obj = unpackObject(splits[i]);
                        lrtable[(uint)obj >> 2] = 0;//>>>
                        pClosed++;
                        i++;
                    }
                    while (i < nSplits && ((ulong)splits[i] & 0xFFFFFFFFF0000000L) == (ulong)ptrPlanar)
                    {
                        int obj = unpackObject(splits[i]);
                        lrtable[(uint)obj >> 2] = 0;//>>>
                        pPlanar++;
                        i++;
                    }
                    while (i < nSplits && ((ulong)splits[i] & 0xFFFFFFFFF0000000L) == (ulong)ptrOpened)
                    {
                        int obj = unpackObject(splits[i]);
                        lrtable[(uint)obj >> 2] = 0;//>>>
                        pOpened++;
                        i++;
                    }
                    // now we have summed all contributions from this plane
                    nr[axis] -= pPlanar + pClosed;
                    // compute cost
                    if (split >= nodeMin[axis] && split <= nodeMax[axis])
                    {
                        // left and right surface area (factor of 2 ommitted)
                        float dl = split - nodeMin[axis];
                        float dr = nodeMax[axis] - split;
                        float lp = dp[axis] + dl * ds[axis];
                        float rp = dp[axis] + dr * ds[axis];
                        // planar prims go to smallest cell always
                        bool  planarLeft = dl < dr;
                        int   numLeft    = nl[axis] + (planarLeft ? pPlanar : 0);
                        int   numRight   = nr[axis] + (planarLeft ? 0 : pPlanar);
                        float eb         = ((numLeft == 0 && dl > 0) || (numRight == 0 && dr > 0)) ? EMPTY_BONUS : 0;
                        float cost       = TRAVERSAL_COST + ISECT_COST * (1 - eb) * (lp * numLeft + rp * numRight);
                        if (cost < bestCost)
                        {
                            bestCost        = cost;
                            bestAxis        = axis;
                            bestSplit       = split;
                            bestOffsetStart = currentOffset;
                            bestOffsetEnd   = i;
                            bnl             = numLeft;
                            bnr             = numRight;
                            bestPlanarLeft  = planarLeft;
                        }
                    }
                    // move objects left
                    nl[axis] += pOpened + pPlanar;
                }
                // debug check for correctness of the scan
                for (int axis = 0; axis < 3; axis++)
                {
                    int numLeft  = nl[axis];
                    int numRight = nr[axis];
                    if (numLeft != task.numObjects || numRight != 0)
                    {
                        UI.printError(UI.Module.ACCEL, "Didn't scan full range of objects @depth={0}. Left overs for axis {1}: [L: {2}] [R: {3}]", depth, axis, numLeft, numRight);
                    }
                }
                // found best split?
                if (bestAxis != -1)
                {
                    // allocate space for child nodes
                    BuildTask taskL = new BuildTask(bnl, task);
                    BuildTask taskR = new BuildTask(bnr, task);
                    int       lk = 0, rk = 0;
                    for (int i = 0; i < bestOffsetStart; i++)
                    {
                        long ptr = splits[i];
                        if (unpackAxis(ptr) == bestAxis)
                        {
                            if (unpackSplitType(ptr) != CLOSED)
                            {
                                int obj = unpackObject(ptr);
                                lrtable[(uint)obj >> 2] |= (byte)(1 << ((obj & 3) << 1));//>>>
                                lk++;
                            }
                        }
                    }
                    for (int i = bestOffsetStart; i < bestOffsetEnd; i++)
                    {
                        long ptr = splits[i];
                        Debug.Assert(unpackAxis(ptr) == bestAxis);
                        if (unpackSplitType(ptr) == PLANAR)
                        {
                            if (bestPlanarLeft)
                            {
                                int obj = unpackObject(ptr);
                                lrtable[(uint)obj >> 2] |= (byte)(1 << ((obj & 3) << 1));//>>>
                                lk++;
                            }
                            else
                            {
                                int obj = unpackObject(ptr);
                                lrtable[(uint)obj >> 2] |= (byte)(2 << ((obj & 3) << 1));//>>>
                                rk++;
                            }
                        }
                    }
                    for (int i = bestOffsetEnd; i < nSplits; i++)
                    {
                        long ptr = splits[i];
                        if (unpackAxis(ptr) == bestAxis)
                        {
                            if (unpackSplitType(ptr) != OPENED)
                            {
                                int obj = unpackObject(ptr);
                                lrtable[(uint)obj >> 2] |= (byte)(2 << ((obj & 3) << 1));//>>>
                                rk++;
                            }
                        }
                    }
                    // output new splits while maintaining order
                    long[] splitsL = taskL.splits;
                    long[] splitsR = taskR.splits;
                    int    nsl = 0, nsr = 0;
                    for (int i = 0; i < nSplits; i++)
                    {
                        long ptr  = splits[i];
                        int  obj  = unpackObject(ptr);
                        int  idx  = (int)((uint)obj >> 2);//>>>
                        int  mask = 1 << ((obj & 3) << 1);
                        if ((lrtable[idx] & mask) != 0)
                        {
                            splitsL[nsl] = ptr;
                            nsl++;
                        }
                        if ((lrtable[idx] & (mask << 1)) != 0)
                        {
                            splitsR[nsr] = ptr;
                            nsr++;
                        }
                    }
                    taskL.n = nsl;
                    taskR.n = nsr;
                    // free more memory
                    task.splits = splits = splitsL = splitsR = null;
                    task        = null;
                    // allocate child nodes
                    int nextOffset = tempTree.Count;
                    tempTree.Add(0);
                    tempTree.Add(0);
                    tempTree.Add(0);
                    tempTree.Add(0);
                    // create current node
                    tempTree[offset + 0] = (bestAxis << 30) | nextOffset;
                    tempTree[offset + 1] = ByteUtil.floatToRawIntBits(bestSplit);
                    // recurse for child nodes - free object arrays after each step
                    stats.updateInner();
                    switch (bestAxis)
                    {
                    case 0:
                        buildTree(minx, bestSplit, miny, maxy, minz, maxz, taskL, depth + 1, tempTree, nextOffset, tempList, stats);
                        taskL = null;
                        buildTree(bestSplit, maxx, miny, maxy, minz, maxz, taskR, depth + 1, tempTree, nextOffset + 2, tempList, stats);
                        taskR = null;
                        return;

                    case 1:
                        buildTree(minx, maxx, miny, bestSplit, minz, maxz, taskL, depth + 1, tempTree, nextOffset, tempList, stats);
                        taskL = null;
                        buildTree(minx, maxx, bestSplit, maxy, minz, maxz, taskR, depth + 1, tempTree, nextOffset + 2, tempList, stats);
                        taskR = null;
                        return;

                    case 2:
                        buildTree(minx, maxx, miny, maxy, minz, bestSplit, taskL, depth + 1, tempTree, nextOffset, tempList, stats);
                        taskL = null;
                        buildTree(minx, maxx, miny, maxy, bestSplit, maxz, taskR, depth + 1, tempTree, nextOffset + 2, tempList, stats);
                        taskR = null;
                        return;

                    default:
                        Debug.Assert(false);
                        break;
                    }
                }
            }
            // create leaf node
            int listOffset = tempList.Count;
            int n          = 0;

            for (int i = 0; i < task.n; i++)
            {
                long ptr = task.splits[i];
                if (unpackAxis(ptr) == 0 && unpackSplitType(ptr) != CLOSED)
                {
                    tempList.Add(unpackObject(ptr));
                    n++;
                }
            }
            stats.updateLeaf(depth, n);
            if (n != task.numObjects)
            {
                UI.printError(UI.Module.ACCEL, "Error creating leaf node - expecting {0} found {1}", task.numObjects, n);
            }
            tempTree[offset + 0] = (3 << 30) | listOffset;
            tempTree[offset + 1] = task.numObjects;
            // free some memory
            task.splits = null;
        }
Пример #11
0
        public void build(PrimitiveList primitives)
        {
            UI.printDetailed(UI.Module.ACCEL, "KDTree settings");
            UI.printDetailed(UI.Module.ACCEL, "  * Max Leaf Size:  {0}", maxPrims);
            UI.printDetailed(UI.Module.ACCEL, "  * Max Depth:      {0}", MAX_DEPTH);
            UI.printDetailed(UI.Module.ACCEL, "  * Traversal cost: {0}", TRAVERSAL_COST);
            UI.printDetailed(UI.Module.ACCEL, "  * Intersect cost: {0}", INTERSECT_COST);
            UI.printDetailed(UI.Module.ACCEL, "  * Empty bonus:    {0}", EMPTY_BONUS);
            UI.printDetailed(UI.Module.ACCEL, "  * Dump leaves:    {0}", dump ? "enabled" : "disabled");
            Timer total = new Timer();

            total.start();
            this.primitiveList = primitives;
            // get the object space bounds
            bounds = primitives.getWorldBounds(null);
            int       nPrim = primitiveList.getNumPrimitives(), nSplits = 0;
            BuildTask task    = new BuildTask(nPrim);
            Timer     prepare = new Timer();

            prepare.start();
            for (int i = 0; i < nPrim; i++)
            {
                for (int axis = 0; axis < 3; axis++)
                {
                    float ls = primitiveList.getPrimitiveBound(i, 2 * axis + 0);
                    float rs = primitiveList.getPrimitiveBound(i, 2 * axis + 1);
                    if (ls == rs)
                    {
                        // flat in this dimension
                        task.splits[nSplits] = pack(ls, PLANAR, axis, i);
                        nSplits++;
                    }
                    else
                    {
                        task.splits[nSplits + 0] = pack(ls, OPENED, axis, i);
                        task.splits[nSplits + 1] = pack(rs, CLOSED, axis, i);
                        nSplits += 2;
                    }
                }
            }
            task.n = nSplits;
            prepare.end();
            Timer      t        = new Timer();
            List <int> tempTree = new List <int>();
            List <int> tempList = new List <int>();

            tempTree.Add(0);
            tempTree.Add(1);
            t.start();
            // sort it
            Timer sorting = new Timer();

            sorting.start();
            radix12(task.splits, task.n);
            sorting.end();
            // build the actual tree
            BuildStats stats = new BuildStats();

            buildTree(bounds.getMinimum().x, bounds.getMaximum().x, bounds.getMinimum().y, bounds.getMaximum().y, bounds.getMinimum().z, bounds.getMaximum().z, task, 1, tempTree, 0, tempList, stats);
            t.end();
            // write out arrays
            // free some memory
            task            = null;
            tree            = tempTree.ToArray();
            tempTree        = null;
            this.primitives = tempList.ToArray();
            tempList        = null;
            total.end();
            // display some extra info
            stats.printStats();
            UI.printDetailed(UI.Module.ACCEL, "  * Node memory:    {0}", Memory.SizeOf(tree));
            UI.printDetailed(UI.Module.ACCEL, "  * Object memory:  {0}", Memory.SizeOf(this.primitives));
            UI.printDetailed(UI.Module.ACCEL, "  * Prepare time:   {0}", prepare);
            UI.printDetailed(UI.Module.ACCEL, "  * Sorting time:   {0}", sorting);
            UI.printDetailed(UI.Module.ACCEL, "  * Tree creation:  {0}", t);
            UI.printDetailed(UI.Module.ACCEL, "  * Build time:     {0}", total);
            if (dump)
            {
                try
                {
                    UI.printInfo(UI.Module.ACCEL, "Dumping mtls to {0}.mtl ...", dumpPrefix);
                    StreamWriter mtlFile = new StreamWriter(dumpPrefix + ".mtl");
                    int          maxN    = stats.maxObjects;
                    for (int n = 0; n <= maxN; n++)
                    {
                        float blend = (float)n / (float)maxN;
                        Color nc;
                        if (blend < 0.25)
                        {
                            nc = Color.blend(Color.BLUE, Color.GREEN, blend / 0.25f);
                        }
                        else if (blend < 0.5)
                        {
                            nc = Color.blend(Color.GREEN, Color.YELLOW, (blend - 0.25f) / 0.25f);
                        }
                        else if (blend < 0.75)
                        {
                            nc = Color.blend(Color.YELLOW, Color.RED, (blend - 0.50f) / 0.25f);
                        }
                        else
                        {
                            nc = Color.MAGENTA;
                        }
                        mtlFile.WriteLine(string.Format("newmtl mtl{0}", n));
                        float[] rgb = nc.getRGB();
                        mtlFile.WriteLine("Ka 0.1 0.1 0.1");
                        mtlFile.WriteLine(string.Format("Kd {0}g {1}g {2}g", rgb[0], rgb[1], rgb[2]));
                        mtlFile.WriteLine("illum 1\n");
                    }
                    StreamWriter objFile = new StreamWriter(dumpPrefix + ".obj");
                    UI.printInfo(UI.Module.ACCEL, "Dumping tree to {0}.obj ...", dumpPrefix);
                    dumpObj(0, 0, maxN, new BoundingBox(bounds), objFile, mtlFile);
                    objFile.Close();
                    mtlFile.Close();
                }
                catch (Exception e)
                {
                    Console.WriteLine(e);
                }
            }
        }
Пример #12
0
 public void build(PrimitiveList primitives)
 {
     UI.printDetailed(UI.Module.ACCEL, "KDTree settings");
     UI.printDetailed(UI.Module.ACCEL, "  * Max Leaf Size:  {0}", maxPrims);
     UI.printDetailed(UI.Module.ACCEL, "  * Max Depth:      {0}", MAX_DEPTH);
     UI.printDetailed(UI.Module.ACCEL, "  * Traversal cost: {0}", TRAVERSAL_COST);
     UI.printDetailed(UI.Module.ACCEL, "  * Intersect cost: {0}", INTERSECT_COST);
     UI.printDetailed(UI.Module.ACCEL, "  * Empty bonus:    {0}", EMPTY_BONUS);
     UI.printDetailed(UI.Module.ACCEL, "  * Dump leaves:    {0}", dump ? "enabled" : "disabled");
     Timer total = new Timer();
     total.start();
     primitiveList = primitives;
     // get the object space bounds
     bounds = primitives.getWorldBounds(null);
     int nPrim = primitiveList.getNumPrimitives(), nSplits = 0;
     BuildTask task = new BuildTask(nPrim);
     Timer prepare = new Timer();
     prepare.start();
     for (int i = 0; i < nPrim; i++)
     {
         for (int axis = 0; axis < 3; axis++)
         {
             float ls = primitiveList.getPrimitiveBound(i, 2 * axis + 0);
             float rs = primitiveList.getPrimitiveBound(i, 2 * axis + 1);
             if (ls == rs)
             {
                 // flat in this dimension
                 task.splits[nSplits] = pack(ls, PLANAR, axis, i);
                 nSplits++;
             }
             else
             {
                 task.splits[nSplits + 0] = pack(ls, OPENED, axis, i);
                 task.splits[nSplits + 1] = pack(rs, CLOSED, axis, i);
                 nSplits += 2;
             }
         }
     }
     task.n = nSplits;
     prepare.end();
     Timer t = new Timer();
     List<int> tempTree = new List<int>();
     List<int> tempList = new List<int>();
     tempTree.Add(0);
     tempTree.Add(1);
     t.start();
     // sort it
     Timer sorting = new Timer();
     sorting.start();
     radix12(task.splits, task.n);
     sorting.end();
     // build the actual tree
     BuildStats stats = new BuildStats();
     buildTree(bounds.getMinimum().x, bounds.getMaximum().x, bounds.getMinimum().y, bounds.getMaximum().y, bounds.getMinimum().z, bounds.getMaximum().z, task, 1, tempTree, 0, tempList, stats);
     t.end();
     // write out arrays
     // free some memory
     task = null;
     tree = tempTree.ToArray();
     tempTree = null;
     this.primitives = tempList.ToArray();
     tempList = null;
     total.end();
     // display some extra info
     stats.printStats();
     UI.printDetailed(UI.Module.ACCEL, "  * Node memory:    {0}", Memory.SizeOf(tree));
     UI.printDetailed(UI.Module.ACCEL, "  * Object memory:  {0}", Memory.SizeOf(this.primitives));
     UI.printDetailed(UI.Module.ACCEL, "  * Prepare time:   {0}", prepare);
     UI.printDetailed(UI.Module.ACCEL, "  * Sorting time:   {0}", sorting);
     UI.printDetailed(UI.Module.ACCEL, "  * Tree creation:  {0}", t);
     UI.printDetailed(UI.Module.ACCEL, "  * Build time:     {0}", total);
     if (dump)
     {
         try
         {
             UI.printInfo(UI.Module.ACCEL, "Dumping mtls to {0}.mtl ...", dumpPrefix);
             StreamWriter mtlFile = new StreamWriter(dumpPrefix + ".mtl");
             int maxN = stats.maxObjects;
             for (int n = 0; n <= maxN; n++)
             {
                 float blend = (float)n / (float)maxN;
                 Color nc;
                 if (blend < 0.25)
                     nc = Color.blend(Color.BLUE, Color.GREEN, blend / 0.25f);
                 else if (blend < 0.5)
                     nc = Color.blend(Color.GREEN, Color.YELLOW, (blend - 0.25f) / 0.25f);
                 else if (blend < 0.75)
                     nc = Color.blend(Color.YELLOW, Color.RED, (blend - 0.50f) / 0.25f);
                 else
                     nc = Color.MAGENTA;
                 mtlFile.WriteLine(string.Format("newmtl mtl{0}", n));
                 float[] rgb = nc.getRGB();
                 mtlFile.WriteLine("Ka 0.1 0.1 0.1");
                 mtlFile.WriteLine(string.Format("Kd {0}g {1}g {2}g", rgb[0], rgb[1], rgb[2]));
                 mtlFile.WriteLine("illum 1\n");
             }
             StreamWriter objFile = new StreamWriter(dumpPrefix + ".obj");
             UI.printInfo(UI.Module.ACCEL, "Dumping tree to {0}.obj ...", dumpPrefix);
             dumpObj(0, 0, maxN, new BoundingBox(bounds), objFile, mtlFile);
             objFile.Close();
             mtlFile.Close();
         }
         catch (Exception e)
         {
             Console.WriteLine(e);
         }
     }
 }
Пример #13
0
 private void buildHierarchy(List<int> tempTree, int[] indices, BuildStats stats)
 {
     // create space for the first node
     tempTree.Add(3 << 30); // dummy leaf
     tempTree.Add(0);
     tempTree.Add(0);
     if (objects.Length == 0)
         return;
     // seed bbox
     float[] gridBox = { bounds.getMinimum().x, bounds.getMaximum().x,
         bounds.getMinimum().y, bounds.getMaximum().y,
         bounds.getMinimum().z, bounds.getMaximum().z };
     float[] nodeBox = { bounds.getMinimum().x, bounds.getMaximum().x,
         bounds.getMinimum().y, bounds.getMaximum().y,
         bounds.getMinimum().z, bounds.getMaximum().z };
     // seed subdivide function
     subdivide(0, objects.Length - 1, tempTree, indices, gridBox, nodeBox, 0, 1, stats);
 }
Пример #14
0
        private void subdivide(int left, int right, List <int> tempTree, int[] indices, float[] gridBox, float[] nodeBox, int nodeIndex, int depth, BuildStats stats)
        {
            if ((right - left + 1) <= maxPrims || depth >= 64)
            {
                // write leaf node
                stats.updateLeaf(depth, right - left + 1);
                createNode(tempTree, nodeIndex, left, right);
                return;
            }
            // calculate extents
            int   axis = -1, prevAxis, rightOrig;
            float clipL = float.NaN, clipR = float.NaN, prevClip = float.NaN;
            float split = float.NaN, prevSplit;
            bool  wasLeft = true;

            while (true)
            {
                prevAxis  = axis;
                prevSplit = split;
                // perform quick consistency checks
                float[] d = { gridBox[1] - gridBox[0], gridBox[3] - gridBox[2],
                              gridBox[5] - gridBox[4] };
                if (d[0] < 0 || d[1] < 0 || d[2] < 0)
                {
                    throw new Exception("negative node extents");
                }
                for (int i = 0; i < 3; i++)
                {
                    if (nodeBox[2 * i + 1] < gridBox[2 * i] || nodeBox[2 * i] > gridBox[2 * i + 1])
                    {
                        UI.printError(UI.Module.ACCEL, "Reached tree area in error - discarding node with: {0} objects", right - left + 1);
                        throw new Exception("invalid node overlap");
                    }
                }
                // find longest axis
                if (d[0] > d[1] && d[0] > d[2])
                {
                    axis = 0;
                }
                else if (d[1] > d[2])
                {
                    axis = 1;
                }
                else
                {
                    axis = 2;
                }
                split = 0.5f * (gridBox[2 * axis] + gridBox[2 * axis + 1]);
                // partition L/R subsets
                clipL     = float.NegativeInfinity;
                clipR     = float.PositiveInfinity;
                rightOrig = right; // save this for later
                float nodeL = float.PositiveInfinity;
                float nodeR = float.NegativeInfinity;
                for (int i = left; i <= right;)
                {
                    int   obj    = indices[i];
                    float minb   = primitives.getPrimitiveBound(obj, 2 * axis + 0);
                    float maxb   = primitives.getPrimitiveBound(obj, 2 * axis + 1);
                    float center = (minb + maxb) * 0.5f;
                    if (center <= split)
                    {
                        // stay left
                        i++;
                        if (clipL < maxb)
                        {
                            clipL = maxb;
                        }
                    }
                    else
                    {
                        // move to the right most
                        int t = indices[i];
                        indices[i]     = indices[right];
                        indices[right] = t;
                        right--;
                        if (clipR > minb)
                        {
                            clipR = minb;
                        }
                    }
                    if (nodeL > minb)
                    {
                        nodeL = minb;
                    }
                    if (nodeR < maxb)
                    {
                        nodeR = maxb;
                    }
                }
                // check for empty space
                if (nodeL > nodeBox[2 * axis + 0] && nodeR < nodeBox[2 * axis + 1])
                {
                    float nodeBoxW = nodeBox[2 * axis + 1] - nodeBox[2 * axis + 0];
                    float nodeNewW = nodeR - nodeL;
                    // node box is too big compare to space occupied by primitives?
                    if (1.3f * nodeNewW < nodeBoxW)
                    {
                        stats.updateBVH2();
                        int nextIndex = tempTree.Count;
                        // allocate child
                        tempTree.Add(0);
                        tempTree.Add(0);
                        tempTree.Add(0);
                        // write bvh2 clip node
                        stats.updateInner();
                        tempTree[nodeIndex + 0] = (axis << 30) | (1 << 29) | nextIndex;
                        tempTree[nodeIndex + 1] = ByteUtil.floatToRawIntBits(nodeL);
                        tempTree[nodeIndex + 2] = ByteUtil.floatToRawIntBits(nodeR);
                        // update nodebox and recurse
                        nodeBox[2 * axis + 0] = nodeL;
                        nodeBox[2 * axis + 1] = nodeR;
                        subdivide(left, rightOrig, tempTree, indices, gridBox, nodeBox, nextIndex, depth + 1, stats);
                        return;
                    }
                }
                // ensure we are making progress in the subdivision
                if (right == rightOrig)
                {
                    // all left
                    if (clipL <= split)
                    {
                        // keep looping on left half
                        gridBox[2 * axis + 1] = split;
                        prevClip = clipL;
                        wasLeft  = true;
                        continue;
                    }
                    if (prevAxis == axis && prevSplit == split)
                    {
                        // we are stuck here - create a leaf
                        stats.updateLeaf(depth, right - left + 1);
                        createNode(tempTree, nodeIndex, left, right);
                        return;
                    }
                    gridBox[2 * axis + 1] = split;
                    prevClip = float.NaN;
                }
                else if (left > right)
                {
                    // all right
                    right = rightOrig;
                    if (clipR >= split)
                    {
                        // keep looping on right half
                        gridBox[2 * axis + 0] = split;
                        prevClip = clipR;
                        wasLeft  = false;
                        continue;
                    }
                    if (prevAxis == axis && prevSplit == split)
                    {
                        // we are stuck here - create a leaf
                        stats.updateLeaf(depth, right - left + 1);
                        createNode(tempTree, nodeIndex, left, right);
                        return;
                    }
                    gridBox[2 * axis + 0] = split;
                    prevClip = float.NaN;
                }
                else
                {
                    // we are actually splitting stuff
                    if (prevAxis != -1 && !float.IsNaN(prevClip))
                    {
                        // second time through - lets create the previous split
                        // since it produced empty space
                        int nextIndex = tempTree.Count;
                        // allocate child node
                        tempTree.Add(0);
                        tempTree.Add(0);
                        tempTree.Add(0);
                        if (wasLeft)
                        {
                            // create a node with a left child
                            // write leaf node
                            stats.updateInner();
                            tempTree[nodeIndex + 0] = (prevAxis << 30) | nextIndex;
                            tempTree[nodeIndex + 1] = ByteUtil.floatToRawIntBits(prevClip);
                            tempTree[nodeIndex + 2] = ByteUtil.floatToRawIntBits(float.PositiveInfinity);
                        }
                        else
                        {
                            // create a node with a right child
                            // write leaf node
                            stats.updateInner();
                            tempTree[nodeIndex + 0] = (prevAxis << 30) | (nextIndex - 3);
                            tempTree[nodeIndex + 1] = ByteUtil.floatToRawIntBits(float.NegativeInfinity);
                            tempTree[nodeIndex + 2] = ByteUtil.floatToRawIntBits(prevClip);
                        }
                        // count stats for the unused leaf
                        depth++;
                        stats.updateLeaf(depth, 0);
                        // now we keep going as we are, with a new nodeIndex:
                        nodeIndex = nextIndex;
                    }
                    break;
                }
            }
            // compute index of child nodes
            int nextIndex1 = tempTree.Count;
            // allocate left node
            int nl = right - left + 1;
            int nr = rightOrig - (right + 1) + 1;

            if (nl > 0)
            {
                tempTree.Add(0);
                tempTree.Add(0);
                tempTree.Add(0);
            }
            else
            {
                nextIndex1 -= 3;
            }
            // allocate right node
            if (nr > 0)
            {
                tempTree.Add(0);
                tempTree.Add(0);
                tempTree.Add(0);
            }
            // write leaf node
            stats.updateInner();
            tempTree[nodeIndex + 0] = (axis << 30) | nextIndex1;
            tempTree[nodeIndex + 1] = ByteUtil.floatToRawIntBits(clipL);
            tempTree[nodeIndex + 2] = ByteUtil.floatToRawIntBits(clipR);
            // prepare L/R child boxes
            float[] gridBoxL = new float[6];
            float[] gridBoxR = new float[6];
            float[] nodeBoxL = new float[6];
            float[] nodeBoxR = new float[6];
            for (int i = 0; i < 6; i++)
            {
                gridBoxL[i] = gridBoxR[i] = gridBox[i];
                nodeBoxL[i] = nodeBoxR[i] = nodeBox[i];
            }
            gridBoxL[2 * axis + 1] = gridBoxR[2 * axis] = split;
            nodeBoxL[2 * axis + 1] = clipL;
            nodeBoxR[2 * axis + 0] = clipR;
            // free memory
            gridBox = nodeBox = null;
            // recurse
            if (nl > 0)
            {
                subdivide(left, right, tempTree, indices, gridBoxL, nodeBoxL, nextIndex1, depth + 1, stats);
            }
            else
            {
                stats.updateLeaf(depth + 1, 0);
            }
            if (nr > 0)
            {
                subdivide(right + 1, rightOrig, tempTree, indices, gridBoxR, nodeBoxR, nextIndex1 + 3, depth + 1, stats);
            }
            else
            {
                stats.updateLeaf(depth + 1, 0);
            }
        }
Пример #15
0
 private void subdivide(int left, int right, List<int> tempTree, int[] indices, float[] gridBox, float[] nodeBox, int nodeIndex, int depth, BuildStats stats)
 {
     if ((right - left + 1) <= maxPrims || depth >= 64)
     {
         // write leaf node
         stats.updateLeaf(depth, right - left + 1);
         createNode(tempTree, nodeIndex, left, right);
         return;
     }
     // calculate extents
     int axis = -1, prevAxis, rightOrig;
     float clipL = float.NaN, clipR = float.NaN, prevClip = float.NaN;
     float split = float.NaN, prevSplit;
     bool wasLeft = true;
     while (true)
     {
         prevAxis = axis;
         prevSplit = split;
         // perform quick consistency checks
         float[] d = { gridBox[1] - gridBox[0], gridBox[3] - gridBox[2],
             gridBox[5] - gridBox[4] };
         if (d[0] < 0 || d[1] < 0 || d[2] < 0)
             throw new Exception("negative node extents");
         for (int i = 0; i < 3; i++)
         {
             if (nodeBox[2 * i + 1] < gridBox[2 * i] || nodeBox[2 * i] > gridBox[2 * i + 1])
             {
                 UI.printError(UI.Module.ACCEL, "Reached tree area in error - discarding node with: {0} objects", right - left + 1);
                 throw new Exception("invalid node overlap");
             }
         }
         // find longest axis
         if (d[0] > d[1] && d[0] > d[2])
             axis = 0;
         else if (d[1] > d[2])
             axis = 1;
         else
             axis = 2;
         split = 0.5f * (gridBox[2 * axis] + gridBox[2 * axis + 1]);
         // partition L/R subsets
         clipL = float.NegativeInfinity;
         clipR = float.PositiveInfinity;
         rightOrig = right; // save this for later
         float nodeL = float.PositiveInfinity;
         float nodeR = float.NegativeInfinity;
         for (int i = left; i <= right; )
         {
             int obj = indices[i];
             float minb = primitives.getPrimitiveBound(obj, 2 * axis + 0);
             float maxb = primitives.getPrimitiveBound(obj, 2 * axis + 1);
             float center = (minb + maxb) * 0.5f;
             if (center <= split)
             {
                 // stay left
                 i++;
                 if (clipL < maxb)
                     clipL = maxb;
             }
             else
             {
                 // move to the right most
                 int t = indices[i];
                 indices[i] = indices[right];
                 indices[right] = t;
                 right--;
                 if (clipR > minb)
                     clipR = minb;
             }
             if (nodeL > minb)
                 nodeL = minb;
             if (nodeR < maxb)
                 nodeR = maxb;
         }
         // check for empty space
         if (nodeL > nodeBox[2 * axis + 0] && nodeR < nodeBox[2 * axis + 1])
         {
             float nodeBoxW = nodeBox[2 * axis + 1] - nodeBox[2 * axis + 0];
             float nodeNewW = nodeR - nodeL;
             // node box is too big compare to space occupied by primitives?
             if (1.3f * nodeNewW < nodeBoxW)
             {
                 stats.updateBVH2();
                 int nextIndex = tempTree.Count;
                 // allocate child
                 tempTree.Add(0);
                 tempTree.Add(0);
                 tempTree.Add(0);
                 // write bvh2 clip node
                 stats.updateInner();
                 tempTree[nodeIndex + 0] = (axis << 30) | (1 << 29) | nextIndex;
                 tempTree[nodeIndex + 1] = ByteUtil.floatToRawIntBits(nodeL);
                 tempTree[nodeIndex + 2] = ByteUtil.floatToRawIntBits(nodeR);
                 // update nodebox and recurse
                 nodeBox[2 * axis + 0] = nodeL;
                 nodeBox[2 * axis + 1] = nodeR;
                 subdivide(left, rightOrig, tempTree, indices, gridBox, nodeBox, nextIndex, depth + 1, stats);
                 return;
             }
         }
         // ensure we are making progress in the subdivision
         if (right == rightOrig)
         {
             // all left
             if (clipL <= split)
             {
                 // keep looping on left half
                 gridBox[2 * axis + 1] = split;
                 prevClip = clipL;
                 wasLeft = true;
                 continue;
             }
             if (prevAxis == axis && prevSplit == split)
             {
                 // we are stuck here - create a leaf
                 stats.updateLeaf(depth, right - left + 1);
                 createNode(tempTree, nodeIndex, left, right);
                 return;
             }
             gridBox[2 * axis + 1] = split;
             prevClip = float.NaN;
         }
         else if (left > right)
         {
             // all right
             right = rightOrig;
             if (clipR >= split)
             {
                 // keep looping on right half
                 gridBox[2 * axis + 0] = split;
                 prevClip = clipR;
                 wasLeft = false;
                 continue;
             }
             if (prevAxis == axis && prevSplit == split)
             {
                 // we are stuck here - create a leaf
                 stats.updateLeaf(depth, right - left + 1);
                 createNode(tempTree, nodeIndex, left, right);
                 return;
             }
             gridBox[2 * axis + 0] = split;
             prevClip = float.NaN;
         }
         else
         {
             // we are actually splitting stuff
             if (prevAxis != -1 && !float.IsNaN(prevClip))
             {
                 // second time through - lets create the previous split
                 // since it produced empty space
                 int nextIndex = tempTree.Count;
                 // allocate child node
                 tempTree.Add(0);
                 tempTree.Add(0);
                 tempTree.Add(0);
                 if (wasLeft)
                 {
                     // create a node with a left child
                     // write leaf node
                     stats.updateInner();
                     tempTree[nodeIndex + 0] = (prevAxis << 30) | nextIndex;
                     tempTree[nodeIndex + 1] = ByteUtil.floatToRawIntBits(prevClip);
                     tempTree[nodeIndex + 2] = ByteUtil.floatToRawIntBits(float.PositiveInfinity);
                 }
                 else
                 {
                     // create a node with a right child
                     // write leaf node
                     stats.updateInner();
                     tempTree[nodeIndex + 0] = (prevAxis << 30) | (nextIndex - 3);
                     tempTree[nodeIndex + 1] = ByteUtil.floatToRawIntBits(float.NegativeInfinity);
                     tempTree[nodeIndex + 2] = ByteUtil.floatToRawIntBits(prevClip);
                 }
                 // count stats for the unused leaf
                 depth++;
                 stats.updateLeaf(depth, 0);
                 // now we keep going as we are, with a new nodeIndex:
                 nodeIndex = nextIndex;
             }
             break;
         }
     }
     // compute index of child nodes
     int nextIndex1 = tempTree.Count;
     // allocate left node
     int nl = right - left + 1;
     int nr = rightOrig - (right + 1) + 1;
     if (nl > 0)
     {
         tempTree.Add(0);
         tempTree.Add(0);
         tempTree.Add(0);
     }
     else
         nextIndex1 -= 3;
     // allocate right node
     if (nr > 0)
     {
         tempTree.Add(0);
         tempTree.Add(0);
         tempTree.Add(0);
     }
     // write leaf node
     stats.updateInner();
     tempTree[nodeIndex + 0] = (axis << 30) | nextIndex1;
     tempTree[nodeIndex + 1] = ByteUtil.floatToRawIntBits(clipL);
     tempTree[nodeIndex + 2] = ByteUtil.floatToRawIntBits(clipR);
     // prepare L/R child boxes
     float[] gridBoxL = new float[6];
     float[] gridBoxR = new float[6];
     float[] nodeBoxL = new float[6];
     float[] nodeBoxR = new float[6];
     for (int i = 0; i < 6; i++)
     {
         gridBoxL[i] = gridBoxR[i] = gridBox[i];
         nodeBoxL[i] = nodeBoxR[i] = nodeBox[i];
     }
     gridBoxL[2 * axis + 1] = gridBoxR[2 * axis] = split;
     nodeBoxL[2 * axis + 1] = clipL;
     nodeBoxR[2 * axis + 0] = clipR;
     // free memory
     gridBox = nodeBox = null;
     // recurse
     if (nl > 0)
         subdivide(left, right, tempTree, indices, gridBoxL, nodeBoxL, nextIndex1, depth + 1, stats);
     else
         stats.updateLeaf(depth + 1, 0);
     if (nr > 0)
         subdivide(right + 1, rightOrig, tempTree, indices, gridBoxR, nodeBoxR, nextIndex1 + 3, depth + 1, stats);
     else
         stats.updateLeaf(depth + 1, 0);
 }
Пример #16
0
        void Subdivide(int left, int right, List <uint> tempTree, buildData dat, AABound gridBox, AABound nodeBox, int nodeIndex, int depth, BuildStats stats)
        {
            if ((right - left + 1) <= dat.maxPrims || depth >= 64)
            {
                // write leaf node
                stats.UpdateLeaf(depth, right - left + 1);
                CreateNode(tempTree, nodeIndex, left, right);
                return;
            }
            // calculate extents
            int   axis = -1, prevAxis, rightOrig;
            float clipL = float.NaN, clipR = float.NaN, prevClip = float.NaN;
            float split = float.NaN, prevSplit;
            bool  wasLeft = true;

            while (true)
            {
                prevAxis  = axis;
                prevSplit = split;
                // perform quick consistency checks
                Vector3 d = gridBox.hi - gridBox.lo;
                for (int i = 0; i < 3; i++)
                {
                    if (nodeBox.hi[i] < gridBox.lo[i] || nodeBox.lo[i] > gridBox.hi[i])
                    {
                        Log.outError(LogFilter.Server, "Reached tree area in error - discarding node with: {0} objects", right - left + 1);
                    }
                }
                // find longest axis
                axis  = (int)d.primaryAxis();
                split = 0.5f * (gridBox.lo[axis] + gridBox.hi[axis]);
                // partition L/R subsets
                clipL     = float.NegativeInfinity;
                clipR     = float.PositiveInfinity;
                rightOrig = right; // save this for later
                float nodeL = float.PositiveInfinity;
                float nodeR = float.NegativeInfinity;
                for (int i = left; i <= right;)
                {
                    int   obj    = (int)dat.indices[i];
                    float minb   = dat.primBound[obj].Lo[axis];
                    float maxb   = dat.primBound[obj].Hi[axis];
                    float center = (minb + maxb) * 0.5f;
                    if (center <= split)
                    {
                        // stay left
                        i++;
                        if (clipL < maxb)
                        {
                            clipL = maxb;
                        }
                    }
                    else
                    {
                        // move to the right most
                        int t = (int)dat.indices[i];
                        dat.indices[i]     = dat.indices[right];
                        dat.indices[right] = (uint)t;
                        right--;
                        if (clipR > minb)
                        {
                            clipR = minb;
                        }
                    }
                    nodeL = Math.Min(nodeL, minb);
                    nodeR = Math.Max(nodeR, maxb);
                }
                // check for empty space
                if (nodeL > nodeBox.lo[axis] && nodeR < nodeBox.hi[axis])
                {
                    float nodeBoxW = nodeBox.hi[axis] - nodeBox.lo[axis];
                    float nodeNewW = nodeR - nodeL;
                    // node box is too big compare to space occupied by primitives?
                    if (1.3f * nodeNewW < nodeBoxW)
                    {
                        stats.UpdateBVH2();
                        int nextIndex1 = tempTree.Count;
                        // allocate child
                        tempTree.Add(0);
                        tempTree.Add(0);
                        tempTree.Add(0);
                        // write bvh2 clip node
                        stats.UpdateInner();
                        tempTree[nodeIndex + 0] = (uint)((axis << 30) | (1 << 29) | nextIndex1);
                        tempTree[nodeIndex + 1] = FloatToRawIntBits(nodeL);
                        tempTree[nodeIndex + 2] = FloatToRawIntBits(nodeR);
                        // update nodebox and recurse
                        nodeBox.lo[axis] = nodeL;
                        nodeBox.hi[axis] = nodeR;
                        Subdivide(left, rightOrig, tempTree, dat, gridBox, nodeBox, nextIndex1, depth + 1, stats);
                        return;
                    }
                }
                // ensure we are making progress in the subdivision
                if (right == rightOrig)
                {
                    // all left
                    if (prevAxis == axis && MathFunctions.fuzzyEq(prevSplit, split))
                    {
                        // we are stuck here - create a leaf
                        stats.UpdateLeaf(depth, right - left + 1);
                        CreateNode(tempTree, nodeIndex, left, right);
                        return;
                    }
                    if (clipL <= split)
                    {
                        // keep looping on left half
                        gridBox.hi[axis] = split;
                        prevClip         = clipL;
                        wasLeft          = true;
                        continue;
                    }
                    gridBox.hi[axis] = split;
                    prevClip         = float.NaN;
                }
                else if (left > right)
                {
                    // all right
                    right = rightOrig;
                    if (prevAxis == axis && MathFunctions.fuzzyEq(prevSplit, split))
                    {
                        // we are stuck here - create a leaf
                        stats.UpdateLeaf(depth, right - left + 1);
                        CreateNode(tempTree, nodeIndex, left, right);
                        return;
                    }

                    if (clipR >= split)
                    {
                        // keep looping on right half
                        gridBox.lo[axis] = split;
                        prevClip         = clipR;
                        wasLeft          = false;
                        continue;
                    }
                    gridBox.lo[axis] = split;
                    prevClip         = float.NaN;
                }
                else
                {
                    // we are actually splitting stuff
                    if (prevAxis != -1 && !float.IsNaN(prevClip))
                    {
                        // second time through - lets create the previous split
                        // since it produced empty space
                        int nextIndex0 = tempTree.Count;
                        // allocate child node
                        tempTree.Add(0);
                        tempTree.Add(0);
                        tempTree.Add(0);
                        if (wasLeft)
                        {
                            // create a node with a left child
                            // write leaf node
                            stats.UpdateInner();
                            tempTree[nodeIndex + 0] = (uint)((prevAxis << 30) | nextIndex0);
                            tempTree[nodeIndex + 1] = FloatToRawIntBits(prevClip);
                            tempTree[nodeIndex + 2] = FloatToRawIntBits(float.PositiveInfinity);
                        }
                        else
                        {
                            // create a node with a right child
                            // write leaf node
                            stats.UpdateInner();
                            tempTree[nodeIndex + 0] = (uint)((prevAxis << 30) | (nextIndex0 - 3));
                            tempTree[nodeIndex + 1] = FloatToRawIntBits(float.NegativeInfinity);
                            tempTree[nodeIndex + 2] = FloatToRawIntBits(prevClip);
                        }
                        // count stats for the unused leaf
                        depth++;
                        stats.UpdateLeaf(depth, 0);
                        // now we keep going as we are, with a new nodeIndex:
                        nodeIndex = nextIndex0;
                    }
                    break;
                }
            }
            // compute index of child nodes
            int nextIndex = tempTree.Count;
            // allocate left node
            int nl = right - left + 1;
            int nr = rightOrig - (right + 1) + 1;

            if (nl > 0)
            {
                tempTree.Add(0);
                tempTree.Add(0);
                tempTree.Add(0);
            }
            else
            {
                nextIndex -= 3;
            }
            // allocate right node
            if (nr > 0)
            {
                tempTree.Add(0);
                tempTree.Add(0);
                tempTree.Add(0);
            }
            // write leaf node
            stats.UpdateInner();
            tempTree[nodeIndex + 0] = (uint)((axis << 30) | nextIndex);
            tempTree[nodeIndex + 1] = FloatToRawIntBits(clipL);
            tempTree[nodeIndex + 2] = FloatToRawIntBits(clipR);
            // prepare L/R child boxes
            AABound gridBoxL = gridBox;
            AABound gridBoxR = gridBox;
            AABound nodeBoxL = nodeBox;
            AABound nodeBoxR = nodeBox;

            gridBoxL.hi[axis] = gridBoxR.lo[axis] = split;
            nodeBoxL.hi[axis] = clipL;
            nodeBoxR.lo[axis] = clipR;
            // recurse
            if (nl > 0)
            {
                Subdivide(left, right, tempTree, dat, gridBoxL, nodeBoxL, nextIndex, depth + 1, stats);
            }
            else
            {
                stats.UpdateLeaf(depth + 1, 0);
            }
            if (nr > 0)
            {
                Subdivide(right + 1, rightOrig, tempTree, dat, gridBoxR, nodeBoxR, nextIndex + 3, depth + 1, stats);
            }
            else
            {
                stats.UpdateLeaf(depth + 1, 0);
            }
        }
Пример #17
0
 private void buildTree(float minx, float maxx, float miny, float maxy, float minz, float maxz, BuildTask task, int depth, List<int> tempTree, int offset, List<int> tempList, BuildStats stats)
 {
     // get node bounding box extents
     if (task.numObjects > maxPrims && depth < MAX_DEPTH)
     {
         float dx = maxx - minx;
         float dy = maxy - miny;
         float dz = maxz - minz;
         // search for best possible split
         float bestCost = INTERSECT_COST * task.numObjects;
         int bestAxis = -1;
         int bestOffsetStart = -1;
         int bestOffsetEnd = -1;
         float bestSplit = 0;
         bool bestPlanarLeft = false;
         int bnl = 0, bnr = 0;
         // inverse area of the bounding box (factor of 2 ommitted)
         float area = (dx * dy + dy * dz + dz * dx);
         float ISECT_COST = INTERSECT_COST / area;
         // setup counts for each axis
         int[] nl = { 0, 0, 0 };
         int[] nr = { task.numObjects, task.numObjects, task.numObjects };
         // setup bounds for each axis
         float[] dp = { dy * dz, dz * dx, dx * dy };
         float[] ds = { dy + dz, dz + dx, dx + dy };
         float[] nodeMin = { minx, miny, minz };
         float[] nodeMax = { maxx, maxy, maxz };
         // search for best cost
         int nSplits = task.n;
         long[] splits = task.splits;
         byte[] lrtable = task.leftRightTable;
         for (int i = 0; i < nSplits; )
         {
             // extract current split
             long ptr = splits[i];
             float split = unpackSplit(ptr);
             int axis = unpackAxis(ptr);
             // mark current position
             int currentOffset = i;
             // count number of primitives start/stopping/lying on the
             // current plane
             int pClosed = 0, pPlanar = 0, pOpened = 0;
             long ptrMasked = (long)((ulong)ptr & (~((ulong)TYPE_MASK) & 0xFFFFFFFFF0000000L));
             long ptrClosed = ptrMasked | CLOSED;
             long ptrPlanar = ptrMasked | PLANAR;
             long ptrOpened = ptrMasked | OPENED;
             while (i < nSplits && ((ulong)splits[i] & 0xFFFFFFFFF0000000L) == (ulong)ptrClosed)
             {
                 int obj = unpackObject(splits[i]);
                 lrtable[(uint)obj >> 2] = 0;//>>>
                 pClosed++;
                 i++;
             }
             while (i < nSplits && ((ulong)splits[i] & 0xFFFFFFFFF0000000L) == (ulong)ptrPlanar)
             {
                 int obj = unpackObject(splits[i]);
                 lrtable[(uint)obj >> 2] = 0;//>>>
                 pPlanar++;
                 i++;
             }
             while (i < nSplits && ((ulong)splits[i] & 0xFFFFFFFFF0000000L) == (ulong)ptrOpened)
             {
                 int obj = unpackObject(splits[i]);
                 lrtable[(uint)obj >> 2] = 0;//>>>
                 pOpened++;
                 i++;
             }
             // now we have summed all contributions from this plane
             nr[axis] -= pPlanar + pClosed;
             // compute cost
             if (split >= nodeMin[axis] && split <= nodeMax[axis])
             {
                 // left and right surface area (factor of 2 ommitted)
                 float dl = split - nodeMin[axis];
                 float dr = nodeMax[axis] - split;
                 float lp = dp[axis] + dl * ds[axis];
                 float rp = dp[axis] + dr * ds[axis];
                 // planar prims go to smallest cell always
                 bool planarLeft = dl < dr;
                 int numLeft = nl[axis] + (planarLeft ? pPlanar : 0);
                 int numRight = nr[axis] + (planarLeft ? 0 : pPlanar);
                 float eb = ((numLeft == 0 && dl > 0) || (numRight == 0 && dr > 0)) ? EMPTY_BONUS : 0;
                 float cost = TRAVERSAL_COST + ISECT_COST * (1 - eb) * (lp * numLeft + rp * numRight);
                 if (cost < bestCost)
                 {
                     bestCost = cost;
                     bestAxis = axis;
                     bestSplit = split;
                     bestOffsetStart = currentOffset;
                     bestOffsetEnd = i;
                     bnl = numLeft;
                     bnr = numRight;
                     bestPlanarLeft = planarLeft;
                 }
             }
             // move objects left
             nl[axis] += pOpened + pPlanar;
         }
         // debug check for correctness of the scan
         for (int axis = 0; axis < 3; axis++)
         {
             int numLeft = nl[axis];
             int numRight = nr[axis];
             if (numLeft != task.numObjects || numRight != 0)
                 UI.printError(UI.Module.ACCEL, "Didn't scan full range of objects @depth={0}. Left overs for axis {1}: [L: {2}] [R: {3}]", depth, axis, numLeft, numRight);
         }
         // found best split?
         if (bestAxis != -1)
         {
             // allocate space for child nodes
             BuildTask taskL = new BuildTask(bnl, task);
             BuildTask taskR = new BuildTask(bnr, task);
             int lk = 0, rk = 0;
             for (int i = 0; i < bestOffsetStart; i++)
             {
                 long ptr = splits[i];
                 if (unpackAxis(ptr) == bestAxis)
                 {
                     if (unpackSplitType(ptr) != CLOSED)
                     {
                         int obj = unpackObject(ptr);
                         lrtable[(uint)obj >> 2] |= (byte)(1 << ((obj & 3) << 1));//>>>
                         lk++;
                     }
                 }
             }
             for (int i = bestOffsetStart; i < bestOffsetEnd; i++)
             {
                 long ptr = splits[i];
                 Debug.Assert(unpackAxis(ptr) == bestAxis);
                 if (unpackSplitType(ptr) == PLANAR)
                 {
                     if (bestPlanarLeft)
                     {
                         int obj = unpackObject(ptr);
                         lrtable[(uint)obj >> 2] |= (byte)(1 << ((obj & 3) << 1));//>>>
                         lk++;
                     }
                     else
                     {
                         int obj = unpackObject(ptr);
                         lrtable[(uint)obj >> 2] |= (byte)(2 << ((obj & 3) << 1));//>>>
                         rk++;
                     }
                 }
             }
             for (int i = bestOffsetEnd; i < nSplits; i++)
             {
                 long ptr = splits[i];
                 if (unpackAxis(ptr) == bestAxis)
                 {
                     if (unpackSplitType(ptr) != OPENED)
                     {
                         int obj = unpackObject(ptr);
                         lrtable[(uint)obj >> 2] |= (byte)(2 << ((obj & 3) << 1));//>>>
                         rk++;
                     }
                 }
             }
             // output new splits while maintaining order
             long[] splitsL = taskL.splits;
             long[] splitsR = taskR.splits;
             int nsl = 0, nsr = 0;
             for (int i = 0; i < nSplits; i++)
             {
                 long ptr = splits[i];
                 int obj = unpackObject(ptr);
                 int idx = (int)((uint)obj >> 2);//>>>
                 int mask = 1 << ((obj & 3) << 1);
                 if ((lrtable[idx] & mask) != 0)
                 {
                     splitsL[nsl] = ptr;
                     nsl++;
                 }
                 if ((lrtable[idx] & (mask << 1)) != 0)
                 {
                     splitsR[nsr] = ptr;
                     nsr++;
                 }
             }
             taskL.n = nsl;
             taskR.n = nsr;
             // free more memory
             task.splits = splits = splitsL = splitsR = null;
             task = null;
             // allocate child nodes
             int nextOffset = tempTree.Count;
             tempTree.Add(0);
             tempTree.Add(0);
             tempTree.Add(0);
             tempTree.Add(0);
             // create current node
             tempTree[offset + 0] = (bestAxis << 30) | nextOffset;
             tempTree[offset + 1] = ByteUtil.floatToRawIntBits(bestSplit);
             // recurse for child nodes - free object arrays after each step
             stats.updateInner();
             switch (bestAxis)
             {
                 case 0:
                     buildTree(minx, bestSplit, miny, maxy, minz, maxz, taskL, depth + 1, tempTree, nextOffset, tempList, stats);
                     taskL = null;
                     buildTree(bestSplit, maxx, miny, maxy, minz, maxz, taskR, depth + 1, tempTree, nextOffset + 2, tempList, stats);
                     taskR = null;
                     return;
                 case 1:
                     buildTree(minx, maxx, miny, bestSplit, minz, maxz, taskL, depth + 1, tempTree, nextOffset, tempList, stats);
                     taskL = null;
                     buildTree(minx, maxx, bestSplit, maxy, minz, maxz, taskR, depth + 1, tempTree, nextOffset + 2, tempList, stats);
                     taskR = null;
                     return;
                 case 2:
                     buildTree(minx, maxx, miny, maxy, minz, bestSplit, taskL, depth + 1, tempTree, nextOffset, tempList, stats);
                     taskL = null;
                     buildTree(minx, maxx, miny, maxy, bestSplit, maxz, taskR, depth + 1, tempTree, nextOffset + 2, tempList, stats);
                     taskR = null;
                     return;
                 default:
                     Debug.Assert(false);
                     break;
             }
         }
     }
     // create leaf node
     int listOffset = tempList.Count;
     int n = 0;
     for (int i = 0; i < task.n; i++)
     {
         long ptr = task.splits[i];
         if (unpackAxis(ptr) == 0 && unpackSplitType(ptr) != CLOSED)
         {
             tempList.Add(unpackObject(ptr));
             n++;
         }
     }
     stats.updateLeaf(depth, n);
     if (n != task.numObjects)
         UI.printError(UI.Module.ACCEL, "Error creating leaf node - expecting {0} found {1}", task.numObjects, n);
     tempTree[offset + 0] = (3 << 30) | listOffset;
     tempTree[offset + 1] = task.numObjects;
     // free some memory
     task.splits = null;
 }