Advertisement
Guest User

Untitled

a guest
Dec 27th, 2013
94
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
D 7.55 KB | None | 0 0
  1. module dmech.bvh;
  2.  
  3. import std.array;
  4. import std.math;
  5.  
  6. import dlib.core.compound;
  7. import dlib.math.utils;
  8. import dlib.math.vector;
  9. import dlib.geometry.aabb;
  10. import dlib.geometry.sphere;
  11. import dlib.geometry.ray;
  12.  
  13. /*
  14.  * Bounding Volume Hierarchy implementation
  15.  */
  16.  
  17. // Returns the axis that has the largest length
  18. Axis boxGetMainAxis(AABB box)
  19. {
  20.     float xl = box.size.x;
  21.     float yl = box.size.y;
  22.     float zl = box.size.z;
  23.          
  24.     if (xl < yl)
  25.     {
  26.         if (yl < zl)
  27.            return Axis.z;
  28.         return Axis.y;
  29.     }
  30.     else if (xl < zl)
  31.         return Axis.z;
  32.     return Axis.x;        
  33. }
  34.  
  35. struct SplitPlane
  36. {
  37.     public:
  38.     float split;
  39.     Axis axis;
  40.    
  41.     this(float s, Axis ax)
  42.     {
  43.         split = s;
  44.         axis = ax;
  45.     }
  46. }
  47.  
  48. SplitPlane boxGetSplitPlaneForAxis(AABB box, Axis a)
  49. {
  50.     return SplitPlane(box.center[a], a);
  51. }
  52.  
  53. Compound!(AABB, AABB) boxSplitWithPlane(AABB box, SplitPlane sp)
  54. {
  55.     Vector3f minLP = box.pmin;
  56.     Vector3f maxLP = box.pmax;
  57.     maxLP[sp.axis] = sp.split;
  58.    
  59.     Vector3f minRP = box.pmin;
  60.     Vector3f maxRP = box.pmax;
  61.     minRP[sp.axis] = sp.split;
  62.  
  63.     AABB leftB = boxFromMinMaxPoints(minLP, maxLP);
  64.     AABB rightB = boxFromMinMaxPoints(minRP, maxRP);
  65.  
  66.     return compound(leftB, rightB);
  67. }
  68.  
  69. AABB enclosingAABB(T)(T[] objects)
  70. {
  71.     Vector3f pmin = objects[0].boundingBox.pmin;
  72.     Vector3f pmax = pmin;
  73.    
  74.     void adjustMinPoint(Vector3f p)
  75.     {    
  76.         if (p.x < pmin.x) pmin.x = p.x;
  77.         if (p.y < pmin.y) pmin.y = p.y;
  78.         if (p.z < pmin.z) pmin.z = p.z;
  79.     }
  80.    
  81.     void adjustMaxPoint(Vector3f p)
  82.     {
  83.         if (p.x > pmax.x) pmax.x = p.x;
  84.         if (p.y > pmax.y) pmax.y = p.y;
  85.         if (p.z > pmax.z) pmax.z = p.z;
  86.     }
  87.  
  88.     foreach(ref obj; objects)
  89.     {
  90.         adjustMinPoint(obj.boundingBox.pmin);
  91.         adjustMaxPoint(obj.boundingBox.pmax);
  92.     }
  93.    
  94.     return boxFromMinMaxPoints(pmin, pmax);
  95. }
  96.  
  97. class BVHNode(T)
  98. {
  99.     T[] objects;
  100.     AABB aabb;
  101.     BVHNode[2] child;
  102.     uint userData;
  103.  
  104.     this(T[] objs)
  105.     {
  106.         objects = objs;
  107.         aabb = enclosingAABB(objects); //boxFromTriangles(objects);
  108.     }
  109. }
  110.  
  111. void traverseBySphere(T)(BVHNode!T node, ref Sphere sphere, void delegate(ref T) func)
  112. {
  113.     Vector3f cn;
  114.     float pd;
  115.     if (node.aabb.intersectsSphere(sphere, cn, pd))
  116.     {
  117.         if (node.child[0] !is null)
  118.             node.child[0].traverseBySphere(sphere, func);
  119.         if (node.child[1] !is null)
  120.             node.child[1].traverseBySphere(sphere, func);
  121.  
  122.         foreach(ref obj; node.objects)
  123.             func(obj);
  124.     }
  125. }
  126.  
  127. void traverse(T)(BVHNode!T node, void delegate(BVHNode!T) func)
  128. {
  129.     if (node.child[0] !is null)
  130.         node.child[0].traverse(func);
  131.     if (node.child[1] !is null)
  132.         node.child[1].traverse(func);
  133.  
  134.     func(node);
  135. }
  136.  
  137. void traverseByRay(T)(BVHNode!T node, Ray ray, void delegate(ref T) func)
  138. {
  139.     float it = 0.0f;
  140.     if (node.aabb.intersectsSegment(ray.p0, ray.p1, it))
  141.     {
  142.         if (node.child[0] !is null)
  143.             node.child[0].traverseByRay(ray, func);
  144.         if (node.child[1] !is null)
  145.             node.child[1].traverseByRay(ray, func);
  146.  
  147.         foreach(ref obj; node.objects)
  148.             func(obj);
  149.     }
  150. }
  151.  
  152. // TODO:
  153. // - support multithreading (2 children = 2 threads)
  154. // - add ESC (Early Split Clipping)
  155. enum Heuristic
  156. {
  157.     HMA, // Half Main Axis
  158.     SAH, // Surface Area Heuristic
  159.     //ESC  // Early Split Clipping
  160. }
  161.  
  162. class BVHTree(T)
  163. {
  164.     BVHNode!T root;
  165.  
  166.     this(T[] objects,
  167.          uint maxObjectsPerNode = 8,
  168.          Heuristic splitHeuristic = Heuristic.SAH)
  169.     {
  170.         root = construct(objects, maxObjectsPerNode, splitHeuristic);
  171.     }
  172.  
  173.     BVHNode!T construct(
  174.          T[] objects,
  175.          uint maxObjectsPerNode,
  176.          Heuristic splitHeuristic)
  177.     {
  178.         AABB box = enclosingAABB(objects);
  179.        
  180.         SplitPlane sp;
  181.         if (splitHeuristic == Heuristic.HMA)
  182.             sp = getHalfMainAxisSplitPlane(objects, box);
  183.         else if (splitHeuristic == Heuristic.SAH)
  184.             sp = getSAHSplitPlane(objects, box);
  185.         else
  186.             assert(0, "BVH: unsupported split heuristic");
  187.            
  188.         auto boxes = boxSplitWithPlane(box, sp);
  189.  
  190.         T[] leftObjects;
  191.         T[] rightObjects;
  192.    
  193.         foreach(obj; objects)
  194.         {
  195.             if (boxes[0].intersectsAABB(obj.boundingBox))
  196.                 leftObjects ~= obj;
  197.             else if (boxes[1].intersectsAABB(obj.boundingBox))
  198.                 rightObjects ~= obj;
  199.         }
  200.    
  201.         BVHNode!T node = new BVHNode!T(objects);
  202.  
  203.         if (objects.length <= maxObjectsPerNode)
  204.             return node;
  205.        
  206.         if (leftObjects.length > 0 || rightObjects.length > 0)
  207.             node.objects = [];
  208.  
  209.         if (leftObjects.length > 0)
  210.             node.child[0] = construct(leftObjects, maxObjectsPerNode, splitHeuristic);
  211.         else
  212.             node.child[0] = null;
  213.    
  214.         if (rightObjects.length > 0)
  215.             node.child[1] = construct(rightObjects, maxObjectsPerNode, splitHeuristic);
  216.         else
  217.             node.child[1] = null;
  218.  
  219.         return node;    
  220.     }
  221.  
  222.     SplitPlane getHalfMainAxisSplitPlane(ref T[] objects, ref AABB box)
  223.     {
  224.         Axis axis = boxGetMainAxis(box);
  225.         return boxGetSplitPlaneForAxis(box, axis);
  226.     }
  227.  
  228.     SplitPlane getSAHSplitPlane(ref T[] objects, ref AABB box)
  229.     {
  230.         Axis axis = boxGetMainAxis(box);
  231.        
  232.         float minAlongSplitPlane = box.pmin[axis];
  233.         float maxAlongSplitPlane = box.pmax[axis];
  234.        
  235.         float bestSAHCost = float.nan;
  236.         float bestSplitPoint = float.nan;
  237.  
  238.         int iterations = 12;
  239.         foreach (i; 0..iterations)
  240.         {
  241.             float valueOfSplit = minAlongSplitPlane +
  242.                                ((maxAlongSplitPlane - minAlongSplitPlane) / (iterations + 1.0f) * (i + 1.0f));
  243.  
  244.             SplitPlane SAHSplitPlane = SplitPlane(valueOfSplit, axis);
  245.             auto boxes = boxSplitWithPlane(box, SAHSplitPlane);
  246.  
  247.             uint leftObjectsLength = 0;
  248.             uint rightObjectsLength = 0;
  249.  
  250.             foreach(obj; objects)
  251.             {
  252.                 if (boxes[0].intersectsAABB(obj.boundingBox))
  253.                     leftObjectsLength++;
  254.                 else if (boxes[1].intersectsAABB(obj.boundingBox))
  255.                     rightObjectsLength++;
  256.             }
  257.  
  258.             if (leftObjectsLength > 0 && rightObjectsLength > 0)
  259.             {
  260.                 float SAHCost = getSAHCost(boxes[0], leftObjectsLength,
  261.                                            boxes[1], rightObjectsLength, box);
  262.  
  263.                 if (bestSAHCost.isNaN || SAHCost < bestSAHCost)
  264.                 {
  265.                     bestSAHCost = SAHCost;
  266.                     bestSplitPoint = valueOfSplit;
  267.                 }
  268.             }
  269.         }
  270.        
  271.         return SplitPlane(bestSplitPoint, axis);
  272.     }
  273.  
  274.     float getSAHCost(AABB leftBox, uint numLeftObjects,
  275.                      AABB rightBox, uint numRightObjects,
  276.                      AABB parentBox)
  277.     {
  278.         return getSurfaceArea(leftBox) / getSurfaceArea(parentBox) * numLeftObjects
  279.              + getSurfaceArea(rightBox) / getSurfaceArea(parentBox) * numRightObjects;
  280.     }
  281.  
  282.     float getSurfaceArea(AABB bbox)
  283.     {
  284.         float width = bbox.pmax.x - bbox.pmin.x;
  285.         float height = bbox.pmax.y - bbox.pmin.y;
  286.         float depth = bbox.pmax.z - bbox.pmin.z;
  287.         return 2.0f * (width * height + width * depth + height * depth);
  288.     }
  289. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement