forked from jbikker/bvh_article
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathbvh.h
174 lines (157 loc) · 4.83 KB
/
bvh.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
#pragma once
// enable the use of SSE in the AABB intersection function
#define USE_SSE
// bin count for binned BVH building
#define BINS 8
namespace Tmpl8
{
// minimalist triangle struct
__declspec(align(64)) struct Tri
{
// union each float3 with a 16-byte __m128 for faster BVH construction
union { float3 vertex0; __m128 v0; };
union { float3 vertex1; __m128 v1; };
union { float3 vertex2; __m128 v2; };
union { float3 centroid; __m128 centroid4; }; // total size: 64 bytes
};
// additional triangle data, for texturing and shading
struct TriEx { float2 uv0, uv1, uv2; float3 N0, N1, N2; };
// minimalist AABB struct with grow functionality
struct aabb
{
float3 bmin = 1e30f, bmax = -1e30f;
void grow( float3 p ) { bmin = fminf( bmin, p ); bmax = fmaxf( bmax, p ); }
void grow( aabb& b ) { if (b.bmin.x != 1e30f) { grow( b.bmin ); grow( b.bmax ); } }
float area()
{
float3 e = bmax - bmin; // box extent
return e.x * e.y + e.y * e.z + e.z * e.x;
}
};
// intersection record, carefully tuned to be 16 bytes in size
struct Intersection
{
float t; // intersection distance along ray
float u, v; // barycentric coordinates of the intersection
uint instPrim; // instance index (12 bit) and primitive index (20 bit)
};
// ray struct, prepared for SIMD AABB intersection
__declspec(align(64)) struct Ray
{
Ray() { O4 = D4 = rD4 = _mm_set1_ps( 1 ); }
union { struct { float3 O; float dummy1; }; __m128 O4; };
union { struct { float3 D; float dummy2; }; __m128 D4; };
union { struct { float3 rD; float dummy3; }; __m128 rD4; };
Intersection hit; // total ray size: 64 bytes
};
// 32-byte BVH node struct
struct BVHNode
{
union { struct { float3 aabbMin; uint leftFirst; }; __m128 aabbMin4; };
union { struct { float3 aabbMax; uint triCount; }; __m128 aabbMax4; };
bool isLeaf() const { return triCount > 0; } // empty BVH leaves do not exist
float CalculateNodeCost()
{
float3 e = aabbMax - aabbMin; // extent of the node
return (e.x * e.y + e.y * e.z + e.z * e.x) * triCount;
}
};
// bounding volume hierarchy, to be used as BLAS
__declspec(align(64)) class BVH
{
struct BuildJob
{
uint nodeIdx;
float3 centroidMin, centroidMax;
};
public:
BVH() = default;
BVH( class Mesh* mesh );
void Build();
void Refit();
void Intersect( Ray& ray, uint instanceIdx );
private:
void Subdivide( uint nodeIdx, uint depth, uint& nodePtr, float3& centroidMin, float3& centroidMax );
void UpdateNodeBounds( uint nodeIdx, float3& centroidMin, float3& centroidMax );
float FindBestSplitPlane( BVHNode& node, int& axis, int& splitPos, float3& centroidMin, float3& centroidMax );
class Mesh* mesh = 0;
public:
uint* triIdx = 0;
uint nodesUsed;
BVHNode* bvhNode = 0;
bool subdivToOnePrim = false; // for TLAS experiment
BuildJob buildStack[64];
int buildStackPtr;
};
// minimalist mesh class
class Mesh
{
public:
Mesh() = default;
Mesh( uint primCount );
Mesh( const char* objFile, const char* texFile );
Tri* tri = 0; // triangle data for intersection
TriEx* triEx = 0; // triangle data for shading
int triCount = 0;
BVH* bvh = 0;
Surface* texture = 0;
float3* P = 0, * N = 0;
};
// instance of a BVH, with transform and world bounds
class BVHInstance
{
public:
BVHInstance() = default;
BVHInstance( BVH* blas, uint index ) : bvh( blas ), idx( index ) { SetTransform( mat4() ); }
void SetTransform( mat4& transform );
mat4& GetTransform() { return transform; }
void Intersect( Ray& ray );
private:
mat4 transform;
mat4 invTransform; // inverse transform
public:
aabb bounds; // in world space
private:
BVH* bvh = 0;
uint idx;
int dummy[7];
};
// top-level BVH node
struct TLASNode
{
union { struct { float dummy1[3]; uint leftRight; }; struct { float dummy3[3]; unsigned short left, right; }; float3 aabbMin; __m128 aabbMin4; };
union { struct { float dummy2[3]; uint BLAS; }; float3 aabbMax; __m128 aabbMax4; };
bool isLeaf() { return leftRight == 0; }
};
// include kD-tree logic for fast agglomerative clustering
#include "kdtree.h"
// top-level BVH class
__declspec(align(64)) class TLAS
{
public:
TLAS() = default;
TLAS( BVHInstance* bvhList, int N );
void Build();
void Intersect( Ray& ray );
private:
int FindBestMatch( int N, int A );
public:
TLASNode* tlasNode = 0;
BVHInstance* blas = 0;
uint nodesUsed, blasCount;
uint* nodeIdx = 0;
// fast agglomerative clustering functionality
struct SortItem { float pos; uint blasIdx; };
void BuildQuick();
void SortAndSplit( uint first, uint last, uint level );
void CreateParent( uint idx, uint left, uint right );
static void Swap( SortItem& a, SortItem& b ) { SortItem t = a; a = b; b = t; }
void QuickSort( SortItem a[], int first, int last );
// data for fast agglomerative clustering
KDTree* tree[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
uint treeSize[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
SortItem* item = 0;
uint treeIdx = 0;
};
} // namespace Tmpl8
// EOF