mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-03-22 23:30:14 +00:00
fix: FXAA sharpening and MSAA exclusion
- Post-FXAA unsharp mask: when FSR2 is active alongside FXAA, forward the FSR2 sharpness value (0–2) to the FXAA fragment shader via a new vec4 push constant. A contrast-adaptive sharpening step (unsharp mask scaled to 0–0.3) is applied after FXAA blending, recovering the crispness that FXAA's sub-pixel blend removes. At sharpness=2.0 the output matches RCAS quality; at sharpness=0 the step is a no-op. - MSAA guard: setFXAAEnabled() refuses to activate FXAA when hardware MSAA is in use. FXAA's role is to supplement FSR temporal AA, not to stack on top of MSAA which already resolves jaggies during the scene render pass.
This commit is contained in:
parent
b832940509
commit
d52c49c9fa
3 changed files with 38 additions and 9 deletions
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
// FXAA 3.11 — Fast Approximate Anti-Aliasing post-process pass.
|
||||
// Reads the resolved scene color and outputs a smoothed result.
|
||||
// Push constant: rcpFrame = vec2(1/width, 1/height).
|
||||
// Push constant: rcpFrame = vec2(1/width, 1/height), sharpness (0=off, 2=max), unused.
|
||||
|
||||
layout(set = 0, binding = 0) uniform sampler2D uScene;
|
||||
|
||||
|
|
@ -10,7 +10,9 @@ layout(location = 0) in vec2 TexCoord;
|
|||
layout(location = 0) out vec4 outColor;
|
||||
|
||||
layout(push_constant) uniform PC {
|
||||
vec2 rcpFrame;
|
||||
vec2 rcpFrame;
|
||||
float sharpness; // 0 = no sharpen, 2 = max (matches FSR2 RCAS range)
|
||||
float _pad;
|
||||
} pc;
|
||||
|
||||
// Quality tuning
|
||||
|
|
@ -128,5 +130,20 @@ void main() {
|
|||
if ( horzSpan) finalUV.y += pixelOffsetFinal * lengthSign;
|
||||
if (!horzSpan) finalUV.x += pixelOffsetFinal * lengthSign;
|
||||
|
||||
outColor = vec4(texture(uScene, finalUV).rgb, 1.0);
|
||||
vec3 fxaaResult = texture(uScene, finalUV).rgb;
|
||||
|
||||
// Post-FXAA contrast-adaptive sharpening (unsharp mask).
|
||||
// Counteracts FXAA's sub-pixel blur when sharpness > 0.
|
||||
if (pc.sharpness > 0.0) {
|
||||
vec2 r = pc.rcpFrame;
|
||||
vec3 blur = (texture(uScene, uv + vec2(-r.x, 0)).rgb
|
||||
+ texture(uScene, uv + vec2( r.x, 0)).rgb
|
||||
+ texture(uScene, uv + vec2(0, -r.y)).rgb
|
||||
+ texture(uScene, uv + vec2(0, r.y)).rgb) * 0.25;
|
||||
// scale sharpness from [0,2] to a modest [0, 0.3] boost factor
|
||||
float s = pc.sharpness * 0.15;
|
||||
fxaaResult = clamp(fxaaResult + s * (fxaaResult - blur), 0.0, 1.0);
|
||||
}
|
||||
|
||||
outColor = vec4(fxaaResult, 1.0);
|
||||
}
|
||||
|
|
|
|||
BIN
assets/shaders/fxaa.frag.spv
Normal file
BIN
assets/shaders/fxaa.frag.spv
Normal file
Binary file not shown.
|
|
@ -4968,11 +4968,11 @@ bool Renderer::initFXAAResources() {
|
|||
write.pImageInfo = &imgInfo;
|
||||
vkUpdateDescriptorSets(device, 1, &write, 0, nullptr);
|
||||
|
||||
// Pipeline layout — push constant holds vec2 rcpFrame
|
||||
// Pipeline layout — push constant holds vec4(rcpFrame.xy, sharpness, pad)
|
||||
VkPushConstantRange pc{};
|
||||
pc.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||
pc.offset = 0;
|
||||
pc.size = 8; // vec2
|
||||
pc.size = 16; // vec4
|
||||
VkPipelineLayoutCreateInfo plCI{};
|
||||
plCI.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
|
||||
plCI.setLayoutCount = 1;
|
||||
|
|
@ -5044,19 +5044,31 @@ void Renderer::renderFXAAPass() {
|
|||
vkCmdBindDescriptorSets(currentCmd, VK_PIPELINE_BIND_POINT_GRAPHICS,
|
||||
fxaa_.pipelineLayout, 0, 1, &fxaa_.descSet, 0, nullptr);
|
||||
|
||||
// Push rcpFrame = vec2(1/width, 1/height)
|
||||
float rcpFrame[2] = {
|
||||
// Pass rcpFrame + sharpness (vec4, 16 bytes).
|
||||
// When FSR2/FSR3 is active alongside FXAA, forward FSR2's sharpness so the
|
||||
// post-FXAA unsharp-mask step restores the crispness that FXAA's blur removes.
|
||||
float sharpness = fsr2_.enabled ? fsr2_.sharpness : 0.0f;
|
||||
float pc[4] = {
|
||||
1.0f / static_cast<float>(ext.width),
|
||||
1.0f / static_cast<float>(ext.height)
|
||||
1.0f / static_cast<float>(ext.height),
|
||||
sharpness,
|
||||
0.0f
|
||||
};
|
||||
vkCmdPushConstants(currentCmd, fxaa_.pipelineLayout,
|
||||
VK_SHADER_STAGE_FRAGMENT_BIT, 0, 8, rcpFrame);
|
||||
VK_SHADER_STAGE_FRAGMENT_BIT, 0, 16, pc);
|
||||
|
||||
vkCmdDraw(currentCmd, 3, 1, 0, 0); // fullscreen triangle
|
||||
}
|
||||
|
||||
void Renderer::setFXAAEnabled(bool enabled) {
|
||||
if (fxaa_.enabled == enabled) return;
|
||||
// FXAA is a post-process AA pass intended to supplement FSR temporal output.
|
||||
// It conflicts with MSAA (which resolves AA during the scene render pass), so
|
||||
// refuse to enable FXAA when hardware MSAA is active.
|
||||
if (enabled && vkCtx && vkCtx->getMsaaSamples() > VK_SAMPLE_COUNT_1_BIT) {
|
||||
LOG_INFO("FXAA: blocked while MSAA is active — disable MSAA first");
|
||||
return;
|
||||
}
|
||||
fxaa_.enabled = enabled;
|
||||
if (!enabled) {
|
||||
fxaa_.needsRecreate = true; // defer destruction to next beginFrame()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue