public void Construct(Aggregate aggregate) { Material = ((IIntersectable)aggregate).Material; Aggregate objects = new IntersectableList(); foreach (IIntersectable intersectable in aggregate.GetObjects()) { objects.Add(intersectable); } BoundingBox = ((IIntersectable)aggregate).BoundingBox; //Calculate max treed depth = 8+1.3*log(n); maxTreeDepth = (int)Math.Ceiling(8 + (1.3 * Math.Log(objects.Intersectables.Count))); RootNode = new BspNode(); //Kick off the recursive tree construction RootNode.BuildSubTree(objects, BoundingBox, maxTreeDepth, 0); }
public HitRecord Intersect(Ray ray) { #region BSP Tree Traversal BspNode node = RootNode; HitRecord hit = null; Stack <BspStackItem> nodeStack = new Stack <BspStackItem>(); BspNode first, second; float[] boxIntersections = node.BoundingBox.Intersect(ray); if (boxIntersections == null) { return(null); } float tmin = boxIntersections[0]; float tmax = boxIntersections[1]; float isect = float.MaxValue; while (node != null) { if (isect < tmin) { return(hit); } if (!node.IsLeaf) { //process interior node //tsplit = compute ray-split plane intersection //<order of children> //<process of children> float tSplit = node.DistanceToSplitPlane(ray); //Order children if (ray.Origin[node.Axis] < node.PlanePos) { first = node.RightNode; second = node.LeftNode; } else { first = node.LeftNode; second = node.RightNode; } //Process children if (tSplit < 0 || tSplit > tmax || (tSplit == 0.0f && ray.Direction[node.Axis] > 0)) { node = first; } else if (tSplit < tmin || (tSplit == 0.0f && ray.Direction[node.Axis] < 0)) { node = second; } else { node = first; BspStackItem item = new BspStackItem(second, tSplit, tmax); nodeStack.Push(item); tmax = tSplit; } } else { //Intersection = first intersection in leaf HitRecord tmpHitRecord = node.Intersectables.Intersect(ray);; if (tmpHitRecord != null) { isect = tmpHitRecord.Distance; hit = tmpHitRecord; } if (nodeStack.Count > 0) { BspStackItem sItem = nodeStack.Pop(); node = sItem.Node; tmin = sItem.Tmin; tmax = sItem.Tmax; } else { node = null; } } } return(hit); #endregion #region simple tree traversal /** * Traverse the tree and do intersection */ /*Stack<BspNode> nodesToVisit = new Stack<BspNode>(); * nodesToVisit.Push(RootNode); * HitRecord hit = null; * HitRecord tempHit; * while (nodesToVisit.Count > 0) * { * BspNode currentNode = nodesToVisit.Pop(); * if (currentNode.IsLeaf) * { * foreach (IIntersectable intersectable in currentNode.Intersectables) * { * tempHit = intersectable.Intersect(ray); * if (tempHit != null) * { * if (hit == null) hit = tempHit; * else if (tempHit.Distance < hit.Distance) hit = tempHit; * } * } * } * else * { * nodesToVisit.Push(currentNode.LeftNode); * nodesToVisit.Push(currentNode.RightNode); * } * } * return hit;*/ #endregion }
public BspStackItem(BspNode node, float tmin, float tmax) { Node = node; Tmin = tmin; Tmax = tmax; }
public void BuildSubTree(Aggregate intersectables, IBoundingBox boundingBox, int maxTreeDepth, int currentTreeDetph) { Intersectables = intersectables; BoundingBox = boundingBox; if (Intersectables.GetNumberOfComponents() <= 5 || currentTreeDetph == maxTreeDepth) { IsLeaf = true; } else { Aggregate leftIntersectables = new IntersectableList(); Aggregate rightIntersectables = new IntersectableList(); //Find the maximal Axis Axis = 0; float max = BoundingBox.Dimension.X; if (BoundingBox.Dimension.Y > max) { Axis = 1; } if (BoundingBox.Dimension.Z > max) { Axis = 2; } //Axis = currentTreeDetph % 3; PlanePos = BoundingBox.MaxVector[Axis] - (BoundingBox.MaxVector[Axis] - BoundingBox.MinVector[Axis]) / 2; Vector3 leftMin = Vector3.Zero; Vector3 leftMax = Vector3.Zero; Vector3 rightMin = Vector3.Zero; Vector3 rightMax = Vector3.Zero; switch (Axis) { case 0: leftMin = new Vector3(PlanePos, BoundingBox.MinVector.Y, BoundingBox.MinVector.Z); leftMax = new Vector3(BoundingBox.MaxVector); rightMin = new Vector3(BoundingBox.MinVector); rightMax = new Vector3(PlanePos, BoundingBox.MaxVector.Y, BoundingBox.MaxVector.Z); break; case 1: leftMin = new Vector3(BoundingBox.MinVector.X, PlanePos, BoundingBox.MinVector.Z); leftMax = new Vector3(BoundingBox.MaxVector); rightMin = new Vector3(BoundingBox.MinVector); rightMax = new Vector3(BoundingBox.MaxVector.X, PlanePos, BoundingBox.MaxVector.Z); break; case 2: leftMin = new Vector3(BoundingBox.MinVector.X, BoundingBox.MinVector.Y, PlanePos); leftMax = new Vector3(BoundingBox.MaxVector); rightMin = new Vector3(BoundingBox.MinVector); rightMax = new Vector3(BoundingBox.MaxVector.X, BoundingBox.MaxVector.Y, PlanePos); break; } IBoundingBox leftBb = new AxisAlignedBoundingBox(leftMin, leftMax); IBoundingBox rightBb = new AxisAlignedBoundingBox(rightMin, rightMax); LeftNode = new BspNode(); RightNode = new BspNode(); foreach (IIntersectable intersectable in Intersectables.GetObjects()) { if (intersectable.BoundingBox.Intersect(leftBb)) { leftIntersectables.Add(intersectable); } if (intersectable.BoundingBox.Intersect(rightBb)) { rightIntersectables.Add(intersectable); } } LeftNode.BuildSubTree(leftIntersectables, leftBb, maxTreeDepth, currentTreeDetph + 1); RightNode.BuildSubTree(rightIntersectables, rightBb, maxTreeDepth, currentTreeDetph + 1); Intersectables = null; //Clear up the intersectables in non leaf nodes to save space } }