blob: 4c50ada8a8b1c00875d0e2e3d2314920c7edf222 [file] [log] [blame]
#ifndef BVH_H
#define BVH_H
//==============================================================================================
// Originally written in 2016 by Peter Shirley <ptrshrl@gmail.com>
//
// To the extent possible under law, the author(s) have dedicated all copyright
// and related and neighboring rights to this software to the public domain
// worldwide. This software is distributed without any warranty.
//
// You should have received a copy (see file COPYING.txt) of the CC0 Public
// Domain Dedication along with this software. If not, see
// <http://creativecommons.org/publicdomain/zero/1.0/>.
//
// The original source code is from
// https://github.com/RayTracing/raytracing.github.io/tree/release/src/TheNextWeek
//
// Changes to the original code follow the following license.
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//==============================================================================================
#include "rtweekend.h"
#include "hittable.h"
#include "hittable_list.h"
#include <algorithm>
class bvh_node : public hittable {
public:
__host__ __device__ bvh_node(const hittable_list &list, unsigned &rng)
: bvh_node(list.objects, 0, list.objects.size(), rng) {}
__host__ __device__ bvh_node(const Vector<SharedPtr<hittable>> &src_objects,
size_t start, size_t end, unsigned &rng) {
auto objects =
src_objects; // Create a modifiable array of the source scene objects
int axis = random_int(0, 2, rng);
auto comparator = (axis == 0) ? box_x_compare
: (axis == 1) ? box_y_compare
: box_z_compare;
size_t object_span = end - start;
if (object_span == 1) {
left = right = objects[start];
} else if (object_span == 2) {
if (comparator(objects[start], objects[start + 1])) {
left = objects[start];
right = objects[start + 1];
} else {
left = objects[start + 1];
right = objects[start];
}
} else {
sort(objects.begin() + start, objects.begin() + end, comparator);
auto mid = start + object_span / 2;
left = makeShared<bvh_node>(objects, start, mid, rng);
right = makeShared<bvh_node>(objects, mid, end, rng);
}
bbox = aabb(left->bounding_box(), right->bounding_box());
}
__host__ __device__ bool hit(const ray &r, interval ray_t, hit_record &rec,
unsigned &rng) const override {
if (!bbox.hit(r, ray_t))
return false;
bool hit_left = left->hit(r, ray_t, rec, rng);
bool hit_right = right->hit(
r, interval(ray_t.min, hit_left ? rec.t : ray_t.max), rec, rng);
return hit_left || hit_right;
}
__host__ __device__ aabb bounding_box() const override { return bbox; }
private:
SharedPtr<hittable> left;
SharedPtr<hittable> right;
aabb bbox;
__host__ __device__ static bool box_compare(const SharedPtr<hittable> a,
const SharedPtr<hittable> b,
int axis_index) {
return a->bounding_box().axis(axis_index).min <
b->bounding_box().axis(axis_index).min;
}
__host__ __device__ static bool box_x_compare(const SharedPtr<hittable> a,
const SharedPtr<hittable> b) {
return box_compare(a, b, 0);
}
__host__ __device__ static bool box_y_compare(const SharedPtr<hittable> a,
const SharedPtr<hittable> b) {
return box_compare(a, b, 1);
}
__host__ __device__ static bool box_z_compare(const SharedPtr<hittable> a,
const SharedPtr<hittable> b) {
return box_compare(a, b, 2);
}
};
#endif