Advertisement
Zgragselus

Untitled

Aug 17th, 2023
957
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 36.10 KB | None | 0 0
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using Unity.VisualScripting;
  5. using UnityEngine;
  6. using UnityEngine.Profiling;
  7.  
  8. namespace RayTracer
  9. {
  10.     public class BVH
  11.     {
  12.         public enum SplitMode
  13.         {
  14.             EQUAL_COUNTS = 0,
  15.             MIDDLE,
  16.             SAH
  17.         };
  18.  
  19.         public class PrimitiveInfo
  20.         {
  21.             public Vector3 centroid;
  22.             public AABB bounds;
  23.             public int primitiveID;
  24.  
  25.             public PrimitiveInfo(int id, AABB bbox)
  26.             {
  27.                 primitiveID = id;
  28.                 bounds = bbox;
  29.                 centroid = bounds.min * 0.5f + bounds.max * 0.5f;
  30.             }
  31.         };
  32.  
  33.         public class BuildNode
  34.         {
  35.             public AABB bounds;
  36.             public BuildNode[] children;
  37.             public int splitAxis;
  38.             public int primitiveOffset;
  39.             public int primitiveCount;
  40.  
  41.             public BuildNode()
  42.             {
  43.                 bounds = new AABB();
  44.                 children = new BuildNode[2];
  45.             }
  46.  
  47.             public void InitLeaf(int first, int n, AABB bbox)
  48.             {
  49.                 primitiveOffset = first;
  50.                 primitiveCount = n;
  51.                 bounds = bbox;
  52.                 children = new BuildNode[2];
  53.                 children[0] = null;
  54.                 children[1] = null;
  55.             }
  56.  
  57.             public void InitInterior(int axis, BuildNode child0, BuildNode child1)
  58.             {
  59.                 children = new BuildNode[2];
  60.                 children[0] = child0;
  61.                 children[1] = child1;
  62.                 bounds.Union(children[0].bounds);
  63.                 bounds.Union(children[1].bounds);
  64.                 splitAxis = axis;
  65.                 primitiveCount = 0;
  66.             }
  67.         };
  68.  
  69.         public struct LinearBVHNode
  70.         {
  71.             public Vector4 l_xy;
  72.             public Vector4 r_xy;
  73.             public Vector4 lr_z;
  74.             public int offset;
  75.             public int primitiveCount;
  76.             public int axis;
  77.             public int pad;
  78.         };
  79.  
  80.         public class BucketInfo
  81.         {
  82.             public AABB bounds;
  83.             public int count;
  84.  
  85.             public BucketInfo()
  86.             {
  87.                 bounds = new AABB();
  88.                 count = 0;
  89.             }
  90.         };
  91.  
  92.         Triangle[] triangles;
  93.  
  94.         SplitMode splitMode = SplitMode.SAH;
  95.  
  96.         int maxDepth = 32;
  97.  
  98.         int maxPrimitivesInNode = 32;
  99.         List<int> primitiveIndices;
  100.  
  101.         int bucketsCount = 16;
  102.         List<BucketInfo> buckets;
  103.         List<float> sahCost;
  104.  
  105.         AABB bvhBounds;
  106.  
  107.         BuildNode root;
  108.  
  109.         List<LinearBVHNode> nodes;
  110.  
  111.         public List<LinearBVHNode> GetNodes()
  112.         {
  113.             return nodes;
  114.         }
  115.  
  116.         public List<int> GetPrimitiveIndexes()
  117.         {
  118.             return primitiveIndices;
  119.         }
  120.  
  121.         int FindIfNot<T>(List<T> data, int first, int last, Func<T, bool> predicate)
  122.         {
  123.             int i = first;
  124.             for (; i != last; i++)
  125.             {
  126.                 if (!predicate(data[i]))
  127.                 {
  128.                     return i;
  129.                 }
  130.             }
  131.  
  132.             return last;
  133.         }
  134.  
  135.         int Partition<T>(List<T> data, int first, int last, Func<T, bool> predicate)
  136.         {
  137.             int curr = FindIfNot<T>(data, first, last, predicate);
  138.  
  139.             if (curr == last)
  140.             {
  141.                 return curr;
  142.             }
  143.  
  144.             for (int i = curr++; i != last; i++)
  145.             {
  146.                 if (predicate(data[i]))
  147.                 {
  148.                     T tmp = data[i];
  149.                     data[i] = data[curr];
  150.                     data[curr] = tmp;
  151.  
  152.                     curr++;
  153.                 }
  154.             }
  155.  
  156.             return curr;
  157.         }
  158.  
  159.         BuildNode RecursiveBuild(List<PrimitiveInfo> info, int begin, int end, ref int totalNodes, int depth)
  160.         {
  161.             Profiler.BeginSample("BVH - Setup Node Bounds");
  162.  
  163.             // Allocate node
  164.             BuildNode node = new BuildNode();
  165.             node.children[0] = null;
  166.             node.children[1] = null;
  167.  
  168.             // Increment node counter
  169.             totalNodes++;
  170.  
  171.             // Calculate node bounds
  172.             AABB bounds = new AABB();
  173.             for (int i = begin; i < end; i++)
  174.             {
  175.                 bounds.max.x = Mathf.Max(bounds.max.x, info[i].bounds.max.x);
  176.                 bounds.max.y = Mathf.Max(bounds.max.y, info[i].bounds.max.y);
  177.                 bounds.max.z = Mathf.Max(bounds.max.z, info[i].bounds.max.z);
  178.                 bounds.min.x = Mathf.Min(bounds.min.x, info[i].bounds.min.x);
  179.                 bounds.min.y = Mathf.Min(bounds.min.y, info[i].bounds.min.y);
  180.                 bounds.min.z = Mathf.Min(bounds.min.z, info[i].bounds.min.z);
  181.             }
  182.  
  183.             Profiler.EndSample();
  184.  
  185.             // If there is less primitives than max prims in node count, create leaf node
  186.             int primitives = end - begin;
  187.             if ((primitives <= maxPrimitivesInNode) || (depth >= maxDepth))
  188.             {
  189.                 Profiler.BeginSample("BVH - Build Leaf Node - Prims");
  190.  
  191.                 int idx = primitiveIndices.Count;
  192.  
  193.                 for (int i = 0; i < primitives; i++)
  194.                 {
  195.                     primitiveIndices.Add(info[begin + i].primitiveID);
  196.                 }
  197.  
  198.                 node.InitLeaf(idx, primitives, bounds);
  199.  
  200.                 Profiler.EndSample();
  201.  
  202.                 return node;
  203.             }
  204.             else
  205.             {
  206.                 Profiler.BeginSample("BVH - Centroid Computation");
  207.  
  208.                 // Compute bounds of primitive centroids
  209.                 AABB centroidBounds = new AABB();
  210.                 for (int i = begin; i < end; i++)
  211.                 {
  212.                     centroidBounds.max.x = Mathf.Max(centroidBounds.max.x, info[i].centroid.x);
  213.                     centroidBounds.max.y = Mathf.Max(centroidBounds.max.y, info[i].centroid.y);
  214.                     centroidBounds.max.z = Mathf.Max(centroidBounds.max.z, info[i].centroid.z);
  215.                     centroidBounds.min.x = Mathf.Min(centroidBounds.min.x, info[i].centroid.x);
  216.                     centroidBounds.min.y = Mathf.Min(centroidBounds.min.y, info[i].centroid.y);
  217.                     centroidBounds.min.z = Mathf.Min(centroidBounds.min.z, info[i].centroid.z);
  218.                 }
  219.  
  220.                 // Get splitting dimension
  221.                 int dim = centroidBounds.GetLongestAxis();
  222.  
  223.                 Profiler.EndSample();
  224.  
  225.                 // If we can't split by axis (degenerate triangles case - longest axis being 0), create leaf
  226.                 if (centroidBounds.min[dim] == centroidBounds.max[dim] || end - begin <= maxPrimitivesInNode)
  227.                 {
  228.                     Profiler.BeginSample("BVH - Build Leaf Node - Conditions");
  229.  
  230.                     int idx = primitiveIndices.Count;
  231.  
  232.                     for (int i = 0; i < primitives; i++)
  233.                     {
  234.                         primitiveIndices.Add(info[begin + i].primitiveID);
  235.                     }
  236.  
  237.                     node.InitLeaf(idx, primitives, bounds);
  238.  
  239.                     Profiler.EndSample();
  240.  
  241.                     return node;
  242.                 }
  243.                 // Otherwise we need to split
  244.                 else
  245.                 {
  246.                     Profiler.BeginSample("BVH - Build Interior Node");
  247.  
  248.                     int mid = 0;
  249.  
  250.                     switch (splitMode)
  251.                     {
  252.                         case SplitMode.MIDDLE:
  253.                             Profiler.BeginSample("BVH - Split Middle");
  254.                             float pmid = (centroidBounds.min[dim] + centroidBounds.max[dim]) * 0.5f;
  255.                             mid = Partition<PrimitiveInfo>(info, begin, end, (PrimitiveInfo pi) =>
  256.                             {
  257.                                 return pi.centroid[dim] < pmid;
  258.                             });
  259.                             if (mid != begin && mid != end)
  260.                             {
  261.                                 break;
  262.                             }
  263.  
  264.                             mid = (begin + end) / 2;
  265.                             info.Sort((PrimitiveInfo a, PrimitiveInfo b) =>
  266.                             {
  267.                                 return (int)(a.centroid[dim] - b.centroid[dim]);
  268.                             });
  269.                             Profiler.EndSample();
  270.                             break;
  271.  
  272.                         case SplitMode.EQUAL_COUNTS:
  273.                             Profiler.BeginSample("BVH - Split Equal Counts");
  274.                             mid = (begin + end) / 2;
  275.                             info.Sort((PrimitiveInfo a, PrimitiveInfo b) =>
  276.                             {
  277.                                 return (int)(a.centroid[dim] - b.centroid[dim]);
  278.                             });
  279.                             Profiler.EndSample();
  280.                             break;
  281.  
  282.                         case SplitMode.SAH:
  283.                             Profiler.BeginSample("BVH - Split SAH");
  284.                             int bestAxis = 0;
  285.                             int minBucket = 0;
  286.                             float minCost = 999999.0f;
  287.  
  288.                             Profiler.BeginSample("BVH - Calculate SAH");
  289.                             for (int axis = 0; axis < 3; axis++)
  290.                             {
  291.                                 // Init buckets for SAH computation
  292.                                 for (int i = 0; i < bucketsCount; i++)
  293.                                 {
  294.                                     buckets[i].bounds = new AABB();
  295.                                     buckets[i].count = 0;
  296.                                     sahCost[i] = 0.0f;
  297.                                 }
  298.  
  299.                                 // Prepare buckets data by calculating their bounds
  300.                                 for (int i = begin; i < end; i++)
  301.                                 {
  302.                                     int b = (int)((float)bucketsCount * ((info[i].centroid[axis] - centroidBounds.min[axis]) / (centroidBounds.max[axis] - centroidBounds.min[axis])));
  303.                                     if (b >= bucketsCount)
  304.                                     {
  305.                                         b = bucketsCount - 1;
  306.                                     }
  307.  
  308.                                     if (b < 0)
  309.                                     {
  310.                                         b = 0;
  311.                                     }
  312.  
  313.                                     buckets[b].count++;
  314.  
  315.                                     buckets[b].bounds.max.x = Mathf.Max(buckets[b].bounds.max.x, info[i].bounds.max.x);
  316.                                     buckets[b].bounds.max.y = Mathf.Max(buckets[b].bounds.max.y, info[i].bounds.max.y);
  317.                                     buckets[b].bounds.max.z = Mathf.Max(buckets[b].bounds.max.z, info[i].bounds.max.z);
  318.                                     buckets[b].bounds.min.x = Mathf.Min(buckets[b].bounds.min.x, info[i].bounds.min.x);
  319.                                     buckets[b].bounds.min.y = Mathf.Min(buckets[b].bounds.min.y, info[i].bounds.min.y);
  320.                                     buckets[b].bounds.min.z = Mathf.Min(buckets[b].bounds.min.z, info[i].bounds.min.z);
  321.                                 }
  322.  
  323.                                 // Calculate costs for splitting after each bucket
  324.                                 for (int i = 0; i < bucketsCount - 1; i++)
  325.                                 {
  326.                                     AABB b0 = new AABB();
  327.                                     AABB b1 = new AABB();
  328.  
  329.                                     int count0 = 0;
  330.                                     int count1 = 0;
  331.  
  332.                                     for (int j = 0; j <= i; j++)
  333.                                     {
  334.                                         b0.max.x = Mathf.Max(b0.max.x, buckets[j].bounds.max.x);
  335.                                         b0.max.y = Mathf.Max(b0.max.y, buckets[j].bounds.max.y);
  336.                                         b0.max.z = Mathf.Max(b0.max.z, buckets[j].bounds.max.z);
  337.                                         b0.min.x = Mathf.Min(b0.min.x, buckets[j].bounds.min.x);
  338.                                         b0.min.y = Mathf.Min(b0.min.y, buckets[j].bounds.min.y);
  339.                                         b0.min.z = Mathf.Min(b0.min.z, buckets[j].bounds.min.z);
  340.  
  341.                                         count0 += buckets[j].count;
  342.                                     }
  343.  
  344.                                     for (int j = i + 1; j < bucketsCount; j++)
  345.                                     {
  346.                                         b1.max.x = Mathf.Max(b1.max.x, buckets[j].bounds.max.x);
  347.                                         b1.max.y = Mathf.Max(b1.max.y, buckets[j].bounds.max.y);
  348.                                         b1.max.z = Mathf.Max(b1.max.z, buckets[j].bounds.max.z);
  349.                                         b1.min.x = Mathf.Min(b1.min.x, buckets[j].bounds.min.x);
  350.                                         b1.min.y = Mathf.Min(b1.min.y, buckets[j].bounds.min.y);
  351.                                         b1.min.z = Mathf.Min(b1.min.z, buckets[j].bounds.min.z);
  352.  
  353.                                         count1 += buckets[j].count;
  354.                                     }
  355.  
  356.                                     sahCost[i] = 1.0f + (count0 * b0.GetSurfaceArea() + count1 * b1.GetSurfaceArea()) / bounds.GetSurfaceArea();
  357.                                 }
  358.  
  359.                                 // Select best cost bucket
  360.                                 for (int i = 0; i < bucketsCount; i++)
  361.                                 {
  362.                                     if (sahCost[i] < minCost)
  363.                                     {
  364.                                         minCost = sahCost[i];
  365.                                         minBucket = i;
  366.                                         bestAxis = axis;
  367.                                     }
  368.                                 }
  369.                             }
  370.  
  371.                             dim = bestAxis;
  372.                             Profiler.EndSample();
  373.  
  374.                             // Create interior node
  375.                             Profiler.BeginSample("BVH - Partition Interior Node");
  376.                             mid = Partition<PrimitiveInfo>(info, begin, end, (PrimitiveInfo pi) =>
  377.                             {
  378.                                 int b = (int)((float)bucketsCount * ((pi.centroid[dim] - centroidBounds.min[dim]) / (centroidBounds.max[dim] - centroidBounds.min[dim])));
  379.                                 if (b >= bucketsCount)
  380.                                 {
  381.                                     b = bucketsCount - 1;
  382.                                 }
  383.  
  384.                                 return b <= minBucket;
  385.                             });
  386.                             Profiler.EndSample();
  387.  
  388.                             Profiler.BeginSample("BVH - Sort Build Info");
  389.                             if (begin == mid || mid == end)
  390.                             {
  391.                                 mid = (begin + end) / 2;
  392.  
  393.                                 if (dim == 0)
  394.                                 {
  395.                                     info.OrderBy(pi => pi.centroid.x);
  396.                                     //info.Sort((PrimitiveInfo a, PrimitiveInfo b) => { return (int)(a.centroid.x - b.centroid.x); });
  397.                                 }
  398.                                 else if (dim == 1)
  399.                                 {
  400.                                     info.OrderBy(pi => pi.centroid.y);
  401.                                     //info.Sort((PrimitiveInfo a, PrimitiveInfo b) => { return (int)(a.centroid.y - b.centroid.y); });
  402.                                 }
  403.                                 else
  404.                                 {
  405.                                     info.OrderBy(pi => pi.centroid.z);
  406.                                     //info.Sort((PrimitiveInfo a, PrimitiveInfo b) => { return (int)(a.centroid.z - b.centroid.z); });
  407.                                 }
  408.  
  409.                                 /*info.Sort((PrimitiveInfo a, PrimitiveInfo b) =>
  410.                                 {
  411.                                     return (int)(a.centroid[dim] - b.centroid[dim]);
  412.                                 });*/
  413.                             }
  414.                             Profiler.EndSample();
  415.  
  416.                             Profiler.EndSample();
  417.                             break;
  418.                     }
  419.  
  420.                     Profiler.EndSample();
  421.  
  422.                     // Split the node
  423.                     node.InitInterior(dim,
  424.                         RecursiveBuild(info, begin, mid, ref totalNodes, depth + 1),
  425.                         RecursiveBuild(info, mid, end, ref totalNodes, depth + 1));
  426.  
  427.                     return node;
  428.  
  429.                     // Perform SAH based splitting, loop through axes and calculate SAH
  430.                     /*int bestAxis = 0;
  431.                     int minBucket = 0;
  432.                     float minCost = 0.0f;
  433.  
  434.                     for (int axis = 0; axis < 3; axis++)
  435.                     {
  436.                         // Init buckets for SAH computation
  437.                         for (int i = 0; i < bucketsCount; i++)
  438.                         {
  439.                             buckets[i].bounds = AABB.Identity();
  440.                             buckets[i].count = 0;
  441.                             sahCost[i] = 0.0f;
  442.                         }
  443.  
  444.                         // Prepare buckets data by calculating their bounds
  445.                         for (int i = begin; i < end; i++)
  446.                         {
  447.                             int b = (int)((float)bucketsCount * ((info[i].centroid[axis] - centroidBounds.min[axis]) / (centroidBounds.max[axis] - centroidBounds.min[axis])));
  448.                             if (b >= bucketsCount)
  449.                             {
  450.                                 b = bucketsCount - 1;
  451.                             }
  452.  
  453.                             buckets[b].count++;
  454.                             buckets[b].bounds.Union(info[i].bounds);
  455.                         }
  456.  
  457.                         // Calculate costs for splitting after each bucket
  458.                         for (int i = 0; i < bucketsCount - 1; i++)
  459.                         {
  460.                             AABB b0 = AABB.Identity();
  461.                             AABB b1 = AABB.Identity();
  462.  
  463.                             int count0 = 0;
  464.                             int count1 = 0;
  465.  
  466.                             for (int j = 0; j <= i; j++)
  467.                             {
  468.                                 b0.Union(buckets[j].bounds);
  469.                                 count0 += buckets[j].count;
  470.                             }
  471.  
  472.                             for (int j = i + 1; j < bucketsCount; j++)
  473.                             {
  474.                                 b1.Union(buckets[j].bounds);
  475.                                 count1 += buckets[j].count;
  476.                             }
  477.  
  478.                             sahCost[i] = 1.0f + (count0 * b0.GetSurfaceArea() + count1 * b1.GetSurfaceArea()) / bounds.GetSurfaceArea();
  479.                         }
  480.  
  481.                         // Select best cost bucket
  482.                         for (int i = 0; i < bucketsCount; i++)
  483.                         {
  484.                             if (sahCost[i] < minCost)
  485.                             {
  486.                                 minCost = sahCost[i];
  487.                                 minBucket = i;
  488.                                 bestAxis = axis;
  489.                             }
  490.                         }
  491.                     }
  492.  
  493.                     dim = bestAxis;
  494.  
  495.                     // Create interior node
  496.                     List<PrimitiveInfo> partitioned = new List<PrimitiveInfo>(info);
  497.                     int mid = Partition<PrimitiveInfo>(partitioned, 0, partitioned.Count, (PrimitiveInfo pi) =>
  498.                     {
  499.                         int b = (int)((float)bucketsCount * ((pi.centroid[dim] - centroidBounds.min[dim]) / (centroidBounds.max[dim] - centroidBounds.min[dim])));
  500.                         if (b >= bucketsCount)
  501.                         {
  502.                             b = bucketsCount - 1;
  503.                         }
  504.  
  505.                         return b <= minBucket;
  506.                     });
  507.  
  508.                     if (begin == mid || mid == end)
  509.                     {
  510.                         mid = (begin + end) / 2;
  511.                         partitioned.Sort((PrimitiveInfo a, PrimitiveInfo b) =>
  512.                         {
  513.                             return (a.centroid[dim] < b.centroid[dim] ? -1 : 1);
  514.                         });
  515.                     }
  516.  
  517.                     node.InitInterior(dim,
  518.                         RecursiveBuild(partitioned, begin, mid, ref totalNodes),
  519.                         RecursiveBuild(partitioned, mid, end, ref totalNodes));
  520.  
  521.                     return node;*/
  522.                 }
  523.             }
  524.         }
  525.         private int FlattenBVH(BuildNode node, ref int offset)
  526.         {
  527.             int tempOffset = offset;
  528.             LinearBVHNode n = nodes[tempOffset];
  529.             offset++;
  530.  
  531.             if(node.primitiveCount > 0)
  532.             {
  533.                 n.offset = node.primitiveOffset;
  534.                 n.primitiveCount = node.primitiveCount;
  535.  
  536.                 nodes[tempOffset] = n;
  537.             }
  538.             else
  539.             {
  540.                 n.l_xy = new Vector4(node.children[0].bounds.min.x,
  541.                     node.children[0].bounds.max.x,
  542.                     node.children[0].bounds.min.y,
  543.                     node.children[0].bounds.max.y);
  544.  
  545.                 n.r_xy = new Vector4(node.children[1].bounds.min.x,
  546.                     node.children[1].bounds.max.x,
  547.                     node.children[1].bounds.min.y,
  548.                     node.children[1].bounds.max.y);
  549.  
  550.                 n.lr_z = new Vector4(node.children[0].bounds.min.z,
  551.                     node.children[0].bounds.max.z,
  552.                     node.children[1].bounds.min.z,
  553.                     node.children[1].bounds.max.z);
  554.  
  555.                 n.axis = node.splitAxis;
  556.                 n.primitiveCount = 0;
  557.  
  558.                 FlattenBVH(node.children[0], ref offset);
  559.                 n.offset = FlattenBVH(node.children[1], ref offset);
  560.  
  561.                 nodes[tempOffset] = n;
  562.             }
  563.  
  564.             return tempOffset;
  565.         }
  566.  
  567.         public BVH(Triangle[] tris)
  568.         {
  569.             float begin = Time.realtimeSinceStartup;
  570.  
  571.             Profiler.BeginSample("BVH - Prepare Arrays");
  572.  
  573.             triangles = tris;
  574.  
  575.             primitiveIndices = new List<int>();
  576.  
  577.             buckets = new List<BucketInfo>();
  578.             sahCost = new List<float>();
  579.             for (int i = 0; i < bucketsCount; i++)
  580.             {
  581.                 buckets.Add(new BucketInfo());
  582.                 sahCost.Add(0.0f);
  583.             }
  584.  
  585.             List<PrimitiveInfo> info = new List<PrimitiveInfo>(triangles.Length);
  586.  
  587.             Profiler.EndSample();
  588.  
  589.             Profiler.BeginSample("BVH - Bounds");
  590.  
  591.             bvhBounds = new AABB();
  592.             for (int i = 0; i < triangles.Length; i++)
  593.             {
  594.                 AABB triBounds = new AABB();
  595.                 triBounds.max.x = Mathf.Max(triangles[i].a.x, Mathf.Max(triangles[i].b.x, triangles[i].c.x));
  596.                 triBounds.max.y = Mathf.Max(triangles[i].a.y, Mathf.Max(triangles[i].b.y, triangles[i].c.y));
  597.                 triBounds.max.z = Mathf.Max(triangles[i].a.z, Mathf.Max(triangles[i].b.z, triangles[i].c.z));
  598.                 triBounds.min.x = Mathf.Min(triangles[i].a.x, Mathf.Min(triangles[i].b.x, triangles[i].c.x));
  599.                 triBounds.min.y = Mathf.Min(triangles[i].a.y, Mathf.Min(triangles[i].b.y, triangles[i].c.y));
  600.                 triBounds.min.z = Mathf.Min(triangles[i].a.z, Mathf.Min(triangles[i].b.z, triangles[i].c.z));
  601.  
  602.                 PrimitiveInfo pi = new PrimitiveInfo(i, triBounds);
  603.  
  604.                 info.Add(pi);
  605.  
  606.                 bvhBounds.max.x = Mathf.Max(bvhBounds.max.x, triBounds.max.x);
  607.                 bvhBounds.max.y = Mathf.Max(bvhBounds.max.y, triBounds.max.y);
  608.                 bvhBounds.max.z = Mathf.Max(bvhBounds.max.z, triBounds.max.z);
  609.                 bvhBounds.min.x = Mathf.Min(bvhBounds.min.x, triBounds.min.x);
  610.                 bvhBounds.min.y = Mathf.Min(bvhBounds.min.y, triBounds.min.y);
  611.                 bvhBounds.min.z = Mathf.Min(bvhBounds.min.z, triBounds.min.z);
  612.             }
  613.  
  614.             Profiler.EndSample();
  615.  
  616.             int totalNodes = 0;
  617.             root = RecursiveBuild(info, 0, info.Count, ref totalNodes, 0);
  618.  
  619.             nodes = new List<LinearBVHNode>();
  620.             for (int i = 0; i < totalNodes; i++)
  621.             {
  622.                 nodes.Add(new LinearBVHNode());
  623.             }
  624.  
  625.             int offset = 0;
  626.             FlattenBVH(root, ref offset);
  627.  
  628.             Debug.Log("Time elapsed: " + (Time.realtimeSinceStartup - begin) * 1000 + " ms\n" +
  629.                 "Statistics:\n" +
  630.                 "\ttTotal number of primitives: " + primitiveIndices.Count + "\n" +
  631.                 "\ttTotal number of nodes:" + totalNodes);
  632.         }
  633.  
  634.         /*private Stack<BuildNode> traversalStack = new Stack<BuildNode>();*/
  635.         private IntersectResult c0res = new IntersectResult();
  636.         private IntersectResult c1res = new IntersectResult();
  637.         private IntersectResult triRes = new IntersectResult();
  638.  
  639.  
  640.         private int[] traversalStack = new int[32];
  641.  
  642.         public int IntersectRay(Ray r, ref IntersectResult result)
  643.         {
  644.             Profiler.BeginSample("Traversal - Begin");
  645.  
  646.             int hitIndex = -1;
  647.             float t = result.distance;
  648.             float baryU = 0.0f;
  649.             float baryV = 0.0f;
  650.  
  651.             int[] stack = traversalStack;
  652.             int stackPtr = 0;
  653.             stack[stackPtr] = 0x7FFFFFFF;
  654.  
  655.             int nodeID = 0;
  656.  
  657.             float tmin = 0.0f;
  658.             float tmax = 10000.0f;
  659.  
  660.             r.direction.Normalize();
  661.  
  662.             Vector4 inv = new Vector4(1.0f / r.direction.x, 1.0f / r.direction.y, 1.0f / r.direction.z, 1.0f);
  663.             Vector4 oinv = new Vector4(r.origin.x * inv.x, r.origin.y * inv.y, r.origin.z * inv.z, 1.0f);
  664.  
  665.             Profiler.EndSample();
  666.  
  667.             Profiler.BeginSample("Traversal - Loop");
  668.  
  669.             do
  670.             {
  671.                 int primCount = nodes[nodeID].primitiveCount;
  672.  
  673.                 if (primCount == 0)
  674.                 {
  675.                     Profiler.BeginSample("Traversal - Interior Node");
  676.  
  677.                     Vector4 n0xy = nodes[nodeID].l_xy;
  678.                     Vector4 n1xy = nodes[nodeID].r_xy;
  679.                     Vector4 nz = nodes[nodeID].lr_z;
  680.  
  681.                     // Test against child AABBs
  682.                     AABB bb0 = new AABB(new Vector3(n0xy.x, n0xy.z, nz.x), new Vector3(n0xy.y, n0xy.w, nz.y));
  683.                     AABB bb1 = new AABB(new Vector3(n1xy.x, n1xy.z, nz.z), new Vector3(n1xy.y, n1xy.w, nz.w));
  684.  
  685.                     c0res.distance = t;
  686.                     bool traverseChild0 = Intersect.RayAABB(r, bb0, ref c0res);
  687.  
  688.                     c1res.distance = t;
  689.                     bool traverseChild1 = Intersect.RayAABB(r, bb1, ref c1res);
  690.  
  691.                     /*float c0lox = n0xy.x * inv.x - oinv.x;
  692.                     float c0hix = n0xy.y * inv.x - oinv.x;
  693.                     float c0loy = n0xy.z * inv.y - oinv.y;
  694.                     float c0hiy = n0xy.w * inv.y - oinv.y;
  695.                     float c0loz = nz.x * inv.z - oinv.z;
  696.                     float c0hiz = nz.y * inv.z - oinv.z;
  697.                     float c1loz = nz.z * inv.z - oinv.z;
  698.                     float c1hiz = nz.w * inv.z - oinv.z;
  699.                     float c0min = Mathf.Max(Mathf.Max(Mathf.Min(c0lox, c0hix), Mathf.Min(c0loy, c0hiy)), Mathf.Max(Mathf.Min(c0loz, c0hiz), tmin));
  700.                     float c0max = Mathf.Min(Mathf.Min(Mathf.Max(c0lox, c0hix), Mathf.Max(c0loy, c0hiy)), Mathf.Min(Mathf.Max(c0loz, c0hiz), tmax));
  701.                     float c1lox = n1xy.x * inv.x - oinv.x;
  702.                     float c1hix = n1xy.y * inv.x - oinv.x;
  703.                     float c1loy = n1xy.z * inv.y - oinv.y;
  704.                     float c1hiy = n1xy.w * inv.y - oinv.y;
  705.                     float c1min = Mathf.Max(Mathf.Max(Mathf.Min(c1lox, c1hix), Mathf.Min(c1loy, c1hiy)), Mathf.Max(Mathf.Min(c1loz, c1hiz), tmin));
  706.                     float c1max = Mathf.Min(Mathf.Min(Mathf.Max(c1lox, c1hix), Mathf.Max(c1loy, c1hiy)), Mathf.Min(Mathf.Max(c1loz, c1hiz), tmax));
  707.  
  708.                     bool traverseChild0 = (c0max >= c0min);
  709.                     bool traverseChild1 = (c1max >= c1min);*/
  710.  
  711.                     float c0min = c0res.distance;
  712.                     float c1min = c1res.distance;
  713.  
  714.                     // If no children was hit, get node from stack
  715.                     if (!traverseChild0 && !traverseChild1)
  716.                     {
  717.                         nodeID = stack[stackPtr];
  718.                         stackPtr--;
  719.                     }
  720.                     else
  721.                     {
  722.                         int first_child = nodeID + 1;
  723.                         int second_child = nodes[nodeID].offset;
  724.                         nodeID = (traverseChild0) ? first_child : second_child;
  725.  
  726.                         if (traverseChild0 && traverseChild1)
  727.                         {
  728.                             if (c1min < c0min)
  729.                             {
  730.                                 nodeID = second_child;
  731.                                 stackPtr++;
  732.                                 stack[stackPtr] = first_child;
  733.                             }
  734.                             else
  735.                             {
  736.                                 stackPtr++;
  737.                                 stack[stackPtr] = second_child;
  738.                             }
  739.                         }
  740.                     }
  741.  
  742.                     Profiler.EndSample();
  743.                 }
  744.                 else
  745.                 {
  746.                     Profiler.BeginSample("Traversal - Leaf Node");
  747.  
  748.                     int primOffset = nodes[nodeID].offset;
  749.                     for (int i = 0; i < nodes[nodeID].primitiveCount; i++)
  750.                     {
  751.                         int triIndex = primitiveIndices[primOffset + i];
  752.  
  753.                         //IntersectResult triRes = new IntersectResult();
  754.                         triRes.distance = t;
  755.  
  756.                         Profiler.BeginSample("Traversal - Ray-Triangle");
  757.  
  758.                         if (Intersect.RayTriangle(r, triangles[triIndex], ref triRes))
  759.                         {
  760.                             if (triRes.distance < t && triRes.distance > 0.0f)
  761.                             {
  762.                                 hitIndex = primOffset + i;
  763.                                 t = triRes.distance;
  764.                                 baryU = triRes.baryU;
  765.                                 baryV = triRes.baryV;
  766.                             }
  767.                         }
  768.  
  769.                         Profiler.EndSample();
  770.                     }
  771.  
  772.                     nodeID = stack[stackPtr];
  773.                     stackPtr--;
  774.  
  775.                     Profiler.EndSample();
  776.                 }
  777.             }
  778.             while (nodeID != 0x7FFFFFFF);
  779.  
  780.             Profiler.EndSample();
  781.  
  782.             if (hitIndex >= 0)
  783.             {
  784.                 result.distance = t;
  785.                 result.baryU = baryU;
  786.                 result.baryV = baryV;
  787.                 return hitIndex;
  788.             }
  789.             else
  790.             {
  791.                 return -1;
  792.             }
  793.  
  794.             /*Profiler.BeginSample("Traversal - Begin");
  795.  
  796.             //Stack<BuildNode> stack;
  797.             //stack = new Stack<BuildNode>();
  798.             Stack<BuildNode> stack = traversalStack;
  799.             stack.Clear();
  800.             stack.Push(root);
  801.  
  802.             int hitIndex = -1;
  803.             float t = result.distance;
  804.             float baryU = 0.0f;
  805.             float baryV = 0.0f;
  806.  
  807.             Profiler.EndSample();
  808.  
  809.             Profiler.BeginSample("Traversal - Loop");
  810.  
  811.             while (stack.Count > 0)
  812.             {
  813.                 BuildNode n = stack.Pop();
  814.  
  815.                 if (n.primitiveCount == 0)
  816.                 {
  817.                     Profiler.BeginSample("Traversal - Interior Node");
  818.  
  819.                     Profiler.BeginSample("Traversal - Ray-AABB");
  820.  
  821.                     //IntersectResult c0res = new IntersectResult();
  822.                     c0res.distance = t;
  823.                     bool c0hit = Intersect.RayAABB(r, n.children[0].bounds, ref c0res);
  824.  
  825.                     //IntersectResult c1res = new IntersectResult();
  826.                     c1res.distance = t;
  827.                     bool c1hit = Intersect.RayAABB(r, n.children[1].bounds, ref c1res);
  828.  
  829.                     Profiler.EndSample();
  830.  
  831.                     if (!c0hit && !c1hit)
  832.                     {
  833.                         Profiler.EndSample();
  834.  
  835.                         continue;
  836.                     }
  837.                     else
  838.                     {
  839.                         if (c0hit && c1hit)
  840.                         {
  841.                             if (c0res.distance < c1res.distance)
  842.                             {
  843.                                 stack.Push(n.children[1]);
  844.                                 stack.Push(n.children[0]);
  845.                             }
  846.                             else
  847.                             {
  848.                                 stack.Push(n.children[0]);
  849.                                 stack.Push(n.children[1]);
  850.                             }
  851.                         }
  852.                         else
  853.                         {
  854.                             if (c0hit)
  855.                             {
  856.                                 stack.Push(n.children[0]);
  857.                             }
  858.                             else
  859.                             {
  860.                                 stack.Push(n.children[1]);
  861.                             }
  862.                         }
  863.                     }
  864.  
  865.                     Profiler.EndSample();
  866.                 }
  867.                 else
  868.                 {
  869.                     Profiler.BeginSample("Traversal - Leaf Node");
  870.  
  871.                     int primOffset = n.primitiveOffset;
  872.                     for (int i = 0; i < n.primitiveCount; i++)
  873.                     {
  874.                         int triIndex = primitiveIndices[primOffset + i];
  875.  
  876.                         //IntersectResult triRes = new IntersectResult();
  877.                         triRes.distance = t;
  878.  
  879.                         Profiler.BeginSample("Traversal - Ray-Triangle");
  880.  
  881.                         if (Intersect.RayTriangle(r, triangles[triIndex], ref triRes))
  882.                         {
  883.                             if (triRes.distance < t && triRes.distance > 0.0f)
  884.                             {
  885.                                 hitIndex = primOffset + i;
  886.                                 t = triRes.distance;
  887.                                 baryU = triRes.baryU;
  888.                                 baryV = triRes.baryV;
  889.                             }
  890.                         }
  891.  
  892.                         Profiler.EndSample();
  893.                     }
  894.  
  895.                     Profiler.EndSample();
  896.                 }
  897.             }
  898.  
  899.             Profiler.EndSample();
  900.  
  901.             if (hitIndex >= 0)
  902.             {
  903.                 result.distance = t;
  904.                 result.baryU = baryU;
  905.                 result.baryV = baryV;
  906.                 return hitIndex;
  907.             }
  908.             else
  909.             {
  910.                 return -1;
  911.             }*/
  912.         }
  913.  
  914.         public List<int> GetIndices()
  915.         {
  916.             return primitiveIndices;
  917.         }
  918.  
  919.         public BuildNode GetHelperBuildNode(int index)
  920.         {
  921.             Stack<BuildNode> stack = new Stack<BuildNode>();
  922.             stack.Push(root);
  923.  
  924.             int steps = -1;
  925.  
  926.             while (stack.Count > 0)
  927.             {
  928.                 steps++;
  929.                 BuildNode node = stack.Pop();
  930.  
  931.                 if (index == steps)
  932.                 {
  933.                     return node;
  934.                 }
  935.  
  936.                 if (node.primitiveCount == 0)
  937.                 {
  938.                     stack.Push(node.children[1]);
  939.                     stack.Push(node.children[0]);
  940.                 }
  941.             }
  942.  
  943.             return null;
  944.         }
  945.     }
  946. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement