From eb07d0fdd1cde8de9b31583985d1f416b6b7fd7d Mon Sep 17 00:00:00 2001 From: Dynamitos Date: Sun, 6 Jul 2025 20:57:09 +0200 Subject: [PATCH] Trying to add prefiltered environment mapping --- CMakeLists.txt | 3 + res/shaders/Skybox.slang | 4 +- src/Editor/Asset/EnvironmentLoader.cpp | 122 +++++++++++++++----- src/Editor/Asset/EnvironmentLoader.h | 5 +- src/Editor/main.cpp | 4 +- src/Engine/Asset/EnvironmentMapAsset.h | 4 +- src/Engine/Graphics/RenderPass/BasePass.cpp | 12 +- 7 files changed, 113 insertions(+), 41 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 082a38f..0e86fda 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -99,6 +99,9 @@ if(UNIX) endif() add_executable(Editor "") +set_target_properties(Editor PROPERTIES + INSTALL_RPATH "$ORIGIN" +) target_link_libraries(Editor PRIVATE Engine) target_include_directories(Editor PRIVATE src/Editor) target_include_directories(Editor PRIVATE ${Stb_INCLUDE_DIR}) diff --git a/res/shaders/Skybox.slang b/res/shaders/Skybox.slang index a7be67a..6137ca9 100644 --- a/res/shaders/Skybox.slang +++ b/res/shaders/Skybox.slang @@ -96,8 +96,8 @@ static const float upperLimit = 0.1; float4 fragmentMain( VertexShaderOutput output) : SV_Target { - float4 texture1 = pSkyboxTextures.cubeMap.Sample(pSkyboxTextures.sampler, output.texCoords); - float4 texture2 = pSkyboxTextures.cubeMap2.Sample(pSkyboxTextures.sampler, output.texCoords); + float4 texture1 = pSkyboxTextures.cubeMap.SampleLevel(pSkyboxTextures.sampler, output.texCoords, 5); + float4 texture2 = pSkyboxTextures.cubeMap2.SampleLevel(pSkyboxTextures.sampler, output.texCoords, 5); float4 finalColor = lerp(texture1, texture2, pSkyboxData.fogBlend.w); float factor = (output.texCoords.y - lowerLimit) / (upperLimit - lowerLimit); diff --git a/src/Editor/Asset/EnvironmentLoader.cpp b/src/Editor/Asset/EnvironmentLoader.cpp index 94ee63a..3acc462 100644 --- a/src/Editor/Asset/EnvironmentLoader.cpp +++ b/src/Editor/Asset/EnvironmentLoader.cpp @@ -26,6 +26,16 @@ EnvironmentLoader::EnvironmentLoader(Gfx::PGraphics graphics) : graphics(graphic }, .fieldOfView = glm::radians(90.0f), }); + for (uint32 i = 0; i < prefilterViewports.size(); ++i) { + prefilterViewports[i] = graphics->createViewport(nullptr, ViewportCreateInfo{ + .dimensions = + { + .size = {128 * std::pow(0.5, i), 128 * std::pow(0.5, i)}, + .offset = {0, 0}, + }, + .fieldOfView = glm::radians(90.0f), + }); + } cubeSampler = graphics->createSampler({ .magFilter = Gfx::SE_FILTER_LINEAR, .minFilter = Gfx::SE_FILTER_LINEAR, @@ -61,16 +71,20 @@ EnvironmentLoader::EnvironmentLoader(Gfx::PGraphics graphics) : graphics(graphic cubePipelineLayout = graphics->createPipelineLayout("CubeRenderLayout"); cubePipelineLayout->addDescriptorLayout(cubeRenderLayout); + cubePipelineLayout->addPushConstants(Gfx::SePushConstantRange{ + .stageFlags = Gfx::SE_SHADER_STAGE_FRAGMENT_BIT, + .offset = 0, + .size = sizeof(float), + .name = "pRoughness", + }); graphics->beginShaderCompilation(ShaderCompilationInfo{ .name = "CubeRenderPipeline", .modules = {"EnvironmentMapping"}, - .entryPoints = - { - {"vertMain", "EnvironmentMapping"}, - {"computeCubemap", "EnvironmentMapping"}, - {"convolveCubemap", "EnvironmentMapping"}, - }, + .entryPoints = {{"vertMain", "EnvironmentMapping"}, + {"computeCubemap", "EnvironmentMapping"}, + {"convolveCubemap", "EnvironmentMapping"}, + {"computePrefilteredCubemap", "EnvironmentMapping"}}, .rootSignature = cubePipelineLayout, }); cubePipelineLayout->create(); @@ -78,6 +92,7 @@ EnvironmentLoader::EnvironmentLoader(Gfx::PGraphics graphics) : graphics(graphic cubeRenderVertex = graphics->createVertexShader({0}); cubeRenderFrag = graphics->createFragmentShader({1}); convolutionFrag = graphics->createFragmentShader({2}); + prefilterFrag = graphics->createFragmentShader({3}); } EnvironmentLoader::~EnvironmentLoader() {} @@ -138,13 +153,14 @@ void EnvironmentLoader::import(EnvironmentImportArgs args, PEnvironmentMapAsset cubeViews.add(cubeMap->createTextureView(0, 1, 3, 1)); cubeViews.add(cubeMap->createTextureView(0, 1, 4, 1)); cubeViews.add(cubeMap->createTextureView(0, 1, 5, 1)); - for(uint32 i = 0; i < 6; ++i) { + for (uint32 i = 0; i < 6; ++i) { Gfx::ORenderPass cubeRenderPass = graphics->createRenderPass( Gfx::RenderTargetLayout{ .colorAttachments = { - Gfx::RenderTargetAttachment(cubeViews[i], Gfx::SE_IMAGE_LAYOUT_UNDEFINED, Gfx::SE_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, - Gfx::SE_ATTACHMENT_LOAD_OP_DONT_CARE, Gfx::SE_ATTACHMENT_STORE_OP_STORE), + Gfx::RenderTargetAttachment(cubeViews[i], Gfx::SE_IMAGE_LAYOUT_UNDEFINED, + Gfx::SE_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, Gfx::SE_ATTACHMENT_LOAD_OP_DONT_CARE, + Gfx::SE_ATTACHMENT_STORE_OP_STORE), }, }, { @@ -162,7 +178,7 @@ void EnvironmentLoader::import(EnvironmentImportArgs args, PEnvironmentMapAsset .offset = {0, 0}, }, "EnvironmentRenderPass"); - cubeRenderPipeline = graphics->createGraphicsPipeline(Gfx::LegacyPipelineCreateInfo{ + Gfx::PGraphicsPipeline cubeRenderPipeline = graphics->createGraphicsPipeline(Gfx::LegacyPipelineCreateInfo{ .vertexShader = cubeRenderVertex, .fragmentShader = cubeRenderFrag, .renderPass = cubeRenderPass, @@ -177,37 +193,37 @@ void EnvironmentLoader::import(EnvironmentImportArgs args, PEnvironmentMapAsset renderCommand->bindPipeline(cubeRenderPipeline); renderCommand->bindDescriptor({set}); renderCommand->setViewport(cubeRenderViewport); - renderCommand->draw(6, 1, i*6, 0); + renderCommand->draw(6, 1, i * 6, 0); graphics->executeCommands(std::move(renderCommand)); graphics->endRenderPass(); } - + set = cubeRenderLayout->allocateDescriptorSet(); set->updateConstants("view", 0, captureViews); set->updateConstants("projection", 0, &captureProjection); set->updateSampler("sampler", 0, cubeSampler); set->updateTexture("cubeMap", 0, cubeMap->getDefaultView()); set->writeChanges(); - + Gfx::OTextureCube convolutedMap = graphics->createTextureCube(TextureCreateInfo{ .format = Gfx::SE_FORMAT_R32G32B32A32_SFLOAT, .width = CONVOLUTED_RESOLUTION, .height = CONVOLUTED_RESOLUTION, - .usage = Gfx::SE_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, + .usage = Gfx::SE_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | Gfx::SE_IMAGE_USAGE_SAMPLED_BIT, }); Array convolutedViews; - convolutedViews.add(cubeMap->createTextureView(0, 1, 0, 1)); - convolutedViews.add(cubeMap->createTextureView(0, 1, 1, 1)); - convolutedViews.add(cubeMap->createTextureView(0, 1, 2, 1)); - convolutedViews.add(cubeMap->createTextureView(0, 1, 3, 1)); - convolutedViews.add(cubeMap->createTextureView(0, 1, 4, 1)); - convolutedViews.add(cubeMap->createTextureView(0, 1, 5, 1)); - for(uint32 i = 0; i < 6; ++i) { + convolutedViews.add(convolutedMap->createTextureView(0, 1, 0, 1)); + convolutedViews.add(convolutedMap->createTextureView(0, 1, 1, 1)); + convolutedViews.add(convolutedMap->createTextureView(0, 1, 2, 1)); + convolutedViews.add(convolutedMap->createTextureView(0, 1, 3, 1)); + convolutedViews.add(convolutedMap->createTextureView(0, 1, 4, 1)); + convolutedViews.add(convolutedMap->createTextureView(0, 1, 5, 1)); + for (uint32 i = 0; i < 6; ++i) { Gfx::ORenderPass convolutionPass = graphics->createRenderPass( Gfx::RenderTargetLayout{ .colorAttachments = {Gfx::RenderTargetAttachment(convolutedViews[i], Gfx::SE_IMAGE_LAYOUT_UNDEFINED, - Gfx::SE_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, - Gfx::SE_ATTACHMENT_LOAD_OP_DONT_CARE, Gfx::SE_ATTACHMENT_STORE_OP_STORE)}, + Gfx::SE_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + Gfx::SE_ATTACHMENT_LOAD_OP_DONT_CARE, Gfx::SE_ATTACHMENT_STORE_OP_STORE)}, }, {}, { @@ -215,7 +231,7 @@ void EnvironmentLoader::import(EnvironmentImportArgs args, PEnvironmentMapAsset .offset = {0, 0}, }, "EnvironmentRenderPass"); - convolutionPipeline = graphics->createGraphicsPipeline(Gfx::LegacyPipelineCreateInfo{ + Gfx::PGraphicsPipeline convolutionPipeline = graphics->createGraphicsPipeline(Gfx::LegacyPipelineCreateInfo{ .vertexShader = cubeRenderVertex, .fragmentShader = convolutionFrag, .renderPass = convolutionPass, @@ -231,13 +247,65 @@ void EnvironmentLoader::import(EnvironmentImportArgs args, PEnvironmentMapAsset cmd->bindPipeline(convolutionPipeline); cmd->bindDescriptor({set}); cmd->setViewport(convolutionViewport); - cmd->draw(6, 1, i*6, 0); + cmd->draw(6, 1, i * 6, 0); graphics->executeCommands(std::move(cmd)); graphics->endRenderPass(); - } - + + Gfx::OTextureCube prefilteredCubeMap = graphics->createTextureCube(TextureCreateInfo{ + .format = Gfx::SE_FORMAT_R32G32B32A32_SFLOAT, + .width = 128, + .height = 128, + .useMip = true, + .usage = Gfx::SE_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | Gfx::SE_IMAGE_USAGE_SAMPLED_BIT, + }); + for (uint32 mip = 0; mip < prefilteredCubeMap->getMipLevels(); ++mip) { + Array views; + views.add(prefilteredCubeMap->createTextureView(mip, 1, 0, 1)); + views.add(prefilteredCubeMap->createTextureView(mip, 1, 1, 1)); + views.add(prefilteredCubeMap->createTextureView(mip, 1, 2, 1)); + views.add(prefilteredCubeMap->createTextureView(mip, 1, 3, 1)); + views.add(prefilteredCubeMap->createTextureView(mip, 1, 4, 1)); + views.add(prefilteredCubeMap->createTextureView(mip, 1, 5, 1)); + for (uint32 i = 0; i < 6; ++i) { + Gfx::ORenderPass prefilterPass = graphics->createRenderPass( + Gfx::RenderTargetLayout{ + .colorAttachments = {Gfx::RenderTargetAttachment( + views[i], Gfx::SE_IMAGE_LAYOUT_UNDEFINED, Gfx::SE_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + Gfx::SE_ATTACHMENT_LOAD_OP_DONT_CARE, Gfx::SE_ATTACHMENT_STORE_OP_STORE)}, + }, + {}, + { + .size = {prefilterViewports[mip]->getWidth(), prefilterViewports[mip]->getHeight()}, + .offset = {0, 0}, + }, + "PrefilterPass"); + Gfx::PGraphicsPipeline prefilterPipeline = graphics->createGraphicsPipeline(Gfx::LegacyPipelineCreateInfo{ + .vertexShader = cubeRenderVertex, + .fragmentShader = prefilterFrag, + .renderPass = prefilterPass, + .pipelineLayout = cubePipelineLayout, + .colorBlend = + { + .attachmentCount = 1, + }, + }); + + graphics->beginRenderPass(prefilterPass); + Gfx::ORenderCommand cmd = graphics->createRenderCommand("PrefilterPass"); + cmd->bindPipeline(prefilterPipeline); + cmd->bindDescriptor({set}); + float roughness = (float)mip / (float)(prefilteredCubeMap->getMipLevels() - 1); + cmd->pushConstants(Gfx::SE_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(float), &roughness); + cmd->setViewport(prefilterViewports[mip]); + cmd->draw(6, 1, i * 6, 0); + graphics->executeCommands(std::move(cmd)); + graphics->endRenderPass(); + } + } + asset->skybox = std::move(cubeMap); asset->irradianceMap = std::move(convolutedMap); + asset->prefilteredMap = std::move(prefilteredCubeMap); graphics->waitDeviceIdle(); } diff --git a/src/Editor/Asset/EnvironmentLoader.h b/src/Editor/Asset/EnvironmentLoader.h index 968b018..621eced 100644 --- a/src/Editor/Asset/EnvironmentLoader.h +++ b/src/Editor/Asset/EnvironmentLoader.h @@ -24,11 +24,12 @@ class EnvironmentLoader { Gfx::OFragmentShader cubeRenderFrag; Gfx::ODescriptorLayout cubeRenderLayout; Gfx::OPipelineLayout cubePipelineLayout; - Gfx::PGraphicsPipeline cubeRenderPipeline; Gfx::OFragmentShader convolutionFrag; - Gfx::PGraphicsPipeline convolutionPipeline; + Gfx::OFragmentShader prefilterFrag; Gfx::OViewport cubeRenderViewport; Gfx::OViewport convolutionViewport; + // for now we hardcode 128x128 as mip 0, so we have 8 roughness levels + StaticArray prefilterViewports; Gfx::OSampler cubeSampler; }; } \ No newline at end of file diff --git a/src/Editor/main.cpp b/src/Editor/main.cpp index 3872bc7..b65152f 100644 --- a/src/Editor/main.cpp +++ b/src/Editor/main.cpp @@ -26,8 +26,8 @@ static Gfx::OGraphics graphics; int main() { std::string gameName = "MeshShadingDemo"; - std::filesystem::path outputPath = fmt::format("../../../../{0}Game", gameName); - std::filesystem::path sourcePath = fmt::format("../../../../{0}", gameName); + std::filesystem::path outputPath = fmt::format("../../../../{0}Game/", gameName); + std::filesystem::path sourcePath = fmt::format("../../../../{0}/", gameName); #ifdef WIN32 std::string libraryEnding = "dll"; #elif __APPLE__ diff --git a/src/Engine/Asset/EnvironmentMapAsset.h b/src/Engine/Asset/EnvironmentMapAsset.h index 2f3116a..139ee13 100644 --- a/src/Engine/Asset/EnvironmentMapAsset.h +++ b/src/Engine/Asset/EnvironmentMapAsset.h @@ -13,11 +13,11 @@ class EnvironmentMapAsset : public Asset { virtual void load(ArchiveBuffer& buffer) override; Gfx::PTextureCube getSkybox() const { return skybox; } Gfx::PTextureCube getIrradianceMap() const { return irradianceMap; } - Gfx::PTextureCube getSpecularMap() const { return specularMap; } + Gfx::PTextureCube getPrefilteredMap() const { return prefilteredMap; } private: Gfx::OTextureCube skybox; Gfx::OTextureCube irradianceMap; - Gfx::OTextureCube specularMap; + Gfx::OTextureCube prefilteredMap; friend class EnvironmentLoader; }; } // namespace Seele \ No newline at end of file diff --git a/src/Engine/Graphics/RenderPass/BasePass.cpp b/src/Engine/Graphics/RenderPass/BasePass.cpp index 63e3358..9f7f869 100644 --- a/src/Engine/Graphics/RenderPass/BasePass.cpp +++ b/src/Engine/Graphics/RenderPass/BasePass.cpp @@ -79,8 +79,8 @@ BasePass::BasePass(Gfx::PGraphics graphics, PScene scene) : RenderPass(graphics) }); } skybox = Seele::Component::Skybox{ - .day = scene->getLightEnvironment()->getEnvironmentMap()->getSkybox(), - .night = scene->getLightEnvironment()->getEnvironmentMap()->getSkybox(), + .day = scene->getLightEnvironment()->getEnvironmentMap()->getPrefilteredMap(), + .night = scene->getLightEnvironment()->getEnvironmentMap()->getPrefilteredMap(), .fogColor = Vector(0, 0, 0), .blendFactor = 0, }; @@ -179,7 +179,7 @@ void BasePass::render() { const Gfx::ShaderCollection* collection = graphics->getShaderCompiler()->findShaders(id); assert(collection != nullptr); - bool twoSided = materialData.material->isTwoSided(); + //bool twoSided = materialData.material->isTwoSided(); if (graphics->supportMeshShading()) { Gfx::MeshPipelineCreateInfo pipelineInfo = { @@ -283,7 +283,7 @@ void BasePass::render() { const Gfx::ShaderCollection* collection = graphics->getShaderCompiler()->findShaders(id); assert(collection != nullptr); - bool twoSided = t.matInst->getBaseMaterial()->isTwoSided(); + //bool twoSided = t.matInst->getBaseMaterial()->isTwoSided(); if (graphics->supportMeshShading()) { Gfx::MeshPipelineCreateInfo pipelineInfo = { @@ -298,7 +298,7 @@ void BasePass::render() { }, .rasterizationState = { - .cullMode = Gfx::SeCullModeFlags(twoSided ? Gfx::SE_CULL_MODE_NONE : Gfx::SE_CULL_MODE_BACK_BIT), + .cullMode = Gfx::SE_CULL_MODE_BACK_BIT, }, .colorBlend = { @@ -325,7 +325,7 @@ void BasePass::render() { }, .rasterizationState = { - .cullMode = Gfx::SeCullModeFlags(twoSided ? Gfx::SE_CULL_MODE_NONE : Gfx::SE_CULL_MODE_BACK_BIT), + .cullMode = Gfx::SE_CULL_MODE_BACK_BIT, }, .depthStencilState = {