示例#1
0
 public void SplitPlanes()
 {
     for (int i = 0; i < 100; i++)
     {
         Vector3    direction = Utils.Random.UnitVector();
         float      start     = (float)Utils.Random.NextDouble();
         float      end       = (float)Utils.Random.NextDouble();
         SpatialBin bin       = new SpatialBin(direction, start, end);
         Assert.AreEqual(direction * start, bin.SplitPlaneLeft.Position);
         Assert.AreEqual(direction, bin.SplitPlaneLeft.Normal);
         Assert.AreEqual(direction * end, bin.SplitPlaneRight.Position);
         Assert.AreEqual(-direction, bin.SplitPlaneRight.Normal);
     }
 }
示例#2
0
        public void BoundingBox()
        {
            Vector3    direction = Vector3.UnitX;
            float      start     = -1f;
            float      end       = 1f;
            SpatialBin bin       = new SpatialBin(direction, start, end);

            for (int i = 0; i < 1000; i++)
            {
                bin.AABB.Add(Utils.Random.Sphere(0f, 1f));
                bin.ClipAndAdd(Utils.Random.Primitive(1f, 3f));
            }
            Vector3[] bounds = bin.AABB.Bounds;
            Assert.AreEqual(-1f, bounds[0].X);
            Assert.AreEqual(1f, bounds[1].X);
        }
示例#3
0
        public void Constructor()
        {
            SpatialBin bin = new SpatialBin(Vector3.UnitX, 0f, 1f);

            Assert.IsTrue(bin != null);
        }
    private SpatialSplit FindSpatialSplit(NodeSpec spec, float nodeSAH)
    {
        // _bins变量每一次分割都被复用
        var origin     = spec.bounds.min;
        var binSize    = (spec.bounds.max - origin) / N_SPATIAL_BINS;
        var invBinSize = new Vector3(1f / binSize.x, 1f / binSize.y, 1f / binSize.z);

        for (int dim = 0; dim < 3; dim++)
        {
            for (int i = 0; i < N_SPATIAL_BINS; i++)
            {
                _bins[dim, i] = SpatialBin.New();
            }
        }

        // 把图元分配到3个维度的bin中
        for (int refIdx = _refStack.Count - spec.numRef; refIdx < _refStack.Count; refIdx++)
        {
            var pRef = _refStack[refIdx];
            // ....Vector3Int.FloorToInt 误用了 celling...查半天。。。。
            var firstBin = MathUtils.ClampV3Int(Vector3Int.FloorToInt((pRef.bounds.min - origin).Multiply(invBinSize)), Vector3Int.zero, new Vector3Int(N_SPATIAL_BINS - 1, N_SPATIAL_BINS - 1, N_SPATIAL_BINS - 1));
            var lastBin  = MathUtils.ClampV3Int(Vector3Int.FloorToInt((pRef.bounds.max - origin).Multiply(invBinSize)), firstBin, new Vector3Int(N_SPATIAL_BINS - 1, N_SPATIAL_BINS - 1, N_SPATIAL_BINS - 1));

            for (int dim = 0; dim < 3; dim++)
            {
                var curRef = pRef;
                // 从左到右分割,curRef并不更新图元索引,只更新包围盒
                for (int i = firstBin[dim]; i < lastBin[dim]; i++)
                {
                    PrimitiveRef leftRef, rightRef;
                    SplitReference(out leftRef, out rightRef, curRef, dim, origin[dim] + binSize[dim] * (i + 1));
                    _bins[dim, i].bounds.Union(leftRef.bounds);
                    curRef = rightRef;
                }

                _bins[dim, lastBin[dim]].bounds.Union(curRef.bounds); // 分割后图元最右边的包围盒也算进来
                                                                      // 只对分割后图元所在的第一个和最后一个bin添加图元引用计数
                _bins[dim, firstBin[dim]].enter++;
                _bins[dim, lastBin[dim]].exit++;
            }
        }

        // 根据分割好的bins,来选择最佳分割平面,跟FindObjectSplit类似,只不过是以bin为单位,而不是图元
        SpatialSplit split = SpatialSplit.New();

        for (byte dim = 0; dim < 3; dim++)
        {
            // 从右到左,记录每一种可能的分割后,处在“右边”包围盒的
            AABB rightBounds = AABB.New();
            for (int i = N_SPATIAL_BINS - 1; i > 0; i--)
            {
                rightBounds.Union(_bins[dim, i].bounds);
                _rightBounds[i - 1] = rightBounds; //_rightBounds用来临时记录右边包围盒的,被复用
            }

            AABB leftBounds = AABB.New();
            int  leftNum    = 0;
            int  rightNum   = spec.numRef;
            for (int i = 1; i < N_SPATIAL_BINS; i++)
            {
                leftBounds.Union(_bins[dim, i - 1].bounds);
                leftNum  += _bins[dim, i - 1].enter;
                rightNum -= _bins[dim, i - 1].exit;

                float sah = nodeSAH + leftBounds.Area * leftNum + _rightBounds[i - 1].Area * rightNum;
                if (sah < split.sah)
                {
                    split.sah = sah;
                    split.dim = dim;
                    split.pos = origin[dim] + binSize[dim] * i;
                }
            }
        }

        return(split);
    }