diff --git a/samples/api/texture_loading/texture_loading.cpp b/samples/api/texture_loading/texture_loading.cpp index 3165905..1c4c2e2 100644 --- a/samples/api/texture_loading/texture_loading.cpp +++ b/samples/api/texture_loading/texture_loading.cpp @@ -1,13 +1,11 @@ - - -#include "texture_loading.h" +#include "texture_loading.h" TextureLoading* TextureLoading::loadTextIns = nullptr; TextureLoading::TextureLoading() { - zoom = -2.5f; - rotation = {0.0f, 15.0f, 0.0f}; - title = "Texture loading"; + zoom = -2.5f; + rotation = { 0.0f, 15.0f, 0.0f }; + title = "Texture loading"; loadTextIns = this; } @@ -19,9 +17,18 @@ TextureLoading::~TextureLoading() // Note : Inherited destructor cleans up resources stored in base class vkDestroyPipeline(get_device().get_handle(), pipelines.solid, nullptr); + if (pipelines.background != VK_NULL_HANDLE) { + vkDestroyPipeline(get_device().get_handle(), pipelines.background, nullptr); + } vkDestroyPipelineLayout(get_device().get_handle(), pipeline_layout, nullptr); + if (pipeline_layout_bg != VK_NULL_HANDLE) { + vkDestroyPipelineLayout(get_device().get_handle(), pipeline_layout_bg, nullptr); + } vkDestroyDescriptorSetLayout(get_device().get_handle(), descriptor_set_layout, nullptr); + if (descriptor_set_layout_bg != VK_NULL_HANDLE) { + vkDestroyDescriptorSetLayout(get_device().get_handle(), descriptor_set_layout_bg, nullptr); + } } destroy_texture(texture); @@ -32,7 +39,7 @@ TextureLoading::~TextureLoading() } // Enable physical device features required for this example -void TextureLoading::request_gpu_features(vkb::PhysicalDevice &gpu) +void TextureLoading::request_gpu_features(vkb::PhysicalDevice& gpu) { // Enable anisotropic filtering if supported if (gpu.get_features().samplerAnisotropy) @@ -43,28 +50,32 @@ void TextureLoading::request_gpu_features(vkb::PhysicalDevice &gpu) void TextureLoading::destroy_texture(Texture texture) { - vkDestroyImageView(get_device().get_handle(), texture.view, nullptr); - vkDestroyImage(get_device().get_handle(), texture.image, nullptr); - vkDestroySampler(get_device().get_handle(), texture.sampler, nullptr); - vkFreeMemory(get_device().get_handle(), texture.device_memory, nullptr); + if (texture.view != VK_NULL_HANDLE) vkDestroyImageView(get_device().get_handle(), texture.view, nullptr); + if (texture.image != VK_NULL_HANDLE) vkDestroyImage(get_device().get_handle(), texture.image, nullptr); + if (texture.sampler != VK_NULL_HANDLE) vkDestroySampler(get_device().get_handle(), texture.sampler, nullptr); + if (texture.device_memory != VK_NULL_HANDLE) vkFreeMemory(get_device().get_handle(), texture.device_memory, nullptr); + // Reset struct + texture = { 0 }; } + void TextureLoading::build_command_buffers() { VkCommandBufferBeginInfo command_buffer_begin_info = vkb::initializers::command_buffer_begin_info(); + // 注意:深度缓冲区清除值改为 1.0f (最远) VkClearValue clear_values[2]; - clear_values[0].color = default_clear_color; - clear_values[1].depthStencil = {0.0f, 0}; + clear_values[0].color = default_clear_color; + clear_values[1].depthStencil = { 1.0f, 0 }; // 使用 1.0f 作为深度清除值 - VkRenderPassBeginInfo render_pass_begin_info = vkb::initializers::render_pass_begin_info(); - render_pass_begin_info.renderPass = render_pass; - render_pass_begin_info.renderArea.offset.x = 0; - render_pass_begin_info.renderArea.offset.y = 0; - render_pass_begin_info.renderArea.extent.width = width; + VkRenderPassBeginInfo render_pass_begin_info = vkb::initializers::render_pass_begin_info(); + render_pass_begin_info.renderPass = render_pass; + render_pass_begin_info.renderArea.offset.x = 0; + render_pass_begin_info.renderArea.offset.y = 0; + render_pass_begin_info.renderArea.extent.width = width; render_pass_begin_info.renderArea.extent.height = height; - render_pass_begin_info.clearValueCount = 2; - render_pass_begin_info.pClearValues = clear_values; + render_pass_begin_info.clearValueCount = 2; // 现在清除颜色和深度 + render_pass_begin_info.pClearValues = clear_values; for (int32_t i = 0; i < draw_cmd_buffers.size(); ++i) { @@ -81,16 +92,30 @@ void TextureLoading::build_command_buffers() VkRect2D scissor = vkb::initializers::rect2D(width, height, 0, 0); vkCmdSetScissor(draw_cmd_buffers[i], 0, 1, &scissor); - 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); + // --- 绘制全屏背景 --- + if (cam_text.image != VK_NULL_HANDLE && cam_text.view != VK_NULL_HANDLE && cam_text.sampler != VK_NULL_HANDLE) { + vkCmdBindPipeline(draw_cmd_buffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines.background); + vkCmdBindDescriptorSets(draw_cmd_buffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout_bg, 0, 1, &descriptor_set_bg, 0, NULL); + // 绘制一个三角形 strip,覆盖整个屏幕 (NDC -1 to 1) + // 顶点顺序: (-1,-1), (1,-1), (-1,1), (1,1) + vkCmdDraw(draw_cmd_buffers[i], 4, 1, 0, 0); // 4 个顶点, 1 个实例, 从索引 0 开始 + } - 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); + // --- 绘制前景四边形 --- + // 确保前景管线和描述符集有效 + if (pipelines.solid != VK_NULL_HANDLE && descriptor_set != VK_NULL_HANDLE && + vertex_buffer && index_buffer) { + 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); - vkCmdDrawIndexed(draw_cmd_buffers[i], index_count, 1, 0, 0, 0); + 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); - draw_ui(draw_cmd_buffers[i]); + vkCmdDrawIndexed(draw_cmd_buffers[i], index_count, 1, 0, 0, 0); + } + + draw_ui(draw_cmd_buffers[i]); // UI 通常在最后绘制 vkCmdEndRenderPass(draw_cmd_buffers[i]); @@ -98,9 +123,10 @@ void TextureLoading::build_command_buffers() } } -// ɼ򵥵IJͼݣɫ + +// 生成简单的测试图像数据(红绿蓝三色条) std::vector generateSimpleTestImage(int width, int height, int* outRowStride = nullptr) { - int rowStride = width * 4; // RGBA ÿ4ֽ + int rowStride = width * 4; // RGBA 每个像素4字节 if (outRowStride) { *outRowStride = rowStride; } @@ -112,27 +138,27 @@ std::vector generateSimpleTestImage(int width, int height, int* outRowS for (int x = 0; x < width; x++) { int pixelOffset = y * rowStride + x * 4; - // 򵥷ֳ򣺺졢̡ + // 简单分成三个区域:红、绿、蓝 if (x < width / 3) { - // ɫ + // 红色区域 imageData[pixelOffset] = 255; // R imageData[pixelOffset + 1] = 0; // G imageData[pixelOffset + 2] = 0; // B } else if (x < 2 * width / 3) { - // ɫ + // 绿色区域 imageData[pixelOffset] = 0; // R imageData[pixelOffset + 1] = 255; // G imageData[pixelOffset + 2] = 0; // B } else { - // ɫ + // 蓝色区域 imageData[pixelOffset] = 0; // R imageData[pixelOffset + 1] = 0; // G imageData[pixelOffset + 2] = 255; // B } - imageData[pixelOffset + 3] = 255; // A (ȫ͸) + imageData[pixelOffset + 3] = 255; // A (完全不透明) } } @@ -145,7 +171,7 @@ void TextureLoading::draw() // Command buffer to be submitted to the queue submit_info.commandBufferCount = 1; - submit_info.pCommandBuffers = &draw_cmd_buffers[current_buffer]; + submit_info.pCommandBuffers = &draw_cmd_buffers[current_buffer]; // Submit to queue VK_CHECK(vkQueueSubmit(queue, 1, &submit_info, VK_NULL_HANDLE)); @@ -157,220 +183,375 @@ void TextureLoading::generate_quad() { // Setup vertices for a single uv-mapped quad made from two triangles std::vector vertices = - { - {{1.0f, 1.0f, 0.0f}, {1.0f, 1.0f}, {0.0f, 0.0f, 1.0f}}, - {{-1.0f, 1.0f, 0.0f}, {0.0f, 1.0f}, {0.0f, 0.0f, 1.0f}}, - {{-1.0f, -1.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f, 1.0f}}, - {{1.0f, -1.0f, 0.0f}, {1.0f, 0.0f}, {0.0f, 0.0f, 1.0f}}}; + { + {{1.0f, 1.0f, 0.0f}, {1.0f, 1.0f}, {0.0f, 0.0f, 1.0f}}, + {{-1.0f, 1.0f, 0.0f}, {0.0f, 1.0f}, {0.0f, 0.0f, 1.0f}}, + {{-1.0f, -1.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f, 1.0f}}, + {{1.0f, -1.0f, 0.0f}, {1.0f, 0.0f}, {0.0f, 0.0f, 1.0f}} }; // Setup indices - std::vector indices = {0, 1, 2, 2, 3, 0}; - index_count = static_cast(indices.size()); + std::vector indices = { 0, 1, 2, 2, 3, 0 }; + index_count = static_cast(indices.size()); auto vertex_buffer_size = vkb::to_u32(vertices.size() * sizeof(TextureLoadingVertexStructure)); - auto index_buffer_size = vkb::to_u32(indices.size() * sizeof(uint32_t)); + auto index_buffer_size = vkb::to_u32(indices.size() * sizeof(uint32_t)); // Create buffers // For the sake of simplicity we won't stage the vertex data to the gpu memory // Vertex buffer vertex_buffer = std::make_unique(get_device(), - vertex_buffer_size, - VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, - VMA_MEMORY_USAGE_CPU_TO_GPU); + vertex_buffer_size, + VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, + VMA_MEMORY_USAGE_CPU_TO_GPU); vertex_buffer->update(vertices.data(), vertex_buffer_size); index_buffer = std::make_unique(get_device(), - index_buffer_size, - VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT, - VMA_MEMORY_USAGE_CPU_TO_GPU); + index_buffer_size, + VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT, + VMA_MEMORY_USAGE_CPU_TO_GPU); index_buffer->update(indices.data(), index_buffer_size); } void TextureLoading::setup_descriptor_pool() { - // Example uses one ubo and one image sampler + // Example uses one ubo and two image samplers (one for foreground, one for background) + // 增加 Combined Image Sampler 的数量到 2 std::vector pool_sizes = - { - vkb::initializers::descriptor_pool_size(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1), - vkb::initializers::descriptor_pool_size(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1)}; + { + vkb::initializers::descriptor_pool_size(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1), + vkb::initializers::descriptor_pool_size(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 2) // 改为 2 + }; VkDescriptorPoolCreateInfo descriptor_pool_create_info = - vkb::initializers::descriptor_pool_create_info( - static_cast(pool_sizes.size()), - pool_sizes.data(), - 2); + vkb::initializers::descriptor_pool_create_info( + static_cast(pool_sizes.size()), + pool_sizes.data(), + 2); // 最大描述符集数量改为 2 VK_CHECK(vkCreateDescriptorPool(get_device().get_handle(), &descriptor_pool_create_info, nullptr, &descriptor_pool)); } void TextureLoading::setup_descriptor_set_layout() { + // Foreground descriptor set layout (UBO + Texture) std::vector set_layout_bindings = - { - // Binding 0 : Vertex shader uniform buffer - vkb::initializers::descriptor_set_layout_binding( - VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, - VK_SHADER_STAGE_VERTEX_BIT, - 0), - // Binding 1 : Fragment shader image sampler - vkb::initializers::descriptor_set_layout_binding( - VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, - VK_SHADER_STAGE_FRAGMENT_BIT, - 1)}; + { + // Binding 0 : Vertex shader uniform buffer + vkb::initializers::descriptor_set_layout_binding( + VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, + VK_SHADER_STAGE_VERTEX_BIT, + 0), + // Binding 1 : Fragment shader image sampler (foreground texture) + vkb::initializers::descriptor_set_layout_binding( + VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, + VK_SHADER_STAGE_FRAGMENT_BIT, + 1) }; VkDescriptorSetLayoutCreateInfo descriptor_layout = - vkb::initializers::descriptor_set_layout_create_info( - set_layout_bindings.data(), - static_cast(set_layout_bindings.size())); + vkb::initializers::descriptor_set_layout_create_info( + set_layout_bindings.data(), + static_cast(set_layout_bindings.size())); VK_CHECK(vkCreateDescriptorSetLayout(get_device().get_handle(), &descriptor_layout, nullptr, &descriptor_set_layout)); + // Foreground pipeline layout VkPipelineLayoutCreateInfo pipeline_layout_create_info = - vkb::initializers::pipeline_layout_create_info( - &descriptor_set_layout, - 1); + vkb::initializers::pipeline_layout_create_info( + &descriptor_set_layout, + 1); VK_CHECK(vkCreatePipelineLayout(get_device().get_handle(), &pipeline_layout_create_info, nullptr, &pipeline_layout)); } +// 新增:设置背景描述符集布局 (仅包含纹理) +void TextureLoading::setup_descriptor_set_layout_bg() +{ + std::vector set_layout_bindings_bg = + { + // Binding 0 : Fragment shader image sampler (background texture) + vkb::initializers::descriptor_set_layout_binding( + VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, + VK_SHADER_STAGE_FRAGMENT_BIT, + 0) // Binding 0 for background + }; + + VkDescriptorSetLayoutCreateInfo descriptor_layout_bg = + vkb::initializers::descriptor_set_layout_create_info( + set_layout_bindings_bg.data(), + static_cast(set_layout_bindings_bg.size())); + + VK_CHECK(vkCreateDescriptorSetLayout(get_device().get_handle(), &descriptor_layout_bg, nullptr, &descriptor_set_layout_bg)); + + // Background pipeline layout + VkPipelineLayoutCreateInfo pipeline_layout_create_info_bg = + vkb::initializers::pipeline_layout_create_info( + &descriptor_set_layout_bg, + 1); + + VK_CHECK(vkCreatePipelineLayout(get_device().get_handle(), &pipeline_layout_create_info_bg, nullptr, &pipeline_layout_bg)); +} + + void TextureLoading::setup_descriptor_set() { + // Foreground descriptor set VkDescriptorSetAllocateInfo alloc_info = - vkb::initializers::descriptor_set_allocate_info( - descriptor_pool, - &descriptor_set_layout, - 1); + vkb::initializers::descriptor_set_allocate_info( + descriptor_pool, + &descriptor_set_layout, + 1); VK_CHECK(vkAllocateDescriptorSets(get_device().get_handle(), &alloc_info, &descriptor_set)); VkDescriptorBufferInfo buffer_descriptor = create_descriptor(*uniform_buffer_vs); - // Setup a descriptor image info for the current texture to be used as a combined image sampler + // Setup a descriptor image info for the current foreground texture VkDescriptorImageInfo image_descriptor; - image_descriptor.imageView = texture.view; // The image's view (images are never directly accessed by the shader, but rather through views defining subresources) - image_descriptor.sampler = texture.sampler; // The sampler (Telling the pipeline how to sample the texture, including repeat, border, etc.) - image_descriptor.imageLayout = texture.image_layout; // The current layout of the image (Note: Should always fit the actual use, e.g. shader read) + image_descriptor.imageView = texture.view; + image_descriptor.sampler = texture.sampler; + image_descriptor.imageLayout = texture.image_layout; std::vector write_descriptor_sets = - { - // Binding 0 : Vertex shader uniform buffer - vkb::initializers::write_descriptor_set( - descriptor_set, - VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, - 0, - &buffer_descriptor), - // Binding 1 : Fragment shader texture sampler - // Fragment shader: layout (binding = 1) uniform sampler2D samplerColor; - vkb::initializers::write_descriptor_set( - descriptor_set, - VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, // The descriptor set will use a combined image sampler (sampler and image could be split) - 1, // Shader binding point 1 - &image_descriptor) // Pointer to the descriptor image for our texture - }; + { + // Binding 0 : Vertex shader uniform buffer + vkb::initializers::write_descriptor_set( + descriptor_set, + VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, + 0, + &buffer_descriptor), + // Binding 1 : Fragment shader texture sampler (foreground) + vkb::initializers::write_descriptor_set( + descriptor_set, + VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, + 1, + &image_descriptor) + }; vkUpdateDescriptorSets(get_device().get_handle(), static_cast(write_descriptor_sets.size()), write_descriptor_sets.data(), 0, NULL); } +// 新增:设置背景描述符集 +void TextureLoading::setup_descriptor_set_bg() +{ + // Background descriptor set + VkDescriptorSetAllocateInfo alloc_info_bg = + vkb::initializers::descriptor_set_allocate_info( + descriptor_pool, + &descriptor_set_layout_bg, + 1); + + VK_CHECK(vkAllocateDescriptorSets(get_device().get_handle(), &alloc_info_bg, &descriptor_set_bg)); + + // Setup a descriptor image info for the background texture (cam_text) + VkDescriptorImageInfo image_descriptor_bg; + // 注意:这里使用 cam_text + image_descriptor_bg.imageView = cam_text.view; + image_descriptor_bg.sampler = cam_text.sampler; + image_descriptor_bg.imageLayout = cam_text.image_layout; // 应该是 VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL + + std::vector write_descriptor_sets_bg = + { + // Binding 0 : Fragment shader texture sampler (background) + vkb::initializers::write_descriptor_set( + descriptor_set_bg, + VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, + 0, // Binding 0 for background + &image_descriptor_bg) + }; + + vkUpdateDescriptorSets(get_device().get_handle(), static_cast(write_descriptor_sets_bg.size()), write_descriptor_sets_bg.data(), 0, NULL); +} + + void TextureLoading::prepare_pipelines() { + // --- 前景管线 --- VkPipelineInputAssemblyStateCreateInfo input_assembly_state = - vkb::initializers::pipeline_input_assembly_state_create_info( - VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, - 0, - VK_FALSE); + vkb::initializers::pipeline_input_assembly_state_create_info( + VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, + 0, + VK_FALSE); VkPipelineRasterizationStateCreateInfo rasterization_state = - vkb::initializers::pipeline_rasterization_state_create_info( - VK_POLYGON_MODE_FILL, - VK_CULL_MODE_NONE, - VK_FRONT_FACE_COUNTER_CLOCKWISE, - 0); + vkb::initializers::pipeline_rasterization_state_create_info( + VK_POLYGON_MODE_FILL, + VK_CULL_MODE_NONE, // 保持不变,或根据需要调整 + VK_FRONT_FACE_COUNTER_CLOCKWISE, + 0); VkPipelineColorBlendAttachmentState blend_attachment_state = - vkb::initializers::pipeline_color_blend_attachment_state( - 0xf, - VK_FALSE); + vkb::initializers::pipeline_color_blend_attachment_state( + 0xf, + VK_FALSE); VkPipelineColorBlendStateCreateInfo color_blend_state = - vkb::initializers::pipeline_color_blend_state_create_info( - 1, - &blend_attachment_state); + vkb::initializers::pipeline_color_blend_state_create_info( + 1, + &blend_attachment_state); // Note: Using reversed depth-buffer for increased precision, so Greater depth values are kept + // 前景管线启用深度测试和写入 VkPipelineDepthStencilStateCreateInfo depth_stencil_state = - vkb::initializers::pipeline_depth_stencil_state_create_info( - VK_TRUE, - VK_TRUE, - VK_COMPARE_OP_GREATER); + vkb::initializers::pipeline_depth_stencil_state_create_info( + VK_TRUE, // depthTestEnable + VK_TRUE, // depthWriteEnable + VK_COMPARE_OP_GREATER); // Reversed depth buffer VkPipelineViewportStateCreateInfo viewport_state = - vkb::initializers::pipeline_viewport_state_create_info(1, 1, 0); + vkb::initializers::pipeline_viewport_state_create_info(1, 1, 0); VkPipelineMultisampleStateCreateInfo multisample_state = - vkb::initializers::pipeline_multisample_state_create_info( - VK_SAMPLE_COUNT_1_BIT, - 0); + vkb::initializers::pipeline_multisample_state_create_info( + VK_SAMPLE_COUNT_1_BIT, + 0); std::vector dynamic_state_enables = { - VK_DYNAMIC_STATE_VIEWPORT, - VK_DYNAMIC_STATE_SCISSOR}; + VK_DYNAMIC_STATE_VIEWPORT, + VK_DYNAMIC_STATE_SCISSOR }; VkPipelineDynamicStateCreateInfo dynamic_state = - vkb::initializers::pipeline_dynamic_state_create_info( - dynamic_state_enables.data(), - static_cast(dynamic_state_enables.size()), - 0); + vkb::initializers::pipeline_dynamic_state_create_info( + dynamic_state_enables.data(), + static_cast(dynamic_state_enables.size()), + 0); - // Load shaders + // Load shaders (确保你有对应的 SPIR-V 文件) std::array shader_stages; - + // 假设着色器文件名为 texture.vert.spv 和 texture.frag.spv shader_stages[0] = load_shader("texture_loading", "texture.vert.spv", VK_SHADER_STAGE_VERTEX_BIT); shader_stages[1] = load_shader("texture_loading", "texture.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT); - // Vertex bindings and attributes + // Vertex bindings and attributes (用于前景 quad) const std::vector vertex_input_bindings = { - vkb::initializers::vertex_input_binding_description(0, sizeof(TextureLoadingVertexStructure), VK_VERTEX_INPUT_RATE_VERTEX), + vkb::initializers::vertex_input_binding_description(0, sizeof(TextureLoadingVertexStructure), VK_VERTEX_INPUT_RATE_VERTEX), }; const std::vector vertex_input_attributes = { - vkb::initializers::vertex_input_attribute_description(0, 0, VK_FORMAT_R32G32B32_SFLOAT, offsetof(TextureLoadingVertexStructure, pos)), - vkb::initializers::vertex_input_attribute_description(0, 1, VK_FORMAT_R32G32_SFLOAT, offsetof(TextureLoadingVertexStructure, uv)), - vkb::initializers::vertex_input_attribute_description(0, 2, VK_FORMAT_R32G32B32_SFLOAT, offsetof(TextureLoadingVertexStructure, normal)), + vkb::initializers::vertex_input_attribute_description(0, 0, VK_FORMAT_R32G32B32_SFLOAT, offsetof(TextureLoadingVertexStructure, pos)), + vkb::initializers::vertex_input_attribute_description(0, 1, VK_FORMAT_R32G32_SFLOAT, offsetof(TextureLoadingVertexStructure, uv)), + vkb::initializers::vertex_input_attribute_description(0, 2, VK_FORMAT_R32G32B32_SFLOAT, offsetof(TextureLoadingVertexStructure, normal)), }; VkPipelineVertexInputStateCreateInfo vertex_input_state = vkb::initializers::pipeline_vertex_input_state_create_info(); - vertex_input_state.vertexBindingDescriptionCount = static_cast(vertex_input_bindings.size()); - vertex_input_state.pVertexBindingDescriptions = vertex_input_bindings.data(); - vertex_input_state.vertexAttributeDescriptionCount = static_cast(vertex_input_attributes.size()); - vertex_input_state.pVertexAttributeDescriptions = vertex_input_attributes.data(); + vertex_input_state.vertexBindingDescriptionCount = static_cast(vertex_input_bindings.size()); + vertex_input_state.pVertexBindingDescriptions = vertex_input_bindings.data(); + vertex_input_state.vertexAttributeDescriptionCount = static_cast(vertex_input_attributes.size()); + vertex_input_state.pVertexAttributeDescriptions = vertex_input_attributes.data(); VkGraphicsPipelineCreateInfo pipeline_create_info = - vkb::initializers::pipeline_create_info( - pipeline_layout, - render_pass, - 0); + vkb::initializers::pipeline_create_info( + pipeline_layout, // 前景管线布局 + render_pass, + 0); - pipeline_create_info.pVertexInputState = &vertex_input_state; + pipeline_create_info.pVertexInputState = &vertex_input_state; pipeline_create_info.pInputAssemblyState = &input_assembly_state; pipeline_create_info.pRasterizationState = &rasterization_state; - pipeline_create_info.pColorBlendState = &color_blend_state; - pipeline_create_info.pMultisampleState = &multisample_state; - pipeline_create_info.pViewportState = &viewport_state; - pipeline_create_info.pDepthStencilState = &depth_stencil_state; - pipeline_create_info.pDynamicState = &dynamic_state; - pipeline_create_info.stageCount = static_cast(shader_stages.size()); - pipeline_create_info.pStages = shader_stages.data(); + pipeline_create_info.pColorBlendState = &color_blend_state; + pipeline_create_info.pMultisampleState = &multisample_state; + pipeline_create_info.pViewportState = &viewport_state; + pipeline_create_info.pDepthStencilState = &depth_stencil_state; + pipeline_create_info.pDynamicState = &dynamic_state; + pipeline_create_info.stageCount = static_cast(shader_stages.size()); + pipeline_create_info.pStages = shader_stages.data(); VK_CHECK(vkCreateGraphicsPipelines(get_device().get_handle(), pipeline_cache, 1, &pipeline_create_info, nullptr, &pipelines.solid)); } +// 新增:准备背景管线 +void TextureLoading::prepare_pipeline_bg() +{ + // --- 背景管线 (简单 quad, 全屏覆盖) --- + VkPipelineInputAssemblyStateCreateInfo input_assembly_state_bg = + vkb::initializers::pipeline_input_assembly_state_create_info( + VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, // 使用 Triangle Strip + 0, + VK_FALSE); + + VkPipelineRasterizationStateCreateInfo rasterization_state_bg = + vkb::initializers::pipeline_rasterization_state_create_info( + VK_POLYGON_MODE_FILL, + VK_CULL_MODE_BACK_BIT, // 通常对全屏 quad 启用背面剔除,但这里可能不需要,因为是屏幕对齐的 + VK_FRONT_FACE_COUNTER_CLOCKWISE, + 0); + + VkPipelineColorBlendAttachmentState blend_attachment_state_bg = + vkb::initializers::pipeline_color_blend_attachment_state( + 0xf, + VK_FALSE); // 通常背景不需要混合 + + VkPipelineColorBlendStateCreateInfo color_blend_state_bg = + vkb::initializers::pipeline_color_blend_state_create_info( + 1, + &blend_attachment_state_bg); + + // 背景管线配置:启用深度测试,但禁用深度写入,使用 LESS 比较 (或 ALWAYS) + // 这样背景会被绘制,但不会影响前景物体的深度值(如果前景物体 Z 值更近) + VkPipelineDepthStencilStateCreateInfo depth_stencil_state_bg = + vkb::initializers::pipeline_depth_stencil_state_create_info( + VK_TRUE, // depthTestEnable - 启用深度测试 + VK_FALSE, // depthWriteEnable - 禁用深度写入,让前景物体能正确遮挡背景 + VK_COMPARE_OP_LESS); // 比较操作:如果片段的深度小于深度缓冲区中的值,则通过。 + // 结合清除深度为 1.0 和前景使用 GREATER,这应该可以正确工作。 + // 或者使用 VK_COMPARE_OP_ALWAYS 来强制绘制背景,忽略深度。 + + VkPipelineViewportStateCreateInfo viewport_state_bg = + vkb::initializers::pipeline_viewport_state_create_info(1, 1, 0); + + VkPipelineMultisampleStateCreateInfo multisample_state_bg = + vkb::initializers::pipeline_multisample_state_create_info( + VK_SAMPLE_COUNT_1_BIT, + 0); + + // 背景管线不需要动态状态或顶点输入(如果顶点在着色器中生成) + std::vector dynamic_state_enables_bg = { + VK_DYNAMIC_STATE_VIEWPORT, + VK_DYNAMIC_STATE_SCISSOR + }; + VkPipelineDynamicStateCreateInfo dynamic_state_bg = + vkb::initializers::pipeline_dynamic_state_create_info( + dynamic_state_enables_bg.data(), + static_cast(dynamic_state_enables_bg.size()), + 0); + + // Load shaders for background (你需要创建对应的 SPIR-V 文件) + // 假设着色器文件名为 bg.vert.spv 和 bg.frag.spv + std::array shader_stages_bg; + shader_stages_bg[0] = load_shader("texture_loading", "bg.vert.spv", VK_SHADER_STAGE_VERTEX_BIT); + shader_stages_bg[1] = load_shader("texture_loading", "bg.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT); + + // 背景管线不需要顶点缓冲区输入 + VkPipelineVertexInputStateCreateInfo vertex_input_state_bg = vkb::initializers::pipeline_vertex_input_state_create_info(); + // vertex_input_state_bg 保持默认空状态即可 + + VkGraphicsPipelineCreateInfo pipeline_create_info_bg = + vkb::initializers::pipeline_create_info( + pipeline_layout_bg, // 背景管线布局 + render_pass, + 0); + + pipeline_create_info_bg.pVertexInputState = &vertex_input_state_bg; // 空的顶点输入 + pipeline_create_info_bg.pInputAssemblyState = &input_assembly_state_bg; + pipeline_create_info_bg.pRasterizationState = &rasterization_state_bg; + pipeline_create_info_bg.pColorBlendState = &color_blend_state_bg; + pipeline_create_info_bg.pMultisampleState = &multisample_state_bg; + pipeline_create_info_bg.pViewportState = &viewport_state_bg; + pipeline_create_info_bg.pDepthStencilState = &depth_stencil_state_bg; + pipeline_create_info_bg.pDynamicState = &dynamic_state_bg; + pipeline_create_info_bg.stageCount = static_cast(shader_stages_bg.size()); + pipeline_create_info_bg.pStages = shader_stages_bg.data(); + + VK_CHECK(vkCreateGraphicsPipelines(get_device().get_handle(), pipeline_cache, 1, &pipeline_create_info_bg, nullptr, &pipelines.background)); +} + + // Prepare and initialize uniform buffer containing shader uniforms void TextureLoading::prepare_uniform_buffers() { // Vertex shader uniform buffer block uniform_buffer_vs = std::make_unique(get_device(), - sizeof(ubo_vs), - VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, - VMA_MEMORY_USAGE_CPU_TO_GPU); + sizeof(ubo_vs), + VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, + VMA_MEMORY_USAGE_CPU_TO_GPU); update_uniform_buffers(); } @@ -378,7 +559,7 @@ void TextureLoading::prepare_uniform_buffers() void TextureLoading::update_uniform_buffers() { // Vertex shader - ubo_vs.projection = glm::perspective(glm::radians(60.0f), static_cast(width) / static_cast(height), 0.001f, 256.0f); + ubo_vs.projection = glm::perspective(glm::radians(60.0f), static_cast(width) / static_cast(height), 0.001f, 256.0f); glm::mat4 view_matrix = glm::translate(glm::mat4(1.0f), glm::vec3(0.0f, 0.0f, zoom)); ubo_vs.model = view_matrix * glm::translate(glm::mat4(1.0f), camera_pos); @@ -391,33 +572,41 @@ void TextureLoading::update_uniform_buffers() uniform_buffer_vs->convert_and_update(ubo_vs); } -bool TextureLoading::prepare(const vkb::ApplicationOptions &options) +bool TextureLoading::prepare(const vkb::ApplicationOptions& options) { if (!ApiVulkanSample::prepare(options)) { return false; } - //load_texture(); + + // --- 初始化 cam_text 纹理对象 --- + // 注意:这里只是初始化结构体,图像内存等由外部函数分配 + // cam_text = {0}; // 已在构造函数或销毁时重置 + + // --- 加载前景纹理 (示例) --- int width = 640; int height = 480; int rowStride; - auto testImage = generateSimpleTestImage(width, height, &rowStride); size_t dataSize = testImage.size(); - std::cout << "Generated test image: " << width << "x" << height << std::endl; std::cout << "Row stride: " << rowStride << std::endl; std::cout << "Data size: " << dataSize << " bytes" << std::endl; - processWithVulkan(testImage.data(), width, height, 1, rowStride, dataSize, texture); - + // --- 生成前景几何体 --- generate_quad(); + + // --- 准备资源 --- prepare_uniform_buffers(); - setup_descriptor_set_layout(); - prepare_pipelines(); - setup_descriptor_pool(); - setup_descriptor_set(); + setup_descriptor_set_layout(); // 前景 DSL + setup_descriptor_set_layout_bg(); // 背景 DSL + prepare_pipelines(); // 前景管线 + prepare_pipeline_bg(); // 背景管线 + setup_descriptor_pool(); // 描述符池 (已更新大小) + setup_descriptor_set(); // 前景 DS + setup_descriptor_set_bg(); // 背景 DS + build_command_buffers(); prepared = true; return true; @@ -430,7 +619,10 @@ void TextureLoading::render(float delta_time) return; } - if (texture.width == 0) + // 可以在这里添加逻辑来更新 cam_text 纹理 + // 例如,如果 cam_text.image != VK_NULL_HANDLE,调用 updateTexture + + if (texture.width == 0) // 检查前景纹理 { return; } @@ -443,7 +635,7 @@ void TextureLoading::view_changed() update_uniform_buffers(); } -void TextureLoading::on_update_ui_overlay(vkb::Drawer &drawer) +void TextureLoading::on_update_ui_overlay(vkb::Drawer& drawer) { if (drawer.header("Settings")) { @@ -459,10 +651,18 @@ std::unique_ptr create_texture_loading() return std::make_unique(); } +// 外部函数保持不变 void TextureLoadProcessWithVulkan(uint8_t* data, int width, int height, int format, int rowStride, size_t dataSize) { - TextureLoading::Texture& cam_texture = TextureLoading::Get()->cam_text; - TextureLoading::Get()->processWithVulkan(data, width, height, format, rowStride, dataSize, cam_texture); + if (TextureLoading::Get()) { + TextureLoading::Texture& cam_texture = TextureLoading::Get()->cam_text; + TextureLoading::Get()->processWithVulkan(data, width, height, format, rowStride, dataSize, cam_texture); + // 可能需要重建命令缓冲区或更新描述符集,如果管线已经创建 + // 这里简单地重建命令缓冲区 + if (TextureLoading::Get()->prepared) { + TextureLoading::Get()->build_command_buffers(); + } + } } @@ -472,13 +672,20 @@ void TextureLoading::processWithVulkan(uint8_t* data, int width, int height, int const VkPhysicalDevice& physicalDevice = get_device().get_gpu().get_handle(); if (out_texture.image == VK_NULL_HANDLE) { createTexture(device, physicalDevice, width, height, format, out_texture); + // 如果纹理是新创建的,并且管线已经准备好,需要更新描述符集 + if (prepared && &out_texture == &cam_text) { + setup_descriptor_set_bg(); // 重新设置背景描述符集 + } } const VkCommandPool& commandPool = get_device().get_command_pool().get_handle(); updateTexture(device, physicalDevice, commandPool, queue, data, width, height, rowStride, dataSize, out_texture); + // 如果纹理被更新,并且管线已经准备好,可能需要重建命令缓冲区 + // 这取决于你的应用逻辑。简单起见,在外部函数中处理。 } +// --- 以下函数保持不变 --- void TextureLoading::createTexture(VkDevice device, VkPhysicalDevice physicalDevice, int width, int height, int format, Texture& texture) { @@ -489,7 +696,7 @@ void TextureLoading::createTexture(VkDevice device, VkPhysicalDevice physicalDev VkImageCreateInfo imageInfo = {}; imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; imageInfo.imageType = VK_IMAGE_TYPE_2D; - imageInfo.format = VK_FORMAT_R8G8B8A8_UNORM; // ƥ RGBA_8888 + imageInfo.format = VK_FORMAT_R8G8B8A8_UNORM; // Æ¥Åä RGBA_8888 imageInfo.extent.width = width; imageInfo.extent.height = height; imageInfo.extent.depth = 1; diff --git a/samples/api/texture_loading/texture_loading.h b/samples/api/texture_loading/texture_loading.h index fc2f0df..a98285a 100644 --- a/samples/api/texture_loading/texture_loading.h +++ b/samples/api/texture_loading/texture_loading.h @@ -1,10 +1,10 @@ - -#pragma once +#pragma once #include #include "api_vulkan_sample.h" +// 顶点结构保持不变,因为背景 quad 可能不需要顶点缓冲区 struct TextureLoadingVertexStructure { float pos[3]; @@ -14,7 +14,7 @@ struct TextureLoadingVertexStructure class TextureLoading : public ApiVulkanSample { - public: +public: struct Texture { VkSampler sampler; @@ -26,8 +26,8 @@ class TextureLoading : public ApiVulkanSample uint32_t mip_levels; }; - Texture texture = {0}; - Texture cam_text = {0}; + Texture texture = { 0 }; + Texture cam_text = { 0 }; // 将由外部函数初始化 std::unique_ptr vertex_buffer; std::unique_ptr index_buffer; @@ -45,47 +45,56 @@ class TextureLoading : public ApiVulkanSample struct { - VkPipeline solid; + VkPipeline solid; // 原有前景管线 + VkPipeline background; // 新增背景管线 } pipelines; - VkPipelineLayout pipeline_layout; - VkDescriptorSet descriptor_set; - VkDescriptorSetLayout descriptor_set_layout; + // 管线布局 + VkPipelineLayout pipeline_layout; // 前景管线布局 + VkPipelineLayout pipeline_layout_bg; // 背景管线布局 + + // 描述符集 + VkDescriptorSet descriptor_set; // 前景描述符集 + VkDescriptorSet descriptor_set_bg; // 背景描述符集 + + // 描述符集布局 + VkDescriptorSetLayout descriptor_set_layout; // 前景描述符集布局 + VkDescriptorSetLayout descriptor_set_layout_bg; // 背景描述符集布局 (仅包含 combined image sampler) + static TextureLoading* Get() { return loadTextIns; } static TextureLoading* loadTextIns; + TextureLoading(); ~TextureLoading(); - virtual void request_gpu_features(vkb::PhysicalDevice &gpu) override; + virtual void request_gpu_features(vkb::PhysicalDevice& gpu) override; void build_command_buffers() override; void draw(); - void generate_quad(); + void generate_quad(); // 生成前景 quad void setup_descriptor_pool(); void setup_descriptor_set_layout(); + void setup_descriptor_set_layout_bg(); // 新增:设置背景描述符集布局 void setup_descriptor_set(); + void setup_descriptor_set_bg(); // 新增:设置背景描述符集 void prepare_pipelines(); + void prepare_pipeline_bg(); // 新增:准备背景管线 void prepare_uniform_buffers(); void update_uniform_buffers(); - bool prepare(const vkb::ApplicationOptions &options) override; + bool prepare(const vkb::ApplicationOptions& options) override; virtual void render(float delta_time) override; virtual void view_changed() override; - virtual void on_update_ui_overlay(vkb::Drawer &drawer) override; + virtual void on_update_ui_overlay(vkb::Drawer& drawer) override; void destroy_texture(Texture texture); -public: - + // 现有函数保持不变 void processWithVulkan(uint8_t* data, int width, int height, int format, int rowStride, size_t dataSize, Texture& out_texture); - void createTexture(VkDevice device, VkPhysicalDevice physicalDevice, int width, int height, int format, Texture& texture); - - void updateTexture(VkDevice device, VkPhysicalDevice physicalDevice, VkCommandPool commandPool, VkQueue queue, uint8_t* data, int width, int height, int rowStride, size_t dataSize, Texture& texture); - - uint32_t findMemoryType(VkPhysicalDevice physicalDevice, uint32_t typeFilter, VkMemoryPropertyFlags properties); - VkCommandBuffer beginSingleTimeCommands(VkDevice device, VkCommandPool commandPool); - void endSingleTimeCommands(VkDevice device, VkCommandPool commandPool, VkQueue queue, VkCommandBuffer commandBuffer); - void transitionImageLayout(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout oldLayout, VkImageLayout newLayout); - + void updateTexture(VkDevice device, VkPhysicalDevice physicalDevice, VkCommandPool commandPool, VkQueue queue, uint8_t* data, int width, int height, int rowStride, size_t dataSize, Texture& texture); + uint32_t findMemoryType(VkPhysicalDevice physicalDevice, uint32_t typeFilter, VkMemoryPropertyFlags properties); + VkCommandBuffer beginSingleTimeCommands(VkDevice device, VkCommandPool commandPool); + void endSingleTimeCommands(VkDevice device, VkCommandPool commandPool, VkQueue queue, VkCommandBuffer commandBuffer); + void transitionImageLayout(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout oldLayout, VkImageLayout newLayout); }; -std::unique_ptr create_texture_loading(); +std::unique_ptr create_texture_loading(); \ No newline at end of file