// // Created by atdunbg on 2026/9/23. // #include #include #include #include #include #include #include #include #include namespace Engine::Passes { SkyboxPass::SkyboxPass(Device& device, ShaderManager& shaders, DescriptorManager& descriptors, FrameSceneData& frame, RG::TextureHandle hdrColor, const Cubemap* env) : m_Device(device), m_Descriptors(descriptors), m_Frame(frame), m_HDRColor(hdrColor), m_Env(env) { // Set0 = {samplerCube}(fragment 采样) std::vector bindings = { {0, vk::DescriptorType::eCombinedImageSampler, vk::ShaderStageFlagBits::eFragment}, }; m_SetLayout = descriptors.CreateLayout(bindings); // push = invVP 64B(skybox.vert/.frag 声明一致,VUID-08878) m_Layout = descriptors.CreatePipelineLayout( std::vector{m_SetLayout}, sizeof(glm::mat4)); const std::string shaderDir = "shaders/"; auto vert = shaders.CreateFromFile( shaderDir + "skybox.vert.spv", vk::ShaderStageFlagBits::eVertex, std::vector{m_SetLayout}, sizeof(glm::mat4)); auto frag = shaders.CreateFromFile( shaderDir + "skybox.frag.spv", vk::ShaderStageFlagBits::eFragment, std::vector{m_SetLayout}, sizeof(glm::mat4)); m_Vert = vert.Handle; m_Frag = frag.Handle; if (!m_Vert || !m_Frag) { ENGINE_FATAL("SkyboxPass: failed to create shader objects"); } // per-slot set:cube view 全程稳定,构造期绑定一次即可 for (u32 slot = 0; slot < kMaxFramesInFlight; ++slot) { m_Sets[slot] = descriptors.AllocateDescriptorSet(m_SetLayout); if (m_Env) { descriptors.UpdateTexture(m_Sets[slot], 0, m_Env->GetSampler(), m_Env->GetView()); } } } SkyboxPass::~SkyboxPass() { const auto& vkDevice = m_Device.GetDevice(); if (m_Vert) vkDevice.destroyShaderEXT(m_Vert); if (m_Frag) vkDevice.destroyShaderEXT(m_Frag); vkDevice.destroyPipelineLayout(m_Layout); vkDevice.destroyDescriptorSetLayout(m_SetLayout); } void SkyboxPass::OnEnvironmentChanged(const Cubemap* env) { m_Env = env; if (!m_Env) return; // cube view 全程稳定语义是"单个环境内";切换环境 = 新 view, // per-slot set 全部重绑 for (u32 slot = 0; slot < kMaxFramesInFlight; ++slot) { m_Descriptors.UpdateTexture(m_Sets[slot], 0, m_Env->GetSampler(), m_Env->GetView()); } } void SkyboxPass::Register(RG::RenderGraph& rg) { rg.AddPass("Skybox", [this](RG::RenderGraphContext& ctx) { ZoneScopedN("Skybox"); const vk::CommandBuffer cmd = ctx.cmd; vk::ClearValue clear; clear.color = vk::ClearColorValue( std::array{0.1f, 0.1f, 0.1f, 1.0f}); vk::RenderingAttachmentInfo color; color.setImageView(ctx.View(m_HDRColor)) .setImageLayout(vk::ImageLayout::eColorAttachmentOptimal) .setLoadOp(vk::AttachmentLoadOp::eClear) // 清屏职责在本 pass .setStoreOp(vk::AttachmentStoreOp::eStore) .setClearValue(clear); vk::RenderingInfo renderingInfo; renderingInfo.setRenderArea({{0, 0}, ctx.extent}) .setLayerCount(1) .setColorAttachments(color); // 无深度附件 cmd.beginRendering(renderingInfo); if (m_Env) { // 无环境贴图:只清屏(Forward loadOp=Load 依赖这里先写) std::array stages = { vk::ShaderStageFlagBits::eVertex, vk::ShaderStageFlagBits::eFragment }; std::array shaders = {m_Vert, m_Frag}; cmd.bindShadersEXT(stages, shaders); cmd.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, m_Layout, 0, m_Sets[ctx.frame.frameSlot], {}); cmd.pushConstants( m_Layout, vk::ShaderStageFlagBits::eVertex | vk::ShaderStageFlagBits::eFragment, 0, m_Frame.skyInvVP); // ---- 动态状态 ---- cmd.setRasterizerDiscardEnable(VK_FALSE); cmd.setDepthTestEnable(VK_FALSE); cmd.setDepthWriteEnable(VK_FALSE); cmd.setDepthBoundsTestEnable(VK_FALSE); cmd.setStencilTestEnable(VK_FALSE); cmd.setDepthBiasEnable(VK_FALSE); cmd.setPolygonModeEXT(vk::PolygonMode::eFill); cmd.setCullMode(vk::CullModeFlagBits::eNone); cmd.setFrontFace(vk::FrontFace::eCounterClockwise); cmd.setPrimitiveTopology(vk::PrimitiveTopology::eTriangleList); cmd.setPrimitiveRestartEnable(VK_FALSE); // 全屏三角:无顶点输入 cmd.setVertexInputEXT({}, {}); cmd.setRasterizationSamplesEXT(vk::SampleCountFlagBits::e1); vk::SampleMask sampleMask = 0xFFFFFFFF; cmd.setSampleMaskEXT(vk::SampleCountFlagBits::e1, sampleMask); cmd.setAlphaToCoverageEnableEXT(VK_FALSE); cmd.setAlphaToOneEnableEXT(VK_FALSE); vk::Viewport viewport(0.0f, 0.0f, static_cast(ctx.extent.width), static_cast(ctx.extent.height), 0.0f, 1.0f); cmd.setViewportWithCount(viewport); cmd.setScissorWithCount(vk::Rect2D({0, 0}, ctx.extent)); // 无混合直写(天空不透明) vk::ColorBlendEquationEXT blendEquation; blendEquation.setSrcColorBlendFactor(vk::BlendFactor::eOne) .setDstColorBlendFactor(vk::BlendFactor::eZero) .setColorBlendOp(vk::BlendOp::eAdd) .setSrcAlphaBlendFactor(vk::BlendFactor::eOne) .setDstAlphaBlendFactor(vk::BlendFactor::eZero) .setAlphaBlendOp(vk::BlendOp::eAdd); // ArrayProxyNoTemporaries 拒绝临时量:具名局部变量传入 vk::Bool32 blendEnable = VK_FALSE; vk::ColorComponentFlags colorWriteMask = vk::ColorComponentFlagBits::eR | vk::ColorComponentFlagBits::eG | vk::ColorComponentFlagBits::eB | vk::ColorComponentFlagBits::eA; cmd.setColorBlendEnableEXT(0, blendEnable); cmd.setColorBlendEquationEXT(0, blendEquation); cmd.setColorWriteMaskEXT(0, colorWriteMask); cmd.draw(3, 1, 0, 0); } cmd.endRendering(); }) .Write(m_HDRColor, RG::ResourceUse::ColorAttachment); } } // namespace Engine::Passes