private static BoundingBox CalculateBoundingBox(Intersectable[] objects, long startIndex, long endIndex) { BoundingBox box = BoundingBox.CreateFromPoints(objects[0].BoundingBox.GetCorners()); for (long i = startIndex; i < endIndex; i++) { BoundingBox.CreateMerged(ref box, ref objects[i].BoundingBox, out box); } return box; }
private static Intersectable[] CopyArraySection(Intersectable[] objects, long startIndex, long length) { Intersectable[] left = new Intersectable[length]; Array.Copy(objects, startIndex, left, 0, length); return left; }
private static BoundingBox CalculateBoundingBox(Intersectable[] objects) { return CalculateBoundingBox(objects, 0, objects.Length); }
private float? FindSplit(BvhNode node, Intersectable[] objects, out int axisIndexa) { float sP = BoxSurface(node.BoundingBox); int bestAxis = MaxAxisIndex(node.BoundingBox); float? bestSplit = null; float minC = float.MaxValue; for (int axis = 0; axis < 3; axis++) { Array.Sort(objects, (objA, objB) => objA.Center.AxisValue(axis).CompareTo(objB.Center.AxisValue(axis))); float[] centers = objects.Select(intersectable => intersectable.Center.AxisValue(axis)).ToArray(); float min = node.BoundingBox.Min.AxisValue(axis); float max = node.BoundingBox.Max.AxisValue(axis); float step = (max - min)/10; for (float split = min + step; split < max; split += step) { int splitIndex = Array.BinarySearch(centers, split); splitIndex = splitIndex < 0 ? ~splitIndex : splitIndex; int nL = splitIndex; int nR = objects.Length - splitIndex; float sL = BoxSurface(CalculateBoundingBox(objects, 0, nL)); float sR = BoxSurface(CalculateBoundingBox(objects, splitIndex, nR)); float c = _boxCost + (sL/sP)*nL*_triangleCost + (sR/sP)*nR*_triangleCost; if (c < minC) { minC = c; bestSplit = split; bestAxis = axis; } } } if (minC < objects.Length*_triangleCost) { axisIndexa = bestAxis; return bestSplit; } else { axisIndexa = 1; return null; } }
private void CreateAndSplitChildNode(BvhNode node, Intersectable[] objects, int splitIndex, long lenght, int depht) { var right = CopyArraySection(objects, splitIndex, lenght); node.BoundingBox = CalculateBoundingBox(right); BuildRecursive(node, right, depht); }
private void BuildRecursive(BvhNode node, Intersectable[] objects, int depht) { //var axisIndex = MaxAxisIndex(node.BoundingBox); int axisIndex; float? splitPoint = FindSplit(node, objects, out axisIndex); if (!splitPoint.HasValue || objects.Length < _minObjectsPerLeaf || depht > _maxDepth) { node.IsLeaf = true; node.Objects = objects; //Console.WriteLine("{2} {1} {0}", depht, objects.Length, Math.Max(Math.Max(node.BoundingBox.Max.X - node.BoundingBox.Min.X,node.BoundingBox.Max.Y - node.BoundingBox.Min.Y),node.BoundingBox.Max.Z - node.BoundingBox.Min.Z)); return; } Array.Sort(objects, (objA, objB) => objA.Center.AxisValue(axisIndex).CompareTo(objB.Center.AxisValue(axisIndex))); float[] centers = objects.Select(intersectable => intersectable.Center.AxisValue(axisIndex)).ToArray(); int splitIndex = Array.BinarySearch(centers, splitPoint); splitIndex = splitIndex < 0 ? ~splitIndex : splitIndex; long leftLenght = splitIndex; if (leftLenght > 0) { node.Left = new BvhNode(); CreateAndSplitChildNode(node.Left, objects, 0, leftLenght, depht + 1); } long rightLenght = objects.LongLength - splitIndex; if (rightLenght > 0) { node.Right = new BvhNode(); CreateAndSplitChildNode(node.Right, objects, splitIndex, rightLenght, depht + 1); } }