K-D Tree Implementation, however intersections don't seem to be working properly

This commit is contained in:
Benjamin Kyd
2023-02-21 16:55:28 +00:00
parent de6153aadd
commit 5b931aebc4
4 changed files with 185 additions and 13 deletions

View File

@@ -0,0 +1,2 @@
#include <kdtree.hpp>

View File

@@ -0,0 +1,148 @@
#include <hart_graphics.hpp>
#include <tracing/ray.hpp>
#include <vector>
#include <algorithm>
#include <limits>
#include <utility>
#include <array>
#include <iostream>
using namespace inferno;
bool AABBIntersection(glm::vec3 min, glm::vec3 max, const Ray* r)
{
float tmin = 0.0, tmax = INFINITY;
glm::vec3 invDir = 1.0f / r->Direction;
for (int i = 0; i < 3; ++i) {
float t1 = (min[i] - r->Origin[i]) * invDir[i];
float t2 = (max[i] - r->Origin[i]) * invDir[i];
tmin = std::max(tmin, std::min(t1, t2));
tmax = std::min(tmax, std::max(t1, t2));
}
return tmin <= tmax;
}
struct KDNode {
uint32_t TriIdx;
glm::vec3 MinBounds;
glm::vec3 MaxBounds;
KDNode* LeftChild;
KDNode* RightChild;
KDNode(uint32_t triIdx, glm::vec3 minBounds, glm::vec3 maxBounds)
: TriIdx(triIdx), MinBounds(minBounds), MaxBounds(maxBounds), LeftChild(nullptr), RightChild(nullptr) {}
~KDNode() {
delete LeftChild;
delete RightChild;
}
void setLeftChild(KDNode* child) {
LeftChild = child;
updateBounds();
}
void setRightChild(KDNode* child) {
RightChild = child;
updateBounds();
}
void updateBounds() {
if (LeftChild && RightChild) {
MinBounds = glm::min(LeftChild->MinBounds, RightChild->MinBounds);
MaxBounds = glm::max(LeftChild->MaxBounds, RightChild->MaxBounds);
}
}
};
class KDTree {
public:
KDTree(float* vertices, uint32_t* indices, std::vector<uint32_t>& indicesToProcess, uint32_t startIdx, uint32_t endIdx, uint32_t depthLimit)
: mVertices(vertices), mIndices(indices), mDepthLimit(depthLimit), mRoot(nullptr)
{
if (indicesToProcess.size() == 0) {
return;
}
mRoot = buildNode(indicesToProcess, startIdx, endIdx, 0);
}
~KDTree() {
delete mRoot;
}
void intersect(const Ray* ray, std::vector<uint32_t>& outIndices) {
intersect(mRoot, ray, outIndices);
}
private:
KDNode* buildNode(std::vector<uint32_t>& indicesToProcess, uint32_t startIdx, uint32_t endIdx, uint32_t depth) {
if (startIdx >= endIdx || depth >= mDepthLimit) {
return nullptr;
}
if (endIdx - startIdx == 1) {
return new KDNode(indicesToProcess[startIdx], getVertexBounds(mIndices[indicesToProcess[startIdx] * 3]), getVertexBounds(mIndices[indicesToProcess[startIdx] * 3]));
}
glm::vec3 minBounds(INFINITY), maxBounds(-INFINITY);
for (uint32_t i = startIdx; i < endIdx; ++i) {
const glm::vec3& v0 = getVertexBounds(mIndices[indicesToProcess[i] * 3]);
const glm::vec3& v1 = getVertexBounds(mIndices[indicesToProcess[i] * 3 + 1]);
const glm::vec3& v2 = getVertexBounds(mIndices[indicesToProcess[i] * 3 + 2]);
minBounds = glm::min(minBounds, glm::min(v0, glm::min(v1, v2)));
maxBounds = glm::max(maxBounds, glm::max(v0, glm::max(v1, v2)));
}
uint32_t axis = depth % 3;
uint32_t median = partition(indicesToProcess, startIdx, endIdx, axis);
KDNode* node = new KDNode(0, minBounds, maxBounds);
std::vector<uint32_t> leftIndices(indicesToProcess.begin() + startIdx, indicesToProcess.begin() + median);
std::vector<uint32_t> rightIndices(indicesToProcess.begin() + median, indicesToProcess.begin() + endIdx);
node->setLeftChild(buildNode(leftIndices, startIdx, median, depth + 1));
node->setRightChild(buildNode(rightIndices, 0, endIdx - median, depth + 1));
return node;
}
void intersect(const KDNode* node, const Ray* ray, std::vector<uint32_t>& outIndices) {
if (!node) {
return;
}
if (AABBIntersection(node->MinBounds, node->MaxBounds, ray)) {
if (node->LeftChild || node->RightChild) {
intersect(node->LeftChild, ray, outIndices);
intersect(node->RightChild, ray, outIndices);
}
else {
outIndices.push_back(node->TriIdx);
}
}
}
glm::vec3 getVertexBounds(uint32_t index) {
return { mVertices[index * 3], mVertices[index * 3 + 1], mVertices[index * 3 + 2] };
}
uint32_t partition(std::vector<uint32_t>& indicesToProcess, uint32_t startIdx, uint32_t endIdx, uint32_t axis) {
uint32_t medianIdx = (startIdx + endIdx) / 2;
glm::vec3 pivot = getVertexBounds(mIndices[indicesToProcess[medianIdx] * 3]);
std::nth_element(indicesToProcess.begin() + startIdx, indicesToProcess.begin() + medianIdx, indicesToProcess.begin() + endIdx,
[this, &pivot, axis](uint32_t a, uint32_t b) { return getVertexBounds(mIndices[a * 3])[axis] < getVertexBounds(mIndices[b * 3])[axis]; });
return medianIdx;
}
private:
float* mVertices;
uint32_t* mIndices;
uint32_t mDepthLimit;
KDNode* mRoot;
};

View File

@@ -4,9 +4,12 @@
#include <tracing/ray.hpp>
#include <tracing/hit.hpp>
#include "kdtree.hpp"
#include <iostream>
#include <thread>
#include <chrono>
#include <numeric>
using namespace inferno;
@@ -27,14 +30,25 @@ public:
void submitTris(void* vert,
void* norm,
int vc,
void* indicies,
void* indices,
int ic) override
{
std::lock_guard<std::mutex> lock(_mData);
mState = EModuleState::Build;
mVert = (float*)vert; mNorm = (float*)norm; mVc = vc; mIndicies = (uint32_t*)indicies; mIc = ic;
spdlog::info("[hartcpu] Recieved {} verticies ({}) and {} indicies ({})", vc / 3, vert, ic / 3, indicies);
mVert = (float*)vert; mNorm = (float*)norm; mVc = vc; mIndices = (uint32_t*)indices; mIc = ic;
spdlog::info("[hartcpu] Recieved {} verticies ({}) and {} indicies ({})", vc / 3, vert, ic / 3, indices);
std::vector<uint32_t> indicesToProcess(ic / 3);
for (uint32_t i = 0; i < ic / 3; ++i)
{
indicesToProcess[i] = i;
}
mKdTree = new KDTree(mVert, mIndices, indicesToProcess, 0, indicesToProcess.size() - 1, 10);
spdlog::info("[hartcpu] Accelerator ready..");
mState = EModuleState::Idle;
}
@@ -91,21 +105,25 @@ public:
float bestDist = INFINITY;
float dist;
for (int i = 0; i < mIc; i += 3)
// Traverse the K-D tree to identify the set of triangles that may intersect the ray.
std::vector<uint32_t> candidateIndices;
mKdTree->intersect(ray, candidateIndices);
for (uint32_t idx : candidateIndices)
{
uint32_t ind1 = mIndicies[i];
uint32_t ind2 = mIndicies[i + 1];
uint32_t ind3 = mIndicies[i + 2];
const glm::vec3 a = { mVert[ind1 * 3], mVert[ind1 * 3 + 1], mVert[ind1 * 3 + 2] };
const glm::vec3 b = { mVert[ind2 * 3], mVert[ind2 * 3 + 1], mVert[ind2 * 3 + 2] };
const glm::vec3 c = { mVert[ind3 * 3], mVert[ind3 * 3 + 1], mVert[ind3 * 3 + 2] };
uint32_t ind1 = mIndices[idx * 3];
uint32_t ind2 = mIndices[idx * 3 + 1];
uint32_t ind3 = mIndices[idx * 3 + 2];
const glm::vec3 a = { mVert[ind1], mVert[ind1 + 1], mVert[ind1 + 2] };
const glm::vec3 b = { mVert[ind2], mVert[ind2 + 1], mVert[ind2 + 2] };
const glm::vec3 c = { mVert[ind3], mVert[ind3 + 1], mVert[ind3 + 2] };
// Perform intersection test...
if (!glm::intersectRayTriangle(ray->Origin, ray->Direction, a, b, c, coords, dist)) { continue; }
if (dist > bestDist || dist < 0.0f) { continue; }
bestIdx = i;
bestIdx = idx;
bestDist = dist;
bestTexcoord = coords;
}
@@ -139,10 +157,12 @@ private:
private:
// Scene Data
KDTree* mKdTree;
float* mVert;
float* mNorm;
int mVc;
uint32_t* mIndicies;
uint32_t* mIndices;
int mIc;
};

View File

@@ -14,3 +14,5 @@ extern "C"
// glm
#include <glm/glm.hpp>
#include <glm/gtx/intersect.hpp>
#include <glm/gtx/component_wise.hpp>