Cleaned up and pulled out some code into Map.cpp in order to start working on the meat of the *Correct* voxel traversal method as explained in the paper.

master
MitchellHansen 7 years ago
parent 1bfc54adf1
commit 316293a110

@ -11,36 +11,53 @@
#define _USE_MATH_DEFINES
#include <math.h>
struct XYZHasher {
std::size_t operator()(const sf::Vector3i& k) const {
return ((std::hash<int>()(k.x)
^ (std::hash<int>()(k.y) << 1)) >> 1)
^ (std::hash<int>()(k.z) << 1);
}
};
class Map {
public:
Map(uint32_t dimensions);
// Sets a voxel in the 3D char dataset
void setVoxel(sf::Vector3i position, int val);
bool getVoxelFromOctree(sf::Vector3i position);
bool getVoxel(sf::Vector3i pos);
Octree octree;
// Gets a voxel at the 3D position in the octree
char getVoxel(sf::Vector3i pos);
std::vector<std::tuple<sf::Vector3i, char>> Map::CastRayOctree(
Octree *octree,
sf::Vector3i* map_dim,
sf::Vector2f* cam_dir,
sf::Vector3f* cam_pos
);
std::vector<std::tuple<sf::Vector3i, char>> Map::CastRayCharArray(
char *map,
sf::Vector3i* map_dim,
sf::Vector2f* cam_dir,
sf::Vector3f* cam_pos
);
bool test();
// Octree handles all basic octree operations
Octree octree;
private:
// ======= DEBUG ===========
int counter = 0;
std::stringstream output_stream;
// =========================
// The 3D char dataset that is generated at runtime. This will be replaced by two different interactions.
// The first a file loading function that loads binary octree data.
// The second being an import tool which will allow Any -> Octree transformation.
char* voxel_data;
// =========================
};
// Might possibly use this struct for hashing XYZ chunk values into a dict for storage and loading
struct XYZHasher {
std::size_t operator()(const sf::Vector3i& k) const {
return ((std::hash<int>()(k.x)
^ (std::hash<int>()(k.y) << 1)) >> 1)
^ (std::hash<int>()(k.z) << 1);
}
};

