├── README.md ├── BVH.cs.meta ├── BVHBox.cs.meta ├── BVHRay.cs.meta ├── BVHObject.cs.meta ├── BVHAabbObject.cs.meta ├── BVHSphereObject.cs.meta ├── RayTracerTest.cs.meta ├── BVHIntersectionInfo.cs.meta ├── BVHTriangleObject.cs.meta ├── BVHIntersectionInfo.cs ├── BVHObject.cs ├── BVHRay.cs ├── BVHSphereObject.cs ├── BVHAabbObject.cs ├── RayTracerTest.cs ├── BVHTriangleObject.cs ├── BVHBox.cs └── BVH.cs /README.md: -------------------------------------------------------------------------------- 1 | # BVHForUnity 2 | BVH tree for unity 3 | 1 针对bhv在空间的应用,做了一个简单的封装,结合自身需求可灵活使用 4 | -------------------------------------------------------------------------------- /BVH.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 92dbab5f86f8fbf42ae7520014dd8a65 3 | timeCreated: 1497003846 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /BVHBox.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 0a0d9cc66380f0b47b1811b97abfc0f7 3 | timeCreated: 1497003845 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /BVHRay.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 249fc80dc62b16c4bab4a69c4ef67ae3 3 | timeCreated: 1497003845 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /BVHObject.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 3c1be945c1825d24fb6bc02b2a0f74a2 3 | timeCreated: 1497003845 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /BVHAabbObject.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 747f996f385c1a34db3eadfac9d676fe 3 | timeCreated: 1497237429 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /BVHSphereObject.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 018632f846c95d242b1dacdaf828636a 3 | timeCreated: 1497237429 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /RayTracerTest.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b4e1ffc4c847063428a2ce0f59273880 3 | timeCreated: 1497003846 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /BVHIntersectionInfo.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 4d81dd376eeb93e4da13b31f30b1e9dd 3 | timeCreated: 1497003845 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /BVHTriangleObject.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 1f971a43637477d4ba54c21bf1b3068f 3 | timeCreated: 1497003845 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /BVHIntersectionInfo.cs: -------------------------------------------------------------------------------- 1 | /******************************************************************************** 2 | ** All rights reserved 3 | ** Auth: kay.yang 4 | ** Date: 6/9/2017 4:52:29 PM 5 | ** Version: v1.0.0 6 | *********************************************************************************/ 7 | 8 | using System; 9 | using System.Collections.Generic; 10 | using System.Linq; 11 | using System.Text; 12 | using UnityEngine; 13 | 14 | namespace BVH 15 | { 16 | public class BVHIntersectionInfo 17 | { 18 | public float mLength; 19 | public BVHObject mObject; 20 | public Vector3 mHitPoint; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /BVHObject.cs: -------------------------------------------------------------------------------- 1 | /******************************************************************************** 2 | ** All rights reserved 3 | ** Auth: kay.yang 4 | ** Date: 6/9/2017 4:52:51 PM 5 | ** Version: v1.0.0 6 | *********************************************************************************/ 7 | 8 | using System; 9 | using System.Collections.Generic; 10 | using System.Linq; 11 | using System.Text; 12 | using UnityEngine; 13 | 14 | namespace BVH 15 | { 16 | public abstract class BVHObject 17 | { 18 | public abstract bool GetIntersection(ref BVHRay ray, ref BVHIntersectionInfo intersection); 19 | public abstract Vector3 GetNormal(ref BVHIntersectionInfo i); 20 | public abstract BVHBox GetBBox(); 21 | public abstract Vector3 GetCentroid(); 22 | 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /BVHRay.cs: -------------------------------------------------------------------------------- 1 | /******************************************************************************** 2 | ** All rights reserved 3 | ** Auth: kay.yang 4 | ** Date: 6/9/2017 4:53:08 PM 5 | ** Version: v1.0.0 6 | *********************************************************************************/ 7 | 8 | using System; 9 | using System.Collections.Generic; 10 | using System.Linq; 11 | using System.Text; 12 | 13 | using UnityEngine; 14 | 15 | namespace BVH 16 | { 17 | public class BVHRay 18 | { 19 | public Vector3 mOrigin; 20 | public Vector3 mDirection; 21 | public Vector3 mInvDirection; 22 | 23 | public BVHRay(Vector3 o, Vector3 d) 24 | { 25 | mOrigin = o; 26 | mDirection = d; 27 | mInvDirection = new Vector3(1 / d[0], 1 / d[1], 1 / d[2]); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /BVHSphereObject.cs: -------------------------------------------------------------------------------- 1 | /******************************************************************************** 2 | ** All rights reserved 3 | ** Auth: kay.yang 4 | ** Date: 6/12/2017 9:12:46 AM 5 | ** Version: v1.0.0 6 | *********************************************************************************/ 7 | 8 | using System; 9 | using System.Collections.Generic; 10 | using System.Linq; 11 | using System.Text; 12 | 13 | using UnityEngine; 14 | 15 | namespace BVH 16 | { 17 | public class BVHSphereObject : BVHObject 18 | { 19 | public Vector3 mCenter; 20 | public float mRadius, mRadius2; // Radius, Radius^2 21 | 22 | public BVHSphereObject(Vector3 center, float r) 23 | { 24 | mCenter = center; 25 | mRadius = r; 26 | mRadius2 = mRadius * mRadius; 27 | } 28 | 29 | override 30 | public bool GetIntersection(ref BVHRay ray, ref BVHIntersectionInfo intersection) 31 | { 32 | Vector3 s = mCenter - ray.mOrigin; 33 | float sd = Vector3.Dot(s, ray.mDirection); 34 | float ss = s.magnitude * s.magnitude; 35 | float disc = sd * sd + mRadius2 - ss; 36 | if (disc < 0.0f) 37 | { 38 | return false; 39 | } 40 | intersection.mObject = this; 41 | intersection.mLength = sd - Mathf.Sqrt(disc); 42 | return true; 43 | } 44 | 45 | override 46 | public Vector3 GetNormal(ref BVHIntersectionInfo i) 47 | { 48 | Vector3 nor = i.mHitPoint - mCenter; 49 | nor.Normalize(); 50 | return nor; 51 | } 52 | 53 | override 54 | public BVHBox GetBBox() 55 | { 56 | return new BVHBox(mCenter - new Vector3(mRadius, mRadius, mRadius), mCenter + new Vector3(mRadius, mRadius, mRadius)); ; 57 | } 58 | 59 | override 60 | public Vector3 GetCentroid() 61 | { 62 | return mCenter; 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /BVHAabbObject.cs: -------------------------------------------------------------------------------- 1 | /******************************************************************************** 2 | ** All rights reserved 3 | ** Auth: kay.yang 4 | ** Date: 6/12/2017 9:51:31 AM 5 | ** Version: v1.0.0 6 | *********************************************************************************/ 7 | 8 | using System; 9 | using System.Collections.Generic; 10 | using System.Linq; 11 | using System.Text; 12 | 13 | using UnityEngine; 14 | 15 | namespace BVH 16 | { 17 | public class BVHAABBObject : BVHObject 18 | { 19 | public BVHBox mAABB; 20 | public BVHAABBObject(Vector3 min, Vector3 max) 21 | { 22 | mAABB = new BVHBox(min, max); 23 | } 24 | override 25 | public bool GetIntersection(ref BVHRay ray, ref BVHIntersectionInfo intersection) 26 | { 27 | float near = 0.0f; 28 | float far = 0.0f; 29 | bool isect = mAABB.Intersect(ray, ref near, ref far); 30 | if (isect) 31 | { 32 | intersection.mObject = this; 33 | intersection.mHitPoint = ray.mOrigin + ray.mDirection * near; 34 | intersection.mLength = near; 35 | } 36 | return isect; 37 | } 38 | 39 | // here not debug test 40 | override 41 | public Vector3 GetNormal(ref BVHIntersectionInfo i) 42 | { 43 | Vector3 v = i.mHitPoint - mAABB.mMin; 44 | if (v.x == 0.0f || v.y == 0.0f || v.z == 0.0f) 45 | { 46 | if (v.x == 0.0f) 47 | { 48 | return Vector3.left; 49 | } 50 | else if (v.y == 0.0f) 51 | { 52 | return Vector3.down; 53 | } 54 | else if (v.z == 0.0f) 55 | { 56 | return Vector3.back; 57 | } 58 | } 59 | else 60 | { 61 | if (v.x == 0.0f) 62 | { 63 | return Vector3.right; 64 | } 65 | else if (v.y == 0.0f) 66 | { 67 | return Vector3.up; 68 | } 69 | else if (v.z == 0.0f) 70 | { 71 | return Vector3.forward; 72 | } 73 | } 74 | // won't be exist 75 | return Vector3.zero; 76 | } 77 | 78 | override 79 | public BVHBox GetBBox() 80 | { 81 | return mAABB; 82 | } 83 | 84 | override 85 | public Vector3 GetCentroid() 86 | { 87 | return (mAABB.mMin + mAABB.mMax) * 0.5f; 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /RayTracerTest.cs: -------------------------------------------------------------------------------- 1 | /******************************************************************************** 2 | ** All rights reserved 3 | ** Auth: kay.yang 4 | ** Date: 6/9/2017 4:53:32 PM 5 | ** Version: v1.0.0 6 | *********************************************************************************/ 7 | 8 | using System; 9 | using System.Collections.Generic; 10 | using System.Linq; 11 | using System.Text; 12 | using UnityEngine; 13 | using KayUtils; 14 | namespace BVH 15 | { 16 | public class RayTracerTest 17 | { 18 | public static void BuildTriangles(ref List triObjects) 19 | { 20 | int w = 100; 21 | int h = 100; 22 | float startW = 0; 23 | float startH = 0; 24 | float wStep = 5f; 25 | float hStep = 5f; 26 | float y = 4.0f; 27 | Vector3 v1; 28 | Vector3 v2; 29 | Vector3 v3; 30 | Vector3 v4; 31 | Vector3 v5; 32 | Vector3 v6; 33 | while (startW < w) 34 | { 35 | while (startH < h) 36 | { 37 | v1 = new Vector3(startW, y, startH); 38 | v2 = new Vector3(startW, y, startH + hStep); 39 | v3 = new Vector3(startW + wStep, y, startH + hStep); 40 | 41 | v4 = new Vector3(startW + wStep, y, startH + hStep); 42 | v5 = new Vector3(startW + wStep, y, startH); 43 | v6 = new Vector3(startW, y, startH); 44 | BVHTriangleObject tri1 = new BVHTriangleObject(v1, v2, v3); 45 | BVHTriangleObject tri2 = new BVHTriangleObject(v4, v5, v6); 46 | triObjects.Add(tri1); 47 | triObjects.Add(tri2); 48 | startH += hStep; 49 | } 50 | startW += wStep; 51 | startH = 0; 52 | } 53 | } 54 | 55 | public static void BuildRay(ref List rayList, ref List triObjects) 56 | { 57 | BVHIntersectionInfo info = new BVHIntersectionInfo(); 58 | for (int i = 0; i < triObjects.Count; ++i) 59 | { 60 | Vector3 pos = triObjects[i].GetCentroid(); 61 | BVHRay ray = new BVHRay(new Vector3(pos.x, 0.0f, pos.z), Vector3.up); 62 | rayList.Add(ray); 63 | } 64 | } 65 | 66 | public static void TestBVH() 67 | { 68 | List triObjects = new List(); 69 | BuildTriangles(ref triObjects); 70 | List rayList = new List(); 71 | BuildRay(ref rayList, ref triObjects); 72 | float start = Time.realtimeSinceStartup; 73 | BVH bvh = new BVH(triObjects); 74 | float end1 = Time.realtimeSinceStartup; 75 | Debug.Log(string.Format("time initialized: {0}", end1 - start)); 76 | BVHIntersectionInfo insect = new BVHIntersectionInfo(); 77 | int insectC = 0; 78 | int missC = 0; 79 | for (int i = 0; i < 200; ++i ) 80 | { 81 | foreach (BVHRay ray in rayList) 82 | { 83 | int test = bvh.GetIntersection(ray, ref insect, false) ? insectC++ : missC++; 84 | } 85 | } 86 | float end2 = Time.realtimeSinceStartup; 87 | Debug.Log(string.Format("time slapped: {0}, insect: {1}, miss: {2}", end2 - end1, insectC, missC)); 88 | } 89 | 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /BVHTriangleObject.cs: -------------------------------------------------------------------------------- 1 | /******************************************************************************** 2 | ** All rights reserved 3 | ** Auth: kay.yang 4 | ** Date: 6/9/2017 5:59:13 PM 5 | ** Version: v1.0.0 6 | *********************************************************************************/ 7 | using System; 8 | using System.Collections.Generic; 9 | using System.Linq; 10 | using System.Text; 11 | using UnityEngine; 12 | 13 | namespace BVH 14 | { 15 | public class BVHTriangleObject : BVHObject 16 | { 17 | public Vector3 mP1; 18 | public Vector3 mP2; 19 | public Vector3 mP3; 20 | public Vector3 mCenter; 21 | public BVHBox mBox; 22 | public Vector3 mNormal; 23 | public BVHTriangleObject(Vector3 p1, Vector3 p2, Vector3 p3) 24 | { 25 | mP1 = p1; 26 | mP2 = p2; 27 | mP3 = p3; 28 | mCenter = (mP1 + mP2 + mP3) * 0.33333f; 29 | Vector3 min = Vector3.Min(Vector3.Min(mP1, mP2), mP3); 30 | Vector3 max = Vector3.Max(Vector3.Max(mP1, mP2), mP3); 31 | mBox = new BVHBox(min, max); 32 | mNormal = Vector3.Cross(mP2 - mP1, mP3 - mP1); 33 | mNormal.Normalize(); 34 | } 35 | 36 | override 37 | public bool GetIntersection(ref BVHRay ray, ref BVHIntersectionInfo intersection) 38 | { 39 | Vector3 edge1, edge2, tvec, pvec, qvec; 40 | double det, inv_det; 41 | double t; 42 | //find vectors for two edges sharing vert0 43 | edge1 = mP2 - mP1; 44 | edge2 = mP3 - mP1; 45 | // begin calculating determinant - also used to calculate U parameter 46 | pvec = Vector3.Cross(ray.mDirection, edge2); 47 | // if determinant is near zero, ray lies in plane of triangle 48 | det = Vector3.Dot(edge1, pvec); 49 | 50 | #if TEST_CULL // define TEST_CULL if culling is desired 51 | if (det < 1e-5f) 52 | return false; 53 | tvec = ray.mOrigin - mP1; 54 | // calculate U parameter and test bounds 55 | double u = Vector3.Dot(tvec, pvec); 56 | if (u < 0.0 || u > det) 57 | return false; 58 | 59 | // prepare to test V parameter 60 | qvec = Vector3.Cross(tvec, edge1); 61 | // calculate V parameter and test bounds 62 | double v = Vector3.Dot(ray.mDirection, qvec); 63 | if (v < 0.0 || u +v > det) 64 | return false; 65 | // calculate t, scale parameters, ray intersects triangle 66 | t = Vector3.Dot(edge2, qvec); 67 | inv_det = 1.0 / det; 68 | t *= inv_det; 69 | u *= inv_det; 70 | v *= inv_det; 71 | #else // the non-culling branch 72 | if (det > -1e-5f && det < 1e-5f) 73 | return false; 74 | inv_det = 1.0 / det; 75 | 76 | // calculate distance from vert0 to ray origin 77 | tvec = ray.mOrigin - mP1; 78 | // calculate U parameter and test bounds 79 | double u = Vector3.Dot(tvec, pvec) * inv_det; 80 | if (u < 0.0 || u > 1.0) 81 | return false; 82 | 83 | // prepare to test V parameters 84 | qvec = Vector3.Cross(tvec, edge1); 85 | 86 | // calculate V paremeter and test bounds 87 | double v = Vector3.Dot(ray.mDirection, qvec) * inv_det; 88 | if (v < 0.0 || u + v > 1.0) 89 | return false; 90 | 91 | //calculate t, ray intersects triangle 92 | t = Vector3.Dot(edge2, qvec) * inv_det; 93 | #endif 94 | intersection.mLength = (float)t; 95 | intersection.mObject = this; 96 | return true; 97 | } 98 | 99 | override 100 | public Vector3 GetNormal(ref BVHIntersectionInfo i) 101 | { 102 | return mNormal; 103 | } 104 | 105 | override 106 | public BVHBox GetBBox() 107 | { 108 | return mBox; 109 | } 110 | 111 | override 112 | public Vector3 GetCentroid() 113 | { 114 | return mCenter; 115 | } 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /BVHBox.cs: -------------------------------------------------------------------------------- 1 | /******************************************************************************** 2 | ** All rights reserved 3 | ** Auth: kay.yang 4 | ** Date: 6/9/2017 4:51:47 PM 5 | ** Version: v1.0.0 6 | *********************************************************************************/ 7 | 8 | using System; 9 | using System.Collections.Generic; 10 | using System.Linq; 11 | using System.Text; 12 | using UnityEngine; 13 | 14 | namespace BVH 15 | { 16 | public class BVHBox 17 | { 18 | public Vector3 mMin = new Vector3(), mMax = new Vector3(), mExtentSize = new Vector3(); 19 | 20 | public BVHBox() 21 | { 22 | 23 | } 24 | 25 | public BVHBox(Vector3 _min, Vector3 _max) 26 | { 27 | mMin = _min; 28 | mMax = _max; 29 | mExtentSize = mMax - mMin; 30 | } 31 | 32 | public BVHBox(Vector3 p) 33 | { 34 | mMin = p; 35 | mMax = p; 36 | mExtentSize = mMax - mMin; 37 | } 38 | 39 | public bool Intersect(BVHRay ray, ref float dnear, ref float dfar) 40 | { 41 | // Intermediate calculation variables. 42 | float tmin = 0.0f; 43 | float tmax = 0.0f; 44 | // X direction. 45 | float div = ray.mInvDirection.x; 46 | if (div >= 0.0f) 47 | { 48 | tmin = (mMin.x - ray.mOrigin.x) * div; 49 | tmax = (mMax.x - ray.mOrigin.x) * div; 50 | } 51 | else 52 | { 53 | tmin = (mMax.x - ray.mOrigin.x) * div; 54 | tmax = (mMin.x - ray.mOrigin.x) * div; 55 | } 56 | dnear = tmin; 57 | dfar = tmax; 58 | 59 | // Check if the ray misses the box. 60 | if (dnear > dfar || dfar < 0.0f) 61 | { 62 | return false; 63 | } 64 | // Y direction. 65 | div = ray.mInvDirection.y; 66 | if (div >= 0.0f) 67 | { 68 | tmin = (mMin.y - ray.mOrigin.y) * div; 69 | tmax = (mMax.y - ray.mOrigin.y) * div; 70 | } 71 | else 72 | { 73 | tmin = (mMax.y - ray.mOrigin.y) * div; 74 | tmax = (mMin.y - ray.mOrigin.y) * div; 75 | } 76 | // Update the near and far intersection distances. 77 | if (tmin > dnear) 78 | { 79 | dnear = tmin; 80 | } 81 | if (tmax < dfar) 82 | { 83 | dfar = tmax; 84 | } 85 | // Check if the ray misses the box. 86 | if (dnear > dfar || dfar < 0.0f) 87 | { 88 | return false; 89 | } 90 | // Z direction. 91 | div = ray.mInvDirection.z; 92 | if (div >= 0.0f) 93 | { 94 | tmin = (mMin.z - ray.mOrigin.z) * div; 95 | tmax = (mMax.z - ray.mOrigin.z) * div; 96 | } 97 | else 98 | { 99 | tmin = (mMax.z - ray.mOrigin.z) * div; 100 | tmax = (mMin.z - ray.mOrigin.z) * div; 101 | } 102 | // Update the near and far intersection distances. 103 | if (tmin > dnear) 104 | { 105 | dnear = tmin; 106 | } 107 | if (tmax < dfar) 108 | { 109 | dfar = tmax; 110 | } 111 | // Check if the ray misses the box. 112 | if (dnear > dfar || dfar < 0.0f) 113 | { 114 | return false; 115 | } 116 | return true; 117 | } 118 | 119 | public void ExpandToInclude(Vector3 p) 120 | { 121 | mMin = Vector3.Min(mMin, p); 122 | mMax = Vector3.Max(mMax, p); 123 | mExtentSize = mMax - mMin; 124 | } 125 | 126 | public void ExpandToInclude(BVHBox b) 127 | { 128 | mMin = Vector3.Min(mMin, b.mMin); 129 | mMax = Vector3.Max(mMax, b.mMax); 130 | mExtentSize = mMax - mMin; 131 | } 132 | 133 | public int MaxDimension() 134 | { 135 | int result = 0; 136 | if (mExtentSize.y > mExtentSize.x) 137 | { 138 | result = 1; 139 | if (mExtentSize.z > mExtentSize.y) 140 | { 141 | result = 2; 142 | } 143 | } 144 | else 145 | { 146 | if (mExtentSize.z > mExtentSize.x) 147 | { 148 | result = 2; 149 | } 150 | } 151 | return result; 152 | } 153 | 154 | public float SurfaceArea() 155 | { 156 | return 2.0f * (mExtentSize.x * mExtentSize.z + mExtentSize.x * mExtentSize.y + mExtentSize.y * mExtentSize.z); 157 | } 158 | } 159 | } 160 | -------------------------------------------------------------------------------- /BVH.cs: -------------------------------------------------------------------------------- 1 | /******************************************************************************** 2 | ** All rights reserved 3 | ** Auth: kay.yang 4 | ** Date: 6/9/2017 4:52:07 PM 5 | ** Version: v1.0.0 6 | *********************************************************************************/ 7 | 8 | using System; 9 | using System.Collections.Generic; 10 | using System.Linq; 11 | using System.Text; 12 | using UnityEngine; 13 | namespace BVH 14 | { 15 | public class BVHFlatNode 16 | { 17 | public BVHBox mBox = new BVHBox(); 18 | public uint mStartIndex; 19 | public uint mLeafCount; 20 | public uint mRightOffset; 21 | } 22 | 23 | public class BVHTraversal 24 | { 25 | public int mIndex; 26 | public float mLength; 27 | public BVHTraversal() { } 28 | public BVHTraversal(int idx, float len) 29 | { 30 | mIndex = idx; 31 | mLength = len; 32 | } 33 | } 34 | 35 | public class BVHBuildEntry 36 | { 37 | public uint mParent; 38 | public uint mStart; 39 | public uint mEnd; 40 | } 41 | 42 | /// 43 | /// 1 对静态的射线检测性能不错 44 | /// 2 对于动态的,需要重构bvh tree,性能比不上静态 45 | /// Note: 最好静态的使用 46 | /// 47 | public class BVH 48 | { 49 | static BVHBuildEntry[] PREALLOC; 50 | static BVH() 51 | { 52 | PREALLOC = new BVHBuildEntry[128]; 53 | for (int i = 0; i < 128; ++i) 54 | { 55 | PREALLOC[i] = new BVHBuildEntry(); 56 | } 57 | } 58 | 59 | private int mNumNodes, mNumLeafs, mNodeMaxLeafSize; 60 | private List mBuildPrims; 61 | private List mFlatTreeList = null; 62 | public BVH(List objects, int _leafSize = 4) 63 | { 64 | mBuildPrims = objects; 65 | mNodeMaxLeafSize = _leafSize; 66 | mNumNodes = mNumLeafs = 0; 67 | Build(); 68 | } 69 | 70 | /// 71 | /// 72 | /// 73 | /// 射线 74 | /// 交点信息 75 | /// 是否找到最短的。 true if 找到交叉就行; false if 找到最短的 76 | /// 77 | public bool GetIntersection(BVHRay ray, ref BVHIntersectionInfo intersection, bool occlusion) 78 | { 79 | intersection.mLength = 999999999.0f; 80 | intersection.mObject = null; 81 | float[] bbhits = new float[4]; 82 | int closer, other; 83 | BVHTraversal[] todo = new BVHTraversal[64]; 84 | todo[0] = new BVHTraversal(); 85 | int stackptr = 0; 86 | todo[stackptr].mIndex = 0; 87 | todo[stackptr].mLength = -9999999.0f; 88 | while(stackptr >= 0) 89 | { 90 | int ni = todo[stackptr].mIndex; 91 | float near = todo[stackptr].mLength; 92 | stackptr--; 93 | BVHFlatNode node = mFlatTreeList[ni]; 94 | if(near > intersection.mLength) 95 | continue; 96 | // 对叶节点做相交测试 97 | if( node.mRightOffset == 0 ) 98 | { 99 | bool hit = false; 100 | for(int o = 0; o < node.mLeafCount; ++o) 101 | { 102 | BVHIntersectionInfo current = new BVHIntersectionInfo(); 103 | BVHObject obj = mBuildPrims[(int)node.mStartIndex + o]; 104 | hit = obj.GetIntersection(ref ray, ref current); 105 | if (hit) 106 | { 107 | if(occlusion) 108 | { 109 | return true; 110 | } 111 | if (current.mLength < intersection.mLength) 112 | { 113 | intersection = current; 114 | } 115 | } 116 | } 117 | } 118 | else 119 | { 120 | // 对父结点做测试 121 | bool hitc0 = mFlatTreeList[ni + 1].mBox.Intersect(ray, ref bbhits[0], ref bbhits[1]); 122 | bool hitc1 = mFlatTreeList[ni + (int)node.mRightOffset].mBox.Intersect(ray, ref bbhits[2], ref bbhits[3]); 123 | if(hitc0 && hitc1) 124 | { 125 | closer = ni + 1; 126 | other = ni + (int)node.mRightOffset; 127 | if(bbhits[2] < bbhits[0]) 128 | { 129 | float temp = bbhits[0]; 130 | bbhits[0] = bbhits[2]; 131 | bbhits[2] = temp; 132 | temp = bbhits[1]; 133 | bbhits[1] = bbhits[3]; 134 | bbhits[3] = temp; 135 | int itemp = closer; 136 | closer = other; 137 | other = itemp; 138 | } 139 | todo[++stackptr] = new BVHTraversal(other, bbhits[2]); 140 | todo[++stackptr] = new BVHTraversal(closer, bbhits[0]); 141 | } 142 | else if (hitc0) 143 | { 144 | todo[++stackptr] = new BVHTraversal(ni + 1, bbhits[0]); 145 | } 146 | else if (hitc1) 147 | { 148 | todo[++stackptr] = new BVHTraversal(ni + (int)node.mRightOffset, bbhits[2]); 149 | } 150 | } 151 | } 152 | if (intersection.mObject != null) 153 | { 154 | intersection.mHitPoint = ray.mOrigin + ray.mDirection * intersection.mLength; 155 | } 156 | return intersection.mObject != null; 157 | } 158 | 159 | // this is not property.but just support dynamic add operator 160 | public void AddObject(BVHObject obj, bool imme = false) 161 | { 162 | mBuildPrims.Add(obj); 163 | if (imme) 164 | { 165 | Build(); 166 | } 167 | } 168 | // this is not property.but just support dynamic delete operator 169 | public void DeleteObject(BVHObject obj, bool imme = false) 170 | { 171 | bool success = mBuildPrims.Remove(obj); 172 | if (success && imme) 173 | { 174 | Build(); 175 | } 176 | } 177 | 178 | private void Build() 179 | { 180 | int stackptr = 0; 181 | uint Untouched = 0xffffffff; 182 | uint TouchedTwice = 0xfffffffd; 183 | PREALLOC[stackptr].mStart = 0; 184 | PREALLOC[stackptr].mEnd = (uint)mBuildPrims.Count; 185 | PREALLOC[stackptr].mParent = 0xfffffffc; 186 | stackptr++; 187 | List buildnodes = new List(mBuildPrims.Count * 2); 188 | while(stackptr > 0) 189 | { 190 | BVHBuildEntry bnode = PREALLOC[--stackptr]; 191 | uint start = bnode.mStart; 192 | uint end = bnode.mEnd; 193 | uint nPrims = end - start; 194 | mNumNodes++; 195 | BVHFlatNode node = new BVHFlatNode(); 196 | node.mStartIndex = start; 197 | node.mLeafCount = nPrims; 198 | node.mRightOffset = Untouched; 199 | BVHBox bb = new BVHBox(mBuildPrims[(int)start].GetBBox().mMin, mBuildPrims[(int)start].GetBBox().mMax); 200 | BVHBox bc = new BVHBox(mBuildPrims[(int)start].GetCentroid()); 201 | for(uint p = start + 1; p < end; ++p) 202 | { 203 | bb.ExpandToInclude(mBuildPrims[(int)p].GetBBox()); 204 | bc.ExpandToInclude(mBuildPrims[(int)p].GetCentroid()); 205 | } 206 | node.mBox = bb; 207 | if(nPrims <= mNodeMaxLeafSize) 208 | { 209 | node.mRightOffset = 0; 210 | mNumLeafs++; 211 | } 212 | 213 | buildnodes.Add(node); 214 | // 记录父节点关于右孩子结点相对父结点的偏移值mRightOffset 215 | // 第一次为左孩子,相对父结点的偏移值为1 216 | // 每个父节点最多被两次 hit 217 | if(bnode.mParent != 0xfffffffc) 218 | { 219 | buildnodes[(int)bnode.mParent].mRightOffset--; 220 | if( buildnodes[(int)bnode.mParent].mRightOffset == TouchedTwice) 221 | { 222 | buildnodes[(int)bnode.mParent].mRightOffset = (uint)mNumNodes - 1 - bnode.mParent; 223 | } 224 | } 225 | if(node.mRightOffset == 0) 226 | continue; 227 | // 选择合适的分割维度 228 | uint split_dim = (uint)bc.MaxDimension(); 229 | float split_coord = 0.5f * (bc.mMin[(int)split_dim] + bc.mMax[(int)split_dim]); 230 | uint mid = start; 231 | // 交换 start 和 end 之间 的数据 232 | for(uint i = start; i < end; ++i) 233 | { 234 | if(mBuildPrims[(int)i].GetCentroid()[(int)split_dim] < split_coord ) 235 | { 236 | BVHObject temp = mBuildPrims[(int)i]; 237 | mBuildPrims[(int)i] = mBuildPrims[(int)mid]; 238 | mBuildPrims[(int)mid] = temp; 239 | ++mid; 240 | } 241 | } 242 | if(mid == start || mid == end) 243 | { 244 | mid = start + (end - start) / 2; 245 | } 246 | // 右孩子 247 | PREALLOC[stackptr].mStart = mid; 248 | PREALLOC[stackptr].mEnd = end; 249 | PREALLOC[stackptr].mParent = (uint)mNumNodes - 1; 250 | stackptr++; 251 | // 左孩子 252 | PREALLOC[stackptr].mStart = start; 253 | PREALLOC[stackptr].mEnd = mid; 254 | PREALLOC[stackptr].mParent = (uint)mNumNodes - 1; 255 | stackptr++; 256 | } 257 | if (mFlatTreeList != null) 258 | mFlatTreeList.Clear(); 259 | mFlatTreeList = new List(mNumNodes); 260 | for (uint n = 0; n < mNumNodes; ++n) 261 | { 262 | mFlatTreeList.Add(buildnodes[(int)n]); 263 | } 264 | } 265 | } 266 | } 267 | --------------------------------------------------------------------------------