From 47b9b5c877d14135da6f6628f7c8e0cf0720d739 Mon Sep 17 00:00:00 2001 From: Dynamitos Date: Wed, 9 Jul 2025 23:25:03 +0200 Subject: [PATCH] Adding prefiltered specular reflections --- CMakeLists.txt | 3 - res/shaders/EnvironmentMapping.slang | 64 ++++ res/shaders/lib/LightEnv.slang | 26 +- src/Editor/Asset/EnvironmentLoader.cpp | 340 +++++++++++------- src/Editor/Asset/EnvironmentLoader.h | 11 + src/Engine/Asset/EnvironmentMapAsset.h | 4 + src/Engine/Graphics/RenderPass/BasePass.cpp | 4 +- .../Graphics/RenderPass/RayTracingPass.cpp | 2 +- src/Engine/Scene/LightEnvironment.cpp | 17 + 9 files changed, 329 insertions(+), 142 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0e86fda..082a38f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -99,9 +99,6 @@ 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/EnvironmentMapping.slang b/res/shaders/EnvironmentMapping.slang index a3b3841..0a942a0 100644 --- a/res/shaders/EnvironmentMapping.slang +++ b/res/shaders/EnvironmentMapping.slang @@ -192,4 +192,68 @@ float4 computePrefilteredCubemap(float3 localPos : LOCALPOS) : SV_Target prefilteredColor = prefilteredColor / totalWeight; return float4(prefilteredColor, 1.0); +} + +// TODO: this is basically duplicate of Cook-Torrance BRDF +float GeometrySchlickGGX(float NdotV, float roughness) +{ + float a = roughness; + float k = (a * a) / 2.0; + + float nom = NdotV; + float denom = NdotV * (1.0 - k) + k; + + return nom / denom; +} +// ---------------------------------------------------------------------------- +float GeometrySmith(float3 N, float3 V, float3 L, float roughness) +{ + float NdotV = max(dot(N, V), 0.0); + float NdotL = max(dot(N, L), 0.0); + float ggx2 = GeometrySchlickGGX(NdotV, roughness); + float ggx1 = GeometrySchlickGGX(NdotL, roughness); + + return ggx1 * ggx2; +} + +float2 integrateBRDF(float nDotV, float roughness) { + float3 V; + V.x = sqrt(1.0 - nDotV * nDotV); + V.y = 0.0f; + V.z = nDotV; + float A = 0.0; + float B = 0.0; + + float3 N = float3(0.0, 0.0, 1.0); + + const uint SAMPLE_COUNT = 1024u; + for (uint i = 0u; i < SAMPLE_COUNT; ++i) + { + float2 Xi = Hammersley(i, SAMPLE_COUNT); + float3 H = ImportanceSampleGGX(Xi, N, roughness); + float3 L = normalize(2.0 * dot(V, H) * H - V); + + float nDotL = max(L.z, 0.0); + float nDotH = max(H.z, 0.0); + float vDotH = max(dot(V, H), 0.0); + + if (nDotL > 0.0) + { + float G = GeometrySmith(N, V, L, roughness); + float G_Vis = (G * vDotH) / (nDotH * nDotV); + float Fc = pow(1.0 - vDotH, 5.0); + + A += (1.0 - Fc) * G_Vis; + B += Fc * G_Vis; + } + } + A /= float(SAMPLE_COUNT); + B /= float(SAMPLE_COUNT); + return float2(A, B); +} + +[shader("pixel")] +float2 precomputeBRDF(float2 texCoords) : SV_Target +{ + return integrateBRDF(texCoords.x, texCoords.y); } \ No newline at end of file diff --git a/res/shaders/lib/LightEnv.slang b/res/shaders/lib/LightEnv.slang index 8231b94..b664c3b 100644 --- a/res/shaders/lib/LightEnv.slang +++ b/res/shaders/lib/LightEnv.slang @@ -70,8 +70,8 @@ struct LightEnv TextureCube irradianceMap; SamplerState irradianceSampler; TextureCube prefilteredMap; - SamplerState prefilteredSampler; Texture2D brdfLUT; + SamplerState lutSampler; }; layout(set=3) ParameterBlock pLightEnv; @@ -314,15 +314,15 @@ struct CookTorrance : IBRDF float G = Smith(n, viewDir_WS, lightDir_WS); float3 F = FresnelSchlickRoughness(max(dot(h, viewDir_WS), 0.0), F0, roughness); - float3 num = NDF * G * F; - float denom = 4.0 * max(dot(n, viewDir_WS), 0.0) * max(dot(n, lightDir_WS), 0.0) + 0.000001; - float3 specular = num / denom; - float3 k_s = F; float3 k_d = float3(1.0) - k_s; k_d *= 1.0 - metallic; + float3 num = NDF * G * F; + float denom = 4.0 * max(dot(n, viewDir_WS), 0.0) * max(dot(n, lightDir_WS), 0.0) + 0.000001; + float3 specular = num / denom; + float nDotL = max(dot(n, lightDir_WS), 0.0); float3 result = (k_d * baseColor / PI + specular) * nDotL * lightColor; @@ -340,12 +340,24 @@ struct CookTorrance : IBRDF { float3 F0 = float3(0.04); F0 = lerp(F0, baseColor, metallic); - float3 k_s = FresnelSchlickRoughness(max(dot(normal, viewDir_WS), 0.0), F0, roughness); + float3 F = FresnelSchlickRoughness(max(dot(normal, viewDir_WS), 0.0), F0, roughness); + + float3 k_s = F; float3 k_d = 1 - k_s; k_d *= 1 - metallic; + float3 irradiance = pLightEnv.irradianceMap.SampleLevel(pLightEnv.irradianceSampler, normal, 4).rgb; float3 diffuse = irradiance * baseColor; - return (k_d * diffuse) * ambientOcclusion; + + float3 r = reflect(-viewDir_WS, normal); + + const float MAX_REFLECTION_LOD = 4; + float3 prefilteredColor = pLightEnv.prefilteredMap.SampleLevel(pLightEnv.irradianceSampler, r, roughness * MAX_REFLECTION_LOD).xyz; + + float2 envBRDF = pLightEnv.brdfLUT.Sample(pLightEnv.lutSampler, float2(max(dot(normal, viewDir_WS), 0), roughness)).rg; + float3 specular = prefilteredColor * (F * envBRDF.x + envBRDF.y); + + return (k_d * diffuse + specular) * ambientOcclusion; } float getAlpha() { diff --git a/src/Editor/Asset/EnvironmentLoader.cpp b/src/Editor/Asset/EnvironmentLoader.cpp index 3acc462..e48e922 100644 --- a/src/Editor/Asset/EnvironmentLoader.cpp +++ b/src/Editor/Asset/EnvironmentLoader.cpp @@ -2,6 +2,10 @@ #include "Asset/AssetRegistry.h" #include "Asset/EnvironmentMapAsset.h" #include "Graphics/Descriptor.h" +#include "Graphics/Enums.h" +#include "Graphics/Graphics.h" +#include "Graphics/Initializer.h" +#include "Graphics/RenderTarget.h" #include "stb_image.h" using namespace Seele; @@ -80,11 +84,16 @@ EnvironmentLoader::EnvironmentLoader(Gfx::PGraphics graphics) : graphics(graphic graphics->beginShaderCompilation(ShaderCompilationInfo{ .name = "CubeRenderPipeline", - .modules = {"EnvironmentMapping"}, - .entryPoints = {{"vertMain", "EnvironmentMapping"}, - {"computeCubemap", "EnvironmentMapping"}, - {"convolveCubemap", "EnvironmentMapping"}, - {"computePrefilteredCubemap", "EnvironmentMapping"}}, + .modules = {"FullScreenQuad", "EnvironmentMapping"}, + .entryPoints = + { + {"vertMain", "EnvironmentMapping"}, + {"computeCubemap", "EnvironmentMapping"}, + {"convolveCubemap", "EnvironmentMapping"}, + {"computePrefilteredCubemap", "EnvironmentMapping"}, + {"quadMain", "FullScreenQuad"}, + {"precomputeBRDF", "EnvironmentMapping"}, + }, .rootSignature = cubePipelineLayout, }); cubePipelineLayout->create(); @@ -93,6 +102,65 @@ EnvironmentLoader::EnvironmentLoader(Gfx::PGraphics graphics) : graphics(graphic cubeRenderFrag = graphics->createFragmentShader({1}); convolutionFrag = graphics->createFragmentShader({2}); prefilterFrag = graphics->createFragmentShader({3}); + lutVert = graphics->createVertexShader({4}); + lutFrag = graphics->createFragmentShader({5}); + Gfx::OPipelineLayout emptyLayout = graphics->createPipelineLayout("LUTlayout"); + { + graphics->beginDebugRegion("PrecomputeBRDF"); + lutTexture = graphics->createTexture2D(TextureCreateInfo{ + .format = Gfx::SE_FORMAT_R16G16_SFLOAT, + .width = 512, + .height = 512, + .usage = Gfx::SE_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | Gfx::SE_IMAGE_USAGE_SAMPLED_BIT, + }); + lutSampler = graphics->createSampler(SamplerCreateInfo{ + .magFilter = Gfx::SE_FILTER_LINEAR, + .minFilter = Gfx::SE_FILTER_LINEAR, + .addressModeU = Gfx::SE_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, + .addressModeV = Gfx::SE_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, + }); + lutViewport = graphics->createViewport(nullptr, ViewportCreateInfo{ + .dimensions = + { + .size = {512, 512}, + .offset = {0, 0}, + }, + .fieldOfView = glm::radians(90.0f), + }); + Gfx::ORenderPass lutPass = graphics->createRenderPass( + Gfx::RenderTargetLayout{ + .colorAttachments = {Gfx::RenderTargetAttachment(lutTexture->getDefaultView(), 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::SubPassDependency{ + .srcSubpass = 0, + .dstSubpass = ~0U, + .srcStage = Gfx::SE_PIPELINE_STAGE_TOP_OF_PIPE_BIT, + .dstStage = Gfx::SE_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, + .srcAccess = Gfx::SE_ACCESS_NONE, + .dstAccess = Gfx::SE_ACCESS_SHADER_READ_BIT, + }}, + URect{{512, 512}, {0, 0}}, "LUTGeneration"); + Gfx::PGraphicsPipeline pipeline = graphics->createGraphicsPipeline(Gfx::LegacyPipelineCreateInfo{ + .vertexShader = lutVert, + .fragmentShader = lutFrag, + .renderPass = lutPass, + .pipelineLayout = emptyLayout, + .colorBlend = + { + .attachmentCount = 1, + }, + }); + graphics->beginRenderPass(lutPass); + Gfx::ORenderCommand cmd = graphics->createRenderCommand("LUT"); + cmd->setViewport(lutViewport); + cmd->bindPipeline(pipeline); + cmd->draw(3, 1, 0, 0); + graphics->executeCommands(std::move(cmd)); + graphics->endRenderPass(); + graphics->endDebugRegion(); + } } EnvironmentLoader::~EnvironmentLoader() {} @@ -146,56 +214,60 @@ void EnvironmentLoader::import(EnvironmentImportArgs args, PEnvironmentMapAsset .height = SOURCE_RESOLUTION, .usage = Gfx::SE_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | Gfx::SE_IMAGE_USAGE_SAMPLED_BIT, }); - Array cubeViews; - cubeViews.add(cubeMap->createTextureView(0, 1, 0, 1)); - cubeViews.add(cubeMap->createTextureView(0, 1, 1, 1)); - cubeViews.add(cubeMap->createTextureView(0, 1, 2, 1)); - 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) { - 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::SubPassDependency{ - .srcSubpass = 0, - .dstSubpass = ~0U, - .srcStage = Gfx::SE_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, - .dstStage = Gfx::SE_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, - .srcAccess = Gfx::SE_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, - .dstAccess = Gfx::SE_ACCESS_SHADER_READ_BIT, + { + graphics->beginDebugRegion("CubemapGeneration"); + Array cubeViews; + cubeViews.add(cubeMap->createTextureView(0, 1, 0, 1)); + cubeViews.add(cubeMap->createTextureView(0, 1, 1, 1)); + cubeViews.add(cubeMap->createTextureView(0, 1, 2, 1)); + 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) { + 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), + }, }, - }, - { - .size = {SOURCE_RESOLUTION, SOURCE_RESOLUTION}, - .offset = {0, 0}, - }, - "EnvironmentRenderPass"); - Gfx::PGraphicsPipeline cubeRenderPipeline = graphics->createGraphicsPipeline(Gfx::LegacyPipelineCreateInfo{ - .vertexShader = cubeRenderVertex, - .fragmentShader = cubeRenderFrag, - .renderPass = cubeRenderPass, - .pipelineLayout = cubePipelineLayout, - .colorBlend = { - .attachmentCount = 1, + Gfx::SubPassDependency{ + .srcSubpass = 0, + .dstSubpass = ~0U, + .srcStage = Gfx::SE_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + .dstStage = Gfx::SE_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, + .srcAccess = Gfx::SE_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, + .dstAccess = Gfx::SE_ACCESS_SHADER_READ_BIT, + }, }, - }); - graphics->beginRenderPass(cubeRenderPass); - Gfx::ORenderCommand renderCommand = graphics->createRenderCommand("CubeMapRender"); - renderCommand->bindPipeline(cubeRenderPipeline); - renderCommand->bindDescriptor({set}); - renderCommand->setViewport(cubeRenderViewport); - renderCommand->draw(6, 1, i * 6, 0); - graphics->executeCommands(std::move(renderCommand)); - graphics->endRenderPass(); + { + .size = {SOURCE_RESOLUTION, SOURCE_RESOLUTION}, + .offset = {0, 0}, + }, + "EnvironmentRenderPass"); + Gfx::PGraphicsPipeline cubeRenderPipeline = graphics->createGraphicsPipeline(Gfx::LegacyPipelineCreateInfo{ + .vertexShader = cubeRenderVertex, + .fragmentShader = cubeRenderFrag, + .renderPass = cubeRenderPass, + .pipelineLayout = cubePipelineLayout, + .colorBlend = + { + .attachmentCount = 1, + }, + }); + graphics->beginRenderPass(cubeRenderPass); + Gfx::ORenderCommand renderCommand = graphics->createRenderCommand("CubeMapRender"); + renderCommand->bindPipeline(cubeRenderPipeline); + renderCommand->bindDescriptor({set}); + renderCommand->setViewport(cubeRenderViewport); + renderCommand->draw(6, 1, i * 6, 0); + graphics->executeCommands(std::move(renderCommand)); + graphics->endRenderPass(); + } + graphics->endDebugRegion(); } set = cubeRenderLayout->allocateDescriptorSet(); @@ -211,45 +283,49 @@ void EnvironmentLoader::import(EnvironmentImportArgs args, PEnvironmentMapAsset .height = CONVOLUTED_RESOLUTION, .usage = Gfx::SE_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | Gfx::SE_IMAGE_USAGE_SAMPLED_BIT, }); - Array convolutedViews; - 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)}, - }, - {}, - { - .size = {CONVOLUTED_RESOLUTION, CONVOLUTED_RESOLUTION}, - .offset = {0, 0}, - }, - "EnvironmentRenderPass"); - Gfx::PGraphicsPipeline convolutionPipeline = graphics->createGraphicsPipeline(Gfx::LegacyPipelineCreateInfo{ - .vertexShader = cubeRenderVertex, - .fragmentShader = convolutionFrag, - .renderPass = convolutionPass, - .pipelineLayout = cubePipelineLayout, - .colorBlend = - { - .attachmentCount = 1, + { + graphics->beginDebugRegion("Convolution"); + Array convolutedViews; + 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)}, }, - }); + {}, + { + .size = {CONVOLUTED_RESOLUTION, CONVOLUTED_RESOLUTION}, + .offset = {0, 0}, + }, + "EnvironmentRenderPass"); + Gfx::PGraphicsPipeline convolutionPipeline = graphics->createGraphicsPipeline(Gfx::LegacyPipelineCreateInfo{ + .vertexShader = cubeRenderVertex, + .fragmentShader = convolutionFrag, + .renderPass = convolutionPass, + .pipelineLayout = cubePipelineLayout, + .colorBlend = + { + .attachmentCount = 1, + }, + }); - graphics->beginRenderPass(convolutionPass); - Gfx::ORenderCommand cmd = graphics->createRenderCommand("ConvolutionPass"); - cmd->bindPipeline(convolutionPipeline); - cmd->bindDescriptor({set}); - cmd->setViewport(convolutionViewport); - cmd->draw(6, 1, i * 6, 0); - graphics->executeCommands(std::move(cmd)); - graphics->endRenderPass(); + graphics->beginRenderPass(convolutionPass); + Gfx::ORenderCommand cmd = graphics->createRenderCommand("ConvolutionPass"); + cmd->bindPipeline(convolutionPipeline); + cmd->bindDescriptor({set}); + cmd->setViewport(convolutionViewport); + cmd->draw(6, 1, i * 6, 0); + graphics->executeCommands(std::move(cmd)); + graphics->endRenderPass(); + } + graphics->endDebugRegion(); } Gfx::OTextureCube prefilteredCubeMap = graphics->createTextureCube(TextureCreateInfo{ @@ -259,53 +335,59 @@ void EnvironmentLoader::import(EnvironmentImportArgs args, PEnvironmentMapAsset .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->beginDebugRegion("Prefiltering"); + 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(); + 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(); + } } + graphics->endDebugRegion(); } asset->skybox = std::move(cubeMap); asset->irradianceMap = std::move(convolutedMap); asset->prefilteredMap = std::move(prefilteredCubeMap); + asset->brdfLUT = lutTexture; + asset->lutSampler = lutSampler; graphics->waitDeviceIdle(); } diff --git a/src/Editor/Asset/EnvironmentLoader.h b/src/Editor/Asset/EnvironmentLoader.h index 621eced..db0d532 100644 --- a/src/Editor/Asset/EnvironmentLoader.h +++ b/src/Editor/Asset/EnvironmentLoader.h @@ -1,4 +1,5 @@ #pragma once +#include "Graphics/Descriptor.h" #include "MinimalEngine.h" #include "Graphics/Graphics.h" #include "Graphics/Shader.h" @@ -20,12 +21,22 @@ class EnvironmentLoader { private: void import(EnvironmentImportArgs args, PEnvironmentMapAsset asset); Gfx::PGraphics graphics; + + Gfx::OTexture2D lutTexture; + Gfx::OSampler lutSampler; + Gfx::OViewport lutViewport; + Gfx::OVertexShader lutVert; + Gfx::OFragmentShader lutFrag; + Gfx::OVertexShader cubeRenderVertex; Gfx::OFragmentShader cubeRenderFrag; Gfx::ODescriptorLayout cubeRenderLayout; Gfx::OPipelineLayout cubePipelineLayout; + Gfx::OFragmentShader convolutionFrag; + Gfx::OFragmentShader prefilterFrag; + Gfx::OViewport cubeRenderViewport; Gfx::OViewport convolutionViewport; // for now we hardcode 128x128 as mip 0, so we have 8 roughness levels diff --git a/src/Engine/Asset/EnvironmentMapAsset.h b/src/Engine/Asset/EnvironmentMapAsset.h index 139ee13..865d1f5 100644 --- a/src/Engine/Asset/EnvironmentMapAsset.h +++ b/src/Engine/Asset/EnvironmentMapAsset.h @@ -14,10 +14,14 @@ class EnvironmentMapAsset : public Asset { Gfx::PTextureCube getSkybox() const { return skybox; } Gfx::PTextureCube getIrradianceMap() const { return irradianceMap; } Gfx::PTextureCube getPrefilteredMap() const { return prefilteredMap; } + Gfx::PTexture2D getBrdfLUT() const { return brdfLUT; } + Gfx::PSampler getLUTSampler() const { return lutSampler; } private: Gfx::OTextureCube skybox; Gfx::OTextureCube irradianceMap; Gfx::OTextureCube prefilteredMap; + Gfx::PTexture2D brdfLUT; + Gfx::PSampler lutSampler; 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 9f7f869..dc31895 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()->getPrefilteredMap(), - .night = scene->getLightEnvironment()->getEnvironmentMap()->getPrefilteredMap(), + .day = scene->getLightEnvironment()->getEnvironmentMap()->getSkybox(), + .night = scene->getLightEnvironment()->getEnvironmentMap()->getSkybox(), .fogColor = Vector(0, 0, 0), .blendFactor = 0, }; diff --git a/src/Engine/Graphics/RenderPass/RayTracingPass.cpp b/src/Engine/Graphics/RenderPass/RayTracingPass.cpp index 2c46811..c6a5fd8 100644 --- a/src/Engine/Graphics/RenderPass/RayTracingPass.cpp +++ b/src/Engine/Graphics/RenderPass/RayTracingPass.cpp @@ -60,7 +60,7 @@ RayTracingPass::RayTracingPass(Gfx::PGraphics graphics, PScene scene) : RenderPa .useMaterial = true, .rayTracing = true, }); - skyBox = AssetRegistry::findEnvironmentMap("", "newport_loft")->getIrradianceMap(); + skyBox = AssetRegistry::findEnvironmentMap("", "newport_loft")->getSkybox(); skyBoxSampler = graphics->createSampler({}); } diff --git a/src/Engine/Scene/LightEnvironment.cpp b/src/Engine/Scene/LightEnvironment.cpp index 8364922..bcdf531 100644 --- a/src/Engine/Scene/LightEnvironment.cpp +++ b/src/Engine/Scene/LightEnvironment.cpp @@ -1,6 +1,8 @@ #include "LightEnvironment.h" #include "Asset/AssetRegistry.h" #include "Asset/EnvironmentMapAsset.h" +#include "Graphics/Descriptor.h" +#include "Graphics/Enums.h" #include "Graphics/Graphics.h" using namespace Seele; @@ -40,6 +42,18 @@ LightEnvironment::LightEnvironment(Gfx::PGraphics graphics) .name = "irradianceSampler", .descriptorType = Gfx::SE_DESCRIPTOR_TYPE_SAMPLER, }); + layout->addDescriptorBinding(Gfx::DescriptorBinding{ + .name = "prefilteredMap", + .descriptorType = Gfx::SE_DESCRIPTOR_TYPE_SAMPLED_IMAGE, + }); + layout->addDescriptorBinding(Gfx::DescriptorBinding{ + .name = "brdfLUT", + .descriptorType = Gfx::SE_DESCRIPTOR_TYPE_SAMPLED_IMAGE, + }); + layout->addDescriptorBinding(Gfx::DescriptorBinding{ + .name = "lutSampler", + .descriptorType = Gfx::SE_DESCRIPTOR_TYPE_SAMPLER, + }); layout->create(); directionalLights = graphics->createShaderBuffer(ShaderBufferCreateInfo{ @@ -128,6 +142,9 @@ void LightEnvironment::commit() { set->updateBuffer("pointLights", 0, pointLights); set->updateTexture("irradianceMap", 0, environment->getIrradianceMap()->getDefaultView()); set->updateSampler("irradianceSampler", 0, environmentSampler); + set->updateTexture("prefilteredMap", 0, environment->getPrefilteredMap()->getDefaultView()); + set->updateTexture("brdfLUT", 0, environment->getBrdfLUT()->getDefaultView()); + set->updateSampler("lutSampler", 0, environment->getLUTSampler()); set->writeChanges(); }