From 3f09515c0a296ea35e3e8194d79ad34c22a874af Mon Sep 17 00:00:00 2001 From: MitchellHansen Date: Wed, 18 Oct 2017 22:10:31 -0700 Subject: [PATCH] Update video demo, tweaking my refactor of the maps. Working on downwards navigation in the oct traversal --- README.md | 2 +- include/map/Octree.h | 6 +- src/Application.cpp | 4 ++ src/CLCaster.cpp | 3 +- src/main.cpp | 12 +++- src/map/ArrayMap.cpp | 12 ++-- src/map/Octree.cpp | 140 +++++++++++++++++++++++++++++++++---------- 7 files changed, 131 insertions(+), 48 deletions(-) diff --git a/README.md b/README.md index ba41343..25e795b 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ In order to build this project you must have Cmake, GLEW, SFML, and the OpenCL d Video demo: -[![Video demo](http://img.youtube.com/vi/JmD5ISHbKbU/0.jpg)](http://www.youtube.com/watch?v=JmD5ISHbKbU) +[![Video demo](http://img.youtube.com/vi/LqmXZJR_gxU/0.jpg)](http://www.youtube.com/watch?v=LqmXZJr_gxU) Screenshots: diff --git a/include/map/Octree.h b/include/map/Octree.h index 174bbf5..2e34d34 100644 --- a/include/map/Octree.h +++ b/include/map/Octree.h @@ -92,10 +92,8 @@ public: static const uint64_t contour_mask = 0xFF00000000000000; std::vector> Octree::CastRayOctree( - Octree *octree, - sf::Vector3i* map_dim, - sf::Vector2f* cam_dir, - sf::Vector3f* cam_pos + sf::Vector2f cam_dir, + sf::Vector3f cam_pos ); private: diff --git a/src/Application.cpp b/src/Application.cpp index a866852..e581ec6 100644 --- a/src/Application.cpp +++ b/src/Application.cpp @@ -29,10 +29,14 @@ bool Application::init_clcaster() { map = std::make_shared(MAP_X); sf::Image bitmap = map->GenerateHeightBitmap(sf::Vector3i(MAP_X, MAP_Y, MAP_Z)); map->ApplyHeightmap(bitmap); + + map->octree.CastRayOctree(sf::Vector2f(1.5f, -2.0f), sf::Vector3f(5.0f, 5.0f, 5.0f)); raycaster->assign_octree(map); raycaster->assign_map(map); + + // Create a new camera with (starting position, direction) camera = std::make_shared( sf::Vector3f(50, 60, 10), diff --git a/src/CLCaster.cpp b/src/CLCaster.cpp index 0d23166..d735348 100644 --- a/src/CLCaster.cpp +++ b/src/CLCaster.cpp @@ -218,7 +218,8 @@ bool CLCaster::compute() { // There is a possibility that I would want to move this over to be all inside it's own // container to make it so it can be changed via CL_MEM_USE_HOST_PTR. But I doubt it -// would ever be called enough to warrent that +// would ever be called enough to warrant that +// TODO : Move CL interaction into the CLCaster? bool CLCaster::create_viewport(int width, int height, float v_fov, float h_fov) { // CL needs the screen resolution diff --git a/src/main.cpp b/src/main.cpp index 4abba57..9b917f4 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -12,21 +12,27 @@ * This project should not be viewed as a product or really anything other than * a cool little example on how real time volumetric ray marching is becoming * very possible on todays hardware. Don't expect this program to work on your hardware, - * preform as expected, have documentation, walk your dog, etc. + * perform as expected, have documentation, walk your dog, etc. * */ /** * TODO: + * * - Inconsistent lighting constants. GUI manipulation * + Ancillary settings buffer and memory controller * - Attachment lookup and aux buffer, contour lookup & masking * - Traversal algorithm + related stacks and data structures - * + Passing to GPU, Syncing? + * + Syncing, loading, unloading * - Octree, Map interface with the GPU - * - Octree, Map refactoring + * - Map/Oct raycasting algo that has parity with GPU * - Separate Application stages into areas that make sense * - Saving, loading of RLE voxel data and raw oct data + * - Bodgy mem sharing of lights with the GPU + * - Multi-stage rendering kernels + * - Multi light support via first-strike resetting + * - + * */ #include "Application.h" diff --git a/src/map/ArrayMap.cpp b/src/map/ArrayMap.cpp index 33d5852..276de59 100644 --- a/src/map/ArrayMap.cpp +++ b/src/map/ArrayMap.cpp @@ -8,14 +8,14 @@ ArrayMap::ArrayMap(sf::Vector3i dimensions) { voxel_data = new char[dimensions.x * dimensions.y * dimensions.z]; for (int i = 0; i < dimensions.x * dimensions.y * dimensions.z; i++) { - voxel_data[i] = 0; + voxel_data[i] = 1; } - for (int x = 0; x < dimensions.x; x++) { - for (int y = 0; y < dimensions.y; y++) { - setVoxel(sf::Vector3i(x, y, 1), 5); - } - } + //for (int x = 0; x < dimensions.x; x++) { + // for (int y = 0; y < dimensions.y; y++) { + // setVoxel(sf::Vector3i(x, y, 1), 5); + // } + //} } diff --git a/src/map/Octree.cpp b/src/map/Octree.cpp index 5bfbf8b..5bf0cb4 100644 --- a/src/map/Octree.cpp +++ b/src/map/Octree.cpp @@ -330,10 +330,6 @@ char Octree::get1DIndexedVoxel(char* data, sf::Vector3i dimensions, sf::Vector3i bool Octree::Validate(char* data, sf::Vector3i dimensions){ -// std::cout << (int)get1DIndexedVoxel(data, dimensions, sf::Vector3i(16, 16, 16)) << std::endl; -// std::cout << (int)GetVoxel(sf::Vector3i(16, 16, 16)) << std::endl; - - for (int x = 0; x < dimensions.x; x++) { for (int y = 0; y < dimensions.y; y++) { for (int z = 0; z < dimensions.z; z++) { @@ -348,7 +344,6 @@ bool Octree::Validate(char* data, sf::Vector3i dimensions){ std::cout << (int)arr_val << " : " << (int)oct_val << std::endl; return false; } - } } } @@ -362,10 +357,8 @@ unsigned int Octree::getDimensions() { std::vector> Octree::CastRayOctree( - Octree *octree, - sf::Vector3i* map_dim, - sf::Vector2f* cam_dir, - sf::Vector3f* cam_pos + sf::Vector2f cam_dir, + sf::Vector3f cam_pos ) { // Setup the voxel coords from the camera origin @@ -375,7 +368,7 @@ std::vector> Octree::CastRayOctree( // This function when passed an "air" voxel will return as far down // the IDX stack as it could go. We use this oct-level to determine // our first position and jump. Updating it as we go - OctState traversal_state = octree->GetVoxel(voxel); + OctState traversal_state = GetVoxel(voxel); std::vector> travel_path; @@ -383,15 +376,15 @@ std::vector> Octree::CastRayOctree( // Pitch ray_dir = sf::Vector3f( - ray_dir.z * sin((*cam_dir).x) + ray_dir.x * cos((*cam_dir).x), + 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) + 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.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 ); @@ -411,7 +404,7 @@ std::vector> Octree::CastRayOctree( voxel_step.z *= (ray_dir.z > 0) - (ray_dir.z < 0); // set the jump multiplier based on the traversal state vs the log base 2 of the maps dimensions - int jump_power = log2(map_dim->x) - traversal_state.scale; + int jump_power = log2(oct_dimensions) - traversal_state.scale; // Delta T is the units a ray must travel along an axis in order to @@ -424,21 +417,14 @@ std::vector> Octree::CastRayOctree( delta_t *= static_cast(jump_power); - // TODO: start here - // Whats the issue? - // Using traversal_scale - // set intersection t to the current hierarchy level each time we change levels - // and use that to step - - // Intersection T is the collection of the next intersection points // for all 3 axis XYZ. We take the full positive cardinality when // subtracting the floor, so we must transfer the sign over from // the voxel step 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 + 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 ); // When we transfer the sign over, we get the correct direction of @@ -494,6 +480,7 @@ std::vector> Octree::CastRayOctree( // If it decreased // Pop up the stack until the oct that the idx flip is valid and we landed on a valid oct while (traversal_state.idx_stack[traversal_state.scale] < prev_val || + // This will endless loop if we hit the empty portion of an octree and cant find a leaf until the we go OOB !((traversal_state.parent_stack[traversal_state.parent_stack_position] >> 16) & Octree::mask_8[mask_index]) ) { @@ -515,6 +502,11 @@ std::vector> Octree::CastRayOctree( traversal_state.parent_stack[traversal_state.parent_stack_position] = 0; traversal_state.parent_stack_position--; + // Compute the new (0,0,0) origin'd oct position + traversal_state.oct_pos.x = floor(traversal_state.oct_pos.x / pow(2, jump_power)) * pow(2, jump_power); + traversal_state.oct_pos.y = floor(traversal_state.oct_pos.y / pow(2, jump_power)) * pow(2, jump_power); + traversal_state.oct_pos.z = floor(traversal_state.oct_pos.z / pow(2, jump_power)) * pow(2, jump_power); + // Set the current CD to the one on top of the stack traversal_state.current_descriptor = traversal_state.parent_stack[traversal_state.parent_stack_position]; @@ -524,18 +516,100 @@ std::vector> Octree::CastRayOctree( mask_index = traversal_state.idx_stack[traversal_state.scale]; } + // At this point we are at the CP of an oct with a valid oct at the leaf indicated by the current idx in the idx stack + + while (jump_power > 1) { + + // Do the logic steps to find which sub oct we step down into + if (voxel.x >= (jump_power / 2) + traversal_state.oct_pos.x) { + + // Set our voxel position to the (0,0) of the correct oct + traversal_state.oct_pos.x += (jump_power / 2); + + // Set the idx to represent the move + traversal_state.idx_stack[traversal_state.scale] |= idx_set_x_mask; + + } + if (voxel.y >= (jump_power / 2) + traversal_state.oct_pos.y) { + + // TODO What the hell is going on with the or operator on this one!??!?!?! + traversal_state.oct_pos.y += (jump_power / 2); + + // TODO What is up with the XOR operator that was on this one? + traversal_state.idx_stack[traversal_state.scale] |= idx_set_y_mask; + + } + if (voxel.z >= (jump_power / 2) + traversal_state.oct_pos.z) { + + traversal_state.oct_pos.z += (jump_power / 2); + + traversal_state.idx_stack[traversal_state.scale] |= idx_set_z_mask; + + } + + // Our count mask matches the way we index our idx so we can just + // copy it over + int mask_index = traversal_state.idx_stack[traversal_state.scale]; + + // Check to see if we are on a valid oct + if ((traversal_state.parent_stack[traversal_state.parent_stack_position] >> 16) & mask_8[mask_index]) { + + // Check to see if it is a leaf + if ((traversal_state.parent_stack[traversal_state.parent_stack_position] >> 24) & mask_8[mask_index]) { + + // If it is, then we cannot traverse further as CP's won't have been generated + traversal_state.found = 1; + return; + } + + // If all went well and we found a valid non-leaf oct then we will traverse further down the hierarchy + traversal_state.scale++; + jump_power /= 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 = count_bits((uint8_t)(traversal_state.parent_stack[traversal_state.parent_stack_position] >> 16) & count_mask_8[mask_index]) - 1; + + // access the far point at which the head points too. Determine it's value, and add + // a count of the valid bits to the index + if (far_bit_mask & descriptor_buffer[current_index]) { + int far_pointer_index = current_index + (traversal_state.parent_stack[traversal_state.parent_stack_position] & child_pointer_mask); + current_index = descriptor_buffer[far_pointer_index] + count; + } + // access the element at which head points to and then add the specified number of indices + // to get to the correct child descriptor + else { + current_index = current_index + (traversal_state.parent_stack[traversal_state.parent_stack_position] & child_pointer_mask) + count; + } + + traversal_state.parent_stack[traversal_state.parent_stack_position] = descriptor_buffer[current_index]; + + // Increment the parent stack position and put the new oct node as the parent + traversal_state.parent_stack_position++; + traversal_state.parent_stack[traversal_state.parent_stack_position] = traversal_state.parent_stack[traversal_state.parent_stack_position]; + + } + 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 + traversal_state.found = 0; + return; + } + } + // Check to see if we are on a valid oct - //if ((traversal_state.parent_stack[traversal_state.parent_stack_position] >> 16) & Octree::mask_8[mask_index]) { + if ((traversal_state.parent_stack[traversal_state.parent_stack_position] >> 16) & Octree::mask_8[mask_index]) { - // // Check to see if it is a leaf - // if ((traversal_state.parent_stack[traversal_state.parent_stack_position] >> 24) & Octree::mask_8[mask_index]) { - // // If it is, then we cannot traverse further as CP's won't have been generated - // state.found = 1; - // return state; - // } - //} + + + } // Check to see if we are on top of a valid branch // Traverse down to the lowest valid oct that the ray is within