Advertisement
Guest User

Untitled

a guest
Nov 15th, 2019
157
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 10.97 KB | None | 0 0
  1. #pragma once
  2.  
  3. #include <Geometry/BoundingBox.h>
  4.  
  5. #include <deque>
  6. #include <set>
  7. #include <algorithm>
  8.  
  9. namespace Geometry
  10. {
  11.    
  12.     class BVH
  13.     {
  14.     private:
  15.         class BVHNode
  16.         {
  17.         private:
  18.             static bool triangleSortCriteria(const Triangle * t1, const Triangle * t2, int axis)
  19.             {
  20.                 return t1->center()[axis] < t2->center()[axis];
  21.             }
  22.  
  23.         protected:
  24.             BoundingBox * m_boundingBox;
  25.             std::vector<Triangle *> m_triangles;
  26.             BVHNode * m_firstSon;
  27.             BVHNode * m_secondSon;
  28.             bool isLeaf;
  29.  
  30.         public:
  31.  
  32.             BVHNode()
  33.             {
  34.                 m_boundingBox = new BoundingBox();
  35.                 this->isLeaf = false;
  36.                 m_firstSon = nullptr;
  37.                 m_secondSon = nullptr;
  38.             }
  39.  
  40.             ~BVHNode()
  41.             {
  42.                 delete m_boundingBox;
  43.                 delete m_firstSon;
  44.                 delete m_secondSon;
  45.             }
  46.  
  47.             // adds a deque of triangles to the node
  48.             void addTriangles(std::vector<Triangle *> & triangles)
  49.             {
  50.                 for (Triangle * t : triangles)
  51.                 {
  52.                     this->addTriangle(t);
  53.                 }
  54.             }
  55.  
  56.             // adds one triangle to the node
  57.             void addTriangle(Triangle * t)
  58.             {
  59.                 m_triangles.push_back(t);
  60.                 m_boundingBox->update(*t);
  61.             }
  62.  
  63.             // adds a deque of triangle to bounding box
  64.             void addTrianglesToBoundingBox(const std::vector<Triangle *> & triangles)
  65.             {
  66.                 for (Triangle * t : triangles)
  67.                 {
  68.                     addTriangleToBoundingBox(t);
  69.                 }
  70.             }
  71.  
  72.             // adds one triangle to bounding box
  73.             void addTriangleToBoundingBox(const Triangle * t)
  74.             {
  75.                 if (m_boundingBox->isEmpty())
  76.                 {
  77.                     Geometry g;
  78.                     g.addTriangle(*t);
  79.                     m_boundingBox->set(g);
  80.                 }
  81.                 m_boundingBox->update(*t);
  82.             }
  83.  
  84.             const BoundingBox & getBoundingBox()
  85.             {
  86.                 return *m_boundingBox;
  87.             }
  88.  
  89.             // This computes the BVH before the first render of the scene
  90.             void compute(std::vector<Triangle *> & triangles, int depth)
  91.             {
  92.                 //std::cout << "\n\ndepth : " << depth << "\nnumber of triangles : " << triangles.size() << std::endl;
  93.                 m_firstSon = new BVHNode();
  94.                 m_secondSon = new BVHNode();
  95.  
  96.                 // adds the triangles to the node
  97.                 this->addTrianglesToBoundingBox(triangles);
  98.  
  99.                 if (triangles.size() < 8)
  100.                 {
  101.                     //std::cout << "added " << triangles.size() << " triangles to leaf node !" << std::endl;
  102.                     this->isLeaf = true;
  103.                     this->addTriangles(triangles);
  104.                     return;
  105.                 }
  106.  
  107.                 std::vector<Triangle *> trianglesL;
  108.                 std::vector<Triangle *> trianglesR;
  109.  
  110.                 // sorts the triangles
  111.                 sortTriangles(triangles, trianglesL, trianglesR);
  112.  
  113.                 // computes the sons of this node
  114.                 this->m_firstSon->compute(trianglesL, depth + 1);
  115.                 this->m_secondSon->compute(trianglesR, depth + 1);
  116.             }
  117.  
  118.             // Sorts triangles relative to an axis using SAH (the axis selected is the one on which the bounding box is the largest)
  119.             void sortTriangles(std::vector<Triangle *> & triangles, std::vector<Triangle *> & trianglesL, std::vector<Triangle *> & trianglesR)
  120.             {
  121.                 int axis = 0;
  122.                 for (int i = 1; i < 3; i++)
  123.                 {
  124.                     double max = this->m_boundingBox->max()[i];
  125.                     double min = this->m_boundingBox->min()[i];
  126.                     if (max - min >= this->m_boundingBox->max()[axis] - this->m_boundingBox->min()[axis])
  127.                         axis = i;
  128.                 }
  129.  
  130.                 // lambda function to sort the triangles using std::sort
  131.                 auto triangleSort = [=](const Triangle * t1, const Triangle * t2) { return triangleSortCriteria(t1, t2, axis); };
  132.  
  133.                 std::sort(triangles.begin(), triangles.end(), triangleSort);
  134.  
  135.                 //std::cout << "sorted array size : " << triangles.size() << std::endl;
  136.                 int size = triangles.size();
  137.  
  138.                 int indexSAH = getSAHIndex(triangles);
  139.  
  140.                 // Dispatching triangles in sub sections (Left & Right)
  141.                 for(int i = size - 1; i >= 0; i--)
  142.                 {
  143.                     if (i < indexSAH + 1)
  144.                     {
  145.                         trianglesL.push_back(triangles.back());
  146.                         triangles.pop_back();
  147.                     }
  148.                     else
  149.                     {
  150.                         trianglesR.push_back(triangles.back());
  151.                         triangles.pop_back();
  152.                     }
  153.                 };
  154.  
  155.                 //std::cout << "Left array size : " << trianglesL.size() << std::endl;
  156.                 //std::cout << "Right array size : " << trianglesR.size() << std::endl;
  157.             }
  158.  
  159.             // this returns the index of the best triangle to dispatch the triangles into two nodes according to the SAH
  160.             int getSAHIndex(std::vector<Triangle *> & triangles)
  161.             {
  162.                 // size of the triangles array
  163.                 int size = triangles.size();
  164.  
  165.                 // vectors used to compute the area of the bounding box of the present node
  166.                 Math::Vector3f min = this->m_boundingBox->min();
  167.                 Math::Vector3f max = this->m_boundingBox->max();
  168.                 Math::Vector3f diff = max - min;
  169.  
  170.                 // surface of this node's bounding box
  171.                 double surface;
  172.  
  173.                 // surfaces of the sons nodes for each triangles (helps to compute the best split)
  174.                 double * surfaceL = new double[size];
  175.                 double * surfaceR = new double[size];
  176.  
  177.                 // vectors used to compute the area of the sons nodes
  178.                 Math::Vector3f minL(Math::makeVector(std::numeric_limits<double>::max(), std::numeric_limits<double>::max(), std::numeric_limits<double>::max()));
  179.                 Math::Vector3f minR(Math::makeVector(std::numeric_limits<double>::max(), std::numeric_limits<double>::max(), std::numeric_limits<double>::max()));
  180.                 Math::Vector3f maxL(Math::makeVector(std::numeric_limits<double>::lowest(), std::numeric_limits<double>::lowest(), std::numeric_limits<double>::lowest()));
  181.                 Math::Vector3f maxR(Math::makeVector(std::numeric_limits<double>::lowest(), std::numeric_limits<double>::lowest(), std::numeric_limits<double>::lowest()));
  182.                 Math::Vector3f diffL, diffR;
  183.  
  184.                 // computation of the area for each possible split of triangles in the sons nodes
  185.                 for (int i = 0; i < size; i++)
  186.                 {
  187.                     // computes the min/max vectors as in a bounding box for the given triangle
  188.                     for (int j = 0; j < 3; j++)
  189.                     {
  190.                         minL = minL.simdMin(triangles.at(i)->vertex(j));
  191.                         maxL = maxL.simdMax(triangles.at(i)->vertex(j));
  192.                         minR = minR.simdMin(triangles.at(size - i - 1)->vertex(j));
  193.                         maxR = maxR.simdMax(triangles.at(size - i - 1)->vertex(j));
  194.                     }
  195.  
  196.                     // used to compute the area (diff[0] = dx, diff[1] = dy, diff[2] = dz)
  197.                     diffL = maxL - minL;
  198.                     diffR = maxR - minR;
  199.  
  200.                     // computation of the surface with the triangles [0, i] and [size - i, size]
  201.                     surfaceL[i] = 2 * (diffL[0] * diffL[1] + diffL[0] * diffL[2] + diffL[1] * diffL[2]);
  202.                     surfaceR[size - i - 1] = 2 * (diffR[0] * diffR[1] + diffR[0] * diffR[2] + diffR[1] * diffR[2]);
  203.  
  204.                     //std::cout << "L : " << surfaceL[i] << "\nR : " << surfaceR[size - i - 1] << std::endl;
  205.                 }
  206.  
  207.                 // computation of the present node bounding box
  208.                 surface = 2 * (diff[0] * diff[1] + diff[0] * diff[2] + diff[1] * diff[2]);
  209.  
  210.                 double cost = 0;
  211.                 double bestCost;
  212.  
  213.                 // definition of the traversal cost and the intersect cost
  214.                 double cost_traversal = 1;
  215.                 double cost_intersect = 1;
  216.  
  217.                 int indexSAH = 0;
  218.  
  219.                 // computation of the cost if the split is [0, 0] | [1, size]
  220.                 bestCost = cost_traversal + surfaceL[0] / surface * 1 * cost_intersect + surfaceR[0] / surface * (size - 1) * cost_intersect;
  221.                 //std::cout << "initial cost :" << bestCost << std::endl;
  222.                 //std::cout << "node surface : " << surface << " | surface L : " << surfaceL[0] << " | surface R : " << surfaceR[1] << " | cost : " << bestCost << std::endl;
  223.  
  224.                 // computation of the best cost
  225.                 for (int i = 1; i < size - 1; i++)
  226.                 {
  227.                     //std::cout << "node surface : " << surface << " | surface L : " << surfaceL[i] << " | surface R : "  << surfaceR[i] << " | cost : " << cost << std::endl;
  228.                     cost = cost_traversal + surfaceL[i] / surface * (i + 1) * cost_intersect + surfaceR[i + 1] / surface * (size - i - 1) * cost_intersect;
  229.                     if (cost <= bestCost)
  230.                     {
  231.                         bestCost = cost;
  232.                         indexSAH = i;
  233.                     }
  234.                     if (cost > size * surface * cost_intersect)
  235.                         break;
  236.                 }
  237.  
  238.                 delete[] surfaceL;
  239.                 delete[] surfaceR;
  240.  
  241.                 return indexSAH;
  242.             }
  243.  
  244.             // This intersects the ray with the BVH. Not optimized yet.
  245.             bool intersection(CastedRay & r, double entryT, double exitT, int depth)
  246.             {
  247.                 if (this->isLeaf)
  248.                 {
  249.                     for (Triangle * t : m_triangles)
  250.                     {
  251.                         r.intersect(t);
  252.                     }
  253.                     return r.validIntersectionFound();
  254.                 }
  255.                 else
  256.                 {
  257.                     double entryTR, exitTR, entryTL, exitTL;
  258.  
  259.                     // epsilon to account errors in floating point operations
  260.                     double epsilon = std::numeric_limits<double>::epsilon() * exitT;
  261.  
  262.                     // tests intersection with the sons node's bounding boxes
  263.                     boolean left = this->m_firstSon->m_boundingBox->intersect(r, entryT-epsilon, exitT+epsilon, entryTL, exitTL);
  264.                     boolean right = this->m_secondSon->m_boundingBox->intersect(r, entryT-epsilon, exitT+epsilon, entryTR, exitTR);
  265.                    
  266.                     // checks if the two intervals are empty
  267.                     if ((!left) && (!right))
  268.                     {
  269.                         return false;
  270.                     }
  271.                     else if (!left || !right) // checks if one of the intervals is empty
  272.                     {
  273.                         if (!right)
  274.                         {
  275.                             return this->m_firstSon->intersection(r, entryTL, exitTL, depth + 1);
  276.                         }
  277.                         else
  278.                         {
  279.                             return this->m_secondSon->intersection(r, entryTR, exitTR, depth + 1);
  280.                         }
  281.                     }
  282.                     else // if none is empty
  283.                     {
  284.                         if (entryTL < entryTR)
  285.                         {
  286.                             bool lSon = this->m_firstSon->intersection(r, entryTL, exitTL, depth + 1);
  287.                             if(!lSon)
  288.                                 return this->m_secondSon->intersection(r, entryTR, exitTR, depth + 1);
  289.                             else if (r.intersectionFound().tRayValue() > entryTR)
  290.                                 return (this->m_secondSon->intersection(r, entryTR, r.intersectionFound().tRayValue(), depth + 1) || lSon);
  291.                             return lSon;
  292.                         }
  293.                         else
  294.                         {
  295.                             bool rSon = this->m_secondSon->intersection(r, entryTR, exitTR, depth + 1);
  296.                             if (!rSon)
  297.                                 return this->m_firstSon->intersection(r, entryTL, exitTL, depth + 1);
  298.                             else if (r.intersectionFound().tRayValue() > entryTL)
  299.                                 return (this->m_firstSon->intersection(r, entryTL, r.intersectionFound().tRayValue(), depth + 1) || rSon);
  300.                             return rSon;
  301.                         }
  302.                     }
  303.                 }
  304.             }
  305.         };
  306.  
  307.     protected:
  308.         BVHNode * m_root;
  309.         std::vector<Triangle *> m_triangles;
  310.  
  311.     public:
  312.  
  313.         BVH()
  314.         {
  315.             m_root = new BVHNode();
  316.         }
  317.  
  318.         ~BVH()
  319.         {
  320.             delete m_root;
  321.             for (Triangle * t : m_triangles)
  322.             {
  323.                 delete t;
  324.             }
  325.         }
  326.  
  327.         // adds every triangle in a geometry to the BVH
  328.         void addGeometry(Geometry & g)
  329.         {
  330.             for (auto it = g.getTriangles().begin(); it!= g.getTriangles().end(); it++)
  331.             {
  332.                 Triangle * t = new Triangle(*it);
  333.                 m_triangles.push_back(t);
  334.             }
  335.         }
  336.  
  337.         // adds a triangle to the bVH
  338.         void addTriangle(Triangle * t)
  339.         {
  340.             this->m_triangles.push_back(t);
  341.         }
  342.  
  343.         // computes BVH tree
  344.         void computeTree()
  345.         {
  346.             std::cout << "nbr de triangles total : " << m_triangles.size() << std::endl;
  347.             this->m_root->compute(this->m_triangles, 0);
  348.         }
  349.  
  350.         // intersects the ray with the scene
  351.         void intersection(CastedRay & r)
  352.         {
  353.             double test1, test2;
  354.             if (!this->m_root->getBoundingBox().intersect(r, 0.0, std::numeric_limits<double>::max(), test1, test2))
  355.                 return;
  356.             this->m_root->intersection(r, 0.0, std::numeric_limits<double>::max(), 0);
  357.         }
  358.     };
  359. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement