加入渲染点的代码

This commit is contained in:
xsl
2025-09-17 22:47:48 +08:00
parent 64ebe51ea4
commit e4c89a2651
3 changed files with 311 additions and 8 deletions
+285 -6
View File
@@ -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<std::mutex> lock(mtx);
std::unique_lock<std::mutex> 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<std::mutex> 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<VkPipelineShaderStageCreateInfo, 2> 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<VkVertexInputAttributeDescription, 2> 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<uint32_t>(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<VkDynamicState> 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<uint32_t>(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<uint32_t>(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<std::mutex> lock(mtx_point);
if (pointCount <= 0) {
point_count = 0;
return; // 没有点数据,无需更新
}
point_count = pointCount;
// 1. 准备顶点数据
std::vector<PointVertex> vertices(point_count);
// 假设 pos 数组是 [x0,y0,z0,x1,y1,z1,...]
// 为了可视化,这里简单地将坐标映射为颜色 (0-1范围)
float min_x = std::numeric_limits<float>::max(), max_x = std::numeric_limits<float>::lowest();
float min_y = std::numeric_limits<float>::max(), max_y = std::numeric_limits<float>::lowest();
float min_z = std::numeric_limits<float>::max(), max_z = std::numeric_limits<float>::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<vkb::core::BufferC>(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 个顶点
}