File: BVH.pde

package info (click to toggle)
libvpx 1.15.0-2.1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 27,004 kB
  • sloc: ansic: 252,377; cpp: 115,241; asm: 22,233; sh: 5,289; python: 4,391; perl: 2,010; makefile: 431
file content (163 lines) | stat: -rw-r--r-- 4,784 bytes parent folder | download | duplicates (21)
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
/*
 *AABB bounding box
 *Bouding Volume Hierarchy
 */
class BoundingBox {
  float min_x, min_y, min_z, max_x, max_y, max_z;
  PVector center;
  BoundingBox() {
    min_x = Float.POSITIVE_INFINITY;
    min_y = Float.POSITIVE_INFINITY;
    min_z = Float.POSITIVE_INFINITY;
    max_x = Float.NEGATIVE_INFINITY;
    max_y = Float.NEGATIVE_INFINITY;
    max_z = Float.NEGATIVE_INFINITY;
    center = new PVector();
  }
  // build a bounding box for a triangle
  void create(Triangle t) {
    min_x = min(t.p1.x, min(t.p2.x, t.p3.x));
    max_x = max(t.p1.x, max(t.p2.x, t.p3.x));

    min_y = min(t.p1.y, min(t.p2.y, t.p3.y));
    max_y = max(t.p1.y, max(t.p2.y, t.p3.y));

    min_z = min(t.p1.z, min(t.p2.z, t.p3.z));
    max_z = max(t.p1.z, max(t.p2.z, t.p3.z));
    center.x = (max_x + min_x) / 2;
    center.y = (max_y + min_y) / 2;
    center.z = (max_z + min_z) / 2;
  }
  // merge two bounding boxes
  void add(BoundingBox bbx) {
    min_x = min(min_x, bbx.min_x);
    min_y = min(min_y, bbx.min_y);
    min_z = min(min_z, bbx.min_z);

    max_x = max(max_x, bbx.max_x);
    max_y = max(max_y, bbx.max_y);
    max_z = max(max_z, bbx.max_z);
    center.x = (max_x + min_x) / 2;
    center.y = (max_y + min_y) / 2;
    center.z = (max_z + min_z) / 2;
  }
  // get bounding box center axis value
  float getCenterAxisValue(int axis) {
    if (axis == 1) {
      return center.x;
    } else if (axis == 2) {
      return center.y;
    }
    // when axis == 3
    return center.z;
  }
  // check if a ray is intersected with the bounding box
  boolean intersect(Ray r) {
    float tmin, tmax;
    if (r.dir.x >= 0) {
      tmin = (min_x - r.ori.x) * (1.0f / r.dir.x);
      tmax = (max_x - r.ori.x) * (1.0f / r.dir.x);
    } else {
      tmin = (max_x - r.ori.x) * (1.0f / r.dir.x);
      tmax = (min_x - r.ori.x) * (1.0f / r.dir.x);
    }

    float tymin, tymax;
    if (r.dir.y >= 0) {
      tymin = (min_y - r.ori.y) * (1.0f / r.dir.y);
      tymax = (max_y - r.ori.y) * (1.0f / r.dir.y);
    } else {
      tymin = (max_y - r.ori.y) * (1.0f / r.dir.y);
      tymax = (min_y - r.ori.y) * (1.0f / r.dir.y);
    }

    if (tmax < tymin || tymax < tmin) {
      return false;
    }

    tmin = tmin < tymin ? tymin : tmin;
    tmax = tmax > tymax ? tymax : tmax;

    float tzmin, tzmax;
    if (r.dir.z >= 0) {
      tzmin = (min_z - r.ori.z) * (1.0f / r.dir.z);
      tzmax = (max_z - r.ori.z) * (1.0f / r.dir.z);
    } else {
      tzmin = (max_z - r.ori.z) * (1.0f / r.dir.z);
      tzmax = (min_z - r.ori.z) * (1.0f / r.dir.z);
    }
    if (tmax < tzmin || tmin > tzmax) {
      return false;
    }
    return true;
  }
}
// Bounding Volume Hierarchy
class BVH {
  // Binary Tree
  BVH left, right;
  BoundingBox overall_bbx;
  ArrayList<Triangle> mesh;
  BVH(ArrayList<Triangle> mesh) {
    this.mesh = mesh;
    overall_bbx = new BoundingBox();
    left = null;
    right = null;
    int mesh_size = this.mesh.size();
    if (mesh_size <= 1) {
      return;
    }
    // random select an axis
    int axis = int(random(100)) % 3 + 1;
    // build bounding box and save the selected center component
    float[] axis_values = new float[mesh_size];
    for (int i = 0; i < mesh_size; i++) {
      Triangle t = this.mesh.get(i);
      overall_bbx.add(t.bbx);
      axis_values[i] = t.bbx.getCenterAxisValue(axis);
    }
    // find the median value of selected center component as pivot
    axis_values = sort(axis_values);
    float pivot;
    if (mesh_size % 2 == 1) {
      pivot = axis_values[mesh_size / 2];
    } else {
      pivot =
          0.5f * (axis_values[mesh_size / 2 - 1] + axis_values[mesh_size / 2]);
    }
    // Build left node and right node by partitioning the mesh based on triangle
    // bounding box center component value
    ArrayList<Triangle> left_mesh = new ArrayList<Triangle>();
    ArrayList<Triangle> right_mesh = new ArrayList<Triangle>();
    for (int i = 0; i < mesh_size; i++) {
      Triangle t = this.mesh.get(i);
      if (t.bbx.getCenterAxisValue(axis) < pivot) {
        left_mesh.add(t);
      } else if (t.bbx.getCenterAxisValue(axis) > pivot) {
        right_mesh.add(t);
      } else if (left_mesh.size() < right_mesh.size()) {
        left_mesh.add(t);
      } else {
        right_mesh.add(t);
      }
    }
    left = new BVH(left_mesh);
    right = new BVH(right_mesh);
  }
  // check if a ray intersect with current volume
  boolean intersect(Ray r, float[] param) {
    if (mesh.size() == 0) {
      return false;
    }
    if (mesh.size() == 1) {
      Triangle t = mesh.get(0);
      return t.intersect(r, param);
    }
    if (!overall_bbx.intersect(r)) {
      return false;
    }
    boolean left_res = left.intersect(r, param);
    boolean right_res = right.intersect(r, param);
    return left_res || right_res;
  }
}