FIX: FXAA, bloom
This commit is contained in:
11
Readme.md
11
Readme.md
@@ -1,21 +1,24 @@
|
|||||||
# CopernicusEngine
|
# CopernicusEngine
|
||||||
Multipurpose Vulkan render engine specialized for physics simulation and solar system visualization
|
Multipurpose Vulkan render engine specialized for physics simulation and solar system visualization
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
## Introduction
|
## Introduction
|
||||||
Work-In-Progress Vulkan render engine
|
Work-In-Progress Vulkan render engine
|
||||||
Current structure:
|
Current structure:
|
||||||
- Flexible render graph system with multiple render passes, Hot reloading
|
- Flexible render graph system with multiple render passes, Hot reloading
|
||||||
- Deferred rendering
|
- Deferred rendering
|
||||||
- PBR, cascaded shadows, normal mapping (MikkTSpace tangents optional)
|
- PBR, cascaded shadows, normal mapping (MikkTSpace tangents optional)
|
||||||
- GLTF loading and rendering, primitive creation and rendering.
|
- GLTF loading and rendering, primitive creation and rendering
|
||||||
- Supports texture compression(BCn, non glTF standard), LRU reload
|
- Supports texture compression(BCn, non glTF standard), LRU reload
|
||||||
- Object clicking, generation.
|
- Runtime object clicking, generation, movement
|
||||||
- Multi light system
|
- Multi light system
|
||||||
- SSR
|
- SSR
|
||||||
|
- FXAA
|
||||||
|
- Bloom
|
||||||
|
|
||||||
Work-In-Progress
|
Work-In-Progress
|
||||||
- [ ] AA
|
- [ ] Floating origin with double precision coordinate system
|
||||||
- [ ] bloom
|
|
||||||
- [ ] Planet Rendering
|
- [ ] Planet Rendering
|
||||||
|
|
||||||
## Build prequsites
|
## Build prequsites
|
||||||
|
|||||||
52
shaders/fxaa.frag
Normal file
52
shaders/fxaa.frag
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
#version 450
|
||||||
|
|
||||||
|
layout(location = 0) in vec2 inUV;
|
||||||
|
layout(location = 0) out vec4 outColor;
|
||||||
|
|
||||||
|
layout(set = 0, binding = 0) uniform sampler2D uColor;
|
||||||
|
|
||||||
|
layout(push_constant) uniform Push
|
||||||
|
{
|
||||||
|
float inverse_width;
|
||||||
|
float inverse_height;
|
||||||
|
float edge_threshold;
|
||||||
|
float edge_threshold_min;
|
||||||
|
} pc;
|
||||||
|
|
||||||
|
float luma(vec3 c)
|
||||||
|
{
|
||||||
|
return dot(c, vec3(0.299, 0.587, 0.114));
|
||||||
|
}
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
vec2 texel = vec2(pc.inverse_width, pc.inverse_height);
|
||||||
|
|
||||||
|
vec3 cM = texture(uColor, inUV).rgb;
|
||||||
|
vec3 cN = texture(uColor, inUV + vec2(0.0, texel.y)).rgb;
|
||||||
|
vec3 cS = texture(uColor, inUV + vec2(0.0, -texel.y)).rgb;
|
||||||
|
vec3 cE = texture(uColor, inUV + vec2( texel.x, 0.0)).rgb;
|
||||||
|
vec3 cW = texture(uColor, inUV + vec2(-texel.x, 0.0)).rgb;
|
||||||
|
|
||||||
|
float lM = luma(cM);
|
||||||
|
float lN = luma(cN);
|
||||||
|
float lS = luma(cS);
|
||||||
|
float lE = luma(cE);
|
||||||
|
float lW = luma(cW);
|
||||||
|
|
||||||
|
float lMin = min(lM, min(min(lN, lS), min(lE, lW)));
|
||||||
|
float lMax = max(lM, max(max(lN, lS), max(lE, lW)));
|
||||||
|
float lRange = lMax - lMin;
|
||||||
|
|
||||||
|
float threshold = max(pc.edge_threshold_min, pc.edge_threshold * lMax);
|
||||||
|
if (lRange < threshold)
|
||||||
|
{
|
||||||
|
outColor = vec4(cM, 1.0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Simple 5-tap cross blur when we detect an edge.
|
||||||
|
vec3 avg = (cM + cN + cS + cE + cW) * 0.2;
|
||||||
|
outColor = vec4(avg, 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
@@ -9,6 +9,9 @@ layout(push_constant) uniform Push
|
|||||||
{
|
{
|
||||||
float exposure;
|
float exposure;
|
||||||
int mode;
|
int mode;
|
||||||
|
int bloomEnabled;
|
||||||
|
float bloomThreshold;
|
||||||
|
float bloomIntensity;
|
||||||
} pc;
|
} pc;
|
||||||
|
|
||||||
vec3 reinhard(vec3 x)
|
vec3 reinhard(vec3 x)
|
||||||
@@ -32,6 +35,34 @@ void main()
|
|||||||
{
|
{
|
||||||
vec3 hdr = texture(uHdr, inUV).rgb;
|
vec3 hdr = texture(uHdr, inUV).rgb;
|
||||||
|
|
||||||
|
// Simple bloom in HDR space: gather bright neighbors and add a small blurred contribution.
|
||||||
|
if (pc.bloomEnabled != 0)
|
||||||
|
{
|
||||||
|
vec2 texel = 1.0 / vec2(textureSize(uHdr, 0));
|
||||||
|
vec3 bloom = vec3(0.0);
|
||||||
|
int radius = 2;
|
||||||
|
int count = 0;
|
||||||
|
for (int x = -radius; x <= radius; ++x)
|
||||||
|
{
|
||||||
|
for (int y = -radius; y <= radius; ++y)
|
||||||
|
{
|
||||||
|
vec2 offset = vec2(x, y) * texel;
|
||||||
|
vec3 c = texture(uHdr, clamp(inUV + offset, vec2(0.0), vec2(1.0))).rgb;
|
||||||
|
float bright = max(max(c.r, c.g), c.b) - pc.bloomThreshold;
|
||||||
|
if (bright > 0.0)
|
||||||
|
{
|
||||||
|
bloom += c * bright;
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (count > 0)
|
||||||
|
{
|
||||||
|
bloom /= float(count);
|
||||||
|
}
|
||||||
|
hdr += pc.bloomIntensity * bloom;
|
||||||
|
}
|
||||||
|
|
||||||
// Simple exposure
|
// Simple exposure
|
||||||
float exposure = max(pc.exposure, 0.0001);
|
float exposure = max(pc.exposure, 0.0001);
|
||||||
vec3 mapped = hdr * exposure;
|
vec3 mapped = hdr * exposure;
|
||||||
|
|||||||
@@ -70,6 +70,8 @@ add_executable (vulkan_engine
|
|||||||
render/passes/lighting.cpp
|
render/passes/lighting.cpp
|
||||||
render/passes/shadow.h
|
render/passes/shadow.h
|
||||||
render/passes/shadow.cpp
|
render/passes/shadow.cpp
|
||||||
|
render/passes/fxaa.h
|
||||||
|
render/passes/fxaa.cpp
|
||||||
render/passes/ssr.h
|
render/passes/ssr.h
|
||||||
render/passes/ssr.cpp
|
render/passes/ssr.cpp
|
||||||
render/passes/transparent.h
|
render/passes/transparent.h
|
||||||
|
|||||||
@@ -42,6 +42,7 @@
|
|||||||
#include "render/passes/imgui_pass.h"
|
#include "render/passes/imgui_pass.h"
|
||||||
#include "render/passes/lighting.h"
|
#include "render/passes/lighting.h"
|
||||||
#include "render/passes/transparent.h"
|
#include "render/passes/transparent.h"
|
||||||
|
#include "render/passes/fxaa.h"
|
||||||
#include "render/passes/tonemap.h"
|
#include "render/passes/tonemap.h"
|
||||||
#include "render/passes/shadow.h"
|
#include "render/passes/shadow.h"
|
||||||
#include "device/resource.h"
|
#include "device/resource.h"
|
||||||
@@ -848,6 +849,12 @@ void VulkanEngine::draw()
|
|||||||
{
|
{
|
||||||
RGImageHandle hdrInput = (ssrEnabled && hSSR.valid()) ? hSSR : hDraw;
|
RGImageHandle hdrInput = (ssrEnabled && hSSR.valid()) ? hSSR : hDraw;
|
||||||
finalColor = tonemap->register_graph(_renderGraph.get(), hdrInput);
|
finalColor = tonemap->register_graph(_renderGraph.get(), hdrInput);
|
||||||
|
|
||||||
|
// Optional FXAA pass: runs on LDR tonemapped output.
|
||||||
|
if (auto *fxaa = _renderPassManager->getPass<FxaaPass>())
|
||||||
|
{
|
||||||
|
finalColor = fxaa->register_graph(_renderGraph.get(), finalColor);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
#include "render/primitives.h"
|
#include "render/primitives.h"
|
||||||
#include "vk_mem_alloc.h"
|
#include "vk_mem_alloc.h"
|
||||||
#include "render/passes/tonemap.h"
|
#include "render/passes/tonemap.h"
|
||||||
|
#include "render/passes/fxaa.h"
|
||||||
#include "render/passes/background.h"
|
#include "render/passes/background.h"
|
||||||
#include <glm/gtx/euler_angles.hpp>
|
#include <glm/gtx/euler_angles.hpp>
|
||||||
#include <glm/gtc/matrix_transform.hpp>
|
#include <glm/gtc/matrix_transform.hpp>
|
||||||
@@ -147,6 +148,30 @@ namespace
|
|||||||
"5x5 spheres: metallic across columns, roughness across rows.\nExtra: chrome + glass.");
|
"5x5 spheres: metallic across columns, roughness across rows.\nExtra: chrome + glass.");
|
||||||
|
|
||||||
ImGui::Separator();
|
ImGui::Separator();
|
||||||
|
|
||||||
|
// Post-processing: FXAA
|
||||||
|
if (auto *fx = eng->_renderPassManager ? eng->_renderPassManager->getPass<FxaaPass>() : nullptr)
|
||||||
|
{
|
||||||
|
bool fxaaEnabled = fx->enabled();
|
||||||
|
if (ImGui::Checkbox("FXAA", &fxaaEnabled))
|
||||||
|
{
|
||||||
|
fx->set_enabled(fxaaEnabled);
|
||||||
|
}
|
||||||
|
float edgeTh = fx->edge_threshold();
|
||||||
|
if (ImGui::SliderFloat("FXAA Edge Threshold", &edgeTh, 0.01f, 0.5f))
|
||||||
|
{
|
||||||
|
fx->set_edge_threshold(edgeTh);
|
||||||
|
}
|
||||||
|
float edgeThMin = fx->edge_threshold_min();
|
||||||
|
if (ImGui::SliderFloat("FXAA Edge Threshold Min", &edgeThMin, 0.0f, 0.1f))
|
||||||
|
{
|
||||||
|
fx->set_edge_threshold_min(edgeThMin);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ImGui::TextUnformatted("FXAA pass not available");
|
||||||
|
}
|
||||||
ImGui::TextUnformatted("IBL Volumes (reflection probes)");
|
ImGui::TextUnformatted("IBL Volumes (reflection probes)");
|
||||||
|
|
||||||
if (!eng->_iblManager)
|
if (!eng->_iblManager)
|
||||||
@@ -740,6 +765,23 @@ namespace
|
|||||||
mode = 1;
|
mode = 1;
|
||||||
tm->setMode(mode);
|
tm->setMode(mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Bloom controls
|
||||||
|
bool bloomEnabled = tm->bloomEnabled();
|
||||||
|
if (ImGui::Checkbox("Bloom", &bloomEnabled))
|
||||||
|
{
|
||||||
|
tm->setBloomEnabled(bloomEnabled);
|
||||||
|
}
|
||||||
|
float bloomThreshold = tm->bloomThreshold();
|
||||||
|
if (ImGui::SliderFloat("Bloom Threshold", &bloomThreshold, 0.0f, 5.0f))
|
||||||
|
{
|
||||||
|
tm->setBloomThreshold(bloomThreshold);
|
||||||
|
}
|
||||||
|
float bloomIntensity = tm->bloomIntensity();
|
||||||
|
if (ImGui::SliderFloat("Bloom Intensity", &bloomIntensity, 0.0f, 2.0f))
|
||||||
|
{
|
||||||
|
tm->setBloomIntensity(bloomIntensity);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
140
src/render/passes/fxaa.cpp
Normal file
140
src/render/passes/fxaa.cpp
Normal file
@@ -0,0 +1,140 @@
|
|||||||
|
#include "fxaa.h"
|
||||||
|
|
||||||
|
#include <core/context.h>
|
||||||
|
#include <core/descriptor/descriptors.h>
|
||||||
|
#include <core/descriptor/manager.h>
|
||||||
|
#include <core/pipeline/manager.h>
|
||||||
|
#include <core/assets/manager.h>
|
||||||
|
#include <core/device/device.h>
|
||||||
|
#include <core/device/resource.h>
|
||||||
|
#include <core/pipeline/sampler.h>
|
||||||
|
#include <render/graph/graph.h>
|
||||||
|
#include <render/graph/resources.h>
|
||||||
|
|
||||||
|
#include "core/frame/resources.h"
|
||||||
|
|
||||||
|
void FxaaPass::init(EngineContext *context)
|
||||||
|
{
|
||||||
|
_context = context;
|
||||||
|
if (!_context || !_context->getDevice() || !_context->getDescriptorLayouts() || !_context->pipelines)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_inputSetLayout = _context->getDescriptorLayouts()->singleImageLayout();
|
||||||
|
|
||||||
|
GraphicsPipelineCreateInfo info{};
|
||||||
|
info.vertexShaderPath = _context->getAssets()->shaderPath("fullscreen.vert.spv");
|
||||||
|
info.fragmentShaderPath = _context->getAssets()->shaderPath("fxaa.frag.spv");
|
||||||
|
info.setLayouts = { _inputSetLayout };
|
||||||
|
|
||||||
|
VkPushConstantRange pcr{};
|
||||||
|
pcr.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||||
|
pcr.offset = 0;
|
||||||
|
pcr.size = sizeof(FxaaPush);
|
||||||
|
info.pushConstants = { pcr };
|
||||||
|
|
||||||
|
info.configure = [this](PipelineBuilder &b) {
|
||||||
|
b.set_input_topology(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST);
|
||||||
|
b.set_polygon_mode(VK_POLYGON_MODE_FILL);
|
||||||
|
b.set_cull_mode(VK_CULL_MODE_NONE, VK_FRONT_FACE_CLOCKWISE);
|
||||||
|
b.set_multisampling_none();
|
||||||
|
b.disable_depthtest();
|
||||||
|
b.disable_blending();
|
||||||
|
b.set_color_attachment_format(VK_FORMAT_R8G8B8A8_UNORM);
|
||||||
|
};
|
||||||
|
|
||||||
|
_context->pipelines->createGraphicsPipeline("fxaa", info);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FxaaPass::cleanup()
|
||||||
|
{
|
||||||
|
_deletionQueue.flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
void FxaaPass::execute(VkCommandBuffer)
|
||||||
|
{
|
||||||
|
// Executed via render graph.
|
||||||
|
}
|
||||||
|
|
||||||
|
RGImageHandle FxaaPass::register_graph(RenderGraph *graph, RGImageHandle ldrInput)
|
||||||
|
{
|
||||||
|
if (!graph || !ldrInput.valid() || !_context)
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
// If disabled, simply bypass and return the input image.
|
||||||
|
if (!_enabled)
|
||||||
|
{
|
||||||
|
return ldrInput;
|
||||||
|
}
|
||||||
|
|
||||||
|
RGImageDesc desc{};
|
||||||
|
desc.name = "ldr.fxaa";
|
||||||
|
desc.format = VK_FORMAT_R8G8B8A8_UNORM;
|
||||||
|
desc.extent = _context->getDrawExtent();
|
||||||
|
desc.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT
|
||||||
|
| VK_IMAGE_USAGE_SAMPLED_BIT
|
||||||
|
| VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
|
||||||
|
RGImageHandle aaOutput = graph->create_image(desc);
|
||||||
|
|
||||||
|
graph->add_pass(
|
||||||
|
"FXAA",
|
||||||
|
RGPassType::Graphics,
|
||||||
|
[ldrInput, aaOutput](RGPassBuilder &builder, EngineContext *) {
|
||||||
|
builder.read(ldrInput, RGImageUsage::SampledFragment);
|
||||||
|
builder.write_color(aaOutput, true /*clear*/);
|
||||||
|
},
|
||||||
|
[this, ldrInput](VkCommandBuffer cmd, const RGPassResources &res, EngineContext *ctx) {
|
||||||
|
draw_fxaa(cmd, ctx, res, ldrInput);
|
||||||
|
});
|
||||||
|
|
||||||
|
return aaOutput;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FxaaPass::draw_fxaa(VkCommandBuffer cmd, EngineContext *ctx, const RGPassResources &res,
|
||||||
|
RGImageHandle ldrInput)
|
||||||
|
{
|
||||||
|
if (!ctx || !ctx->currentFrame) return;
|
||||||
|
DeviceManager *deviceManager = ctx->getDevice();
|
||||||
|
DescriptorManager *descriptorLayouts = ctx->getDescriptorLayouts();
|
||||||
|
PipelineManager *pipelineManager = ctx->pipelines;
|
||||||
|
if (!deviceManager || !descriptorLayouts || !pipelineManager) return;
|
||||||
|
|
||||||
|
VkImageView srcView = res.image_view(ldrInput);
|
||||||
|
if (srcView == VK_NULL_HANDLE) return;
|
||||||
|
|
||||||
|
VkDevice device = deviceManager->device();
|
||||||
|
|
||||||
|
VkDescriptorSet set = ctx->currentFrame->_frameDescriptors.allocate(device, _inputSetLayout);
|
||||||
|
DescriptorWriter writer;
|
||||||
|
writer.write_image(0, srcView, ctx->getSamplers()->defaultLinear(),
|
||||||
|
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER);
|
||||||
|
writer.update_set(device, set);
|
||||||
|
|
||||||
|
VkPipeline pipeline{};
|
||||||
|
VkPipelineLayout layout{};
|
||||||
|
if (!pipelineManager->getGraphics("fxaa", pipeline, layout))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
|
||||||
|
vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, layout, 0, 1, &set, 0, nullptr);
|
||||||
|
|
||||||
|
VkExtent2D extent = ctx->getDrawExtent();
|
||||||
|
|
||||||
|
FxaaPush push{};
|
||||||
|
push.inverse_width = extent.width > 0 ? 1.0f / static_cast<float>(extent.width) : 0.0f;
|
||||||
|
push.inverse_height = extent.height > 0 ? 1.0f / static_cast<float>(extent.height) : 0.0f;
|
||||||
|
push.edge_threshold = _edge_threshold;
|
||||||
|
push.edge_threshold_min = _edge_threshold_min;
|
||||||
|
vkCmdPushConstants(cmd, layout, VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(FxaaPush), &push);
|
||||||
|
|
||||||
|
VkViewport vp{0.f, 0.f, static_cast<float>(extent.width), static_cast<float>(extent.height), 0.f, 1.f};
|
||||||
|
VkRect2D sc{{0, 0}, extent};
|
||||||
|
vkCmdSetViewport(cmd, 0, 1, &vp);
|
||||||
|
vkCmdSetScissor(cmd, 0, 1, &sc);
|
||||||
|
vkCmdDraw(cmd, 3, 1, 0, 0);
|
||||||
|
}
|
||||||
56
src/render/passes/fxaa.h
Normal file
56
src/render/passes/fxaa.h
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <core/types.h>
|
||||||
|
#include <render/renderpass.h>
|
||||||
|
#include <render/graph/types.h>
|
||||||
|
|
||||||
|
class EngineContext;
|
||||||
|
class RenderGraph;
|
||||||
|
class RGPassResources;
|
||||||
|
|
||||||
|
// Simple post-process anti-aliasing pass (FXAA-like).
|
||||||
|
// Operates on the LDR tonemapped image and outputs a smoothed LDR image.
|
||||||
|
class FxaaPass final : public IRenderPass
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void init(EngineContext *context) override;
|
||||||
|
void cleanup() override;
|
||||||
|
void execute(VkCommandBuffer) override; // Not used directly; executed via render graph
|
||||||
|
const char *getName() const override { return "FXAA"; }
|
||||||
|
|
||||||
|
// Register pass in the render graph. Returns the AA output image handle.
|
||||||
|
RGImageHandle register_graph(RenderGraph *graph, RGImageHandle ldrInput);
|
||||||
|
|
||||||
|
// Runtime parameters
|
||||||
|
void set_enabled(bool e) { _enabled = e; }
|
||||||
|
bool enabled() const { return _enabled; }
|
||||||
|
void set_edge_threshold(float v) { _edge_threshold = v; }
|
||||||
|
float edge_threshold() const { return _edge_threshold; }
|
||||||
|
void set_edge_threshold_min(float v) { _edge_threshold_min = v; }
|
||||||
|
float edge_threshold_min() const { return _edge_threshold_min; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct FxaaPush
|
||||||
|
{
|
||||||
|
float inverse_width;
|
||||||
|
float inverse_height;
|
||||||
|
float edge_threshold;
|
||||||
|
float edge_threshold_min;
|
||||||
|
};
|
||||||
|
|
||||||
|
void draw_fxaa(VkCommandBuffer cmd, EngineContext *ctx, const RGPassResources &res,
|
||||||
|
RGImageHandle ldrInput);
|
||||||
|
|
||||||
|
EngineContext *_context = nullptr;
|
||||||
|
|
||||||
|
VkPipeline _pipeline = VK_NULL_HANDLE;
|
||||||
|
VkPipelineLayout _pipelineLayout = VK_NULL_HANDLE;
|
||||||
|
VkDescriptorSetLayout _inputSetLayout = VK_NULL_HANDLE;
|
||||||
|
|
||||||
|
// Tunables for edge detection; chosen to be conservative by default.
|
||||||
|
bool _enabled = true;
|
||||||
|
float _edge_threshold = 0.125f;
|
||||||
|
float _edge_threshold_min = 0.0312f;
|
||||||
|
|
||||||
|
DeletionQueue _deletionQueue;
|
||||||
|
};
|
||||||
@@ -17,6 +17,9 @@ struct TonemapPush
|
|||||||
{
|
{
|
||||||
float exposure;
|
float exposure;
|
||||||
int mode;
|
int mode;
|
||||||
|
int bloomEnabled;
|
||||||
|
float bloomThreshold;
|
||||||
|
float bloomIntensity;
|
||||||
};
|
};
|
||||||
|
|
||||||
void TonemapPass::init(EngineContext *context)
|
void TonemapPass::init(EngineContext *context)
|
||||||
@@ -72,7 +75,9 @@ RGImageHandle TonemapPass::register_graph(RenderGraph *graph, RGImageHandle hdrI
|
|||||||
desc.name = "ldr.tonemap";
|
desc.name = "ldr.tonemap";
|
||||||
desc.format = VK_FORMAT_R8G8B8A8_UNORM;
|
desc.format = VK_FORMAT_R8G8B8A8_UNORM;
|
||||||
desc.extent = _context->getDrawExtent();
|
desc.extent = _context->getDrawExtent();
|
||||||
desc.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
|
desc.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT
|
||||||
|
| VK_IMAGE_USAGE_SAMPLED_BIT
|
||||||
|
| VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
|
||||||
RGImageHandle ldr = graph->create_image(desc);
|
RGImageHandle ldr = graph->create_image(desc);
|
||||||
|
|
||||||
graph->add_pass(
|
graph->add_pass(
|
||||||
@@ -109,7 +114,12 @@ void TonemapPass::draw_tonemap(VkCommandBuffer cmd, EngineContext *ctx, const RG
|
|||||||
vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, _pipeline);
|
vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, _pipeline);
|
||||||
vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, _pipelineLayout, 0, 1, &set, 0, nullptr);
|
vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, _pipelineLayout, 0, 1, &set, 0, nullptr);
|
||||||
|
|
||||||
TonemapPush push{_exposure, _mode};
|
TonemapPush push{};
|
||||||
|
push.exposure = _exposure;
|
||||||
|
push.mode = _mode;
|
||||||
|
push.bloomEnabled = _bloomEnabled ? 1 : 0;
|
||||||
|
push.bloomThreshold = _bloomThreshold;
|
||||||
|
push.bloomIntensity = _bloomIntensity;
|
||||||
vkCmdPushConstants(cmd, _pipelineLayout, VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(TonemapPush), &push);
|
vkCmdPushConstants(cmd, _pipelineLayout, VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(TonemapPush), &push);
|
||||||
|
|
||||||
VkExtent2D extent = ctx->getDrawExtent();
|
VkExtent2D extent = ctx->getDrawExtent();
|
||||||
|
|||||||
@@ -25,6 +25,13 @@ public:
|
|||||||
void setMode(int m) { _mode = m; }
|
void setMode(int m) { _mode = m; }
|
||||||
int mode() const { return _mode; }
|
int mode() const { return _mode; }
|
||||||
|
|
||||||
|
void setBloomEnabled(bool b) { _bloomEnabled = b; }
|
||||||
|
bool bloomEnabled() const { return _bloomEnabled; }
|
||||||
|
void setBloomThreshold(float t) { _bloomThreshold = t; }
|
||||||
|
float bloomThreshold() const { return _bloomThreshold; }
|
||||||
|
void setBloomIntensity(float i) { _bloomIntensity = i; }
|
||||||
|
float bloomIntensity() const { return _bloomIntensity; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void draw_tonemap(VkCommandBuffer cmd, EngineContext *ctx, const RGPassResources &res,
|
void draw_tonemap(VkCommandBuffer cmd, EngineContext *ctx, const RGPassResources &res,
|
||||||
RGImageHandle hdrInput);
|
RGImageHandle hdrInput);
|
||||||
@@ -38,6 +45,10 @@ private:
|
|||||||
float _exposure = 1.0f;
|
float _exposure = 1.0f;
|
||||||
int _mode = 1; // default to ACES
|
int _mode = 1; // default to ACES
|
||||||
|
|
||||||
|
bool _bloomEnabled = true;
|
||||||
|
float _bloomThreshold = 1.0f;
|
||||||
|
float _bloomIntensity = 0.7f;
|
||||||
|
|
||||||
DeletionQueue _deletionQueue;
|
DeletionQueue _deletionQueue;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
#include "passes/imgui_pass.h"
|
#include "passes/imgui_pass.h"
|
||||||
#include "passes/lighting.h"
|
#include "passes/lighting.h"
|
||||||
#include "passes/ssr.h"
|
#include "passes/ssr.h"
|
||||||
|
#include "passes/fxaa.h"
|
||||||
#include "passes/transparent.h"
|
#include "passes/transparent.h"
|
||||||
#include "passes/tonemap.h"
|
#include "passes/tonemap.h"
|
||||||
#include "passes/shadow.h"
|
#include "passes/shadow.h"
|
||||||
@@ -35,6 +36,11 @@ void RenderPassManager::init(EngineContext *context)
|
|||||||
ssrPass->init(context);
|
ssrPass->init(context);
|
||||||
addPass(std::move(ssrPass));
|
addPass(std::move(ssrPass));
|
||||||
|
|
||||||
|
// Post-process AA (FXAA-like) after tonemapping.
|
||||||
|
auto fxaaPass = std::make_unique<FxaaPass>();
|
||||||
|
fxaaPass->init(context);
|
||||||
|
addPass(std::move(fxaaPass));
|
||||||
|
|
||||||
auto transparentPass = std::make_unique<TransparentPass>();
|
auto transparentPass = std::make_unique<TransparentPass>();
|
||||||
transparentPass->init(context);
|
transparentPass->init(context);
|
||||||
addPass(std::move(transparentPass));
|
addPass(std::move(transparentPass));
|
||||||
|
|||||||
Reference in New Issue
Block a user