Skip to content

Commit

Permalink
Adding clang-format, updating Makefile, minor changes to BVH traversal
Browse files Browse the repository at this point in the history
  • Loading branch information
brandonpelfrey committed Mar 29, 2020
1 parent 833e46f commit e6fc721
Show file tree
Hide file tree
Showing 12 changed files with 151 additions and 145 deletions.
9 changes: 9 additions & 0 deletions .clang-format
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
BasedOnStyle: Google
AllowShortFunctionsOnASingleLine: All
ColumnLimit: 120
IndentWidth: '2'
Language: Cpp
UseTab: Never

...
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ render.ppm
*.exe
doxygen/html
examples/CubeOfSpheres
examples/ObjFile
10 changes: 7 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
DOXYGEN := doxygen

CXXFLAGS := -Wall -Wextra -Werror -Wfatal-errors
CXXFLAGS := $(CXXFLAGS) -I $(CURDIR)/include
CXXFLAGS := $(CXXFLAGS) -I $(CURDIR)/include
CXXFLAGS := $(CXXFLAGS) -std=c++14

VPATH += include/fast_bvh
Expand All @@ -14,9 +14,10 @@ headers := include/FastBVH/BBox.h \
include/FastBVH/Vector3.h

example_headers := examples/Log.h \
examples/Stopwatch.h
examples/Stopwatch.h \
examples/tiny_obj_loader.h

examples := examples/CubeOfSpheres
examples := examples/CubeOfSpheres examples/ObjFile

.PHONY: all
all: simple-target
Expand All @@ -26,6 +27,9 @@ simple-target: $(examples)

examples/CubeOfSpheres: examples/CubeOfSpheres.cpp $(headers) $(example_headers)

examples/ObjFile: examples/ObjFile.cpp $(headers) $(example_headers)
$(CXX) $(CXXFLAGS) -I $(CURDIR)/examples examples/tiny_obj_loader.cc $< -o $@

examples/%: examples/%.cpp
$(CXX) $(CXXFLAGS) $< -o $@

Expand Down
90 changes: 36 additions & 54 deletions examples/CubeOfSpheres.cpp
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
#include <cstdio>
#include <vector>
#include <cstdlib>

#include <FastBVH/BVH.h>
#include <FastBVH/Traverser.h>

#include <cstdio>
#include <cstdlib>
#include <vector>

#include "Log.h"
#include "SimpleScheduler.h"
#include "Stopwatch.h"
Expand All @@ -16,57 +16,50 @@ using std::vector;
using namespace FastBVH;

// Return a random number in [0,1]
float rand01() {
return rand() * (1.f / RAND_MAX);
}
float rand01() { return rand() * (1.f / RAND_MAX); }

// Return a random vector with each component in the range [-1,1]
Vector3<float> randVector3() {
return Vector3<float> { rand01(), rand01(), rand01() } * 2.0f - Vector3<float> { 1, 1, 1 };
}
Vector3<float> randVector3() { return Vector3<float>{rand01(), rand01(), rand01()} * 2.0f - Vector3<float>{1, 1, 1}; }

//! For the purposes of demonstrating the BVH, a simple sphere
template <typename Float>
struct Sphere final {
Vector3<Float> center; // Center of the sphere
Float r, r2; // Radius, Radius^2
Vector3<Float> center; // Center of the sphere
Float r, r2; // Radius, Radius^2

constexpr Sphere(const Vector3<Float>& center, Float radius) noexcept
: center(center), r(radius), r2(radius*radius) { }
: center(center), r(radius), r2(radius * radius) {}
};

