Got the octree data to the GPU and it's traversing it, but it having some corruption issues. Endianness???

master
MitchellHansen 7 years ago
parent ba11f9c081
commit ebce781eb3

@ -63,6 +63,7 @@ private:
std::shared_ptr<sf::RenderWindow> window;
std::shared_ptr<Old_Map> map;
std::shared_ptr<Map> octree;
std::shared_ptr<Camera> camera;
std::shared_ptr<CLCaster> raycaster;
std::shared_ptr<LightHandle> light_handle;

@ -10,6 +10,7 @@
#include <GL/glew.h>
#include <unordered_map>
#include "Logger.h"
#include "map/Map.h"
#ifdef linux
#include <CL/cl.h>
@ -86,72 +87,20 @@ struct PackedData;
class CLCaster {
public:
enum ERROR_CODES {
SHARING_NOT_SUPPORTED = 800,
OPENCL_NOT_SUPPORTED = 801,
OPENCL_ERROR = 802,
ERR = 803
};
/**
* Device is a storage container for device data we retrieve from OpenCL
*
* The data is mainly queries as strings or integer types and stored into
* respective containers. We store this data into a file and retrieve it later
* to let users select a preferred compute device and keep track of their choice
*/
class device {
public:
#pragma pack(push, 1)
struct packed_data {
cl_device_type device_type;
cl_uint clock_frequency;
char opencl_version[64];
cl_uint compute_units;
char device_extensions[1024];
char device_name[256];
char platform_name[128];
};
#pragma pack(pop)
device(cl_device_id device_id, cl_platform_id platform_id);
device(const device& d);
void print(std::ostream& stream) const;
void print_packed_data(std::ostream& stream);
cl_device_id getDeviceId() const { return device_id; };
cl_platform_id getPlatformId() const { return platform_id; };
private:
packed_data data;
cl_device_id device_id;
cl_platform_id platform_id;
cl_bool is_little_endian = false;
bool cl_gl_sharing = false;
};
/**
* Hardware caster is the beginning and end to all interaction with the GPU.
* CLCaster is the beginning and end to all interaction with the GPU.
*
* It queries devices, manages the creation of various data structures as well
* as they syncing between the GPU. It Handles computing of the cast as well
* as rendering of the computed cast.
*
*/
CLCaster();
virtual ~CLCaster();
// Queries hardware, creates the command queue and context, and compiles kernel
bool init();
@ -167,6 +116,10 @@ public:
bool assign_map(std::shared_ptr<Old_Map> map);
bool release_map();
// We take a ptr to the map and create the map, and map_dimensions buffer for the GPU
bool assign_octree(std::shared_ptr<Map> octree);
bool release_octree();
// We take a ptr to the camera and create a camera direction and position buffer
bool assign_camera(std::shared_ptr<Camera> camera);
bool release_camera();
@ -200,6 +153,50 @@ public:
private:
/**
* Device is a storage container for device data we retrieve from OpenCL
*
* The data is mainly queries as strings or integer types and stored into
* respective containers. We store this data into a file and retrieve it later
* to let users select a preferred compute device and keep track of their choice
*/
class device {
public:
#pragma pack(push, 1)
struct packed_data {
cl_device_type device_type;
cl_uint clock_frequency;
char opencl_version[64];
cl_uint compute_units;
char device_extensions[1024];
char device_name[256];
char platform_name[128];
};
#pragma pack(pop)
device(cl_device_id device_id, cl_platform_id platform_id);
device(const device& d);
void print(std::ostream& stream) const;
void print_packed_data(std::ostream& stream);
cl_device_id getDeviceId() const { return device_id; };
cl_platform_id getPlatformId() const { return platform_id; };
private:
packed_data data;
cl_device_id device_id;
cl_platform_id platform_id;
cl_bool is_little_endian = false;
bool cl_gl_sharing = false;
};
// Cycle through the OpenCL devices and store *all* of their data, not super useful
bool query_hardware();
@ -281,6 +278,7 @@ private:
std::shared_ptr<Camera> camera;
std::shared_ptr<Old_Map> map;
std::shared_ptr<Map> octree;
std::vector<PackedData> *lights;
int light_count = 0;

@ -7,10 +7,35 @@
#include "CLCaster.h"
#include "LightHandle.h"
// Typical light workflow:
// 1.) Create light prototype with desired values
// 2.) Submit prototype to the LightController
/**
* Light Handle :
* - Contains data relating to movement, and a reference to the rbgi, direction, and position
* elements in the LightController.
* - Resultant of the use of LightController.create_light(LightPrototype). Cannot be self instantiated.
* - On deconstruction, light data is removed from the LightController via a reference and the light disappears
*
* LightPrototype :
* - Contains the desired starting values for the light. The LightHandler object will then be
* instantiated using this data
*
* PackedData :
* - We need to single out the data that the GPU needs into a single contiguous
* array. PackedData holds the values for position, direction, and rgbi
*
* LightController :
* - Contains the PackedData array in a static sized array.
* Empty light slots are set to 0 and still sent over the line
* TODO: This introduces light limits and inefficiencies
* - Contains a factory that takes LightPrototypes and generates unique ptr LightHandles.
* Each light handle is given a light index enabling light removal.
*
* Typical light workflow:
* 1.) Create light prototype with desired values
* 2.) Submit prototype to the LightController
* 3.) Get a light handle back from the controller
* - The handle is unsafe and will break if it exceeds PackedData's lifetime
*
*/
struct LightPrototype {
@ -56,8 +81,10 @@ public:
LightController(std::shared_ptr<CLCaster> raycaster);
~LightController();
// find a free light 'slot' and create
// find a free light 'slot' and create the light
// LightHandles are single instance single lifetime data structures
std::shared_ptr<LightHandle> create_light(LightPrototype light_prototype);
void remove_light(unsigned int light_index);
void recieve_event(VrEventPublisher* publisher, std::unique_ptr<vr::Event> event) override;

@ -6,29 +6,6 @@
#include "Vector4.hpp"
// Light Handle :
// - Contains data relating to movement, and a reference to the rbgi, direction, and position
// elements in the LightController.
// - Resultant of the use of LightController.create_light(LightPrototype). Cannot be self instantiated.
// - On deconstruction, light data is removed from the LightController and the light disappears
// LightPrototype :
// - Contains the desired starting values for the light. The LightHandler object will then be
// instantiated using this data
// PackedData :
// - We need to single out the data that the GPU needs into a single contiguous
// array. PackedData holds the values for position, direction, and rgbi
// LightController :
// - Contains the PackedData array in a static sized array.
// Empty light slots are set to 0 and still sent over the line
// TODO: This introduces light limits and inefficiencies
// - Contains a factory that takes LightPrototypes and generates unique ptr LightHandles.
// Each light handle is given a light index enabling light removal.
struct LightPrototype;
class LightController;
struct PackedData;

@ -95,7 +95,7 @@ private:
};
// Mask for counting the previous valid bits
const uint8_t count_mask_8[8]{
const uint8_t count_mask_8[8] = {
0x1, 0x3, 0x7, 0xF,
0x1F, 0x3F, 0x7F, 0xFF
};

@ -25,13 +25,10 @@ float4 white_light(float4 input, float3 light, int3 mask) {
}
// Phong + diffuse lighting function for g
// 0 1 2 3 4 5 6 7 8 9
// {r, g, b, i, x, y, z, x', y', z'}
float4 view_light(float4 in_color, float3 light, float4 light_color, float3 view, int3 mask) {
float d = Distance(light) / 100.0f;
@ -63,7 +60,155 @@ int rand(int* seed) // 1 <= *seed < m
return(*seed);
}
bool get_oct_vox(
int3 position,
global ulong *octree_descriptor_buffer,
global uint *octree_attachment_lookup_buffer,
global ulong *octree_attachment_buffer,
global ulong *settings_buffer
){
// (X, Y, Z) mask for the idx
const uchar idx_set_x_mask = 0x1;
const uchar idx_set_y_mask = 0x2;
const uchar idx_set_z_mask = 0x4;
const uchar mask_8[8] = {
0x1, 0x2, 0x4, 0x8,
0x10, 0x20, 0x40, 0x80
};
// Mask for counting the previous valid bits
const uchar count_mask_8[8] = {
0x1, 0x3, 0x7, 0xF,
0x1F, 0x3F, 0x7F, 0xFF
};
// uint64_t manipulation masks
const ulong child_pointer_mask = 0x0000000000007fff;
const ulong far_bit_mask = 0x8000;
const ulong valid_mask = 0xFF0000;
const ulong leaf_mask = 0xFF000000;
const ulong contour_pointer_mask = 0xFFFFFF00000000;
const ulong contour_mask = 0xFF00000000000000;
// push the root node to the parent stack
ulong current_index = *settings_buffer;
ulong head = octree_descriptor_buffer[current_index];
uint parent_stack_position = 0;
ulong parent_stack[32];
uchar scale = 0;
uchar idx_stack[32];
ulong current_descriptor = 0;
bool found = false;
parent_stack[parent_stack_position] = head;
// Set our initial dimension and the position at the corner of the oct to keep track of our position
int dimension = 32;
int3 quad_position = (0, 0, 0);
// While we are not at the required resolution
// Traverse down by setting the valid/leaf mask to the subvoxel
// Check to see if it is valid
// Yes?
// Check to see if it is a leaf
// No? Break
// Yes? Scale down to the next hierarchy, push the parent to the stack
//
// No?
// Break
while (dimension > 1) {
// So we can be a little bit tricky here and increment our
// array index that holds our masks as we build the idx.
// Adding 1 for X, 2 for Y, and 4 for Z
int mask_index = 0;
// Do the logic steps to find which sub oct we step down into
if (position.x >= (dimension / 2) + quad_position.x) {
// Set our voxel position to the (0,0) of the correct oct
quad_position.x += (dimension / 2);
// increment the mask index and mentioned above
mask_index += 1;
// Set the idx to represent the move
idx_stack[scale] |= idx_set_x_mask;
}
if (position.y >= (dimension / 2) + quad_position.y) {
quad_position.y |= (dimension / 2);
mask_index += 2;
// TODO What is up with the binary operator on this one?
idx_stack[scale] ^= idx_set_y_mask;
}
if (position.z >= (dimension / 2) + quad_position.z) {
quad_position.z += (dimension / 2);
mask_index += 4;
idx_stack[scale] |= idx_set_z_mask;
}
// Check to see if we are on a valid oct
if ((head >> 16) & mask_8[mask_index]) {
// Check to see if it is a leaf
if ((head >> 24) & mask_8[mask_index]) {
// If it is, then we cannot traverse further as CP's won't have been generated
found = true;
return found;
}
// If all went well and we found a valid non-leaf oct then we will traverse further down the hierarchy
scale++;
dimension /= 2;
// Count the number of valid octs that come before and add it to the index to get the position
// Negate it by one as it counts itself
int count = popcount((uchar)(head >> 16) & count_mask_8[mask_index]) - 1;
// access the element at which head points to and then add the specified number of indices
// to get to the correct child descriptor
current_index = current_index + (head & child_pointer_mask) + count;
head = octree_descriptor_buffer[current_index];
// Increment the parent stack position and put the new oct node as the parent
parent_stack_position++;
parent_stack[parent_stack_position] = head;
}
else {
// If the oct was not valid, then no CP's exists any further
// This implicitly says that if it's non-valid then it must be a leaf!!
// It appears that the traversal is now working but I need
// 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
found = 0;
return found;
}
}
found = 1;
return found;
}
// =================================== Boolean ray intersection ============================
// =========================================================================================
@ -147,12 +292,15 @@ __kernel void raycaster(
global float* lights,
global int* light_count,
__write_only image2d_t image,
global int* seed_memory,
//global int* seed_memory,
__read_only image2d_t texture_atlas,
global int2 *atlas_dim,
global int2 *tile_dim
global int2 *tile_dim,
global ulong *octree_descriptor_buffer,
global uint *octree_attachment_lookup_buffer,
global ulong *octree_attachment_buffer,
global ulong *settings_buffer
){
// int global_id = x * y;
// Get and set the random seed from seed memory
@ -224,8 +372,24 @@ __kernel void raycaster(
return;
}
// If we hit a voxel
if (voxel.x < 32 && voxel.y < 32 && voxel.z < 32){
if (get_oct_vox(
voxel,
octree_descriptor_buffer,
octree_attachment_lookup_buffer,
octree_attachment_buffer,
settings_buffer
)){
voxel_data = 1;
} else {
voxel_data = 0;
}
} else {
voxel_data = map[voxel.x + (*map_dim).x * (voxel.y + (*map_dim).z * (voxel.z))];
}
if (voxel_data != 0) {
@ -323,6 +487,8 @@ __kernel void raycaster(
voxel_color.w = 0.0f;
// This has a very large performance hit, I assume CL doesn't really
// like calling into other functions with lots of state.
if (cast_light_intersection_ray(
map,
map_dim,

@ -3,7 +3,7 @@
#include "imgui/imgui-SFML.h"
Application::Application() {
srand(time(nullptr));
//srand(time(nullptr));
window = std::make_shared<sf::RenderWindow>(sf::VideoMode(WINDOW_X, WINDOW_Y), "SFML");
window->setMouseCursorVisible(false);
@ -23,7 +23,7 @@ Application::~Application() {
bool Application::init_clcaster() {
Map _map(32);
//Map _map(32);
//return 0;
// Start up the raycaster
@ -38,6 +38,10 @@ bool Application::init_clcaster() {
// Send the data to the GPU
raycaster->assign_map(map);
octree = std::make_shared<Map>(32);
raycaster->assign_octree(octree);
// Create a new camera with (starting position, direction)
camera = std::make_shared<Camera>(
sf::Vector3f(50, 50, 50),
@ -90,6 +94,8 @@ bool Application::init_events() {
window_handler->subscribe_to_publisher(&input_handler, vr::Event::EventType::Closed);
window_handler->subscribe_to_publisher(&input_handler, vr::Event::EventType::KeyPressed);
//camera->subscribe_to_publisher(&input_handler, vr::Event::EventType::JoystickMoved);
return true;
}
@ -234,6 +240,47 @@ bool Application::game_loop() {
ImGui::End();
ImGui::Begin("Controller debugger");
ImDrawList* draw_list = ImGui::GetWindowDrawList();
static ImVec4 col = ImVec4(1.0f, 0.0f, 1.0f, 1.0f);
const ImVec2 p = ImGui::GetCursorScreenPos();
const ImU32 col32 = ImColor(col);
std::vector<float> axis_values = {
sf::Joystick::getAxisPosition(0, sf::Joystick::Axis::X) / 2,
sf::Joystick::getAxisPosition(0, sf::Joystick::Axis::Y) / 2,
sf::Joystick::getAxisPosition(0, sf::Joystick::Axis::U) / 2,
sf::Joystick::getAxisPosition(0, sf::Joystick::Axis::R) / 2,
sf::Joystick::getAxisPosition(0, sf::Joystick::Axis::Z) / 2,
sf::Joystick::getAxisPosition(0, sf::Joystick::Axis::V) / 2
};
ImGui::Columns(3, "Axis's"); // 4-ways, with border
ImGui::Separator();
ImGui::Text("X Y"); ImGui::NextColumn();
ImGui::Text("U R"); ImGui::NextColumn();
ImGui::Text("Z V"); ImGui::NextColumn();
ImGui::Separator();
for (int i = 0; i < 3; i++) {
float offset = ImGui::GetColumnWidth(i);
draw_list->AddLine(ImVec2(p.x + 0 + offset * i, p.y + 50), ImVec2(p.x + 100 + offset * i, p.y + 50), col32, 1.0);
draw_list->AddLine(ImVec2(p.x + 50 + offset * i, p.y + 0), ImVec2(p.x + 50 + offset * i, p.y + 100), col32, 1.0);
draw_list->AddCircleFilled(ImVec2(p.x + axis_values[2 * i] + 50 + offset * i, p.y + axis_values[2 * i + 1] + 50), 6, col32, 32);
ImGui::Dummy(ImVec2(100, 100));
ImGui::NextColumn();
}
ImGui::End();
//ImGui::ShowTestWindow();
ImGui::Render();
// ImGUI messes up somthing in the SFML GL state, so we need a single draw call to right things

@ -50,7 +50,6 @@ bool CLCaster::init() {
return false;
}
if (!compile_kernel("../kernels/ray_caster_kernel.cl", true, "raycaster")) {
Logger::log("Failed to compile the kernel", Logger::LogLevel::ERROR, __LINE__, __FILE__);
std::cin.get(); // hang the output window so we can read the error
@ -75,7 +74,6 @@ bool CLCaster::assign_map(std::shared_ptr<Old_Map> map) {
if (!create_buffer("map", sizeof(char) * dimensions.x * dimensions.y * dimensions.z, map->get_voxel_data()))
return false;
if (!create_buffer("map_dimensions", sizeof(int) * 3, &dimensions))
return false;
@ -88,7 +86,6 @@ bool CLCaster::release_map() {
if (!release_buffer("map"))
return false;
if (!release_buffer("map_dimensions"))
return false;
@ -96,13 +93,45 @@ bool CLCaster::release_map() {
}
bool CLCaster::assign_octree(std::shared_ptr<Map> octree) {
this->octree = octree;
if (!create_buffer("octree_descriptor_buffer", octree->octree.buffer_size, &octree->octree.descriptor_buffer))
return false;
if (!create_buffer("octree_attachment_lookup_buffer", octree->octree.buffer_size, &octree->octree.attachment_lookup))
return false;
if (!create_buffer("octree_attachment_buffer", octree->octree.buffer_size, &octree->octree.attachment_buffer))
return false;
if (!create_buffer("settings_buffer", sizeof(uint64_t), &octree->octree.root_index))
return false;
return true;
}
bool CLCaster::release_octree()
{
this->octree = nullptr;
if (!release_buffer("octree_descriptor_buffer"))
return false;
if (!release_buffer("octree_attachment_lookup_buffer"))
return false;
if (!release_buffer("octree_attachment_buffer"))
return false;
if (!release_buffer("settings_buffer"))
return false;
return true;
}
bool CLCaster::assign_camera(std::shared_ptr<Camera> camera) {
this->camera = camera;
if (!create_buffer("camera_direction", sizeof(float) * 4, (void*)camera->get_direction_pointer(), CL_MEM_READ_ONLY | CL_MEM_USE_HOST_PTR))
return false;
if (!create_buffer("camera_position", sizeof(float) * 4, (void*)camera->get_position_pointer(), CL_MEM_READ_ONLY | CL_MEM_USE_HOST_PTR))
return false;
@ -115,7 +144,6 @@ bool CLCaster::release_camera() {
if (!release_buffer("camera_direction"))
return false;
if (!release_buffer("camera_position"))
return false;
@ -154,10 +182,14 @@ bool CLCaster::validate() {
set_kernel_arg("raycaster", 6, "lights");
set_kernel_arg("raycaster", 7, "light_count");
set_kernel_arg("raycaster", 8, "image");
set_kernel_arg("raycaster", 9, "seed");
set_kernel_arg("raycaster", 10, "texture_atlas");
set_kernel_arg("raycaster", 11, "atlas_dim");
set_kernel_arg("raycaster", 12, "tile_dim");
//set_kernel_arg("raycaster", 9, "seed");
set_kernel_arg("raycaster", 9, "texture_atlas");
set_kernel_arg("raycaster", 10, "atlas_dim");
set_kernel_arg("raycaster", 11, "tile_dim");
set_kernel_arg("raycaster", 12, "octree_descriptor_buffer");
set_kernel_arg("raycaster", 13, "octree_attachment_lookup_buffer");
set_kernel_arg("raycaster", 14, "octree_attachment_buffer");
set_kernel_arg("raycaster", 15, "settings_buffer");
return true;
@ -173,7 +205,6 @@ bool CLCaster::create_texture_atlas(sf::Texture *t, sf::Vector2i tile_dim) {
if (!create_buffer("atlas_dim", sizeof(sf::Vector2u) , &v))
return false;
if (!create_buffer("tile_dim", sizeof(sf::Vector2i), &tile_dim))
return false;
@ -283,7 +314,6 @@ bool CLCaster::assign_lights(std::vector<PackedData> *data) {
if (!create_buffer("lights", packed_size * light_count, lights->data(), CL_MEM_READ_ONLY | CL_MEM_USE_HOST_PTR))
return false;
if (!create_buffer("light_count", 8, &light_count))
return false;
@ -1080,18 +1110,6 @@ std::string CLCaster::cl_err_lookup(int error_code) {
case CL_PLATFORM_NOT_FOUND_KHR:
err_msg = "CL_PLATFORM_NOT_FOUND_KHR";
break;
case CLCaster::SHARING_NOT_SUPPORTED:
err_msg = "SHARING_NOT_SUPPORTED";
break;
case CLCaster::OPENCL_NOT_SUPPORTED:
err_msg = "OPENCL_NOT_SUPPORTED";
break;
case CLCaster::OPENCL_ERROR:
err_msg = "OPENCL_ERROR";
break;
case CLCaster::ERR:
err_msg = "ERROR";
break;
default:
err_msg = "UNKNOWN_ERROR";
}

@ -167,23 +167,39 @@ void Camera::recieve_event(VrEventPublisher* publisher, std::unique_ptr<vr::Even
vr::JoystickMoved *joystick_event = static_cast<vr::JoystickMoved*>(event.get());
if (joystick_event->axis == sf::Joystick::Axis::X) {
movement.x -= joystick_event->position / 5;
//add_relative_impulse(Camera::DIRECTION::FORWARD, joystick_event->position);
if (joystick_event->position > 0)
add_relative_impulse(Camera::DIRECTION::RIGHT, joystick_event->position / 100);
else
add_relative_impulse(Camera::DIRECTION::LEFT, joystick_event->position / 100);
}
else if (joystick_event->axis == sf::Joystick::Axis::Y) {
movement.y += joystick_event->position / 5;
//add_relative_impulse(Camera::DIRECTION::RIGHT, joystick_event->position);
if (joystick_event->position > 0)
add_relative_impulse(Camera::DIRECTION::FORWARD, joystick_event->position / 100);
else
add_relative_impulse(Camera::DIRECTION::REARWARD, joystick_event->position / 100);
}
else if (joystick_event->axis == sf::Joystick::Axis::Z) {
if (joystick_event->position > 0)
add_relative_impulse(Camera::DIRECTION::DOWN, joystick_event->position / 100);
else
add_relative_impulse(Camera::DIRECTION::UP, joystick_event->position / 100);
}
else if (joystick_event->axis == sf::Joystick::Axis::U) {
slew_camera(sf::Vector2f(
deltas.y / 1200.0f,
deltas.x / 1200.0f
));
}
//else if (joystick_event->axis == sf::Joystick::Axis::Z) {
// add_relative_impulse(Camera::DIRECTION::DOWN, joystick_event->position);
//}
}
}
void Camera::look_at_center() {
direction = CartToNormalizedSphere(sf::Vector3f(75, 75, 75) - position);
direction = CartToNormalizedSphere(sf::Vector3f(60, 60, 35) - position);
}
sf::Vector2f* Camera::get_direction_pointer() {

@ -2,6 +2,7 @@
#include <iostream>
#include <memory>
#include "imgui/imgui-SFML.h"
#include "Logger.h"
Input::Input() :
@ -22,9 +23,8 @@ void Input::consume_sf_events(sf::RenderWindow *window) {
sf::Event e;
while (window->pollEvent(e)) {
ImGui::SFML::ProcessEvent(e);
sf_event_queue.push_back(e);
ImGui::SFML::ProcessEvent(e);
}
transpose_sf_events(sf_event_queue);
@ -121,6 +121,7 @@ void Input::dispatch_events() {
void Input::transpose_sf_events(std::list<sf::Event> sf_event_queue) {
for (auto sf_event: sf_event_queue) {
switch(sf_event.type) {

@ -70,16 +70,16 @@ void LightHandle::recieve_event(VrEventPublisher* publisher, std::unique_ptr<vr:
vr::JoystickMoved *joystick_event = static_cast<vr::JoystickMoved*>(event.get());
if (joystick_event->axis == sf::Joystick::Axis::X) {
movement.x = -joystick_event->position / 5;
movement.x = -joystick_event->position / 100;
//add_relative_impulse(Camera::DIRECTION::FORWARD, joystick_event->position);
}
else if (joystick_event->axis == sf::Joystick::Axis::Y) {
movement.y = joystick_event->position / 5;
movement.y = joystick_event->position / 100;
//add_relative_impulse(Camera::DIRECTION::RIGHT, joystick_event->position);
}
//else if (joystick_event->axis == sf::Joystick::Axis::Z) {
// add_relative_impulse(Camera::DIRECTION::DOWN, joystick_event->position);
//}
else if (joystick_event->axis == sf::Joystick::Axis::Z) {
movement.y = joystick_event->position / 100;
}
}
}

@ -12,7 +12,7 @@ Map::Map(uint32_t dimensions) {
// randomly set the voxel data for testing
for (uint64_t i = 0; i < dimensions * dimensions * dimensions; i++) {
if (rand() % 25 < 2)
if (i % 2 == 0)
voxel_data[i] = 1;
else
voxel_data[i] = 0;

Loading…
Cancel
Save