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); } }
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); }
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); }