initial implementation, WIP
This commit is contained in:
parent
728b324c5b
commit
3f19627975
2 changed files with 213 additions and 42 deletions
|
@ -4,15 +4,38 @@
|
|||
#include <iostream>
|
||||
|
||||
Texture KDTreeRenderer::renderImage(Scene const &scene, Camera const &camera, int width, int height) {
|
||||
Texture image(width, height);
|
||||
std::cout << "KD Tree renderer will only output KD Tree visualization" << std::endl;
|
||||
return image;
|
||||
Texture image(width, height);
|
||||
std::cout << "KD Tree renderer will only output KD Tree visualization" << std::endl;
|
||||
return image;
|
||||
}
|
||||
|
||||
Texture KDTreeRenderer::renderKDTree(FastScene const &scene, Camera const &camera, int width, int height) {
|
||||
Texture image(width, height);
|
||||
const Color RED = {1, 0, 0};
|
||||
const Color GREEN = {0, 1, 0};
|
||||
Texture image(width, height);
|
||||
|
||||
// IMPLEMENT ME
|
||||
// IMPLEMENT ME
|
||||
std::vector<std::vector<int>> intersections;
|
||||
intersections.reserve(height);
|
||||
|
||||
return image;
|
||||
int max = 0;
|
||||
float const aspectRatio = static_cast<float>(height) / static_cast<float>(width);
|
||||
for (int x = 0; x < image.width(); ++x) {
|
||||
std::vector<int> ints;
|
||||
ints.reserve(width);
|
||||
for (int y = 0; y < image.height(); ++y) {
|
||||
Ray ray = camera.createRay((static_cast<float>(x) / image.width() * 2.0f - 1),
|
||||
-(static_cast<float>(y) / image.height() * 2 - 1) * aspectRatio);
|
||||
ints.push_back(scene.countNodeIntersections(ray));
|
||||
max = std::max(ints[x], max);
|
||||
}
|
||||
intersections.push_back(std::move(ints));
|
||||
}
|
||||
std::cout << "done\n";
|
||||
for (int x = 0; x < image.width(); ++x) {
|
||||
for (int y = 0; y < image.height(); ++y) {
|
||||
image.setPixelAt(x, y, clamped((max - intersections[y][x]) * GREEN + intersections[y][x] * RED));
|
||||
}
|
||||
}
|
||||
return image;
|
||||
}
|
|
@ -3,71 +3,219 @@
|
|||
#include "shader/shader.h"
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <numeric>
|
||||
|
||||
int Node::countNodeIntersections(const Ray &ray, float t0, float t1) const {
|
||||
// IMPLEMENT ME
|
||||
return 0;
|
||||
// IMPLEMENT ME
|
||||
if (isLeaf()) {
|
||||
return 0;
|
||||
}
|
||||
float t_split;
|
||||
if (ray.direction[this->dimension] == 0) {
|
||||
t_split = INFINITY;
|
||||
} else {
|
||||
t_split = (this->split - ray.origin[this->dimension]) / ray.direction[this->dimension];
|
||||
}
|
||||
int nearChild = ray.origin[this->dimension] > this->split ? 1 : 0;
|
||||
int farChild = nearChild == 0 ? 1 : 0;
|
||||
|
||||
if (t_split < 0 || t_split > t1) {
|
||||
return 0 + this->child[nearChild]->countNodeIntersections(ray, t0, t1);
|
||||
} else if (t_split < t0) {
|
||||
return 0 + this->child[farChild]->countNodeIntersections(ray, t0, t1);
|
||||
} else {
|
||||
return 1 + this->child[nearChild]->countNodeIntersections(ray, t0, t_split) +
|
||||
this->child[farChild]->countNodeIntersections(ray, t_split, t1);
|
||||
}
|
||||
}
|
||||
|
||||
bool Node::findIntersection(Ray &ray, float t0, float t1) const {
|
||||
// IMPLEMENT ME
|
||||
// If this is a leaf node, we intersect with all the primitives...
|
||||
// ... otherwise we continue through the branches
|
||||
// Determine the order in which we intersect the child nodes
|
||||
// Traverse the necessary children
|
||||
return false;
|
||||
|
||||
// IMPLEMENT ME
|
||||
// If this is a leaf node, we intersect with all the primitives...
|
||||
if (isLeaf()) {
|
||||
bool found = false;
|
||||
for (const auto &prim: this->primitives) {
|
||||
found |= prim->intersect(ray);
|
||||
}
|
||||
return found;
|
||||
}
|
||||
// ... otherwise we continue through the branches
|
||||
// Determine the order in which we intersect the child nodes
|
||||
// Traverse the necessary children
|
||||
float t_split;
|
||||
if (ray.direction[this->dimension] == 0) {
|
||||
t_split = INFINITY;
|
||||
} else {
|
||||
t_split = (this->split - ray.origin[this->dimension]) / ray.direction[this->dimension];
|
||||
}
|
||||
int nearChild = ray.origin[this->dimension] > this->split ? 1 : 0;
|
||||
int farChild = nearChild == 0 ? 1 : 0;
|
||||
if (t_split < 0 || t_split > t1) {
|
||||
return this->child[nearChild]->findIntersection(ray, t0, t1);
|
||||
} else if (t_split < t0) {
|
||||
return this->child[farChild]->findIntersection(ray, t0, t1);
|
||||
} else {
|
||||
this->child[nearChild]->findIntersection(ray, t0, t_split);
|
||||
if (ray.length < t_split) {
|
||||
return true;
|
||||
}
|
||||
return this->child[farChild]->findIntersection(ray, t_split, t1);
|
||||
}
|
||||
}
|
||||
|
||||
bool Node::findOcclusion(Ray &ray, float t0, float t1) const {
|
||||
// IMPLEMENT ME
|
||||
return false;
|
||||
if (isLeaf()) {
|
||||
for (const auto &prim: this->primitives) {
|
||||
if (prim->intersect(ray)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
float t_split = (this->split - ray.origin[this->dimension]) / ray.direction[this->dimension];
|
||||
int nearChild = ray.origin[this->dimension] > this->split ? 1 : 0;
|
||||
int farChild = nearChild == 0 ? 1 : 0;
|
||||
if (t_split < 0 || t_split > t1) {
|
||||
return this->child[nearChild]->findIntersection(ray, t0, t1);
|
||||
} else if (t_split < t0) {
|
||||
return this->child[farChild]->findIntersection(ray, t0, t1);
|
||||
} else {
|
||||
this->child[nearChild]->findIntersection(ray, t0, t_split);
|
||||
if (ray.length < t_split) {
|
||||
return true;
|
||||
}
|
||||
return this->child[farChild]->findIntersection(ray, t_split, t1);
|
||||
}
|
||||
}
|
||||
|
||||
int FastScene::countNodeIntersections(const Ray &ray) const {
|
||||
// IMPLEMENT ME
|
||||
return false;
|
||||
return root->countNodeIntersections(ray, 0, INFINITY);
|
||||
}
|
||||
|
||||
bool FastScene::findIntersection(Ray &ray) const {
|
||||
// IMPLEMENT ME
|
||||
return false;
|
||||
return root->findIntersection(ray, 0, ray.length);
|
||||
}
|
||||
|
||||
bool FastScene::findOcclusion(Ray &ray) const {
|
||||
// IMPLEMENT ME
|
||||
return false;
|
||||
return root->findOcclusion(ray, 0, ray.length);
|
||||
}
|
||||
|
||||
void FastScene::buildTree(int maximumDepth, int minimumNumberOfPrimitives) {
|
||||
// IMPLEMENT ME
|
||||
// Set the new depth and number of primitives
|
||||
// IMPLEMENT ME
|
||||
// Set the new depth and number of primitives
|
||||
this->maximumDepth = maximumDepth;
|
||||
this->minimumNumberOfPrimitives = minimumNumberOfPrimitives;
|
||||
|
||||
// Determine the bounding box of the kD-Tree
|
||||
// Determine the bounding box of the kD-Tree
|
||||
|
||||
// Recursively build the kD-Tree
|
||||
Vector3d maximumBounds = {
|
||||
std::max_element(this->primitives().begin(),
|
||||
this->primitives().end(),
|
||||
[](const auto &prim1, const auto &prim2) {
|
||||
return prim1->maximumBounds(0) < prim2->maximumBounds(0);
|
||||
})->get()->maximumBounds(0),
|
||||
std::max_element(this->primitives().begin(),
|
||||
this->primitives().end(),
|
||||
[](const auto &prim1, const auto &prim2) {
|
||||
return prim1->maximumBounds(1) < prim2->maximumBounds(1);
|
||||
})->get()->maximumBounds(1),
|
||||
std::max_element(this->primitives().begin(),
|
||||
this->primitives().end(),
|
||||
[](const auto &prim1, const auto &prim2) {
|
||||
return prim1->maximumBounds(2) < prim2->maximumBounds(2);
|
||||
})->get()->maximumBounds(2)
|
||||
};
|
||||
Vector3d minimumBounds = {
|
||||
std::min_element(this->primitives().begin(),
|
||||
this->primitives().end(),
|
||||
[](const auto &prim1, const auto &prim2) {
|
||||
return prim1->minimumBounds(0) < prim2->minimumBounds(0);
|
||||
})->get()->minimumBounds(0),
|
||||
std::min_element(this->primitives().begin(),
|
||||
this->primitives().end(),
|
||||
[](const auto &prim1, const auto &prim2) {
|
||||
return prim1->minimumBounds(1) < prim2->minimumBounds(1);
|
||||
})->get()->minimumBounds(1),
|
||||
std::min_element(this->primitives().begin(),
|
||||
this->primitives().end(),
|
||||
[](const auto &prim1, const auto &prim2) {
|
||||
return prim1->minimumBounds(2) < prim2->minimumBounds(2);
|
||||
})->get()->minimumBounds(2)
|
||||
};
|
||||
this->root = build(minimumBounds, maximumBounds, this->primitives(), 0);
|
||||
// Recursively build the kD-Tree
|
||||
}
|
||||
|
||||
std::unique_ptr<Node> FastScene::build(Vector3d const &minimumBounds, Vector3d const &maximumBounds, const std::vector<std::shared_ptr<Primitive>> &primitives, int depth) {
|
||||
// IMPLEMENT ME
|
||||
// Determine the diameter of the bounding box
|
||||
std::unique_ptr<Node> FastScene::build(Vector3d const &minimumBounds, Vector3d const &maximumBounds,
|
||||
const std::vector<std::shared_ptr<Primitive>> &primitives, int depth) {
|
||||
|
||||
// Test whether we have reached a leaf node...
|
||||
std::unique_ptr<Node> node = std::make_unique<Node>();
|
||||
// IMPLEMENT ME
|
||||
// Determine the diameter of the bounding box
|
||||
float diameter_x = maximumBounds.x - minimumBounds.x;
|
||||
float diameter_y = maximumBounds.y - minimumBounds.y;
|
||||
float diameter_z = maximumBounds.z - minimumBounds.z;
|
||||
|
||||
// ... otherwise create a new inner node by splitting through the widest
|
||||
// dimension
|
||||
// Test whether we have reached a leaf node...
|
||||
if (++depth == maximumDepth) {
|
||||
node->primitives = primitives;
|
||||
return node;
|
||||
}
|
||||
|
||||
// Determine the split position
|
||||
// Note: Use the median of the minimum bounds of the primitives
|
||||
// ... otherwise create a new inner node by splitting through the widest
|
||||
// dimension
|
||||
if (diameter_x >= diameter_y) {
|
||||
if (diameter_x >= diameter_z) {
|
||||
node->dimension = 0;
|
||||
} else {
|
||||
node->dimension = 2;
|
||||
}
|
||||
} else {
|
||||
if (diameter_y > diameter_z) {
|
||||
node->dimension = 1;
|
||||
} else {
|
||||
node->dimension = 2;
|
||||
}
|
||||
}
|
||||
|
||||
// Divide primitives into the left and right lists
|
||||
// Remember: A primitive can be in both lists!
|
||||
// Also remember: You split exactly at the minimum of a primitive,
|
||||
// make sure *that* primitive does *not* appear in both lists!
|
||||
// Determine the split position
|
||||
// Note: Use the median of the minimum bounds of the primitives
|
||||
node->split = std::accumulate(primitives.begin(), primitives.end(), 0.0f,
|
||||
[&node](float &a, const auto &prim) {
|
||||
return a + prim->minimumBounds(node->dimension);
|
||||
}) /
|
||||
static_cast<float>(primitives.size());
|
||||
|
||||
// Print out the number of primitives in the left and right child node
|
||||
// Divide primitives into the left and right lists
|
||||
// Remember: A primitive can be in both lists!
|
||||
// Also remember: You split exactly at the minimum of a primitive,
|
||||
// make sure *that* primitive does *not* appear in both lists!
|
||||
|
||||
// Set the left and right split vectors
|
||||
std::vector<std::shared_ptr<Primitive>> left{};
|
||||
std::vector<std::shared_ptr<Primitive>> right{};
|
||||
for (auto &prim: primitives) {
|
||||
if (prim->minimumBounds(node->dimension) > node->split) {
|
||||
right.push_back(prim);
|
||||
} else {
|
||||
left.push_back(prim);
|
||||
if (prim->maximumBounds(node->dimension) > node->split) {
|
||||
right.push_back(prim);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Recursively build the tree
|
||||
return nullptr;
|
||||
// Print out the number of primitives in the left and right child node
|
||||
std::cout << "Nodes: " << left.size() << " / " << right.size() << "\n";
|
||||
// Set the left and right split vectors
|
||||
Vector3d newMinBounds = {node->dimension == 0 ? node->split : minimumBounds[0],
|
||||
node->dimension == 1 ? node->split : minimumBounds[1],
|
||||
node->dimension == 2 ? node->split : minimumBounds[2]};
|
||||
Vector3d newMaxBounds = {node->dimension == 0 ? node->split : maximumBounds[0],
|
||||
node->dimension == 1 ? node->split : maximumBounds[1],
|
||||
node->dimension == 2 ? node->split : maximumBounds[2]};
|
||||
node->child[0] = build(minimumBounds, newMaxBounds, left, depth);
|
||||
node->child[1] = build(newMinBounds, maximumBounds, right, depth);
|
||||
// Recursively build the tree
|
||||
return node;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue