Commit 4257c19c authored by Johannes Braun's avatar Johannes Braun
Browse files

Played around a wee bit.

parent 2fa06238
#include "some_tree.h"
\ No newline at end of file
#ifndef INCLUDE_SOME_TREE_H
#define INCLUDE_SOME_TREE_H
#include <functional>
#include <memory>
#include <vector>
#include <core/numeric/geometry.h>
template<typename T>
struct some_locality_tree
{
using converter = std::function<math::Bounds(const T& src)>;
enum class node_type : uint32_t
{
eRoot = 0,
eLeaf,
eInner
};
struct node
{
int32_t parent = -1;
node_type type;
int32_t left;
int32_t right;
int32_t data_index;
int32_t bounds_index;
uint32_t cost;
};
some_locality_tree(converter bounds_from_data)
: m_converter(bounds_from_data), m_depth(0)
{
}
void put(const T& data)
{
auto index = m_data_storage.size();
m_data_storage.push_back(data);
if (m_node_storage.empty())
{
node n;
n.type = node_type::eRoot;
n.data_index = 0;
n.cost = 0;
m_node_storage.emplace_back();
n.bounds_index = m_bounds_storage.size();
m_bounds_storage.push_back(m_converter(data));
m_depth = 1;
return;
}
// when adding a node... check if inside the whole bb
const auto bounds = m_converter(data);
m_bounds_storage.push_back(bounds);
auto current_id = 0;
unsigned depth = 0;
while (m_node_storage[current_id].type != node_type::eLeaf && m_node_storage.size() > 1)
{
// decide which child is being overlapped the most
auto cv_l = m_converter(get_bounds_from_dyn(m_node_storage[m_node_storage[current_id].left]));
auto cv_r = m_converter(get_bounds_from_dyn(m_node_storage[m_node_storage[current_id].right]));
auto cost_l = m_node_storage[m_node_storage[current_id].left].cost;
auto cost_r = m_node_storage[m_node_storage[current_id].right].cost;
auto l = cv_l.overlap(bounds);
auto r = cv_r.overlap(bounds);
bool pred = (l != 0 && r != 0) ? (l / float(cost_l) > r / float(cost_r)) : ((l == 0 && r != 0) ? false : ((l != 0 && r == 0) ? true : (cost_l < cost_r)));
if (pred)
{
++(m_node_storage[m_node_storage[current_id].left].cost);
current_id = m_node_storage[current_id].left;
}
else
{
++(m_node_storage[m_node_storage[current_id].right].cost);
current_id = m_node_storage[current_id].right;
}
++depth;
}
if (depth >= m_depth)
m_depth = depth + 1;
//copy old node!
node old_node = m_node_storage[current_id];
auto old_parent = old_node.parent;
old_node.parent = current_id;
old_node.type = node_type::eLeaf;
node new_node;
new_node.type = node_type::eLeaf;
new_node.data_index = index;
new_node.parent = current_id;
new_node.bounds_index = m_bounds_storage.size() - 1;
// now being at a leaf node.
// create a parent, attach the leaf to it.
auto old_bounds = m_converter(get_from(old_node));
int sizing = 0;
auto center_old = old_bounds.center();
auto center_new = bounds.center();
for (auto i = 0; i < 3; ++i)
{
if (center_old[i] < center_new[i])
++sizing;
}
auto node_id_left = m_node_storage.size() + (sizing >= 2 ? 0 : 1);
auto node_id_right = m_node_storage.size() + (sizing >= 2 ? 1 : 0);
m_node_storage.push_back(sizing >= 2 ? old_node : new_node);
m_node_storage.push_back(sizing >= 2 ? new_node : old_node);
node new_parent;
new_parent.parent = old_parent;
new_parent.left = node_id_left;
new_parent.right = node_id_right;
new_parent.type = old_parent == -1 ? node_type::eRoot : node_type::eInner;
old_bounds.expand(bounds);
math::Bounds new_bounds = old_bounds;
new_parent.bounds_index = m_bounds_storage.size();
m_bounds_storage.push_back(new_bounds);
if (new_parent.type != node_type::eRoot)
{
auto c_id = new_parent.parent;
while(true) {
auto&& data = get_bounds_from_dyn(m_node_storage[c_id]);
data.expand(old_bounds);
if (m_node_storage[c_id].type == node_type::eRoot)
break;
c_id = m_node_storage[c_id].parent;
}
}
m_node_storage[current_id] = new_parent;
}
const T& get_from(const node& n)
{
return m_data_storage[n.data_index];
}
unsigned depth() const
{
return m_depth;
}
private:
math::Bounds& get_bounds_from_dyn(const node& n)
{
return m_bounds_storage[n.bounds_index];
}
unsigned m_depth;
converter m_converter;
std::vector<node> m_node_storage;
std::vector<math::Bounds> m_bounds_storage;
std::vector<T> m_data_storage;
};
#endif // !INCLUDE_SOME_TREE_H
#include <any>
#include <vector>
#include <algorithm>
std::vector<std::any> anystuff;
constexpr int bla()
{
return 4;
}
#include <array>
#include <random>
#include <util/log.h>
#include <core/time.h>
#include "dat/some_tree.h"
int main()
{
anystuff.push_back(std::make_any<int>(10));
some_locality_tree<math::Bounds> loctree([](const auto& x) { return x; });
const static auto rnd_bounds = []() {
std::random_device dev;
std::mt19937 gen(dev());
std::uniform_real_distribution<float> dst(-100.f, 100.f);
auto v1 = glm::vec4(dst(gen), dst(gen), dst(gen), 1);
auto v2 = glm::vec4(dst(gen), dst(gen), dst(gen), 1);
return math::Bounds{ glm::min(v1, v2), glm::max(v1, v2) };
};
constexpr auto x = 4000;
std::array<math::Bounds, x> bounds;
std::vector<math::Bounds> test;
for (auto i = 0; i < x; ++i)
{
bounds[i] = rnd_bounds();
}
glare::core::ClockNS clocky;
clocky.restart();
//test.reserve(10000);
for (int i = 0; i < x; ++i)
{
test.insert(test.begin(), bounds[i]);
}
Log_Info << "Took " << clocky.time();
for(auto&& b : bounds)
loctree.put(b);
Log_Info << sizeof(int*);
bool b = true;
system("pause");
}
\ No newline at end of file
......@@ -22,10 +22,9 @@ namespace glare::core
class Framebuffer
{
public:
static constexpr bool is_multisampled = texture_color_type::is_multisampled;
// The type of texture used for color attachments
using texture_color_type = TTextureBase<gl::TextureFormat::eRGBA, gl::TextureInternalFormat::eRGBA32Float, gl::Type::eFloat>;
static constexpr bool is_multisampled = texture_color_type::is_multisampled;
// The type of texture used for the depth attachment
using texture_depth_type = TTextureBase<gl::TextureFormat::eDepthComponent, gl::TextureInternalFormat::eDepthComponent32Float, gl::Type::eFloat>;
......
......@@ -171,12 +171,24 @@ namespace math
float Bounds::overlap(const math::Bounds& other) const
{
const auto calc_overlap = [this, &other](int axis) {
return glm::max(0.f, glm::min(max[axis], other.max[axis]) - glm::max(min[axis], other.min[axis]));
};
return calc_overlap(0) * calc_overlap(1) * calc_overlap(2);
}
bool Bounds::contains(glm::vec4 point) const
{
return point.x >= min.x && point.y >= min.y && point.z >= min.z && point.x <= max.x && point.y <= max.y && point.z <= max.z;
}
bool Bounds::contains(const math::Bounds& other) const
{
return contains(other.min) && contains(other.max);
}
unsigned Bounds::largestAxis() const
{
const float max = glm::compMax(size());
......
......@@ -99,6 +99,8 @@ namespace math
Bounds() = default;
bool contains(glm::vec4 point) const;
bool contains(const math::Bounds& other) const;
float overlap(const math::Bounds& other) const;
unsigned largestAxis() const;
bool splittable() const;
glm::vec4 size() const;
......
......@@ -39,4 +39,176 @@ namespace glare::raytrace
return false;
}
bool intersect::intersects(const Ray &ray, const math::Bounds &bounds, float max_t)
{
const glm::vec3 dirfrac = 1.0f / glm::vec3(ray.direction.xyz);
//intersections with box planes parallel to x, y, z axis
const float t1 = (bounds.min.x - ray.origin.x)*dirfrac.x;
const float t3 = (bounds.min.y - ray.origin.y)*dirfrac.y;
const float t5 = (bounds.min.z - ray.origin.z)*dirfrac.z;
const float t2 = (bounds.max.x - ray.origin.x)*dirfrac.x;
const float t4 = (bounds.max.y - ray.origin.y)*dirfrac.y;
const float t6 = (bounds.max.z - ray.origin.z)*dirfrac.z;
const float tmin = glm::max(glm::max(glm::min(t1, t2), glm::min(t3, t4)), glm::min(t5, t6));
const float tmax = glm::min(glm::min(glm::max(t1, t2), glm::max(t3, t4)), glm::max(t5, t6));
return tmax >= 0 && tmin <= tmax && tmin <= max_t;
}
bool intersect::intersects(const Ray &ray, const math::Triangle &triangle, float &t, float &u, float &v)
{
const float epsilon = std::numeric_limits<float>::epsilon();
const glm::vec3 v1 = triangle.a.xyz;
const glm::vec3 v2 = triangle.b.xyz;
const glm::vec3 v3 = triangle.c.xyz;
//Find vectors for two edges sharing V1
glm::vec3 e1 = v2 - v1;
glm::vec3 e2 = v3 - v1;
//Begin calculating determinant - also used to calculate u parameter
glm::vec3 P = glm::cross(glm::vec3(ray.direction.xyz), e2);
//if determinant is near zero, ray lies in plane of triangle
float det = glm::dot(e1, P);
//NOT CULLING
if (det > -epsilon && det < epsilon)
return false;
float inv_det = 1.f / det;
//calculate distance from V1 to ray origin
glm::vec3 T = ray.origin.xyz - v1;
//Calculate u parameter and test bound
u = glm::dot(T, P) * inv_det;
//The intersection lies outside of the triangle
if (u < 0.f || u > 1.f) return false;
//Prepare to test v parameter
glm::vec3 Q = cross(T, e1);
//Calculate V parameter and test bound
v = glm::dot(glm::vec3(ray.direction.xyz), Q) * inv_det;
//The intersection lies outside of the triangle
if (v < 0.f || u + v > 1.f) return false;
t = glm::dot(e2, Q) * inv_det;
if (t > epsilon) { //ray intersection
return true;
}
// No hit, no win
return false;
}
bool intersect::intersects(const math::Bounds &bounds, const math::Triangle &c_triangle)
{
return intersects(c_triangle, bounds);
}
bool intersect::intersects(const math::Triangle &c_triangle, const math::Bounds &bounds)
{
// SAT: Separating Axis Theorem
// Two convex polyhedra A and B are disjoint, if they can be separated along either an axis parallel to a normal of a face of either A or B,
// or along an Axis formed from the cross product of an edge from A widh an edge from B.
// ------------------------------------------------------------------------------------------------------------------------------------------
// 1) Project triangle points on x, y and z min and max plane normals. Quit if disjoint.
// 2) Project AABB points on triangle normal. Quit if disjoint.
// ------------------------------------------------------------------------------------------------------------------------------------------
// Projection procedure: Calculate vector cp from plane center (eg x max = bounds.max-vec3(0, half[y], half[z])) to triangle point.
// Then check dot(cp, plane_normal) < 0.
math::Triangle triangle = c_triangle;
const glm::vec3 bounds_halfsize = bounds.size().xyz * 0.5f;
sortTriangleLongestAxis(triangle);
// --------------------------------------- NEEDED ----------------------------------------------------
float sidedness_max;
float sidedness_min;
int i;
// ---------------------------------------------------------------------------------------------------
// --------------------------------------- X AXIS ----------------------------------------------------
// Check separating min and max planes on x-plane
glm::vec3 plane_max = bounds.max.xyz - glm::vec3(0, bounds_halfsize[1], bounds_halfsize[2]);
glm::vec3 plane_min = bounds.min.xyz + glm::vec3(0, bounds_halfsize[1], bounds_halfsize[2]);
bool separate_min = true;
bool separate_max = true;
for (i = 0; i < 3; i++) {
sidedness_max = glm::dot(triangle[i].xyz - plane_max, glm::vec3(1, 0, 0));
sidedness_min = glm::dot(triangle[i].xyz - plane_min, glm::vec3(-1, 0, 0));
//separate is true, if all sidedness values are >1.
separate_max &= sidedness_max > 0;
separate_min &= sidedness_min > 0;
}
if (separate_min || separate_max)
return false;
// ---------------------------------------------------------------------------------------------------
// --------------------------------------- Y AXIS ----------------------------------------------------
// Check separating min and max planes on y-plane
plane_max = bounds.max.xyz - glm::vec3(bounds_halfsize[0], 0, bounds_halfsize[2]);
plane_min = bounds.min.xyz + glm::vec3(bounds_halfsize[0], 0, bounds_halfsize[2]);
separate_min = true;
separate_max = true;
for (i = 0; i < 3; i++) {
sidedness_max = glm::dot(triangle[i].xyz - plane_max, glm::vec3(0, 1, 0));
sidedness_min = glm::dot(triangle[i].xyz - plane_min, glm::vec3(0, -1, 0));
//separate is true, if all sidedness values are >1.
separate_max &= sidedness_max > 0;
separate_min &= sidedness_min > 0;
}
if (separate_min || separate_max)
return false;
// ---------------------------------------------------------------------------------------------------
// --------------------------------------- Z AXIS ----------------------------------------------------
// Check separating min and max planes on z-plane
plane_max = bounds.max.xyz - glm::vec3(bounds_halfsize[0], bounds_halfsize[1], 0);
plane_min = bounds.min.xyz + glm::vec3(bounds_halfsize[0], bounds_halfsize[1], 0);
separate_min = true;
separate_max = true;
for (i = 0; i < 3; i++) {
sidedness_max = glm::dot(triangle[i].xyz - plane_max, glm::vec3(0, 0, 1));
sidedness_min = glm::dot(triangle[i].xyz - plane_min, glm::vec3(0, 0, -1));
//separate is true, if all sidedness values are >1.
separate_max &= sidedness_max > 0;
separate_min &= sidedness_min > 0;
}
if (separate_min || separate_max)
return false;
// ---------------------------------------------------------------------------------------------------
// -------------------------------------- TRIANGLE ---------------------------------------------------
// Check separating from triangle
const glm::vec3 normal = triangle.normal().xyz;
separate_min = true;
separate_max = true;
for (int sign : {-1, 1}) {
for (i = -1; i < 3; i++)
{
glm::vec3 corner = bounds[(sign + 1) / 2].xyz;
if (i >= 0)
{
corner[i] += 2 * sign * bounds_halfsize[i];
}
sidedness_min = glm::dot(corner - triangle.a.xyz, normal);
separate_min &= sidedness_min < 0;
separate_max &= sidedness_min > 0;
}
}
if (separate_min || separate_max)
return false;
// ---------------------------------------------------------------------------------------------------
return true;
}
}
\ No newline at end of file
......@@ -9,28 +9,14 @@
namespace glare::raytrace
{
/**
* Class containing all intersection tests between objects as template functions.
*/
class intersect
{
public:
/**
* @brief Template function for intersecting an object from type One to one from type Other.
* @tparam One One intersection candidate type.
* @tparam Other The other intersection candidate type.
*/
template<typename One, typename Other>
static bool intersects(const One &one, const Other &other) {
return false;
}
template<>
static bool intersect::intersects<math::Bounds, math::Triangle>(const math::Bounds &bounds, const math::Triangle &c_triangle);
template<>
static bool intersect::intersects<math::Triangle, math::Bounds>(const math::Triangle &c_triangle, const math::Bounds &bounds);
static bool intersects(const math::Bounds &bounds, const math::Triangle &c_triangle);
static bool intersects(const math::Triangle &c_triangle, const math::Bounds &bounds);
static bool intersects(const Ray &ray, const math::Bounds &bounds, float max_t);
static bool intersects(const Ray &ray, const math::Triangle &triangle, float &t, float &u, float &v);
......@@ -49,181 +35,6 @@ namespace glare::raytrace
if (b[axis] < c[axis]) std::swap(b, c);
if (a[axis] < b[axis]) std::swap(a, b);
}
inline bool intersect::intersects(const Ray &ray, const math::Bounds &bounds, float max_t)
{
const glm::vec3 dirfrac = 1.0f / glm::vec3(ray.direction.xyz);
//intersections with box planes parallel to x, y, z axis
const float t1 = (bounds.min.x - ray.origin.x)*dirfrac.x;
const float t3 = (bounds.min.y - ray.origin.y)*dirfrac.y;
const float t5 = (bounds.min.z - ray.origin.z)*dirfrac.z;
const float t2 = (bounds.max.x - ray.origin.x)*dirfrac.x;
const float t4 = (bounds.max.y - ray.origin.y)*dirfrac.y;
const float t6 = (bounds.max.z - ray.origin.z)*dirfrac.z;
const float tmin = glm::max(glm::max(glm::min(t1, t2), glm::min(t3, t4)), glm::min(t5, t6));
const float tmax = glm::min(glm::min(glm::max(t1, t2), glm::max(t3, t4)), glm::max(t5, t6));
return tmax >= 0 && tmin <= tmax && tmin <= max_t;
}
inline bool intersect::intersects(const Ray &ray, const math::Triangle &triangle, float &t, float &u, float &v)
{
const float epsilon = std::numeric_limits<float>::epsilon();
const glm::vec3 v1 = triangle.a.xyz;
const glm::vec3 v2 = triangle.b.xyz;
const glm::vec3 v3 = triangle.c.xyz;
//Find vectors for two edges sharing V1
glm::vec3 e1 = v2 - v1;
glm::vec3 e2 = v3 - v1;
//Begin calculating determinant - also used to calculate u parameter
glm::vec3 P = glm::cross(glm::vec3(ray.direction.xyz), e2);
//if determinant is near zero, ray lies in plane of triangle
float det = glm::dot(e1, P);
//NOT CULLING
if (det > -epsilon && det < epsilon)
return false;
float inv_det = 1.f / det;
//calculate distance from V1 to ray origin
glm::vec3 T = ray.origin.xyz - v1;
//Calculate u parameter and test bound
u = glm::dot(T, P) * inv_det;
//The intersection lies outside of the triangle
if (u < 0.f || u > 1.f) return false;
//Prepare to test v parameter
glm::vec3 Q = cross(T, e1);
//Calculate V parameter and test bound
v = glm::dot(glm::vec3(ray.direction.xyz), Q) * inv_det;
//The intersection lies outside of the triangle
if (v < 0.f || u + v > 1.f) return false;
t = glm::dot(e2, Q) * inv_det;
if (t > epsilon) { //ray intersection
return true;
}
// No hit, no win
return false;
}
template<>
inline bool intersect::intersects<math::Bounds, math::Triangle>(const math::Bounds &bounds, const math::Triangle &c_triangle)
{
return intersects(c_triangle, bounds);
}
template<>
inline bool intersect::intersects<math::Triangle, math::Bounds>(const math::Triangle &c_triangle, const math::Bounds &bounds)
{
// SAT: Separating Axis Theorem
// Two convex polyhedra A and B are disjoint, if they can be separated along either an axis parallel to a normal of a face of either A or B,
// or along an Axis formed from the cross product of an edge from A widh an edge from B.
// ------------------------------------------------------------------------------------------------------------------------------------------
// 1) Project triangle points on x, y and z min and max plane normals. Quit if disjoint.
// 2) Project AABB points on triangle normal. Quit if disjoint.
// ------------------------------------------------------------------------------------------------------------------------------------------
// Projection procedure: Calculate vector cp from plane center (eg x max = bounds.max-vec3(0, half[y], half[z])) to triangle point.
// Then check dot(cp, plane_normal) < 0.
math::Triangle triangle = c_triangle;
const glm::vec3 bounds_halfsize = bounds.size().xyz * 0.5f;
sortTriangleLongestAxis(triangle);
// --------------------------------------- NEEDED ----------------------------------------------------
float sidedness_max;
float sidedness_min;
int i;
// ---------------------------------------------------------------------------------------------------