@ -6,7 +6,7 @@
#define OCT_DIM 32
struct oct_state {
struct OctState {
int parent_stack_position = 0;
uint64_t parent_stack[32] = { 0 };
@ -16,6 +16,10 @@ struct oct_state {
uint64_t current_descriptor;
// ====== DEBUG =======
char found = 1;
};
@ -27,11 +31,16 @@ public:
Octree();
~Octree() {};
// Generate an octree from 3D indexed array of char data
void Generate(char* data, sf::Vector3i dimensions);
// TODO: Load the octree from a serialized or whatever file
void Load(std::string octree_file_name);
uint64_t *trunk_buffer;
uint64_t trunk_buffer_position = buffer_size;
// I think the best way to transfer all of the data to the GPU. Each buffer will contain a set of blocks
// except for the trunk buffer. The paper indicates that the cutoff point for the trunk can vary,
// but since I'm going to do seperate buffers, I'm going to set a hard cutoff for the trunk so we
// know when to switch buffers
uint64_t *descriptor_buffer;
uint64_t descriptor_buffer_position = buffer_size;
@ -46,16 +55,17 @@ public:
uint64_t root_index = 0;
int page_header_counter = 0x8000;
// Cheat and underflow to get the position
uint64_t current_info_section_position = ((uint64_t)0)-1;
uint64_t stack_pos = 0x8000;
uint64_t global_pos = buffer_size - 50;
uint64_t copy_to_stack(std::vector<uint64_t> children, unsigned int voxel_scale);
// With a position and the head of the stack. Traverse down the voxel hierarchy to find
// the IDX and stack position of the highest resolution (maybe set resolution?) oct
bool GetVoxel(sf::Vector3i position);
OctState GetVoxel(sf::Vector3i position);
void print_block(int block_pos);

@ -8,6 +8,9 @@
#include <string>
#include <imgui/imgui.h>
#include <cmath>
#include <SFML/Graphics/Texture.hpp>
#include <algorithm>
#include <tuple>
const double PI = 3.141592653589793238463;
const float PI_F = 3.14159265358979f;
@ -250,8 +253,6 @@ inline bool CheckContiguousValid(const uint64_t c) {
return (c & bitmask) == bitmask;
}
inline bool IsLeaf(const uint64_t descriptor) {
uint64_t leaf_mask = 0xFF000000;

@ -7,6 +7,8 @@
#include <CL/opencl.h>
#elif defined _WIN32
// Good lord, the C++ std overwrote windows.h min() max() definitions
#define NOMINMAX
#include <windows.h>
// As if hardware is ever going to move away from 1.2
@ -68,6 +70,9 @@ sf::Texture window_texture;
// - Inconsistent lighting constants. GUI manipulation
// Ancilary settings buffer and memory controller
// - Attachment lookup and aux buffer, contour lookup & masking
// - Traversal algorithm + related stacks and data structures
// - Octree, Map interface with the GPU
// - Octree, Map refactoring
int main() {
@ -76,7 +81,9 @@ int main() {
Map _map(32);
//_map.test();
//std::cin.get();
return 0;
//return 0;
// =============================
sf::RenderWindow window(sf::VideoMode(WINDOW_X, WINDOW_Y), "SFML");

@ -3,6 +3,8 @@
Map::Map(uint32_t dimensions) {
// ========= TEMP 3D voxel data ===========
srand(time(nullptr));
voxel_data = new char[dimensions * dimensions * dimensions];
@ -17,10 +19,20 @@ Map::Map(uint32_t dimensions) {
else
voxel_data[i] = 0;
}
sf::Vector3i dim3(dimensions, dimensions, dimensions);
octree.Generate(voxel_data, dim3);
octree.Validate(voxel_data, dim3);
sf::Vector2f cam_dir(2, 0.01);
sf::Vector3f cam_pos(10, 10, 10);
std::vector<std::tuple<sf::Vector3i, char>> list1 = CastRayCharArray(voxel_data, &dim3, &cam_dir, &cam_pos);
std::vector<std::tuple<sf::Vector3i, char>> list2 = CastRayOctree(&octree, &dim3, &cam_dir, &cam_pos);
octree.Generate(voxel_data, sf::Vector3i(dimensions, dimensions, dimensions));
return;
octree.Validate(voxel_data, sf::Vector3i(dimensions, dimensions, dimensions));
}
void Map::setVoxel(sf::Vector3i pos, int val) {
@ -28,76 +40,261 @@ void Map::setVoxel(sf::Vector3i pos, int val) {
voxel_data[pos.x + OCT_DIM * (pos.y + OCT_DIM * pos.z)] = val;
}
bool Map::getVoxelFromOctree(sf::Vector3i position)
{
return 0;
char Map::getVoxel(sf::Vector3i pos){
return octree.GetVoxel(pos).found;
}
bool Map::getVoxel(sf::Vector3i pos){
std::vector<std::tuple<sf::Vector3i, char>> Map::CastRayCharArray(
char* map,
sf::Vector3i* map_dim,
sf::Vector2f* cam_dir,
sf::Vector3f* cam_pos
) {
if (voxel_data[pos.x + OCT_DIM * (pos.y + OCT_DIM * pos.z)]) {
return true;
} else {
return false;
}
}
std::vector<std::tuple<sf::Vector3i, char>> travel_path;
bool Map::test() {
sf::Vector3f ray_dir(1, 0, 0);
std::cout << "Validating map..." << std::endl;
// Pitch
ray_dir = sf::Vector3f(
ray_dir.z * sin((*cam_dir).x) + ray_dir.x * cos((*cam_dir).x),
ray_dir.y,
ray_dir.z * cos((*cam_dir).x) - ray_dir.x * sin((*cam_dir).x)
);
for (int x = 0; x < OCT_DIM; x++) {
for (int y = 0; y < OCT_DIM; y++) {
for (int z = 0; z < OCT_DIM; z++) {
// Yaw
ray_dir = sf::Vector3f(
ray_dir.x * cos((*cam_dir).y) - ray_dir.y * sin((*cam_dir).y),
ray_dir.x * sin((*cam_dir).y) + ray_dir.y * cos((*cam_dir).y),
ray_dir.z
);
sf::Vector3i pos(x, y, z);
bool arr1 = getVoxel(pos);
bool arr2 = getVoxelFromOctree(pos);
// Setup the voxel step based on what direction the ray is pointing
sf::Vector3i voxel_step(1, 1, 1);
if (arr1 != arr2) {
std::cout << "X: " << pos.x << "Y: " << pos.y << "Z: " << pos.z << std::endl;
}
voxel_step.x *= (ray_dir.x > 0) - (ray_dir.x < 0);
voxel_step.y *= (ray_dir.y > 0) - (ray_dir.y < 0);
voxel_step.z *= (ray_dir.z > 0) - (ray_dir.z < 0);
}
}
}
// Setup the voxel coords from the camera origin
sf::Vector3i voxel(*cam_pos);
// Delta T is the units a ray must travel along an axis in order to
// traverse an integer split
sf::Vector3f delta_t(
fabs(1.0f / ray_dir.x),
fabs(1.0f / ray_dir.y),
fabs(1.0f / ray_dir.z)
);
// offset is how far we are into a voxel, enables sub voxel movement
// Intersection T is the collection of the next intersection points
// for all 3 axis XYZ.
sf::Vector3f intersection_t(
delta_t.x * (cam_pos->x - floor(cam_pos->x)) * voxel_step.x,
delta_t.y * (cam_pos->y - floor(cam_pos->y)) * voxel_step.y,
delta_t.z * (cam_pos->z - floor(cam_pos->z)) * voxel_step.z
);
// for negative values, wrap around the delta_t
intersection_t.x += delta_t.x * -(std::min(intersection_t.x, 0.0f));
intersection_t.y += delta_t.y * -(std::min(intersection_t.y, 0.0f));
intersection_t.z += delta_t.z * -(std::min(intersection_t.z, 0.0f));
int dist = 0;
sf::Vector3i face_mask(0, 0, 0);
int voxel_data = 0;
// Andrew Woo's raycasting algo
do {
std::cout << "Done" << std::endl;
face_mask.x = intersection_t.x <= std::min(intersection_t.y, intersection_t.z);
face_mask.y = intersection_t.y <= std::min(intersection_t.z, intersection_t.x);
face_mask.z = intersection_t.z <= std::min(intersection_t.x, intersection_t.y);
sf::Clock timer;
timer.restart();
intersection_t.x += delta_t.x * fabs(face_mask.x);
intersection_t.y += delta_t.y * fabs(face_mask.y);
intersection_t.z += delta_t.z * fabs(face_mask.z);
for (int x = 0; x < OCT_DIM; x++) {
for (int y = 0; y < OCT_DIM; y++) {
for (int z = 0; z < OCT_DIM; z++) {
voxel.x += voxel_step.x * face_mask.x;
voxel.y += voxel_step.y * face_mask.y;
voxel.z += voxel_step.z * face_mask.z;
sf::Vector3i pos(x, y, z);
if ((intersection_t.x) < (intersection_t.y)) {
if ((intersection_t.x) < (intersection_t.z)) {
bool arr1 = getVoxel(pos);
voxel.x += voxel_step.x;
intersection_t.x = intersection_t.x + delta_t.x;
}
else {
voxel.z += voxel_step.z;
intersection_t.z = intersection_t.z + delta_t.z;
}
}
}
else {
if ((intersection_t.y) < (intersection_t.z)) {
voxel.y += voxel_step.y;
intersection_t.y = intersection_t.y + delta_t.y;
}
else {
voxel.z += voxel_step.z;
intersection_t.z = intersection_t.z + delta_t.z;
}
}
if (voxel.x >= map_dim->x || voxel.y >= map_dim->y || voxel.z >= map_dim->z) {
return travel_path;
}
if (voxel.x < 0 || voxel.y < 0 || voxel.z < 0) {
return travel_path;
}
// If we hit a voxel
voxel_data = map[voxel.x + (*map_dim).x * (voxel.y + (*map_dim).z * (voxel.z))];
travel_path.push_back(std::make_tuple(voxel, voxel_data));
if (voxel_data != 0)
return travel_path;
} while (++dist < 700.0f);
return travel_path;
}
class Octree;
std::vector<std::tuple<sf::Vector3i, char>> Map::CastRayOctree(
Octree *octree,
sf::Vector3i* map_dim,
sf::Vector2f* cam_dir,
sf::Vector3f* cam_pos
) {
std::vector<std::tuple<sf::Vector3i, char>> travel_path;
sf::Vector3f ray_dir(1, 0, 0);
// Pitch
ray_dir = sf::Vector3f(
ray_dir.z * sin((*cam_dir).x) + ray_dir.x * cos((*cam_dir).x),
ray_dir.y,
ray_dir.z * cos((*cam_dir).x) - ray_dir.x * sin((*cam_dir).x)
);
// Yaw
ray_dir = sf::Vector3f(
ray_dir.x * cos((*cam_dir).y) - ray_dir.y * sin((*cam_dir).y),
ray_dir.x * sin((*cam_dir).y) + ray_dir.y * cos((*cam_dir).y),
ray_dir.z
);
// Setup the voxel step based on what direction the ray is pointing
sf::Vector3i voxel_step(1, 1, 1);
voxel_step.x *= (ray_dir.x > 0) - (ray_dir.x < 0);
voxel_step.y *= (ray_dir.y > 0) - (ray_dir.y < 0);
voxel_step.z *= (ray_dir.z > 0) - (ray_dir.z < 0);
// Setup the voxel coords from the camera origin
sf::Vector3i voxel(*cam_pos);
// Delta T is the units a ray must travel along an axis in order to
// traverse an integer split
sf::Vector3f delta_t(
fabs(1.0f / ray_dir.x),
fabs(1.0f / ray_dir.y),
fabs(1.0f / ray_dir.z)
);
// offset is how far we are into a voxel, enables sub voxel movement
// Intersection T is the collection of the next intersection points
// for all 3 axis XYZ.
sf::Vector3f intersection_t(
delta_t.x * (cam_pos->y - floor(cam_pos->x)) * voxel_step.x,
delta_t.y * (cam_pos->x - floor(cam_pos->y)) * voxel_step.y,
delta_t.z * (cam_pos->z - floor(cam_pos->z)) * voxel_step.z
);
// for negative values, wrap around the delta_t
intersection_t.x += delta_t.x * -(std::min(intersection_t.x, 0.0f));
intersection_t.y += delta_t.y * -(std::min(intersection_t.y, 0.0f));
intersection_t.z += delta_t.z * -(std::min(intersection_t.z, 0.0f));
int dist = 0;
sf::Vector3i face_mask(0, 0, 0);
int voxel_data = 0;
OctState traversal_state = octree->GetVoxel(voxel);
std::cout << "Array linear xyz access : ";
std::cout << timer.restart().asMicroseconds() << " microseconds" << std::endl;
// Andrew Woo's raycasting algo
do {
for (int x = 0; x < OCT_DIM; x++) {
for (int y = 0; y < OCT_DIM; y++) {
for (int z = 0; z < OCT_DIM; z++) {
face_mask.x = intersection_t.x <= std::min(intersection_t.y, intersection_t.z);
face_mask.y = intersection_t.y <= std::min(intersection_t.z, intersection_t.x);
face_mask.z = intersection_t.z <= std::min(intersection_t.x, intersection_t.y);
sf::Vector3i pos(x, y, z);
bool arr2 = getVoxelFromOctree(pos);
intersection_t.x += delta_t.x * fabs(face_mask.x);
intersection_t.y += delta_t.y * fabs(face_mask.y);
intersection_t.z += delta_t.z * fabs(face_mask.z);
voxel.x += voxel_step.x * face_mask.x;
voxel.y += voxel_step.y * face_mask.y;
voxel.z += voxel_step.z * face_mask.z;
if ((intersection_t.x) < (intersection_t.y)) {
if ((intersection_t.x) < (intersection_t.z)) {
voxel.x += voxel_step.x;
intersection_t.x = intersection_t.x + delta_t.x;
}
else {
voxel.z += voxel_step.z;
intersection_t.z = intersection_t.z + delta_t.z;
}
}
}
else {
if ((intersection_t.y) < (intersection_t.z)) {
std::cout << "Octree linear xyz access : ";
std::cout << timer.restart().asMicroseconds() << " microseconds" << std::endl;
voxel.y += voxel_step.y;
intersection_t.y = intersection_t.y + delta_t.y;
}
else {
voxel.z += voxel_step.z;
intersection_t.z = intersection_t.z + delta_t.z;
}
}
return true;
}
if (voxel.x >= map_dim->x || voxel.y >= map_dim->y || voxel.z >= map_dim->z) {
return travel_path;
}
if (voxel.x < 0 || voxel.y < 0 || voxel.z < 0) {
return travel_path;
}
// If we hit a voxel
//voxel_data = map[voxel.x + (*map_dim).x * (voxel.y + (*map_dim).z * (voxel.z))];
voxel_data = getVoxel(voxel);
travel_path.push_back(std::make_tuple(voxel, voxel_data));
if (voxel_data != 0)
return travel_path;
} while (++dist < 700.0f);
return travel_path;
}

@ -3,7 +3,6 @@
Octree::Octree() {
// initialize the the buffers to 0's
trunk_buffer = new uint64_t[buffer_size]();
descriptor_buffer = new uint64_t[buffer_size]();
attachment_lookup = new uint32_t[buffer_size]();
attachment_buffer = new uint64_t[buffer_size]();
@ -41,10 +40,10 @@ void Octree::Generate(char* data, sf::Vector3i dimensions) {
GetVoxel(sf::Vector3i(0, 0, 0));
}
bool Octree::GetVoxel(sf::Vector3i position) {
OctState Octree::GetVoxel(sf::Vector3i position) {
// Struct that holds the state necessary to continue the traversal from the found voxel
oct_state state;
OctState state;
// push the root node to the parent stack
uint64_t current_index = root_index;
@ -115,7 +114,8 @@ bool Octree::GetVoxel(sf::Vector3i position) {
if ((head >> 24) & mask_8[mask_index]) {
// If it is, then we cannot traverse further as CP's won't have been generated
return true;
state.found = 1;
return state;
}
// If all went well and we found a valid non-leaf oct then we will traverse further down the hierarchy
@ -144,11 +144,13 @@ bool Octree::GetVoxel(sf::Vector3i position) {
// to focus on how to now take care of the end condition.
// Currently it adds the last parent on the second to lowest
// oct CP. Not sure if thats correct
return false;
state.found = 0;
return state;
}
}
return true;
state.found = 1;
return state;
}
void Octree::print_block(int block_pos) {
@ -234,7 +236,8 @@ std::tuple<uint64_t, uint64_t> Octree::GenerationRecursion(char* data, sf::Vecto
}
// We are working bottom up so we need to subtract from the stack position
// the amount of elements we want to use
// the amount of elements we want to use. In the worst case this will be
// a far pointer for ever descriptor (size * 2)
int worst_case_insertion_size = descriptor_position_array.size() * 2;
@ -329,7 +332,7 @@ bool Octree::Validate(char* data, sf::Vector3i dimensions){
sf::Vector3i pos(x, y, z);
char arr_val = get1DIndexedVoxel(data, dimensions, pos);
char oct_val = GetVoxel(pos);
char oct_val = GetVoxel(pos).found;
if (arr_val != oct_val) {
std::cout << "X: " << pos.x << " Y: " << pos.y << " Z: " << pos.z << " ";
@ -342,5 +345,5 @@ bool Octree::Validate(char* data, sf::Vector3i dimensions){
std::cout << "Done" << std::endl;
return true;
}

Loading…
Cancel
Save