diff --git a/CMakeLists.txt b/CMakeLists.txt index 71e3f66f0693291e4a995f03943d5a020f8941fc..5d82d62ebc479996fd7eca4c974d6692fc55b821 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -412,11 +412,11 @@ add_subdirectory(${LIBLAVA_EXT_DIR}/assimp assimp) message("<<< assimp") -message(">>> cgal") +message("<<< boost") -add_subdirectory(${LIBLAVA_EXT_DIR}/cgal cgal) +add_subdirectory(${LIBLAVA_EXT_DIR}/boost boost) -message("<<< cgal") +message(">>> boost") option(LIBLAVA_TESTS "Enable Tests" TRUE) if(LIBLAVA_TESTS) @@ -791,7 +791,7 @@ message("======================================================================= strategy/mesh_based_reprojection/mesh_based_reprojection_indirect.frag strategy/mesh_based_reprojection/mesh_based_reprojection_indirect_shadow.frag strategy/mesh_based_reprojection/mesh_based_reprojection_edge_detection.comp - strategy/mesh_based_reprojection/mesh_based_reprojection_edge_preview.vert + strategy/mesh_based_reprojection/mesh_based_reprojection_edge_preview.vert strategy/mesh_based_reprojection/mesh_based_reprojection_edge_preview.frag utility/deferred_lighting.vert @@ -837,6 +837,35 @@ message("======================================================================= target_include_directories(${NAME} PUBLIC ${OPENVR_HEADER_DIR}) target_link_libraries(${NAME} "${CMAKE_SOURCE_DIR}/ext/openvr/lib/win64/openvr_api.lib") target_link_libraries(${NAME} "${CMAKE_SOURCE_DIR}/ext/cudart/lib/x64/cuda.lib") + + #Moudles required by the CGAL Library + target_link_libraries(${NAME} lava::app Boost::config) + target_link_libraries(${NAME} lava::app Boost::container) + target_link_libraries(${NAME} lava::app Boost::iterator) + target_link_libraries(${NAME} lava::app Boost::mpl) + target_link_libraries(${NAME} lava::app Boost::foreach) + target_link_libraries(${NAME} lava::app Boost::variant) + target_link_libraries(${NAME} lava::app Boost::random) + target_link_libraries(${NAME} lava::app Boost::property_map) + target_link_libraries(${NAME} lava::app Boost::tuple) + target_link_libraries(${NAME} lava::app Boost::math) + target_link_libraries(${NAME} lava::app Boost::algorithm) + target_link_libraries(${NAME} lava::app Boost::multiprecision) + target_link_libraries(${NAME} lava::app Boost::type_traits) + + #CGAL Library + set(CGAL_LIBRARY_DIR ${LIBLAVA_EXT_DIR}/cgal) + + file(GLOB CGAL_LIBRARY_PACKAGES RELATIVE ${CGAL_LIBRARY_DIR} "${CGAL_LIBRARY_DIR}/*") + list(REMOVE_ITEM CGAL_LIBRARY_PACKAGES .svn .git .reuse) + + foreach(package ${CGAL_LIBRARY_PACKAGES}) + if(IS_DIRECTORY "${CGAL_LIBRARY_DIR}/${package}") + if(EXISTS "${CGAL_LIBRARY_DIR}/${package}/package_info/${package}/maintainer") + target_include_directories(${NAME} PUBLIC "${CGAL_LIBRARY_DIR}/${package}/include") + endif() + endif() + endforeach() if(MSVC) source_group("" FILES ${SRC_DIR}/main.cpp) @@ -851,6 +880,49 @@ message("======================================================================= source_group("Strategy" REGULAR_EXPRESSION ${SRC_DIR}/strategy/*) source_group("Transport" REGULAR_EXPRESSION ${SRC_DIR}/transport/*) source_group("Utility" REGULAR_EXPRESSION ${SRC_DIR}/utility/*) + + set_target_properties(assimp PROPERTIES FOLDER "Extern") + set_target_properties(UpdateAssimpLibsDebugSymbolsAndDLLs PROPERTIES FOLDER "Extern") + set_target_properties(zlibstatic PROPERTIES FOLDER "Extern") + + set_target_properties(boost_assert PROPERTIES FOLDER "Extern") + set_target_properties(boost_atomic PROPERTIES FOLDER "Extern") + set_target_properties(boost_chrono PROPERTIES FOLDER "Extern") + set_target_properties(boost_container PROPERTIES FOLDER "Extern") + set_target_properties(boost_context PROPERTIES FOLDER "Extern") + set_target_properties(boost_contract PROPERTIES FOLDER "Extern") + set_target_properties(boost_core PROPERTIES FOLDER "Extern") + set_target_properties(boost_coroutine PROPERTIES FOLDER "Extern") + set_target_properties(boost_date_time PROPERTIES FOLDER "Extern") + set_target_properties(boost_exception PROPERTIES FOLDER "Extern") + set_target_properties(boost_fiber PROPERTIES FOLDER "Extern") + set_target_properties(boost_fiber_numa PROPERTIES FOLDER "Extern") + set_target_properties(boost_filesystem PROPERTIES FOLDER "Extern") + set_target_properties(boost_graph PROPERTIES FOLDER "Extern") + set_target_properties(boost_iostreams PROPERTIES FOLDER "Extern") + set_target_properties(boost_json PROPERTIES FOLDER "Extern") + set_target_properties(boost_locale PROPERTIES FOLDER "Extern") + set_target_properties(boost_log PROPERTIES FOLDER "Extern") + set_target_properties(boost_log_setup PROPERTIES FOLDER "Extern") + set_target_properties(boost_nowide PROPERTIES FOLDER "Extern") + set_target_properties(boost_prg_exec_monitor PROPERTIES FOLDER "Extern") + set_target_properties(boost_program_options PROPERTIES FOLDER "Extern") + set_target_properties(boost_random PROPERTIES FOLDER "Extern") + set_target_properties(boost_serialization PROPERTIES FOLDER "Extern") + set_target_properties(boost_stacktrace_basic PROPERTIES FOLDER "Extern") + set_target_properties(boost_stacktrace_noop PROPERTIES FOLDER "Extern") + set_target_properties(boost_stacktrace_windbg PROPERTIES FOLDER "Extern") + set_target_properties(boost_stacktrace_windbg_cached PROPERTIES FOLDER "Extern") + set_target_properties(boost_system PROPERTIES FOLDER "Extern") + set_target_properties(boost_test_exec_monitor PROPERTIES FOLDER "Extern") + set_target_properties(boost_thread PROPERTIES FOLDER "Extern") + set_target_properties(boost_timer PROPERTIES FOLDER "Extern") + set_target_properties(boost_type_erasure PROPERTIES FOLDER "Extern") + set_target_properties(boost_unit_test_framework PROPERTIES FOLDER "Extern") + set_target_properties(boost_url PROPERTIES FOLDER "Extern") + set_target_properties(boost_variant2 PROPERTIES FOLDER "Extern") + set_target_properties(boost_wave PROPERTIES FOLDER "Extern") + set_target_properties(boost_wserialization PROPERTIES FOLDER "Extern") endif() set_property(TARGET ${NAME} PROPERTY VS_DEBUGGER_WORKING_DIRECTORY "${PROJECT_BINARY_DIR}") diff --git a/res/dpr/strategy/mesh_based_reprojection/mesh_based_reprojection_edge_preview.vert b/res/dpr/strategy/mesh_based_reprojection/mesh_based_reprojection_edge_preview.vert index b573f79fcd694e1b481f73f2a7134a455c27a3f2..2fdcda3517042da4829d41b738295061ac23d6a2 100644 --- a/res/dpr/strategy/mesh_based_reprojection/mesh_based_reprojection_edge_preview.vert +++ b/res/dpr/strategy/mesh_based_reprojection/mesh_based_reprojection_edge_preview.vert @@ -13,7 +13,7 @@ layout(push_constant) uniform Parameters void main() { - vec2 coord = inPos / parameters.layer_resolution; + vec2 coord = (inPos + vec2(0.5)) / parameters.layer_resolution; gl_Position = vec4(coord * 2.0 - 1.0, 0.0, 1.0); } \ No newline at end of file diff --git a/src/scene.cpp b/src/scene.cpp index 11404f1237266739cdde19c509f05fd5f5777743..5eb9a53f6488386ce62def0bde7400641ea100f2 100644 --- a/src/scene.cpp +++ b/src/scene.cpp @@ -1197,19 +1197,19 @@ bool Scene::load_animations(const aiScene* scene, float scale, const std::map<st for (uint32_t frame_index = 0; frame_index < channel->mNumPositionKeys; frame_index++) { const aiVectorKey key = channel->mPositionKeys[frame_index]; - scene_channel.position_frames[frame_index] = std::make_pair((float)key.mTime / animation->mTicksPerSecond, glm::make_vec3(&key.mValue.x) * scale); + scene_channel.position_frames[frame_index] = std::make_pair((float)key.mTime / (float)animation->mTicksPerSecond, glm::make_vec3(&key.mValue.x) * scale); } for (uint32_t frame_index = 0; frame_index < channel->mNumRotationKeys; frame_index++) { const aiQuatKey key = channel->mRotationKeys[frame_index]; - scene_channel.rotation_frames[frame_index] = std::make_pair((float)key.mTime / animation->mTicksPerSecond, key.mValue); + scene_channel.rotation_frames[frame_index] = std::make_pair((float)key.mTime / (float)animation->mTicksPerSecond, key.mValue); } for (uint32_t frame_index = 0; frame_index < channel->mNumScalingKeys; frame_index++) { const aiVectorKey key = channel->mScalingKeys[frame_index]; - scene_channel.scaling_frames[frame_index] = std::make_pair((float)key.mTime / animation->mTicksPerSecond, glm::make_vec3(&key.mValue.x)); + scene_channel.scaling_frames[frame_index] = std::make_pair((float)key.mTime / (float)animation->mTicksPerSecond, glm::make_vec3(&key.mValue.x)); } } } diff --git a/src/strategy/mesh_based_reprojection.cpp b/src/strategy/mesh_based_reprojection.cpp index becc3e0ff0776a05a613aa2f2a7ec8caf75897f0..8aa20de721cebe623db6bd6f1e9b16d8039ad4ff 100644 --- a/src/strategy/mesh_based_reprojection.cpp +++ b/src/strategy/mesh_based_reprojection.cpp @@ -1,8 +1,15 @@ #include "mesh_based_reprojection.hpp" #include "vr_application.hpp" +#include <CGAL/Exact_predicates_inexact_constructions_kernel.h> +#include <CGAL/Constrained_Delaunay_triangulation_2.h> #include <imgui.h> +typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel; +typedef CGAL::Constrained_Delaunay_triangulation_2<Kernel, CGAL::Default, CGAL::Exact_predicates_tag> ConstrainedTriangulation; +typedef ConstrainedTriangulation::Point_2 Point2; +typedef ConstrainedTriangulation::Face_handle FaceHandle; + namespace glsl { using namespace glm; @@ -281,6 +288,9 @@ MeshBasedReprojection::MeshBasedReprojection() : worker_pool(1) { this->layer_descriptor_sets.fill(VK_NULL_HANDLE); this->edge_descriptor_sets.fill(VK_NULL_HANDLE); + + this->edge_preview_count.fill(0); + this->triangle_preview_count.fill(0); } bool MeshBasedReprojection::on_setup_instance(lava::frame_config& config) @@ -379,15 +389,17 @@ bool MeshBasedReprojection::on_interface() ImGui::SliderFloat("Edge Detection Laplacian Threshold", &this->edge_detection_laplacian_threshold, 0.0f, 1.0f); ImGui::SliderFloat("Edge Detection Normal Scale", &this->edge_detection_normal_scale, 0.0f, 2.0f); - ImGui::SliderFloat("Edge Detection Min Value", &this->edge_detection_min_value, 0.0f, 1.0f); - ImGui::SliderFloat("Edge Detection Min Distance", &this->edge_detection_min_distance, 0.0f, 5.0f); + ImGui::SliderInt("Edge Extraction Min Length", (int32_t*)&this->edge_extraction_min_length, 2, 20); + ImGui::SliderFloat("Edge Extraction Min Value", &this->edge_extraction_min_value, 0.0f, 1.0f); + ImGui::SliderFloat("Edge Extraction Min Distance", &this->edge_extraction_min_distance, 0.0f, 5.0f); std::vector<const char*> overlay_names = { "Color", "Normal", "Edge Detection", - "Edge Preview" + "Edge Preview", + "Triangle Preview" }; ImGui::Combo("Overlay", (int32_t*) &this->overlay, overlay_names.data(), overlay_names.size()); @@ -404,7 +416,7 @@ bool MeshBasedReprojection::on_update(lava::delta delta_time) std::unique_lock<std::mutex> lock(this->edge_buffer_mutex); if (this->edge_buffer_process_count > 0) { - double edge_buffer_process_time = (double) this->edge_buffer_process_time_sum / this->edge_buffer_process_count; + double edge_buffer_process_time = (double)this->edge_buffer_process_time_sum / this->edge_buffer_process_count; this->statistic_edge_buffer_time->add_sample(edge_buffer_process_time); @@ -540,6 +552,7 @@ const char* MeshBasedReprojection::get_name() const bool MeshBasedReprojection::create_buffers() { glm::uvec2 resolution = this->get_headset()->get_framebuffer_resolution(); + uint32_t depth_image_buffer_size = resolution.x * resolution.y * sizeof(float); uint32_t edge_image_buffer_size = resolution.x * resolution.y * sizeof(float); uint32_t edge_preview_buffer_size = MESH_BASED_REPROJECTION_EDGE_PEWVIEW_BUFFER_SIZE * 2 * sizeof(glm::vec2); @@ -628,15 +641,6 @@ bool MeshBasedReprojection::create_buffers() for (uint32_t index = 0; index < this->edge_buffers.size(); index++) { - lava::buffer::ptr image_buffer = lava::make_buffer(); - - if (!image_buffer->create_mapped(this->get_device(), nullptr, edge_image_buffer_size, VK_BUFFER_USAGE_TRANSFER_DST_BIT, VMA_MEMORY_USAGE_GPU_TO_CPU)) - { - lava::log()->error("Mesh based Reprojection: Can't create image buffer!"); - - return false; - } - VkSemaphoreCreateInfo semaphore_info; semaphore_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; semaphore_info.pNext = nullptr; @@ -660,10 +664,29 @@ bool MeshBasedReprojection::create_buffers() return false; } + lava::buffer::ptr depth_image_buffer = lava::make_buffer(); + + if (!depth_image_buffer->create_mapped(this->get_device(), nullptr, depth_image_buffer_size, VK_BUFFER_USAGE_TRANSFER_DST_BIT, VMA_MEMORY_USAGE_GPU_TO_CPU)) + { + lava::log()->error("Mesh based Reprojection: Can't create depth image buffer!"); + + return false; + } + + lava::buffer::ptr edge_image_buffer = lava::make_buffer(); + + if (!edge_image_buffer->create_mapped(this->get_device(), nullptr, edge_image_buffer_size, VK_BUFFER_USAGE_TRANSFER_DST_BIT, VMA_MEMORY_USAGE_GPU_TO_CPU)) + { + lava::log()->error("Mesh based Reprojection: Can't create edge image buffer!"); + + return false; + } + MeshBasedReprojectionEdgeBuffer::Ptr edge_buffer = make_mesh_based_reprojection_edge_buffer(); - edge_buffer->image_buffer = image_buffer; edge_buffer->semaphore = semaphore; edge_buffer->fence = fence; + edge_buffer->depth_image_buffer = depth_image_buffer; + edge_buffer->edge_image_buffer = edge_image_buffer; edge_buffer->quad_tree = make_mesh_based_reprojection_quad_tree(resolution); this->edge_buffers[index] = edge_buffer; @@ -1201,6 +1224,131 @@ bool MeshBasedReprojection::create_edge_preview_pipeline() return true; } +bool MeshBasedReprojection::create_triangle_preview_pass() +{ + lava::attachment::ptr color_attachment = lava::make_attachment(this->get_headset()->get_format()); + color_attachment->set_op(VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_STORE); + color_attachment->set_stencil_op(VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE); + color_attachment->set_layouts(VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + + lava::subpass::ptr subpass = lava::make_subpass(); + subpass->set_color_attachment(0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); + + lava::subpass_dependency::ptr subpass_begin_dependency = lava::make_subpass_dependency(VK_SUBPASS_EXTERNAL, 0); + subpass_begin_dependency->set_stage_mask(VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT); + subpass_begin_dependency->set_access_mask(VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT); + + lava::subpass_dependency::ptr subpass_end_dependency = lava::make_subpass_dependency(0, VK_SUBPASS_EXTERNAL); + subpass_end_dependency->set_stage_mask( VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); + subpass_end_dependency->set_access_mask(VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT); + + this->triangle_preview_pass = lava::make_render_pass(this->get_device()); + this->triangle_preview_pass->add(subpass); + this->triangle_preview_pass->add(subpass_begin_dependency); + this->triangle_preview_pass->add(subpass_end_dependency); + this->triangle_preview_pass->add(color_attachment); + + lava::rect framebuffer_area = + { + glm::vec2(0.0f), + this->get_headset()->get_framebuffer_resolution() + }; + + lava::VkAttachments framebuffer_views = + { + { this->get_headset()->get_framebuffer(EYE_LEFT)->get_view() }, + { this->get_headset()->get_framebuffer(EYE_RIGHT)->get_view() } + }; + + if (!this->triangle_preview_pass->create(framebuffer_views, framebuffer_area)) + { + lava::log()->error("Mesh Based Reprojection: Can't create triangle preview pass!"); + + return false; + } + + return true; +} + +bool MeshBasedReprojection::create_triangle_preview_pipeline() +{ + VkPushConstantRange constant_range; + constant_range.stageFlags = VK_SHADER_STAGE_VERTEX_BIT; + constant_range.offset = 0; + //constant_range.size = sizeof(glsl::MeshBasedReprojectionTrianglePreviewParameters); + + this->triangle_preview_pipeline_layout = lava::make_pipeline_layout(); + this->triangle_preview_pipeline_layout->add(constant_range); + + if (!this->edge_preview_pipeline_layout->create(this->get_device())) + { + lava::log()->error("Mesh Based Reprojection: Can't create edge preview pipeline layout!"); + + return false; + } + + VkVertexInputBindingDescription vertex_binding; + vertex_binding.binding = 0; + vertex_binding.stride = sizeof(glm::vec2); + vertex_binding.inputRate = VK_VERTEX_INPUT_RATE_VERTEX; + + VkVertexInputAttributeDescription vertex_attribute; + vertex_attribute.location = 0; + vertex_attribute.binding = 0; + vertex_attribute.format = VK_FORMAT_R32G32_SFLOAT; + vertex_attribute.offset = 0; + + VkPipelineColorBlendAttachmentState blend_state; + blend_state.blendEnable = VK_FALSE; + blend_state.srcColorBlendFactor = VK_BLEND_FACTOR_ZERO; + blend_state.dstColorBlendFactor = VK_BLEND_FACTOR_ZERO; + blend_state.colorBlendOp = VK_BLEND_OP_ADD; + blend_state.srcAlphaBlendFactor = VK_BLEND_FACTOR_ZERO; + blend_state.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO; + blend_state.alphaBlendOp = VK_BLEND_OP_ADD; + blend_state.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; + + this->edge_preview_pipeline = lava::make_graphics_pipeline(this->get_device()); + this->edge_preview_pipeline->set_layout(this->edge_preview_pipeline_layout); + this->edge_preview_pipeline->set_input_assembly_topology(VK_PRIMITIVE_TOPOLOGY_LINE_LIST); + this->edge_preview_pipeline->add_color_blend_attachment(blend_state); + this->edge_preview_pipeline->set_vertex_input_binding(vertex_binding); + this->edge_preview_pipeline->set_vertex_input_attributes( + { + vertex_attribute + }); + + if (!this->edge_preview_pipeline->add_shader(lava::file_data("dpr/binary/mesh_based_reprojection_edge_preview_vertex.spirv"), VK_SHADER_STAGE_VERTEX_BIT)) + { + lava::log()->error("Mesh Based Reprojection: Can't load vertex shader for edge preview pipeline!"); + + return false; + } + + if (!this->edge_preview_pipeline->add_shader(lava::file_data("dpr/binary/mesh_based_reprojection_edge_preview_fragment.spirv"), VK_SHADER_STAGE_FRAGMENT_BIT)) + { + lava::log()->error("Mesh Based Reprojection: Can't load fragment shader for edge preview pipeline!"); + + return false; + } + + this->edge_preview_pipeline->on_process = [this](VkCommandBuffer command_buffer) + { + this->process_edge_preview_pass(command_buffer); + }; + + if (!this->edge_preview_pipeline->create(this->edge_preview_pass->get())) + { + lava::log()->error("Mesh Based Reprojection: Can't create edge preview pipeline!"); + + return false; + } + + this->edge_preview_pass->add_front(this->edge_preview_pipeline); + + return true; +} + bool MeshBasedReprojection::build_projection() { this->layer_resolution = glm::uvec2(0); //NOTE: Will be used later @@ -1251,7 +1399,7 @@ bool MeshBasedReprojection::write_edge_preview(lava::index frame) edge_preview_buffer->flush(); - this->edge_preview_line_count[layer] = edge_count; + this->edge_preview_count[layer] = edge_count; } return true; @@ -1369,24 +1517,41 @@ bool MeshBasedReprojection::process_edge_buffer_copy(VkCommandBuffer command_buf { glm::uvec2 resolution = this->get_headset()->get_framebuffer_resolution(); - std::array<VkImageMemoryBarrier, 2> image_barriers; + std::array<VkImageMemoryBarrier, 4> image_barriers; for (uint32_t layer = 0; layer < 2; layer++) { - image_barriers[layer].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; - image_barriers[layer].pNext = nullptr; - image_barriers[layer].srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT; - image_barriers[layer].dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT; - image_barriers[layer].oldLayout = VK_IMAGE_LAYOUT_GENERAL; - image_barriers[layer].newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; - image_barriers[layer].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - image_barriers[layer].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - image_barriers[layer].image = this->layer_edge_buffers[layer]->get(); - image_barriers[layer].subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - image_barriers[layer].subresourceRange.baseMipLevel = 0; - image_barriers[layer].subresourceRange.levelCount = 1; - image_barriers[layer].subresourceRange.baseArrayLayer = 0; - image_barriers[layer].subresourceRange.layerCount = 1; + VkImageMemoryBarrier& depth_barrier = image_barriers[layer * 2]; + depth_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + depth_barrier.pNext = nullptr; + depth_barrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT; + depth_barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT; + depth_barrier.oldLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + depth_barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; + depth_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + depth_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + depth_barrier.image = this->layer_depth_buffers[layer]->get(); + depth_barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; + depth_barrier.subresourceRange.baseMipLevel = 0; + depth_barrier.subresourceRange.levelCount = 1; + depth_barrier.subresourceRange.baseArrayLayer = 0; + depth_barrier.subresourceRange.layerCount = 1; + + VkImageMemoryBarrier& edge_barrier = image_barriers[layer * 2 + 1]; + edge_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + edge_barrier.pNext = nullptr; + edge_barrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT; + edge_barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT; + edge_barrier.oldLayout = VK_IMAGE_LAYOUT_GENERAL; + edge_barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; + edge_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + edge_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + edge_barrier.image = this->layer_edge_buffers[layer]->get(); + edge_barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + edge_barrier.subresourceRange.baseMipLevel = 0; + edge_barrier.subresourceRange.levelCount = 1; + edge_barrier.subresourceRange.baseArrayLayer = 0; + edge_barrier.subresourceRange.layerCount = 1; } vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, image_barriers.size(), image_barriers.data()); @@ -1402,35 +1567,42 @@ bool MeshBasedReprojection::process_edge_buffer_copy(VkCommandBuffer command_buf return true; } - VkBufferImageCopy image_copy; - image_copy.bufferOffset = 0; - image_copy.bufferRowLength = 0; - image_copy.bufferImageHeight = 0; - image_copy.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - image_copy.imageSubresource.mipLevel = 0; - image_copy.imageSubresource.baseArrayLayer = 0; - image_copy.imageSubresource.layerCount = 1; - image_copy.imageOffset.x = 0; - image_copy.imageOffset.y = 0; - image_copy.imageOffset.z = 0; - image_copy.imageExtent.width = resolution.x; - image_copy.imageExtent.height = resolution.y; - image_copy.imageExtent.depth = 1; - - vkCmdCopyImageToBuffer(command_buffer, this->layer_edge_buffers[layer]->get(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, edge_buffer->image_buffer->get(), 1, &image_copy); - - VkBufferMemoryBarrier buffer_barrier; - buffer_barrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER; - buffer_barrier.pNext = 0; - buffer_barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - buffer_barrier.dstAccessMask = VK_ACCESS_HOST_READ_BIT; - buffer_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - buffer_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - buffer_barrier.buffer = edge_buffer->image_buffer->get(); - buffer_barrier.offset = 0; - buffer_barrier.size = VK_WHOLE_SIZE; - - vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0, 0, nullptr, 1, &buffer_barrier, 0, nullptr); + VkBufferImageCopy depth_copy; + depth_copy.bufferOffset = 0; + depth_copy.bufferRowLength = 0; + depth_copy.bufferImageHeight = 0; + depth_copy.imageSubresource.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; + depth_copy.imageSubresource.mipLevel = 0; + depth_copy.imageSubresource.baseArrayLayer = 0; + depth_copy.imageSubresource.layerCount = 1; + depth_copy.imageOffset.x = 0; + depth_copy.imageOffset.y = 0; + depth_copy.imageOffset.z = 0; + depth_copy.imageExtent.width = resolution.x; + depth_copy.imageExtent.height = resolution.y; + depth_copy.imageExtent.depth = 1; + + VkBufferImageCopy edge_copy = depth_copy; + edge_copy.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + + vkCmdCopyImageToBuffer(command_buffer, this->layer_depth_buffers[layer]->get(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, edge_buffer->depth_image_buffer->get(), 1, &depth_copy); + vkCmdCopyImageToBuffer(command_buffer, this->layer_edge_buffers[layer]->get(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, edge_buffer->edge_image_buffer->get(), 1, &edge_copy); + + std::array<VkBufferMemoryBarrier, 2> buffer_barriers; + buffer_barriers[0].sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER; + buffer_barriers[0].pNext = 0; + buffer_barriers[0].srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + buffer_barriers[0].dstAccessMask = VK_ACCESS_HOST_READ_BIT; + buffer_barriers[0].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + buffer_barriers[0].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + buffer_barriers[0].buffer = edge_buffer->depth_image_buffer->get(); + buffer_barriers[0].offset = 0; + buffer_barriers[0].size = VK_WHOLE_SIZE; + + buffer_barriers[1] = buffer_barriers[0]; + buffer_barriers[1].buffer = edge_buffer->edge_image_buffer->get(); + + vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0, 0, nullptr, buffer_barriers.size(), buffer_barriers.data(), 0, nullptr); VkFence fence = edge_buffer->fence->get(); @@ -1485,7 +1657,7 @@ bool MeshBasedReprojection::process_edge_buffer_copy(VkCommandBuffer command_buf void MeshBasedReprojection::process_edge_preview_pass(VkCommandBuffer command_buffer) { uint32_t frame_index = this->get_application()->get_frame_index(); - uint32_t edge_line_count = this->edge_preview_line_count[this->layer_index] * 2; + uint32_t edge_count = this->edge_preview_count[this->layer_index]; VkBuffer edge_preview_buffer = this->edge_preview_buffers[this->layer_index][frame_index]->get(); glsl::MeshBasedReprojectionEdgePreviewParameters parameters; @@ -1496,7 +1668,7 @@ void MeshBasedReprojection::process_edge_preview_pass(VkCommandBuffer command_bu VkDeviceSize offset = 0; vkCmdBindVertexBuffers(command_buffer, 0, 1, &edge_preview_buffer, &offset); - vkCmdDraw(command_buffer, edge_line_count, 1, 0, 0); + vkCmdDraw(command_buffer, edge_count * 2, 1, 0, 0); } bool MeshBasedReprojection::acquire_edge_buffer(MeshBasedReprojectionEdgeBuffer::Ptr& edge_buffer) @@ -1525,14 +1697,16 @@ void MeshBasedReprojection::worker_process_edge_buffer(uint32_t layer, MeshBased { std::chrono::high_resolution_clock::time_point start = std::chrono::high_resolution_clock::now(); - if(!edge_buffer->quad_tree->fill(edge_buffer->image_buffer)) + if(!edge_buffer->quad_tree->fill(edge_buffer->edge_image_buffer)) { lava::log()->error("Mesh Based Reprojection: Can't fill quad tree!"); return; } + std::vector<glm::ivec2> edge_points; edge_buffer->edges.clear(); + edge_buffer->triangles.clear(); while (true) { @@ -1544,7 +1718,7 @@ void MeshBasedReprojection::worker_process_edge_buffer(uint32_t layer, MeshBased break; } - if (value < this->edge_detection_min_value) + if (value < this->edge_extraction_min_value) { break; } @@ -1554,7 +1728,7 @@ void MeshBasedReprojection::worker_process_edge_buffer(uint32_t layer, MeshBased break; } - this->edge_points.clear(); + edge_points.clear(); glm::ivec2 end = start; while (true) @@ -1566,7 +1740,7 @@ void MeshBasedReprojection::worker_process_edge_buffer(uint32_t layer, MeshBased break; } - if (value < this->edge_detection_min_value) + if (value < this->edge_extraction_min_value) { break; } @@ -1576,21 +1750,21 @@ void MeshBasedReprojection::worker_process_edge_buffer(uint32_t layer, MeshBased break; } - this->edge_points.push_back(next); + edge_points.push_back(next); end = next; } - if (this->edge_points.size() > 10) + if (edge_points.size() > this->edge_extraction_min_length) { int32_t start_index = 0; int32_t end_index = 0; - while (start_index < this->edge_points.size() - 1) + while (start_index < edge_points.size() - 1) { - for (end_index = this->edge_points.size() - 1; end_index > start_index; end_index--) + for (end_index = edge_points.size() - 1; end_index > start_index; end_index--) { - glm::ivec2 edge_start = this->edge_points[start_index]; - glm::ivec2 edge_end = this->edge_points[end_index]; + glm::ivec2 edge_start = edge_points[start_index]; + glm::ivec2 edge_end = edge_points[end_index]; glm::vec2 edge_direction = glm::normalize(glm::vec2(edge_end - edge_start)); glm::vec2 edge_normal = glm::vec2(-edge_direction.y, edge_direction.x); @@ -1599,10 +1773,10 @@ void MeshBasedReprojection::worker_process_edge_buffer(uint32_t layer, MeshBased for (uint32_t check_index = start_index + 1; check_index < end_index - 1; check_index++) { - glm::ivec2 edge_point = this->edge_points[check_index]; + glm::ivec2 edge_point = edge_points[check_index]; float edge_distance = glm::abs(glm::dot(glm::vec2(edge_point - edge_start), edge_normal)); - if (edge_distance > this->edge_detection_min_distance) + if (edge_distance > this->edge_extraction_min_distance) { outside = true; @@ -1617,8 +1791,8 @@ void MeshBasedReprojection::worker_process_edge_buffer(uint32_t layer, MeshBased } MeshBasedReprojectionEdge edge; - edge.start = this->edge_points[start_index]; - edge.end = this->edge_points[end_index]; + edge.start = edge_points[start_index]; + edge.end = edge_points[end_index]; edge_buffer->edges.push_back(edge); @@ -1627,17 +1801,53 @@ void MeshBasedReprojection::worker_process_edge_buffer(uint32_t layer, MeshBased } } - this->edge_points.clear(); + glm::vec2 resolution = this->get_headset()->get_framebuffer_resolution(); + + Point2 border_point1 = Point2(0.0, 0.0); + Point2 border_point2 = Point2(0.0, resolution.y); + Point2 border_point3 = Point2(resolution.x, resolution.y); + Point2 border_point4 = Point2(resolution.x, 0.0); + + ConstrainedTriangulation triangluation; + triangluation.insert_constraint(border_point1, border_point2); + triangluation.insert_constraint(border_point2, border_point3); + triangluation.insert_constraint(border_point3, border_point4); + triangluation.insert_constraint(border_point4, border_point1); + + for (const MeshBasedReprojectionEdge& edge : edge_buffer->edges) + { + Point2 edge_start = Point2(edge.start.x, edge.start.y); + Point2 edge_end = Point2(edge.end.x, edge.end.y); + + triangluation.insert_constraint(edge_start, edge_end); + } + + for (FaceHandle face_handle : triangluation.all_face_handles()) + { + Point2 point1 = face_handle->vertex(0)->point(); + Point2 point2 = face_handle->vertex(1)->point(); + Point2 point3 = face_handle->vertex(2)->point(); + + //TODO: Add depth + + MeshBasedReprojectionTriangle triangle; + triangle.point1 = glm::vec3(point1.x(), point1.y(), 0.0f); + triangle.point2 = glm::vec3(point2.x(), point2.y(), 0.0f); + triangle.point3 = glm::vec3(point3.x(), point3.y(), 0.0f); + + edge_buffer->triangles.push_back(triangle); + } std::chrono::high_resolution_clock::time_point end = std::chrono::high_resolution_clock::now(); double time = std::chrono::duration_cast<std::chrono::duration<double, std::chrono::milliseconds::period>>(end - start).count(); - lava::log()->debug("Edge Count: " + std::to_string(edge_buffer->edges.size())); - std::unique_lock<std::mutex> lock(this->edge_buffer_mutex); this->edge_preview_list[layer].clear(); this->edge_preview_list[layer].insert(this->edge_preview_list[layer].begin(), edge_buffer->edges.begin(), edge_buffer->edges.end()); + this->triangle_preview_list[layer].clear(); + this->triangle_preview_list[layer].insert(this->triangle_preview_list[layer].begin(), edge_buffer->triangles.begin(), edge_buffer->triangles.end()); + this->edge_buffer_process_count += 1; this->edge_buffer_process_time_sum += time; lock.unlock(); diff --git a/src/strategy/mesh_based_reprojection.hpp b/src/strategy/mesh_based_reprojection.hpp index 234efdb97974f5ec22ecdeb7157cfbe076442c67..cc5de2e122149d9c8463873c38598619733461d5 100644 --- a/src/strategy/mesh_based_reprojection.hpp +++ b/src/strategy/mesh_based_reprojection.hpp @@ -10,14 +10,15 @@ #include "utility/statistic.hpp" #define MESH_BASED_REPROJECTION_EDGE_BUFFER_COUNT 32 -#define MESH_BASED_REPROJECTION_EDGE_PEWVIEW_BUFFER_SIZE 1024 +#define MESH_BASED_REPROJECTION_EDGE_PEWVIEW_BUFFER_SIZE 2048 enum MeshBasedReprojectionOverlay { MESH_BASED_REPROJECTION_OVERLAY_COLOR, MESH_BASED_REPROJECTION_OVERLAY_NORMAL, MESH_BASED_REPROJECTION_OVERLAY_EDGE_DETECTION, - MESH_BASED_REPROJECTION_OVERLAY_EDGE_PREVIEW + MESH_BASED_REPROJECTION_OVERLAY_EDGE_PREVIEW, + MESH_BASED_REPROJECTION_OVERLAY_TRIANGLE_PREVIEW }; struct MeshBasedReprojectionEdge @@ -26,6 +27,13 @@ struct MeshBasedReprojectionEdge glm::ivec2 end; }; +struct MeshBasedReprojectionTriangle +{ + glm::vec3 point1; + glm::vec3 point2; + glm::vec3 point3; +}; + class MeshBasedReprojectionQuadTreeLevel { public: @@ -70,14 +78,16 @@ public: typedef std::shared_ptr<MeshBasedReprojectionEdgeBuffer> Ptr; public: - lava::buffer::ptr image_buffer; - VkSemaphore semaphore = VK_NULL_HANDLE; ExternFence::Ptr fence; - std::vector<MeshBasedReprojectionEdge> edges; + lava::buffer::ptr depth_image_buffer; + lava::buffer::ptr edge_image_buffer; MeshBasedReprojectionQuadTree::Ptr quad_tree; + + std::vector<MeshBasedReprojectionEdge> edges; + std::vector<MeshBasedReprojectionTriangle> triangles; }; class MeshBasedReprojection : public StereoStrategy @@ -110,15 +120,19 @@ private: bool create_edge_detection_pipeline(); bool create_edge_preview_pass(); bool create_edge_preview_pipeline(); + bool create_triangle_preview_pass(); + bool create_triangle_preview_pipeline(); bool build_projection(); bool write_transform(lava::index frame); bool write_edge_preview(lava::index frame); + bool write_triangle_preview(lava::index frame); void process_layer_pass(VkCommandBuffer command_buffer); void process_edge_detection_pass(VkCommandBuffer command_buffer); bool process_edge_buffer_copy(VkCommandBuffer command_buffer); void process_edge_preview_pass(VkCommandBuffer command_buffer); + void process_triangle_preview_pass(VkCommandBuffer command_buffer); bool acquire_edge_buffer(MeshBasedReprojectionEdgeBuffer::Ptr& edge_buffer); void release_edge_buffer(MeshBasedReprojectionEdgeBuffer::Ptr edge_buffer); @@ -135,8 +149,9 @@ private: float edge_detection_laplacian_threshold = 0.01f; float edge_detection_normal_scale = 0.0f; - float edge_detection_min_value = 0.01f; - float edge_detection_min_distance = 1.0f; + uint32_t edge_extraction_min_length = 10; + float edge_extraction_min_value = 0.01f; + float edge_extraction_min_distance = 1.0f; private: asio::thread_pool worker_pool; @@ -149,19 +164,21 @@ private: std::vector<lava::buffer::ptr> transform_buffers; std::array<std::vector<lava::buffer::ptr>, 2> edge_preview_buffers; + std::array<std::vector<lava::buffer::ptr>, 2> triangle_preview_buffers; std::array<lava::image::ptr, 2> layer_depth_buffers; std::array<lava::image::ptr, 2> layer_normal_buffers; std::array<lava::image::ptr, 2> layer_edge_buffers; std::mutex edge_buffer_mutex; std::vector<MeshBasedReprojectionEdgeBuffer::Ptr> edge_buffers; - std::vector<MeshBasedReprojectionEdgeBuffer::Ptr> edge_buffer_pool; //NOTE: Protected by edge_buffer_mutex - std::array<std::vector<MeshBasedReprojectionEdge>, 2> edge_preview_list; //NOTE: Protected by edge_buffer_mutex - std::vector<glm::ivec2> edge_points; //NOTE: Owned by worker_thread - uint32_t edge_buffer_process_count = 0; //NOTE: Protected by edge_buffer_mutex - double edge_buffer_process_time_sum = 0.0; //NOTE: Protected by edge_buffer_mutex + std::vector<MeshBasedReprojectionEdgeBuffer::Ptr> edge_buffer_pool; //NOTE: Protected by edge_buffer_mutex + std::array<std::vector<MeshBasedReprojectionEdge>, 2> edge_preview_list; //NOTE: Protected by edge_buffer_mutex + std::array<std::vector<MeshBasedReprojectionTriangle>, 2> triangle_preview_list; //NOTE: Protected by edge_buffer_mutex + uint32_t edge_buffer_process_count = 0; //NOTE: Protected by edge_buffer_mutex + double edge_buffer_process_time_sum = 0.0; //NOTE: Protected by edge_buffer_mutex - std::array<uint32_t, 2> edge_preview_line_count; + std::array<uint32_t, 2> edge_preview_count; + std::array<uint32_t, 2> triangle_preview_count; lava::descriptor::pool::ptr descriptor_pool; lava::descriptor::ptr transform_descriptor; @@ -184,6 +201,10 @@ private: lava::pipeline_layout::ptr edge_preview_pipeline_layout; lava::graphics_pipeline::ptr edge_preview_pipeline; + lava::render_pass::ptr triangle_preview_pass; + lava::pipeline_layout::ptr triangle_preview_pipeline_layout; + lava::graphics_pipeline::ptr triangle_preview_pipeline; + private: Statistic::Ptr statistic_edge_buffer_time; };