From e4c89a265127e48d99ab66a5df19663786332093 Mon Sep 17 00:00:00 2001 From: Xiang Silian Date: Wed, 17 Sep 2025 22:47:48 +0800 Subject: [PATCH] =?UTF-8?q?=E5=8A=A0=E5=85=A5=E6=B8=B2=E6=9F=93=E7=82=B9?= =?UTF-8?q?=E7=9A=84=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- samples/api/texture_loading/CMakeLists.txt | 2 + .../api/texture_loading/texture_loading.cpp | 291 +++++++++++++++++- samples/api/texture_loading/texture_loading.h | 26 +- 3 files changed, 311 insertions(+), 8 deletions(-) diff --git a/samples/api/texture_loading/CMakeLists.txt b/samples/api/texture_loading/CMakeLists.txt index 3f225e5..ab43932 100644 --- a/samples/api/texture_loading/CMakeLists.txt +++ b/samples/api/texture_loading/CMakeLists.txt @@ -30,6 +30,8 @@ add_sample_with_tags( "texture_loading/glsl/texture.frag" "texture_loading/glsl/bg.vert" "texture_loading/glsl/bg.frag" + "texture_loading/glsl/pointcloud.vert" + "texture_loading/glsl/pointcloud.frag" SHADER_FILES_HLSL "texture_loading/hlsl/texture.vert.hlsl" "texture_loading/hlsl/texture.frag.hlsl") \ No newline at end of file diff --git a/samples/api/texture_loading/texture_loading.cpp b/samples/api/texture_loading/texture_loading.cpp index 8cc2692..ecd3b58 100644 --- a/samples/api/texture_loading/texture_loading.cpp +++ b/samples/api/texture_loading/texture_loading.cpp @@ -43,6 +43,15 @@ TextureLoading::~TextureLoading() vkDestroyPipelineLayout(get_device().get_handle(), pipeline_layout_bg, nullptr); vkDestroyDescriptorSetLayout(get_device().get_handle(), descriptor_set_layout, nullptr); vkDestroyDescriptorSetLayout(get_device().get_handle(), descriptor_set_layout_bg, nullptr); + if (point_pipeline) { + vkDestroyPipeline(get_device().get_handle(), point_pipeline, nullptr); + } + if (point_pipeline_layout) { + vkDestroyPipelineLayout(get_device().get_handle(), point_pipeline_layout, nullptr); + } + if (point_descriptor_set_layout) { + vkDestroyDescriptorSetLayout(get_device().get_handle(), point_descriptor_set_layout, nullptr); + } } destroy_texture(texture); @@ -51,6 +60,9 @@ TextureLoading::~TextureLoading() vertex_buffer.reset(); index_buffer.reset(); uniform_buffer_vs.reset(); + + + point_vertex_buffer.reset(); // BufferC 会自动清理 //stop(); } @@ -490,14 +502,16 @@ void TextureLoading::build_command_buffers() vkCmdBindPipeline(draw_cmd_buffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines.background); vkCmdDraw(draw_cmd_buffers[i], 6, 1, 0, 0); - vkCmdBindDescriptorSets(draw_cmd_buffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout, 0, 1, &descriptor_set, 0, NULL); - vkCmdBindPipeline(draw_cmd_buffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines.solid); + //vkCmdBindDescriptorSets(draw_cmd_buffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout, 0, 1, &descriptor_set, 0, NULL); + //vkCmdBindPipeline(draw_cmd_buffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines.solid); - VkDeviceSize offsets[1] = { 0 }; - vkCmdBindVertexBuffers(draw_cmd_buffers[i], 0, 1, vertex_buffer->get(), offsets); - vkCmdBindIndexBuffer(draw_cmd_buffers[i], index_buffer->get_handle(), 0, VK_INDEX_TYPE_UINT32); + //VkDeviceSize offsets[1] = { 0 }; + //vkCmdBindVertexBuffers(draw_cmd_buffers[i], 0, 1, vertex_buffer->get(), offsets); + //vkCmdBindIndexBuffer(draw_cmd_buffers[i], index_buffer->get_handle(), 0, VK_INDEX_TYPE_UINT32); - vkCmdDrawIndexed(draw_cmd_buffers[i], index_count, 1, 0, 0, 0); + //vkCmdDrawIndexed(draw_cmd_buffers[i], index_count, 1, 0, 0, 0); + + draw_point_cloud(draw_cmd_buffers[i]); draw_ui(draw_cmd_buffers[i]); @@ -510,8 +524,15 @@ void TextureLoading::build_command_buffers() void TextureLoading::draw() { std::unique_lock lock(mtx); + std::unique_lock lock_point(mtx_point); ApiVulkanSample::prepare_frame(); + // --- 新增:在命令缓冲区中绘制点云 --- + // 在 build_command_buffers 中已经构建了命令缓冲区,但点数据是动态的。 + // 因此,我们在这里重新记录命令缓冲区。 + // 注意:更高效的做法是使用动态顶点缓冲区或间接绘制,但对于 Demo 来说,重新记录是可以接受的。 + build_command_buffers(); // 重新构建所有命令缓冲区以包含最新的点云 + // Command buffer to be submitted to the queue submit_info.commandBufferCount = 1; submit_info.pCommandBuffers = &draw_cmd_buffers[current_buffer]; @@ -918,6 +939,10 @@ bool TextureLoading::prepare(const vkb::ApplicationOptions& options) setup_descriptor_set(); setup_descriptor_set_bg(); build_command_buffers(); + + setup_point_descriptor_set_layout(); + setup_point_descriptor_set(); + prepare_point_pipeline(); prepared = true; //start(); return true; @@ -996,6 +1021,16 @@ void TextureLoadProcessWithVulkan(uint8_t* data, int width, int height, int rowS TextureLoading::Get()->processWithVulkan(data, width, height, rowStride, dataSize, cam_tex); } +void ReceiveFacePoint(float* pos, int pointCount, int width, int height) +{ + //for (int i = 0; i < pointCount; i++) { + // float x = pos[i * 3]; + // float y = pos[i * 3 + 1]; + // float z = pos[i * 3 + 2]; + //} + TextureLoading::Get()->update_point_vertex_buffer(pos, pointCount); +} + void TextureLoading::processWithVulkan(uint8_t* data, int width, int height, int rowStride, size_t dataSize, Texture& out_texture) { std::unique_lock lock(mtx); @@ -1289,3 +1324,247 @@ void TextureLoading::transitionImageLayout(VkCommandBuffer commandBuffer, VkImag vkCmdPipelineBarrier(commandBuffer, sourceStage, destinationStage, 0, 0, nullptr, 0, nullptr, 1, &barrier); } + +void TextureLoading::setup_point_descriptor_set_layout() +{ + // --- 修改:为点云 UBO 创建描述符集布局绑定,指向 binding 0 --- + VkDescriptorSetLayoutBinding ubo_layout_binding{}; + ubo_layout_binding.binding = 0; // 与着色器中的 layout(binding = 0) 匹配 + ubo_layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + ubo_layout_binding.descriptorCount = 1; + ubo_layout_binding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT; // 仅在顶点着色器中使用 + ubo_layout_binding.pImmutableSamplers = nullptr; + + VkDescriptorSetLayoutCreateInfo layout_info{ VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO }; + layout_info.bindingCount = 1; + layout_info.pBindings = &ubo_layout_binding; // 指向我们的 UBO 绑定 + + VK_CHECK(vkCreateDescriptorSetLayout(get_device().get_handle(), &layout_info, nullptr, &point_descriptor_set_layout)); + // --- 修改结束 --- +} + +void TextureLoading::setup_point_descriptor_set() +{ + // --- 修改:分配点云描述符集 --- + VkDescriptorSetAllocateInfo alloc_info{ VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO }; + alloc_info.descriptorPool = descriptor_pool; // 使用您已有的描述符池 + alloc_info.descriptorSetCount = 1; + alloc_info.pSetLayouts = &point_descriptor_set_layout; + + VK_CHECK(vkAllocateDescriptorSets(get_device().get_handle(), &alloc_info, &point_descriptor_set)); + // --- 修改结束 --- + + // --- 新增:更新点云描述符集,指向已有的 uniform_buffer_vs --- + update_point_descriptor_set(); // 调用辅助函数进行更新 + // --- 新增结束 --- +} + + +// --- 新增:更新点云描述符集以指向 uniform_buffer_vs 的辅助函数 --- +void TextureLoading::update_point_descriptor_set() +{ + if (!uniform_buffer_vs) { // 检查主 UBO 缓冲区是否存在 + LOGW("Main uniform buffer (uniform_buffer_vs) not created yet, cannot update point descriptor set."); + return; + } + + VkDescriptorBufferInfo buffer_info{}; + buffer_info.buffer = uniform_buffer_vs->get_handle(); + // 关键:指定要绑定的 UBO 数据在缓冲区中的范围 + // 我们绑定整个 ubo_vs,因为着色器只访问前两个 mat4,其余部分被忽略但不影响 + buffer_info.offset = 0; + buffer_info.range = sizeof(ubo_vs); // 绑定整个结构体 + + VkWriteDescriptorSet descriptor_write{ VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET }; + descriptor_write.dstSet = point_descriptor_set; // 目标描述符集 + descriptor_write.dstBinding = 0; // 目标绑定 (binding = 0) + descriptor_write.dstArrayElement = 0; // 数组元素索引 (非数组) + descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + descriptor_write.descriptorCount = 1; // 更新一个描述符 + descriptor_write.pBufferInfo = &buffer_info; // 指向缓冲区信息 + // pImageInfo 和 pTexelBufferView 对于 Uniform Buffer 不需要 + + vkUpdateDescriptorSets(get_device().get_handle(), 1, &descriptor_write, 0, nullptr); +} +// --- 新增结束 --- + +void TextureLoading::prepare_point_pipeline() +{ + // 创建管线布局 + VkPipelineLayoutCreateInfo pipeline_layout_create_info{ VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO }; + pipeline_layout_create_info.setLayoutCount = 1; + pipeline_layout_create_info.pSetLayouts = &point_descriptor_set_layout; + // 没有 push constants + pipeline_layout_create_info.pushConstantRangeCount = 0; + pipeline_layout_create_info.pPushConstantRanges = nullptr; + + VK_CHECK(vkCreatePipelineLayout(get_device().get_handle(), &pipeline_layout_create_info, nullptr, &point_pipeline_layout)); + + // 加载着色器 + std::array shader_stages; + shader_stages[0] = load_shader("pointcloud.vert.spv", VK_SHADER_STAGE_VERTEX_BIT); + shader_stages[1] = load_shader("pointcloud.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT); + + // 顶点输入绑定描述 (告诉 Vulkan 顶点数据的格式) + VkVertexInputBindingDescription vertex_input_binding_description{}; + vertex_input_binding_description.binding = 0; // 绑定点 + vertex_input_binding_description.stride = sizeof(PointVertex); // 每个顶点的字节大小 + vertex_input_binding_description.inputRate = VK_VERTEX_INPUT_RATE_VERTEX; + + // 顶点输入属性描述 (告诉 Vulkan 每个属性在顶点结构中的位置) + std::array vertex_input_attributes = { + VkVertexInputAttributeDescription{0, 0, VK_FORMAT_R32G32B32_SFLOAT, offsetof(PointVertex, x)}, // 位置 + VkVertexInputAttributeDescription{1, 0, VK_FORMAT_R32G32B32_SFLOAT, offsetof(PointVertex, r)} // 颜色 + }; + + VkPipelineVertexInputStateCreateInfo vertex_input_state{ VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO }; + vertex_input_state.vertexBindingDescriptionCount = 1; + vertex_input_state.pVertexBindingDescriptions = &vertex_input_binding_description; + vertex_input_state.vertexAttributeDescriptionCount = static_cast(vertex_input_attributes.size()); + vertex_input_state.pVertexAttributeDescriptions = vertex_input_attributes.data(); + + // 输入装配 (绘制点列表) + VkPipelineInputAssemblyStateCreateInfo input_assembly_state{ VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO }; + input_assembly_state.topology = VK_PRIMITIVE_TOPOLOGY_POINT_LIST; // 关键:绘制点 + input_assembly_state.primitiveRestartEnable = VK_FALSE; + + // 视口和裁剪 + VkPipelineViewportStateCreateInfo viewport_state{ VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO }; + viewport_state.viewportCount = 1; + viewport_state.scissorCount = 1; + + // 光栅化 + VkPipelineRasterizationStateCreateInfo rasterization_state{ VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO }; + rasterization_state.polygonMode = VK_POLYGON_MODE_FILL; + rasterization_state.cullMode = VK_CULL_MODE_NONE; // 通常不对点进行剔除 + rasterization_state.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE; + rasterization_state.lineWidth = 1.0f; // 可以通过 VkPhysicalDeviceFeatures::wideLines 扩展来支持更宽的线 + + // 多重采样 + VkPipelineMultisampleStateCreateInfo multisample_state{ VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO }; + multisample_state.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; + + // 深度和模板测试 (通常对点云启用深度测试) + VkPipelineDepthStencilStateCreateInfo depth_stencil_state{ VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO }; + depth_stencil_state.depthTestEnable = VK_TRUE; + depth_stencil_state.depthWriteEnable = VK_TRUE; + depth_stencil_state.depthCompareOp = VK_COMPARE_OP_LESS_OR_EQUAL; // 或 VK_COMPARE_OP_LESS + depth_stencil_state.depthBoundsTestEnable = VK_FALSE; + depth_stencil_state.stencilTestEnable = VK_FALSE; + + // 颜色混合 (点通常不需要混合) + VkPipelineColorBlendAttachmentState blend_attachment_state{}; + blend_attachment_state.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; + blend_attachment_state.blendEnable = VK_FALSE; + + VkPipelineColorBlendStateCreateInfo color_blend_state{ VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO }; + color_blend_state.attachmentCount = 1; + color_blend_state.pAttachments = &blend_attachment_state; + + // 动态状态 (视口和裁剪矩形将在命令缓冲区中设置) + std::vector dynamic_state_enables = { VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR }; + VkPipelineDynamicStateCreateInfo dynamic_state{ VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO }; + dynamic_state.dynamicStateCount = static_cast(dynamic_state_enables.size()); + dynamic_state.pDynamicStates = dynamic_state_enables.data(); + + // 创建图形管线 + VkGraphicsPipelineCreateInfo pipeline_create_info{ VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO }; + pipeline_create_info.stageCount = static_cast(shader_stages.size()); + pipeline_create_info.pStages = shader_stages.data(); + pipeline_create_info.pVertexInputState = &vertex_input_state; + pipeline_create_info.pInputAssemblyState = &input_assembly_state; + pipeline_create_info.pViewportState = &viewport_state; + pipeline_create_info.pRasterizationState = &rasterization_state; + pipeline_create_info.pMultisampleState = &multisample_state; + pipeline_create_info.pDepthStencilState = &depth_stencil_state; + pipeline_create_info.pColorBlendState = &color_blend_state; + pipeline_create_info.pDynamicState = &dynamic_state; + pipeline_create_info.layout = point_pipeline_layout; + pipeline_create_info.renderPass = render_pass; // 使用主渲染通道 + pipeline_create_info.subpass = 0; // 主子通道 + + VK_CHECK(vkCreateGraphicsPipelines(get_device().get_handle(), pipeline_cache, 1, &pipeline_create_info, nullptr, &point_pipeline)); +} + +void TextureLoading::update_point_vertex_buffer(float* pos, int pointCount) +{ + std::lock_guard lock(mtx_point); + if (pointCount <= 0) { + point_count = 0; + return; // 没有点数据,无需更新 + } + + point_count = pointCount; + + // 1. 准备顶点数据 + std::vector vertices(point_count); + // 假设 pos 数组是 [x0,y0,z0,x1,y1,z1,...] + // 为了可视化,这里简单地将坐标映射为颜色 (0-1范围) + float min_x = std::numeric_limits::max(), max_x = std::numeric_limits::lowest(); + float min_y = std::numeric_limits::max(), max_y = std::numeric_limits::lowest(); + float min_z = std::numeric_limits::max(), max_z = std::numeric_limits::lowest(); + + for (int i = 0; i < point_count; ++i) { + float x = pos[i * 3 + 0]; + float y = pos[i * 3 + 1]; + float z = pos[i * 3 + 2]; + min_x = std::min(min_x, x); max_x = std::max(max_x, x); + min_y = std::min(min_y, y); max_y = std::max(max_y, y); + min_z = std::min(min_z, z); max_z = std::max(max_z, z); + } + float range_x = max_x - min_x; + float range_y = max_y - min_y; + float range_z = max_z - min_z; + if (range_x == 0) range_x = 1.0f; // 防止除零 + if (range_y == 0) range_y = 1.0f; + if (range_z == 0) range_z = 1.0f; + + for (int i = 0; i < point_count; ++i) { + vertices[i].x = pos[i * 3 + 0]; + vertices[i].y = pos[i * 3 + 1]; + vertices[i].z = pos[i * 3 + 2]; + // 简单颜色映射 + vertices[i].r = (vertices[i].x - min_x) / range_x; + vertices[i].g = (vertices[i].y - min_y) / range_y; + vertices[i].b = (vertices[i].z - min_z) / range_z; + } + + // 2. 更新或创建顶点缓冲区 + VkDeviceSize buffer_size = sizeof(PointVertex) * point_count; + + if (!point_vertex_buffer || point_vertex_buffer->get_size() < buffer_size) { + // 如果缓冲区不存在或太小,则重新创建 + point_vertex_buffer.reset(); + point_vertex_buffer = std::make_unique(get_device(), + buffer_size, + VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, + VMA_MEMORY_USAGE_CPU_TO_GPU // CPU 可写,GPU 可读 + ); + } + + // 3. 将数据复制到缓冲区 + void* mapped_data = point_vertex_buffer->map(); + if (mapped_data) { + memcpy(mapped_data, vertices.data(), buffer_size); + point_vertex_buffer->unmap(); + } + else { + LOGE("Failed to map point vertex buffer for update."); + } +} + +void TextureLoading::draw_point_cloud(VkCommandBuffer command_buffer) +{ + if (point_count == 0 || !point_vertex_buffer) { + return; // 没有点或缓冲区未准备好 + } + + vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, point_pipeline); + vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, point_pipeline_layout, 0, 1, &point_descriptor_set, 0, nullptr); + + VkDeviceSize offsets[] = { 0 }; + vkCmdBindVertexBuffers(command_buffer, 0, 1, point_vertex_buffer->get(), offsets); + + vkCmdDraw(command_buffer, point_count, 1, 0, 0); // 绘制 point_count 个顶点 +} + diff --git a/samples/api/texture_loading/texture_loading.h b/samples/api/texture_loading/texture_loading.h index 25b8409..818ae1a 100644 --- a/samples/api/texture_loading/texture_loading.h +++ b/samples/api/texture_loading/texture_loading.h @@ -38,8 +38,29 @@ struct TextureLoadingVertexStructure class TextureLoading : public ApiVulkanSample { public: - // Contains all Vulkan objects that are required to store and use a texture - // Note that this repository contains a texture class (vulkan_texture.h) that encapsulates texture loading functionality in a class that is used in subsequent demos + // --- 新增:用于点云渲染的结构 --- + struct PointVertex { + float x, y, z; // 位置 + float r, g, b; // 颜色 (可以根据需要修改) + }; + + std::unique_ptr point_vertex_buffer; + uint32_t point_count = 0; + VkPipeline point_pipeline; + VkPipelineLayout point_pipeline_layout; + VkDescriptorSetLayout point_descriptor_set_layout; + VkDescriptorSet point_descriptor_set; + + void setup_point_descriptor_set_layout(); + void setup_point_descriptor_set(); + void prepare_point_pipeline(); + void update_point_vertex_buffer(float* pos, int pointCount); + void draw_point_cloud(VkCommandBuffer command_buffer); + void ReceiveFacePoint(float* pos, int pointCount, int width, int height); + void update_point_descriptor_set(); + + + struct Texture { VkSampler sampler; @@ -127,6 +148,7 @@ public: //void run(); //void start(); std::mutex mtx; + std::mutex mtx_point; //void stop(); //void updateTexture(); };