//! \brief Used for calculating the bounding boxes
//! associated with spheres.
//! \tparam Float The floating point type of the sphere and bounding box vectors.
template <typename Float>
class SphereBoxConverter final {
public:
public:
//! Converts a sphere to a bounding box.
//! \param sphere The sphere to convert to a bounding box.
//! \return A bounding box that encapsulates the sphere.
BBox<Float> operator () (const Sphere<Float>& sphere) const noexcept {

BBox<Float> operator()(const Sphere<Float>& sphere) const noexcept {
const auto& r = sphere.r;

auto box_delta = Vector3<Float> { r, r, r };
auto box_delta = Vector3<Float>{r, r, r};

return BBox<Float>(sphere.center - box_delta,
sphere.center + box_delta);
return BBox<Float>(sphere.center - box_delta, sphere.center + box_delta);
}
};

//! \brief Used for calculating the intersections between rays and spheres.
//! \tparam Float The floating point type of the spheres and rays.
template <typename Float>
class SphereIntersector final {
public:
public:
//! Indicates if a ray and a sphere intersect.
//! \param sphere The sphere to check intersection for.
//! \param ray The ray being traced.
//! \return An instance of @ref FastBVH::Intersection that contains the intersection
//! data and indicates whether or not there was actually an intersection.
Intersection<Float, Sphere<Float>> operator () (const Sphere<Float>& sphere, const Ray<Float>& ray) const noexcept {

Intersection<Float, Sphere<Float>> operator()(const Sphere<Float>& sphere, const Ray<Float>& ray) const noexcept {
const auto& center = sphere.center;
const auto& r2 = sphere.r2;

Expand All @@ -75,85 +68,74 @@ class SphereIntersector final {
auto ss = dot(s, s);

// Compute discriminant
auto disc = sd*sd - ss + r2;
auto disc = sd * sd - ss + r2;

// Complex values: No intersection
if (disc < 0.f) {
return Intersection<Float, Sphere<Float>>{};
}

// There is a positive and negative branch to the intersection equation. Assuming we are always outside of the
// sphere, then the first intersection is the negative branch.
auto t = sd - std::sqrt(disc);

auto hit_pos = ray.o + (ray.d * t);

auto normal = normalize(hit_pos - sphere.center);

// Assume we are not in a sphere... The first hit is the lesser valued
return Intersection<Float, Sphere<Float>> {
t, &sphere, normal
};
return Intersection<Float, Sphere<Float>>{t, &sphere, normal};
}
};

} // namespace
} // namespace

int main() {

// Create a million spheres packed in the space of a cube
const unsigned int N = 1000000;

vector<Sphere<float>> objects;

printf("Constructing %d spheres...\n", N);
for(size_t i=0; i<N; ++i) {
for (size_t i = 0; i < N; ++i) {
objects.emplace_back(Sphere<float>(randVector3(), .005f));
}

BVH<float, Sphere<float>> bvh;

SphereBoxConverter<float> boxConverter;

Stopwatch sw;
Stopwatch stopwatch;

// Compute a BVH for this object set
BVH<float, Sphere<float>> bvh;
bvh.build(std::move(objects), boxConverter);

// Output tree build time and statistics
double constructionTime = sw.read();
double constructionTime = stopwatch.read();

LOG_STAT("Built BVH (%u nodes, with %u leafs) in %.02f ms",
(unsigned int) bvh.getNodeCount(),
(unsigned int) bvh.getLeafCount(),
1000.0 * constructionTime);
LOG_STAT("Built BVH (%u nodes, with %u leafs) in %.02f ms", (unsigned int)bvh.getNodeCount(),
(unsigned int)bvh.getLeafCount(), 1000.0 * constructionTime);

SphereIntersector<float> intersector;

Traverser<float, Sphere<float>, decltype(intersector)> traverser(bvh, intersector);

auto trace_kernel = [traverser](const Ray<float>& ray) {
auto isect = traverser.traverse(ray, false);
auto isect = traverser.traverse(ray);
if (isect) {
// Just for fun, we'll make the color based on the normal
return Vector3<float> {
std::fabs(isect.normal.x),
std::fabs(isect.normal.y),
std::fabs(isect.normal.z)
};
return Vector3<float>{std::fabs(isect.normal.x), std::fabs(isect.normal.y), std::fabs(isect.normal.z)};
} else {
return Vector3<float> { 0, 0, 0 };
return Vector3<float>{0, 0, 0};
}
};

constexpr std::size_t width = 800;
constexpr std::size_t height = 800;
constexpr std::size_t width = 2048;
constexpr std::size_t height = 2048;

printf("Rendering image (%ux%u)...\n",
(unsigned int) width,
(unsigned int) height);
printf("Rendering image (%ux%u)...\n", (unsigned int)width, (unsigned int)height);

stopwatch.reset();
SimpleScheduler<float> scheduler(width, height);

scheduler.schedule(trace_kernel);
double render_time = stopwatch.read();

printf("Rendered %lu primary rays in %.2f seconds (%.2f MRays/sec)\n", width * height, render_time,
width * height / render_time / 1000000.0);
scheduler.saveResults("render.ppm");
}
18 changes: 1 addition & 17 deletions examples/ObjFile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,6 @@ FastBVH::Vector3<float> findGoodCameraPosition(const FastBVH::BVH<float, uint32_
int main(int argc, char** argv) {

const char* filename = (argc > 1) ? argv[1] : nullptr;

if (!filename) {
std::fprintf(stderr, "No .obj file provided.\n");
return EXIT_FAILURE;
Expand All @@ -284,9 +283,7 @@ int main(int argc, char** argv) {
tinyobj::ObjReader reader;

std::printf("Reading '%s'\n", filename);

if (!reader.ParseFromFile(filename)) {

std::fprintf(stderr, "%s: %s",
filename,
reader.Error().c_str());
Expand All @@ -295,39 +292,30 @@ int main(int argc, char** argv) {
}

std::printf("Combining faces\n");

auto faces = combineFaces(reader.GetShapes());

std::vector<std::uint32_t> face_indices;

face_indices.resize(faces.size());

for (std::size_t i = 0; i < face_indices.size(); i++) {
face_indices[i] = std::uint32_t(i);
}

std::printf("Building BVH\n");

FastBVH::Stopwatch stopwatch;

FaceBoxConverter boxConverter(reader.GetAttrib(), faces);

FastBVH::BVH<float, std::uint32_t> bvh;

bvh.build(std::move(face_indices), boxConverter);

auto time = stopwatch.read();

std::printf("Completing BVH in %.02f ms\n", time * 1000.0);

stopwatch.reset();

FaceIntersector intersector(reader.GetAttrib(), faces);

FastBVH::Traverser<float, uint32_t, decltype(intersector)> traverser(bvh, intersector);

auto traceKernel = [traverser](const FastBVH::Ray<float>& ray) {
auto isect = traverser.traverse(ray, false);
auto isect = traverser.traverse(ray);
if (isect) {
return FastBVH::Vector3<float> { isect.uv[0], isect.uv[1], 1 };
} else {
Expand All @@ -336,16 +324,12 @@ int main(int argc, char** argv) {
};

FastBVH::SimpleScheduler<float> scheduler(800, 800);

scheduler.moveCamera(findGoodCameraPosition(bvh));

scheduler.schedule(traceKernel);

time = stopwatch.read();

std::printf("Model rendered in %.02f ms\n", time * 1000.0);

scheduler.saveResults("render2.ppm");

return EXIT_SUCCESS;
}
7 changes: 7 additions & 0 deletions examples/Stopwatch.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,27 +9,34 @@ namespace FastBVH {
class Stopwatch final {
//! A type definition for the clock used by this class.
using Clock = std::chrono::high_resolution_clock;

//! A type definition for a single point in time.
using TimePoint = Clock::time_point;

//! A type definition for a duration of time.
using Duration = std::chrono::duration<double>;

//! The starting time of the stop watch.
TimePoint start;

//! Gets the current time.
//! \return The current time.
static TimePoint now() noexcept {
return Clock::now();
}

public:
//! Constructs a new instance of the stopwatch.
Stopwatch() noexcept {
reset();
}

//! Resets the stop watch to a new starting time.
//! This should be called right before the profiling begins.
void reset() noexcept {
start = now();
}

//! Reads the current time value from the stopwatch.
//! \return The number of ellapsed seconds since either
//! the construction of the stop watch or the last call
Expand Down
15 changes: 7 additions & 8 deletions include/FastBVH/BBox.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,10 @@ struct BBox final {

//! The minimum point of the bounding box.
Vec3 min;

//! The maximum point of the bounding box.
Vec3 max;

//! The difference between the max and min
//! points of the bounding box.
Vec3 extent;
Expand Down Expand Up @@ -86,7 +88,7 @@ struct BBox final {
//! Calculates the surface area of the box.
//! \return The surface area of the bounding box.
constexpr Float surfaceArea() const noexcept {
return 2.0f * ((extent.x * extent.z) + (extent.x * extent.y) + (extent.y * extent.z));
return Float(2) * ((extent.x * extent.z) + (extent.x * extent.y) + (extent.y * extent.z));
}
};

Expand Down Expand Up @@ -136,17 +138,14 @@ bool BBox<Float>::intersect(const Ray<Float>& ray, Float *tnear, Float *tfar) co

template <typename Float>
uint32_t BBox<Float>::maxDimension() const noexcept {

// Assume X axis is longest first
uint32_t result = 0;

if (extent.y > extent.x) {
if(extent[1] > extent[result])
result = 1;
if (extent.z > extent.y) {
result = 2;
}
} else if (extent.z > extent.x) {

if(extent[2] > extent[result])
result = 2;
}

return result;
}
Expand Down
Loading

0 comments on commit e6fc721

Please sign in to comment.