#include "texture_loading.h" TextureLoading* TextureLoading::loadTextIns = nullptr; TextureLoading::TextureLoading() { zoom = -2.5f; rotation = { 0.0f, 15.0f, 0.0f }; title = "Texture loading"; loadTextIns = this; } TextureLoading::~TextureLoading() { if (has_device()) { // Clean up used Vulkan resources // 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); destroy_texture(cam_text); vertex_buffer.reset(); index_buffer.reset(); uniform_buffer_vs.reset(); } // Enable physical device features required for this example void TextureLoading::request_gpu_features(vkb::PhysicalDevice& gpu) { // Enable anisotropic filtering if supported if (gpu.get_features().samplerAnisotropy) { gpu.get_mutable_requested_features().samplerAnisotropy = VK_TRUE; } } void TextureLoading::destroy_texture(Texture texture) { 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 = { 1.0f, 0 }; // 使用 1.0f 作为深度清除值 //clear_values[1].depthStencil = { 0, 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; render_pass_begin_info.renderArea.extent.height = height; render_pass_begin_info.clearValueCount = 2; // 现在清除颜色和深度 render_pass_begin_info.pClearValues = clear_values; for (int32_t i = 0; i < draw_cmd_buffers.size(); ++i) { // Set target frame buffer render_pass_begin_info.framebuffer = framebuffers[i]; VK_CHECK(vkBeginCommandBuffer(draw_cmd_buffers[i], &command_buffer_begin_info)); vkCmdBeginRenderPass(draw_cmd_buffers[i], &render_pass_begin_info, VK_SUBPASS_CONTENTS_INLINE); VkViewport viewport = vkb::initializers::viewport(static_cast(width), static_cast(height), 0.0f, 1.0f); vkCmdSetViewport(draw_cmd_buffers[i], 0, 1, &viewport); VkRect2D scissor = vkb::initializers::rect2D(width, height, 0, 0); vkCmdSetScissor(draw_cmd_buffers[i], 0, 1, &scissor); // --- 绘制全屏背景 --- 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 开始 } // --- 绘制前景四边形 --- // 确保前景管线和描述符集有效 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); 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); } draw_ui(draw_cmd_buffers[i]); // UI 通常在最后绘制 vkCmdEndRenderPass(draw_cmd_buffers[i]); VK_CHECK(vkEndCommandBuffer(draw_cmd_buffers[i])); } } // 生成简单的测试图像数据(红绿蓝三色条) std::vector generateSimpleTestImage(int width, int height, int* outRowStride = nullptr) { int rowStride = width * 4; // RGBA 每个像素4字节 if (outRowStride) { *outRowStride = rowStride; } size_t dataSize = rowStride * height; std::vector imageData(dataSize, 0); for (int y = 0; y < height; y++) { 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 (完全不透明) } } return imageData; } void TextureLoading::draw() { ApiVulkanSample::prepare_frame(); // Command buffer to be submitted to the queue submit_info.commandBufferCount = 1; submit_info.pCommandBuffers = &draw_cmd_buffers[current_buffer]; // Submit to queue VK_CHECK(vkQueueSubmit(queue, 1, &submit_info, VK_NULL_HANDLE)); ApiVulkanSample::submit_frame(); } 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}} }; // Setup indices 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)); // 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->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->update(indices.data(), index_buffer_size); } void TextureLoading::setup_descriptor_pool() { // 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, 2) // 改为 2 }; VkDescriptorPoolCreateInfo descriptor_pool_create_info = 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 (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())); 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); 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); 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 foreground texture VkDescriptorImageInfo image_descriptor; 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 (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); VkPipelineRasterizationStateCreateInfo rasterization_state = 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); VkPipelineColorBlendStateCreateInfo color_blend_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, // depthTestEnable VK_TRUE, // depthWriteEnable VK_COMPARE_OP_ALWAYS); // VK_COMPARE_OP_LESS); //VK_COMPARE_OP_GREATER); // Reversed depth buffer VkPipelineViewportStateCreateInfo viewport_state = 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); std::vector dynamic_state_enables = { 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); // 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 (用于前景 quad) const std::vector vertex_input_bindings = { 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)), }; 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(); VkGraphicsPipelineCreateInfo pipeline_create_info = vkb::initializers::pipeline_create_info( pipeline_layout, // 前景管线布局 render_pass, 0); 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(); 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_ALWAYS); //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); update_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); 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); ubo_vs.model = glm::rotate(ubo_vs.model, glm::radians(rotation.x), glm::vec3(1.0f, 0.0f, 0.0f)); ubo_vs.model = glm::rotate(ubo_vs.model, glm::radians(rotation.y), glm::vec3(0.0f, 1.0f, 0.0f)); ubo_vs.model = glm::rotate(ubo_vs.model, glm::radians(rotation.z), glm::vec3(0.0f, 0.0f, 1.0f)); ubo_vs.view_pos = glm::vec4(0.0f, 0.0f, -zoom, 0.0f); uniform_buffer_vs->convert_and_update(ubo_vs); } bool TextureLoading::prepare(const vkb::ApplicationOptions& options) { if (!ApiVulkanSample::prepare(options)) { return false; } // --- 初始化 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); auto bgImage = generateSimpleTestImage(width, height, &rowStride); dataSize = bgImage.size(); processWithVulkan(bgImage.data(), width, height, 1, rowStride, dataSize, cam_text); // --- 生成前景几何体 --- generate_quad(); // --- 准备资源 --- prepare_uniform_buffers(); 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; } void TextureLoading::render(float delta_time) { if (!prepared) { return; } // 可以在这里添加逻辑来更新 cam_text 纹理 // 例如,如果 cam_text.image != VK_NULL_HANDLE,调用 updateTexture if (texture.width == 0) // 检查前景纹理 { return; } draw(); } void TextureLoading::view_changed() { update_uniform_buffers(); } void TextureLoading::on_update_ui_overlay(vkb::Drawer& drawer) { if (drawer.header("Settings")) { if (drawer.slider_float("LOD bias", &ubo_vs.lod_bias, 0.0f, static_cast(texture.mip_levels))) { update_uniform_buffers(); } } } 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) { 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(); } } } void TextureLoading::processWithVulkan(uint8_t* data, int width, int height, int format, int rowStride, size_t dataSize, Texture& out_texture) { VkDevice& device = get_device().get_handle(); 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) { texture.width = width; texture.height = height; texture.mip_levels = 1; 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.extent.width = width; imageInfo.extent.height = height; imageInfo.extent.depth = 1; imageInfo.mipLevels = 1; imageInfo.arrayLayers = 1; imageInfo.samples = VK_SAMPLE_COUNT_1_BIT; imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL; imageInfo.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT; imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; if (vkCreateImage(device, &imageInfo, nullptr, &texture.image) != VK_SUCCESS) { throw std::runtime_error("Failed to create image!"); } VkMemoryRequirements memRequirements; vkGetImageMemoryRequirements(device, texture.image, &memRequirements); VkMemoryAllocateInfo allocInfo = {}; allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; allocInfo.allocationSize = memRequirements.size; allocInfo.memoryTypeIndex = findMemoryType(physicalDevice, memRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); if (vkAllocateMemory(device, &allocInfo, nullptr, &texture.device_memory) != VK_SUCCESS) { throw std::runtime_error("Failed to allocate image memory!"); } vkBindImageMemory(device, texture.image, texture.device_memory, 0); VkImageViewCreateInfo viewInfo = {}; viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; viewInfo.image = texture.image; viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; viewInfo.format = VK_FORMAT_R8G8B8A8_UNORM; viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; viewInfo.subresourceRange.baseMipLevel = 0; viewInfo.subresourceRange.levelCount = 1; viewInfo.subresourceRange.baseArrayLayer = 0; viewInfo.subresourceRange.layerCount = 1; if (vkCreateImageView(device, &viewInfo, nullptr, &texture.view) != VK_SUCCESS) { throw std::runtime_error("Failed to create texture image view!"); } VkSamplerCreateInfo samplerInfo = {}; samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; samplerInfo.magFilter = VK_FILTER_LINEAR; samplerInfo.minFilter = VK_FILTER_LINEAR; samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; samplerInfo.anisotropyEnable = VK_FALSE; samplerInfo.maxAnisotropy = 1.0f; samplerInfo.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK; samplerInfo.unnormalizedCoordinates = VK_FALSE; samplerInfo.compareEnable = VK_FALSE; samplerInfo.compareOp = VK_COMPARE_OP_ALWAYS; samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; samplerInfo.mipLodBias = 0.0f; samplerInfo.minLod = 0.0f; samplerInfo.maxLod = 0.0f; if (vkCreateSampler(device, &samplerInfo, nullptr, &texture.sampler) != VK_SUCCESS) { throw std::runtime_error("Failed to create texture sampler!"); } texture.image_layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; } void TextureLoading::updateTexture(VkDevice device, VkPhysicalDevice physicalDevice, VkCommandPool commandPool, VkQueue queue, uint8_t* data, int width, int height, int rowStride, size_t dataSize, Texture& texture) { VkBuffer stagingBuffer; VkDeviceMemory stagingBufferMemory; VkBufferCreateInfo bufferInfo = {}; bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; bufferInfo.size = dataSize; bufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; if (vkCreateBuffer(device, &bufferInfo, nullptr, &stagingBuffer) != VK_SUCCESS) { throw std::runtime_error("Failed to create staging buffer!"); } VkMemoryRequirements memRequirements; vkGetBufferMemoryRequirements(device, stagingBuffer, &memRequirements); VkMemoryAllocateInfo allocInfo = {}; allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; allocInfo.allocationSize = memRequirements.size; allocInfo.memoryTypeIndex = findMemoryType(physicalDevice, memRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); if (vkAllocateMemory(device, &allocInfo, nullptr, &stagingBufferMemory) != VK_SUCCESS) { throw std::runtime_error("Failed to allocate staging buffer memory!"); } vkBindBufferMemory(device, stagingBuffer, stagingBufferMemory, 0); void* mappedData; vkMapMemory(device, stagingBufferMemory, 0, dataSize, 0, &mappedData); if (rowStride == width * 4) { memcpy(mappedData, data, dataSize); } else { uint8_t* dst = static_cast(mappedData); const uint8_t* src = data; size_t dstRowStride = width * 4; for (int y = 0; y < height; y++) { memcpy(dst, src, dstRowStride); dst += dstRowStride; src += rowStride; } } vkUnmapMemory(device, stagingBufferMemory); VkCommandBuffer commandBuffer = beginSingleTimeCommands(device, commandPool); transitionImageLayout(commandBuffer, texture.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); VkBufferImageCopy region = {}; region.bufferOffset = 0; region.bufferRowLength = 0; region.bufferImageHeight = 0; region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; region.imageSubresource.mipLevel = 0; region.imageSubresource.baseArrayLayer = 0; region.imageSubresource.layerCount = 1; region.imageOffset = { 0, 0, 0 }; region.imageExtent = { static_cast(width), static_cast(height), 1 }; vkCmdCopyBufferToImage(commandBuffer, stagingBuffer, texture.image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion); transitionImageLayout(commandBuffer, texture.image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); endSingleTimeCommands(device, commandPool, queue, commandBuffer); vkDestroyBuffer(device, stagingBuffer, nullptr); vkFreeMemory(device, stagingBufferMemory, nullptr); texture.image_layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; } uint32_t TextureLoading::findMemoryType(VkPhysicalDevice physicalDevice, uint32_t typeFilter, VkMemoryPropertyFlags properties) { VkPhysicalDeviceMemoryProperties memProperties; vkGetPhysicalDeviceMemoryProperties(physicalDevice, &memProperties); for (uint32_t i = 0; i < memProperties.memoryTypeCount; i++) { if ((typeFilter & (1 << i)) && (memProperties.memoryTypes[i].propertyFlags & properties) == properties) { return i; } } throw std::runtime_error("Failed to find suitable memory type!"); } VkCommandBuffer TextureLoading::beginSingleTimeCommands(VkDevice device, VkCommandPool commandPool) { VkCommandBufferAllocateInfo allocInfo = {}; allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; allocInfo.commandPool = commandPool; allocInfo.commandBufferCount = 1; VkCommandBuffer commandBuffer; vkAllocateCommandBuffers(device, &allocInfo, &commandBuffer); VkCommandBufferBeginInfo beginInfo = {}; beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; vkBeginCommandBuffer(commandBuffer, &beginInfo); return commandBuffer; } void TextureLoading::endSingleTimeCommands(VkDevice device, VkCommandPool commandPool, VkQueue queue, VkCommandBuffer commandBuffer) { vkEndCommandBuffer(commandBuffer); VkSubmitInfo submitInfo = {}; submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; submitInfo.commandBufferCount = 1; submitInfo.pCommandBuffers = &commandBuffer; vkQueueSubmit(queue, 1, &submitInfo, VK_NULL_HANDLE); vkQueueWaitIdle(queue); vkFreeCommandBuffers(device, commandPool, 1, &commandBuffer); } void TextureLoading::transitionImageLayout(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout oldLayout, VkImageLayout newLayout) { VkImageMemoryBarrier barrier = {}; barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; barrier.oldLayout = oldLayout; barrier.newLayout = newLayout; barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; barrier.image = image; barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; barrier.subresourceRange.baseMipLevel = 0; barrier.subresourceRange.levelCount = 1; barrier.subresourceRange.baseArrayLayer = 0; barrier.subresourceRange.layerCount = 1; VkPipelineStageFlags sourceStage; VkPipelineStageFlags destinationStage; if (oldLayout == VK_IMAGE_LAYOUT_UNDEFINED && newLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) { barrier.srcAccessMask = 0; barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; sourceStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; destinationStage = VK_PIPELINE_STAGE_TRANSFER_BIT; } else if (oldLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) { barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; sourceStage = VK_PIPELINE_STAGE_TRANSFER_BIT; destinationStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; } else { throw std::invalid_argument("Unsupported layout transition!"); } vkCmdPipelineBarrier(commandBuffer, sourceStage, destinationStage, 0, 0, nullptr, 0, nullptr, 1, &barrier); }