From 40f0c8d71f7128def38e6dad331df76fdf3d450a Mon Sep 17 00:00:00 2001 From: __matt Date: Thu, 27 Jan 2022 12:17:37 +0000 Subject: [PATCH 1/4] Added triangle adapter. --- Adapters/BVHTriangleAdapter.cs | 62 ++++++++++++++++++++++++++++++++++ BVH.cs | 26 ++++++++++++++ README.md | 2 +- 3 files changed, 89 insertions(+), 1 deletion(-) create mode 100644 Adapters/BVHTriangleAdapter.cs diff --git a/Adapters/BVHTriangleAdapter.cs b/Adapters/BVHTriangleAdapter.cs new file mode 100644 index 0000000..e0ca151 --- /dev/null +++ b/Adapters/BVHTriangleAdapter.cs @@ -0,0 +1,62 @@ +using UnityEngine; +using System; +using System.Collections.Generic; + + +namespace DataStructures { + public struct Triangle { + public Triangle(Vector3 _a, Vector3 _b, Vector3 _c) { + a = _a; + b = _b; + c = _c; + } + public Vector3 a, b, c; + } + + public class BVHTriangleAdapter : IBVHNodeAdapter { + private BVH _bvh; + private Dictionary> triangeToLeafMap = new Dictionary>(); + + + BVH IBVHNodeAdapter.BVH { get => _bvh; set { _bvh = value; }} + + public void CheckMap(Triangle triangle) { + if (!triangeToLeafMap.ContainsKey(triangle)) { + throw new Exception("missing map for shuffled child!"); + } + } + + public BVHNode GetLeaf(Triangle triangle) => triangeToLeafMap[triangle]; + public Vector3 GetObjectPos(Triangle triangle) { + float x = (triangle.a.x + triangle.b.x + triangle.c.x) / 3.0f; + float y = (triangle.a.y + triangle.b.y + triangle.c.y) / 3.0f; + float z = (triangle.a.z + triangle.b.z + triangle.c.z) / 3.0f; + return new Vector3(x, y, z); + } + + public float GetRadius(Triangle triangle) { + Vector3 centroid = new Vector3( + (triangle.a.x + triangle.b.x + triangle.c.x) / 3.0f, + (triangle.a.y + triangle.b.y + triangle.c.y) / 3.0f, + (triangle.a.z + triangle.b.z + triangle.c.z) / 3.0f + ); + return Mathf.Max( + Mathf.Max(Vector3.Distance(centroid, triangle.a), Vector3.Distance(centroid, triangle.b), + Vector3.Distance(centroid, triangle.c))); + } + + public void MapObjectToBVHLeaf(Triangle triangle, BVHNode node) { + triangeToLeafMap[triangle] = node; + } + + public void OnPositionOrSizeChanged(Triangle changed) + { + // the SSObject has changed, so notify the BVH leaf to refit for the object + triangeToLeafMap[changed].RefitObjectChanged(this, changed); + } + + public void UnmapObject(Triangle triangle) { + triangeToLeafMap.Remove(triangle); + } + } +} \ No newline at end of file diff --git a/BVH.cs b/BVH.cs index 3424ca9..d3d22f1 100644 --- a/BVH.cs +++ b/BVH.cs @@ -202,6 +202,26 @@ public void GetAllNodeMatriciesRecursive(BVHNode n, ref List matri if (n.Left != null) GetAllNodeMatriciesRecursive(n.Left, ref matricies, depth + 1); } + public Matrix4x4 GetNodeMatrix(BVHNode node) => Matrix4x4.Translate(node.Box.center) * Matrix4x4.Scale(node.Box.size); + + + public void RenderNode(BVHNode node) { + Matrix4x4 mat = GetNodeMatrix(node); + List matrices = new List(); + matrices.Add(mat); + Mesh mesh = new Mesh(); + mesh.SetVertices(vertices); + mesh.SetIndices(indices, MeshTopology.Lines, 0); + if(_debugRenderMaterial == null) + { + _debugRenderMaterial = new Material(Shader.Find("Standard")) + { + enableInstancing = true + }; + } + Graphics.DrawMeshInstanced(mesh, 0, _debugRenderMaterial, matrices); + } + public void RenderDebug() { if (!SystemInfo.supportsInstancing) @@ -225,6 +245,12 @@ public void RenderDebug() enableInstancing = true }; } + + int iterations = (int)Mathf.Floor((float)matricies.Count / 1023.0f); + for (int i = 0; i < iterations; i++) { + Graphics.DrawMeshInstanced(mesh, 0, _debugRenderMaterial, matricies.GetRange(0, 1023)); + matricies.RemoveRange(0, 1023); + } Graphics.DrawMeshInstanced(mesh, 0, _debugRenderMaterial, matricies); } } diff --git a/README.md b/README.md index f535809..e295e4c 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Unity Bounding Volume Heirachy +# Unity Bounding Volume Hierachy ![BVH GIF](https://media.giphy.com/media/ZaomLtyboZSp9zl6WY/giphy.gif) From 700eb61f66ddb2679887c8cb51ae0e7dfded3816 Mon Sep 17 00:00:00 2001 From: __matt Date: Thu, 27 Jan 2022 13:50:08 +0000 Subject: [PATCH 2/4] minor fixes. --- Adapters/BVHTriangleAdapter.cs | 8 ++++++++ BVH.cs | 14 ++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/Adapters/BVHTriangleAdapter.cs b/Adapters/BVHTriangleAdapter.cs index e0ca151..04e4e82 100644 --- a/Adapters/BVHTriangleAdapter.cs +++ b/Adapters/BVHTriangleAdapter.cs @@ -13,6 +13,14 @@ public Triangle(Vector3 _a, Vector3 _b, Vector3 _c) { public Vector3 a, b, c; } + public class BVHRayHitTest { + public BVHRayHitTest(Ray _ray) { + ray = _ray; + } + public bool NodeTraversalTest(Bounds box) => box.IntersectRay(ray); + public Ray ray { get; set; } + } + public class BVHTriangleAdapter : IBVHNodeAdapter { private BVH _bvh; private Dictionary> triangeToLeafMap = new Dictionary>(); diff --git a/BVH.cs b/BVH.cs index d3d22f1..13fd14c 100644 --- a/BVH.cs +++ b/BVH.cs @@ -79,6 +79,20 @@ public List> Traverse(NodeTraversalTest hitTest) return hits; } + public SortedList> SortedTraverse(NodeTraversalTest hitTest) { + SortedList> sortedHit = new SortedList>(); + void traverse(BVHNode node, NodeTraversalTest hitTest, SortedList> hitList) { + if (node == null) return; + if (hitTest(node.Box)) { + hitList[Vector3.Magnitude(node.Box.size)] = node; + traverse(node.Left, hitTest, hitList); + traverse(node.Right, hitTest, hitList); + } + } + traverse(rootBVH, hitTest, sortedHit); + return sortedHit; + } + /* public List Traverse(Ray ray) { From 69062da6c521ed0b72000c3b4662fcc7c639d312 Mon Sep 17 00:00:00 2001 From: __matt Date: Thu, 10 Feb 2022 13:08:50 +0000 Subject: [PATCH 3/4] Added minimum node volume for static scenes. --- Adapters/BVHTriangleAdapter.cs | 2 +- BVH.cs | 4 +++- BVHNode.cs | 6 ++++-- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/Adapters/BVHTriangleAdapter.cs b/Adapters/BVHTriangleAdapter.cs index 04e4e82..8d96611 100644 --- a/Adapters/BVHTriangleAdapter.cs +++ b/Adapters/BVHTriangleAdapter.cs @@ -20,7 +20,7 @@ public BVHRayHitTest(Ray _ray) { public bool NodeTraversalTest(Bounds box) => box.IntersectRay(ray); public Ray ray { get; set; } } - + public class BVHTriangleAdapter : IBVHNodeAdapter { private BVH _bvh; private Dictionary> triangeToLeafMap = new Dictionary>(); diff --git a/BVH.cs b/BVH.cs index 13fd14c..5ce22b8 100644 --- a/BVH.cs +++ b/BVH.cs @@ -54,6 +54,7 @@ public class BVH public BVHNode rootBVH; public IBVHNodeAdapter nAda; public readonly int LEAF_OBJ_MAX; + public readonly float MIN_NODE_VOLUME; public int nodeCount = 0; public int maxDepth = 0; @@ -173,9 +174,10 @@ public int CountBVHNodes() /// /// /// WARNING! currently this must be 1 to use dynamic BVH updates - public BVH(IBVHNodeAdapter nodeAdaptor, List objects, int LEAF_OBJ_MAX = 1) + public BVH(IBVHNodeAdapter nodeAdaptor, List objects, int LEAF_OBJ_MAX = 1, float MIN_NODE_VOLUME = 0.7f) { this.LEAF_OBJ_MAX = LEAF_OBJ_MAX; + this.MIN_NODE_VOLUME = MIN_NODE_VOLUME; nodeAdaptor.BVH = this; this.nAda = nodeAdaptor; diff --git a/BVHNode.cs b/BVHNode.cs index 79957b5..a39f7e7 100644 --- a/BVHNode.cs +++ b/BVHNode.cs @@ -903,8 +903,10 @@ private BVHNode(BVH bvh, BVHNode lparent, List gobjectlist, Axis lastSp // if we have more than (bvh.LEAF_OBJECT_COUNT) objects, then compute the volume and split GObjects = gobjectlist; ComputeVolume(nAda); - SplitNode(nAda); - ChildRefit(nAda, propagate: false); + if (Box.size.magnitude > bvh.MIN_NODE_VOLUME) { + SplitNode(nAda); + ChildRefit(nAda, propagate: false); + } } } From 3a63da3fc887b11bd7a7498f13c7154de123c4bf Mon Sep 17 00:00:00 2001 From: __matt Date: Thu, 10 Mar 2022 17:41:57 +0000 Subject: [PATCH 4/4] Made the triangle adapter an interface. --- Adapters/BVHTriangleAdapter.cs | 11 ++++------- Adapters/BVHTriangleAdapter.cs.meta | 11 +++++++++++ BVH.cs | 18 ++++++++++++++++++ BVHNode.cs | 1 - 4 files changed, 33 insertions(+), 8 deletions(-) create mode 100644 Adapters/BVHTriangleAdapter.cs.meta diff --git a/Adapters/BVHTriangleAdapter.cs b/Adapters/BVHTriangleAdapter.cs index 8d96611..395ba43 100644 --- a/Adapters/BVHTriangleAdapter.cs +++ b/Adapters/BVHTriangleAdapter.cs @@ -4,13 +4,10 @@ namespace DataStructures { - public struct Triangle { - public Triangle(Vector3 _a, Vector3 _b, Vector3 _c) { - a = _a; - b = _b; - c = _c; - } - public Vector3 a, b, c; + public interface Triangle { + Vector3 a { get; set; } + Vector3 b { get; set; } + Vector3 c { get; set; } } public class BVHRayHitTest { diff --git a/Adapters/BVHTriangleAdapter.cs.meta b/Adapters/BVHTriangleAdapter.cs.meta new file mode 100644 index 0000000..c59cc51 --- /dev/null +++ b/Adapters/BVHTriangleAdapter.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 068a34072d4ee724599ebed5a2664491 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/BVH.cs b/BVH.cs index 5ce22b8..2c83032 100644 --- a/BVH.cs +++ b/BVH.cs @@ -94,6 +94,24 @@ void traverse(BVHNode node, NodeTraversalTest hitTest, SortedList nodeHit) { + BVHNode _hit = null; + void traverse(BVHNode node) { + if (node == null) return; + if (node.Box.IntersectRay(ray)) { + if (node.IsLeaf) { + _hit = node; + return; + } + traverse(node.Left); + traverse(node.Right); + } + } + traverse(rootBVH); + nodeHit = _hit; + return nodeHit != null && nodeHit.IsLeaf; + } + /* public List Traverse(Ray ray) { diff --git a/BVHNode.cs b/BVHNode.cs index a39f7e7..5b7df3f 100644 --- a/BVHNode.cs +++ b/BVHNode.cs @@ -909,6 +909,5 @@ private BVHNode(BVH bvh, BVHNode lparent, List gobjectlist, Axis lastSp } } } - } }