123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163 |
- /*
- *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;
- }
- }
|