ADD: SSR with RT
This commit is contained in:
@@ -76,6 +76,9 @@ public:
|
||||
// Runtime settings visible to passes/shaders
|
||||
ShadowSettings shadowSettings{};
|
||||
bool enableSSR = false; // optional screen-space reflections toggle
|
||||
// Reflection mode for SSR/RT reflections; encoded into sceneData.rtOptions.w
|
||||
// 0 = SSR only, 1 = SSR + RT fallback, 2 = RT only
|
||||
uint32_t reflectionMode = 0;
|
||||
|
||||
// Ray tracing manager (optional, nullptr if unsupported)
|
||||
RayTracingManager* ray = nullptr;
|
||||
|
||||
@@ -569,8 +569,12 @@ void VulkanEngine::draw()
|
||||
//now that we are sure that the commands finished executing, we can safely reset the command buffer to begin recording again.
|
||||
VK_CHECK(vkResetCommandBuffer(get_current_frame()._mainCommandBuffer, 0));
|
||||
|
||||
// Build or update TLAS for current frame now that the previous frame is idle
|
||||
if (_rayManager && _context->shadowSettings.mode != 0u)
|
||||
// Build or update TLAS for current frame now that the previous frame is idle.
|
||||
// TLAS is used for hybrid/full RT shadows and RT-assisted SSR reflections.
|
||||
// For reflections, only build TLAS when RT is actually enabled (reflectionMode != 0).
|
||||
if (_rayManager &&
|
||||
(_context->shadowSettings.mode != 0u ||
|
||||
(_context->enableSSR && _context->reflectionMode != 0u)))
|
||||
{
|
||||
_rayManager->buildTLASFromDrawContext(_context->getMainDrawContext(), get_current_frame()._deletionQueue);
|
||||
}
|
||||
|
||||
@@ -602,6 +602,34 @@ namespace
|
||||
static void ui_postfx(VulkanEngine *eng)
|
||||
{
|
||||
if (!eng) return;
|
||||
if (!eng->_context) return;
|
||||
|
||||
EngineContext *ctx = eng->_context.get();
|
||||
|
||||
ImGui::TextUnformatted("Reflections");
|
||||
bool ssrEnabled = ctx->enableSSR;
|
||||
if (ImGui::Checkbox("Enable Screen-Space Reflections", &ssrEnabled))
|
||||
{
|
||||
ctx->enableSSR = ssrEnabled;
|
||||
}
|
||||
|
||||
int reflMode = static_cast<int>(ctx->reflectionMode);
|
||||
ImGui::TextUnformatted("Reflection Mode");
|
||||
ImGui::RadioButton("SSR only", &reflMode, 0);
|
||||
ImGui::SameLine();
|
||||
ImGui::RadioButton("SSR + RT fallback", &reflMode, 1);
|
||||
ImGui::SameLine();
|
||||
ImGui::RadioButton("RT only", &reflMode, 2);
|
||||
|
||||
const bool rq = eng->_deviceManager->supportsRayQuery();
|
||||
const bool as = eng->_deviceManager->supportsAccelerationStructure();
|
||||
if (!(rq && as) && reflMode != 0)
|
||||
{
|
||||
reflMode = 0; // guard for unsupported HW
|
||||
}
|
||||
ctx->reflectionMode = static_cast<uint32_t>(reflMode);
|
||||
|
||||
ImGui::Separator();
|
||||
if (auto *tm = eng->_renderPassManager ? eng->_renderPassManager->getPass<TonemapPass>() : nullptr)
|
||||
{
|
||||
float exp = tm->exposure();
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "ssr.h"
|
||||
|
||||
#include "raytracing.h"
|
||||
#include "core/frame/resources.h"
|
||||
#include "core/descriptor/manager.h"
|
||||
#include "core/descriptor/descriptors.h"
|
||||
@@ -38,16 +39,15 @@ void SSRPass::init(EngineContext *context)
|
||||
VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT);
|
||||
}
|
||||
|
||||
// Graphics pipeline: fullscreen triangle, no depth, HDR color attachment.
|
||||
GraphicsPipelineCreateInfo info{};
|
||||
info.vertexShaderPath = _context->getAssets()->shaderPath("fullscreen.vert.spv");
|
||||
info.fragmentShaderPath = _context->getAssets()->shaderPath("ssr.frag.spv");
|
||||
info.setLayouts = {
|
||||
_context->getDescriptorLayouts()->gpuSceneDataLayout(), // set = 0 (sceneData UBO)
|
||||
// Graphics pipelines: fullscreen triangle, no depth, HDR color attachment.
|
||||
GraphicsPipelineCreateInfo baseInfo{};
|
||||
baseInfo.vertexShaderPath = _context->getAssets()->shaderPath("fullscreen.vert.spv");
|
||||
baseInfo.setLayouts = {
|
||||
_context->getDescriptorLayouts()->gpuSceneDataLayout(), // set = 0 (sceneData UBO + optional TLAS)
|
||||
_inputSetLayout // set = 1 (HDR + GBuffer)
|
||||
};
|
||||
|
||||
info.configure = [this](PipelineBuilder &b)
|
||||
baseInfo.configure = [this](PipelineBuilder &b)
|
||||
{
|
||||
b.set_input_topology(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST);
|
||||
b.set_polygon_mode(VK_POLYGON_MODE_FILL);
|
||||
@@ -61,7 +61,15 @@ void SSRPass::init(EngineContext *context)
|
||||
}
|
||||
};
|
||||
|
||||
_context->pipelines->createGraphicsPipeline("ssr", info);
|
||||
// Non-RT variant (pure screen-space reflections).
|
||||
GraphicsPipelineCreateInfo infoNoRT = baseInfo;
|
||||
infoNoRT.fragmentShaderPath = _context->getAssets()->shaderPath("ssr.frag.spv");
|
||||
_context->pipelines->createGraphicsPipeline("ssr.nort", infoNoRT);
|
||||
|
||||
// RT-assisted variant (SSR + ray-query fallback using TLAS).
|
||||
GraphicsPipelineCreateInfo infoRT = baseInfo;
|
||||
infoRT.fragmentShaderPath = _context->getAssets()->shaderPath("ssr_rt.frag.spv");
|
||||
_context->pipelines->createGraphicsPipeline("ssr.rt", infoRT);
|
||||
}
|
||||
|
||||
void SSRPass::cleanup()
|
||||
@@ -148,10 +156,21 @@ void SSRPass::draw_ssr(VkCommandBuffer cmd,
|
||||
return;
|
||||
}
|
||||
|
||||
// Fetch (or refresh) pipeline for hot-reload support.
|
||||
if (!pipelineManager->getGraphics("ssr", _pipeline, _pipelineLayout))
|
||||
// Choose RT variant only if TLAS is valid; otherwise fall back to non-RT.
|
||||
const bool haveRTFeatures = deviceManager->supportsAccelerationStructure();
|
||||
const VkAccelerationStructureKHR tlas = (ctxLocal->ray ? ctxLocal->ray->tlas() : VK_NULL_HANDLE);
|
||||
const VkDeviceAddress tlasAddr = (ctxLocal->ray ? ctxLocal->ray->tlasAddress() : 0);
|
||||
const bool useRT = haveRTFeatures && (tlas != VK_NULL_HANDLE) && (tlasAddr != 0);
|
||||
|
||||
const char *pipeName = useRT ? "ssr.rt" : "ssr.nort";
|
||||
if (!pipelineManager->getGraphics(pipeName, _pipeline, _pipelineLayout))
|
||||
{
|
||||
return;
|
||||
// Try the other variant as a fallback.
|
||||
const char *fallback = useRT ? "ssr.nort" : "ssr.rt";
|
||||
if (!pipelineManager->getGraphics(fallback, _pipeline, _pipelineLayout))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Scene UBO (set=0, binding=0) – mirror LightingPass behavior.
|
||||
@@ -175,6 +194,10 @@ void SSRPass::draw_ssr(VkCommandBuffer cmd,
|
||||
{
|
||||
DescriptorWriter writer;
|
||||
writer.write_buffer(0, sceneBuf.buffer, sizeof(GPUSceneData), 0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER);
|
||||
if (useRT)
|
||||
{
|
||||
writer.write_acceleration_structure(1, tlas);
|
||||
}
|
||||
writer.update_set(deviceManager->device(), globalSet);
|
||||
}
|
||||
|
||||
|
||||
@@ -347,7 +347,10 @@ void SceneManager::update_scene()
|
||||
{
|
||||
const auto &ss = _context->shadowSettings;
|
||||
const uint32_t rtEnabled = (ss.mode != 0) ? 1u : 0u;
|
||||
sceneData.rtOptions = glm::uvec4(rtEnabled, ss.hybridRayCascadesMask, ss.mode, 0u);
|
||||
const uint32_t reflMode = _context->reflectionMode;
|
||||
// rtOptions.x = RT shadows enabled, y = cascade mask, z = shadow mode, w = reflection mode (SSR/RT)
|
||||
sceneData.rtOptions = glm::uvec4(rtEnabled, ss.hybridRayCascadesMask, ss.mode, reflMode);
|
||||
// rtParams.x = N·L threshold for hybrid shadows; remaining components reserved
|
||||
sceneData.rtParams = glm::vec4(ss.hybridRayNoLThreshold, 0.0f, 0.0f, 0.0f);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user