Implement BVH.
This commit is contained in:
parent
945c0ea97e
commit
ce102449b8
6
Makefile
6
Makefile
@ -1,9 +1,9 @@
|
||||
CXX = g++
|
||||
|
||||
CXXFLAGS = -std=c++20 -Wall -Wextra -Wno-unused-parameter -march=native -Ofast -flto -fopenmp
|
||||
CXXFLAGS = -std=c++20 -Wall -Wextra -Wno-unused-parameter -march=native -O3 -flto -fopenmp
|
||||
|
||||
DEPS = util.h vec3.h color.h ray.h camera.h hittable.h hittable_list.h sphere.h material.h lodepng.h moving_sphere.h
|
||||
OBJ = main.o material.o vec3.o lodepng.o moving_sphere.o
|
||||
DEPS = util.h vec3.h color.h ray.h camera.h hittable.h hittable_list.h sphere.h material.h lodepng.h moving_sphere.h bvh.h aabb.h
|
||||
OBJ = main.o material.o vec3.o lodepng.o moving_sphere.o bvh.o
|
||||
|
||||
TARGET = toytracer
|
||||
|
||||
|
50
aabb.h
Normal file
50
aabb.h
Normal file
@ -0,0 +1,50 @@
|
||||
#ifndef AABB_H
|
||||
#define AABB_H
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#include "vec3.h"
|
||||
|
||||
class Aabb {
|
||||
public:
|
||||
Aabb() {}
|
||||
Aabb(const Point3& a, const Point3& b) {
|
||||
_min = a;
|
||||
_max = b;
|
||||
}
|
||||
|
||||
Point3 min() const { return _min; }
|
||||
Point3 max() const { return _max; }
|
||||
|
||||
bool hit(const Ray& r, double tmin, double tmax) const {
|
||||
for (int a = 0; a < 3; a++) {
|
||||
auto invD = 1.0f / r.direction()[a];
|
||||
auto t0 = (min()[a] - r.origin()[a]) * invD;
|
||||
auto t1 = (max()[a] - r.origin()[a]) * invD;
|
||||
if (invD < 0.0f)
|
||||
std::swap(t0, t1);
|
||||
tmin = t0 > tmin ? t0 : tmin;
|
||||
tmax = t1 < tmax ? t1 : tmax;
|
||||
if (tmax <= tmin)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
Point3 _min;
|
||||
Point3 _max;
|
||||
};
|
||||
|
||||
inline Aabb surrounding_box(Aabb box0, Aabb box1) {
|
||||
Point3 small(std::fmin(box0.min().x(), box1.min().x()),
|
||||
std::fmin(box0.min().y(), box1.min().y()),
|
||||
std::fmin(box0.min().z(), box1.min().z()));
|
||||
|
||||
Point3 big(std::fmax(box0.max().x(), box1.max().x()),
|
||||
std::fmax(box0.max().y(), box1.max().y()),
|
||||
std::fmax(box0.max().z(), box1.max().z()));
|
||||
return Aabb(small, big);
|
||||
}
|
||||
|
||||
#endif // AABB_H
|
67
bvh.cpp
Normal file
67
bvh.cpp
Normal file
@ -0,0 +1,67 @@
|
||||
#include "bvh.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
|
||||
bool Bvh_node::bounding_box(double t0, double t1, Aabb& output_box) const {
|
||||
output_box = box;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Bvh_node::hit(const Ray& r, double t_min, double t_max, hit_record& rec) const {
|
||||
if (!box.hit(r, t_min, t_max))
|
||||
return false;
|
||||
|
||||
bool hit_left = left->hit(r, t_min, t_max, rec);
|
||||
bool hit_right = right->hit(r, t_min, hit_left ? rec.t : t_max, rec);
|
||||
|
||||
return hit_left || hit_right;
|
||||
}
|
||||
|
||||
bool box_compare(const std::shared_ptr<Hittable> a, const std::shared_ptr<Hittable> b, int axis, double t0, double t1) {
|
||||
Aabb box_a;
|
||||
Aabb box_b;
|
||||
|
||||
if (!a->bounding_box(t0, t1, box_a) || !b->bounding_box(t0, t1, box_b)) {
|
||||
std::cerr << "No bounding box in Bvh_node constructor.\n";
|
||||
std::exit(1);
|
||||
}
|
||||
|
||||
return box_a.min()[axis] < box_b.min()[axis];
|
||||
}
|
||||
|
||||
Bvh_node::Bvh_node(std::vector<std::shared_ptr<Hittable>>& objects, int start, int end, double time0, double time1) {
|
||||
using namespace std::placeholders;
|
||||
|
||||
int axis = random_int(0, 2);
|
||||
auto comparator = std::bind(box_compare, _1, _2, axis, time0, time1);
|
||||
|
||||
int 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 {
|
||||
std::sort(objects.begin() + start, objects.begin() + end, comparator);
|
||||
|
||||
auto mid = start + object_span/2;
|
||||
left = std::make_shared<Bvh_node>(objects, start, mid, time0, time1);
|
||||
right = std::make_shared<Bvh_node>(objects, mid, end, time0, time1);
|
||||
}
|
||||
|
||||
Aabb box_left, box_right;
|
||||
|
||||
if (!left->bounding_box(time0, time1, box_left) || !right->bounding_box(time0, time1, box_right)) {
|
||||
std::cerr << "No bounding box in Bvh_node constructor.\n";
|
||||
std::exit(1);
|
||||
}
|
||||
|
||||
box = surrounding_box(box_left, box_right);
|
||||
}
|
23
bvh.h
Normal file
23
bvh.h
Normal file
@ -0,0 +1,23 @@
|
||||
#ifndef BVH_H
|
||||
#define BVH_H
|
||||
|
||||
#include "hittable.h"
|
||||
|
||||
class Bvh_node : public Hittable {
|
||||
public:
|
||||
Bvh_node();
|
||||
|
||||
Bvh_node(
|
||||
std::vector<std::shared_ptr<Hittable>>& objects,
|
||||
int start, int end, double time0, double time1);
|
||||
|
||||
virtual bool hit(const Ray&, double tmin, double tmax, hit_record& rec) const;
|
||||
virtual bool bounding_box(double t0, double t1, Aabb& output_box) const;
|
||||
|
||||
private:
|
||||
std::shared_ptr<Hittable> left;
|
||||
std::shared_ptr<Hittable> right;
|
||||
Aabb box;
|
||||
};
|
||||
|
||||
#endif // BVH_H
|
@ -5,6 +5,7 @@
|
||||
|
||||
#include "ray.h"
|
||||
#include "material.h"
|
||||
#include "aabb.h"
|
||||
|
||||
class Material;
|
||||
|
||||
@ -24,6 +25,7 @@ struct hit_record {
|
||||
class Hittable {
|
||||
public:
|
||||
virtual bool hit(const Ray &r, double tmin, double tmax, hit_record &rec) const = 0;
|
||||
virtual bool bounding_box(double t0, double t1, Aabb& output_box) const = 0;
|
||||
};
|
||||
|
||||
#endif // HITTABLE_H
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include <vector>
|
||||
|
||||
#include "hittable.h"
|
||||
#include "bvh.h"
|
||||
|
||||
class Hittable_list : public Hittable {
|
||||
public:
|
||||
@ -15,9 +16,13 @@ public:
|
||||
void add(std::shared_ptr<Hittable> object) { objects.push_back(object); }
|
||||
|
||||
virtual bool hit(const Ray &r, double tmin, double tmax, hit_record &rec) const;
|
||||
bool bounding_box(double t0, double t1, Aabb& output_box) const;
|
||||
|
||||
Bvh_node generate_bvh(double t0, double t1);
|
||||
|
||||
private:
|
||||
std::vector<std::shared_ptr<Hittable>> objects;
|
||||
|
||||
};
|
||||
|
||||
bool Hittable_list::hit(const Ray &r, double tmin, double tmax, hit_record &rec) const {
|
||||
@ -36,4 +41,22 @@ bool Hittable_list::hit(const Ray &r, double tmin, double tmax, hit_record &rec)
|
||||
return hit_anything;
|
||||
}
|
||||
|
||||
bool Hittable_list::bounding_box(double t0, double t1, Aabb& output_box) const {
|
||||
if (objects.empty()) return false;
|
||||
|
||||
Aabb temp_box;
|
||||
bool first_box = true;
|
||||
|
||||
for (const auto& object : objects) {
|
||||
if (!object->bounding_box(t0, t1, temp_box)) return false;
|
||||
output_box = first_box ? temp_box : surrounding_box(output_box, temp_box);
|
||||
first_box = false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
Bvh_node Hittable_list::generate_bvh(double t0, double t1) {
|
||||
return Bvh_node(objects, 0, objects.size(), t0, t1);
|
||||
}
|
||||
|
||||
#endif // HITTABLE_LIST_H
|
||||
|
8
main.cpp
8
main.cpp
@ -36,7 +36,7 @@ Color ray_color(const Ray& r, const Hittable& world, int depth) {
|
||||
return (1.0 - t) * Color(1.0, 1.0, 1.0) + t * Color(0.5, 0.7, 1.0);
|
||||
}
|
||||
|
||||
Hittable_list setup_random_scene(const int sph_i) {
|
||||
Bvh_node setup_random_scene(const int sph_i) {
|
||||
Hittable_list world;
|
||||
|
||||
auto ground_material = std::make_shared<Lambertian>(Color(0.5, 0.5, 0.5));
|
||||
@ -79,7 +79,7 @@ Hittable_list setup_random_scene(const int sph_i) {
|
||||
auto material3 = std::make_shared<Metal>(Color(0.7, 0.6, 0.5), 0.0);
|
||||
world.add(std::make_shared<Sphere>(Point3(4, 1, 0), 1.0, material3));
|
||||
|
||||
return world;
|
||||
return world.generate_bvh(0, 1);
|
||||
}
|
||||
|
||||
struct render_tile {
|
||||
@ -92,8 +92,8 @@ struct render_tile {
|
||||
int main() {
|
||||
const auto aspect_ratio = 16.0 / 9.0;
|
||||
//const int image_width = 1920;
|
||||
const int image_width = 1280;
|
||||
//const int image_width = 768;
|
||||
//const int image_width = 1280;
|
||||
const int image_width = 768;
|
||||
//const int image_width = 384;
|
||||
const int image_height = static_cast<int>(image_width / aspect_ratio);
|
||||
//const int samples_per_pixel = 2000;
|
||||
|
@ -33,3 +33,14 @@ bool Moving_sphere::hit(const Ray& r, double tmin, double tmax, hit_record& rec)
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Moving_sphere::bounding_box(double t0, double t1, Aabb& output_box) const {
|
||||
Aabb box0(
|
||||
center(t0) - Vec3(radius, radius, radius),
|
||||
center(t0) + Vec3(radius, radius, radius));
|
||||
Aabb box1(
|
||||
center(t1) - Vec3(radius, radius, radius),
|
||||
center(t1) + Vec3(radius, radius, radius));
|
||||
output_box = surrounding_box(box0, box1);
|
||||
return true;
|
||||
}
|
||||
|
@ -13,6 +13,7 @@ class Moving_sphere : public Hittable {
|
||||
: center0(cen0), center1(cen1), time0(t0), time1(t1), radius(r), mat_ptr(m) {}
|
||||
|
||||
virtual bool hit(const Ray& r, double tmin, double tmax, hit_record& rec) const;
|
||||
virtual bool bounding_box(double t0, double t1, Aabb& output_box) const;
|
||||
|
||||
Point3 center(double time) const;
|
||||
|
||||
|
8
sphere.h
8
sphere.h
@ -14,6 +14,7 @@ public:
|
||||
Sphere(Point3 cen, double r, std::shared_ptr<Material> m) : center(cen), radius(r), mat_ptr(m) {}
|
||||
|
||||
virtual bool hit(const Ray& r, double tmin, double tmax, hit_record& rec) const;
|
||||
virtual bool bounding_box(double t0, double t1, Aabb& output_box) const;
|
||||
|
||||
private:
|
||||
Point3 center;
|
||||
@ -51,5 +52,12 @@ bool Sphere::hit(const Ray& r, double tmin, double tmax, hit_record& rec) const
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Sphere::bounding_box(double t0, double t1, Aabb& output_box) const {
|
||||
output_box = Aabb(
|
||||
center - Vec3(radius, radius, radius),
|
||||
center + Vec3(radius, radius, radius));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
#endif // SPHERE_H
|
||||
|
4
util.h
4
util.h
@ -22,6 +22,10 @@ inline double random_double(double min, double max) {
|
||||
return min + (max-min) * random_double();
|
||||
}
|
||||
|
||||
inline int random_int(int min, int max) {
|
||||
return static_cast<int>(random_double(min, max+1));
|
||||
}
|
||||
|
||||
inline double clamp(double x, double min, double max) {
|
||||
if (x < min) return min;
|
||||
if (x > max) return max;
|
||||
|
Loading…
Reference in New Issue
Block a user