diff --git a/Content/Editor/MaterialTemplates/Features/DeferredShading.hlsl b/Content/Editor/MaterialTemplates/Features/DeferredShading.hlsl
index d3a7a2518..556cc99a1 100644
--- a/Content/Editor/MaterialTemplates/Features/DeferredShading.hlsl
+++ b/Content/Editor/MaterialTemplates/Features/DeferredShading.hlsl
@@ -25,7 +25,7 @@ void PS_GBuffer(
#endif
)
{
- Light = 0;
+ Light = float4(0, 0, 0, 1);
#if USE_DITHERED_LOD_TRANSITION
// LOD masking
diff --git a/Source/Engine/Graphics/Materials/MaterialShader.h b/Source/Engine/Graphics/Materials/MaterialShader.h
index fae152681..3c8bf37bf 100644
--- a/Source/Engine/Graphics/Materials/MaterialShader.h
+++ b/Source/Engine/Graphics/Materials/MaterialShader.h
@@ -10,7 +10,7 @@
///
/// Current materials shader version.
///
-#define MATERIAL_GRAPH_VERSION 155
+#define MATERIAL_GRAPH_VERSION 156
class Material;
class GPUShader;
diff --git a/Source/Engine/Graphics/RenderBuffers.cpp b/Source/Engine/Graphics/RenderBuffers.cpp
index 51e4a3436..6edceab8e 100644
--- a/Source/Engine/Graphics/RenderBuffers.cpp
+++ b/Source/Engine/Graphics/RenderBuffers.cpp
@@ -111,6 +111,33 @@ GPUTexture* RenderBuffers::RequestHalfResDepth(GPUContext* context)
return HalfResDepth;
}
+PixelFormat RenderBuffers::GetOutputFormat() const
+{
+ return _useAlpha ? PixelFormat::R16G16B16A16_Float : PixelFormat::R11G11B10_Float;
+}
+
+bool RenderBuffers::GetUseAlpha() const
+{
+ return _useAlpha;
+}
+
+void RenderBuffers::SetUseAlpha(bool value)
+{
+ if (_useAlpha != value)
+ {
+ _useAlpha = value;
+
+ // Reallocate buffers
+ if (_width != 0)
+ {
+ auto desc = GPUTextureDescription::New2D(_width, _height, GetOutputFormat(), GPUTextureFlags::ShaderResource | GPUTextureFlags::RenderTarget);
+ desc.DefaultClearColor = Color::Transparent;
+ RT1_FloatRGB->Init(desc);
+ RT2_FloatRGB->Init(desc);
+ }
+ }
+}
+
const RenderBuffers::CustomBuffer* RenderBuffers::FindCustomBuffer(const StringView& name) const
{
for (const CustomBuffer* e : CustomBuffers)
@@ -169,7 +196,7 @@ bool RenderBuffers::Init(int32 width, int32 height)
result |= GBuffer3->Init(desc);
// Helper HDR buffers
- desc.Format = PixelFormat::R11G11B10_Float;
+ desc.Format = GetOutputFormat();
desc.DefaultClearColor = Color::Transparent;
result |= RT1_FloatRGB->Init(desc);
result |= RT2_FloatRGB->Init(desc);
diff --git a/Source/Engine/Graphics/RenderBuffers.h b/Source/Engine/Graphics/RenderBuffers.h
index 0e3aef27d..d5f56119d 100644
--- a/Source/Engine/Graphics/RenderBuffers.h
+++ b/Source/Engine/Graphics/RenderBuffers.h
@@ -13,9 +13,6 @@
#define GBUFFER2_FORMAT PixelFormat::R8G8B8A8_UNorm
#define GBUFFER3_FORMAT PixelFormat::R8G8B8A8_UNorm
-// Light accumulation buffer format (direct+indirect light, materials emissive)
-#define LIGHT_BUFFER_FORMAT PixelFormat::R11G11B10_Float
-
///
/// The scene rendering buffers container.
///
@@ -39,6 +36,7 @@ protected:
int32 _width = 0;
int32 _height = 0;
float _aspectRatio = 0.0f;
+ bool _useAlpha = false;
Viewport _viewport;
Array> _resources;
@@ -153,6 +151,21 @@ public:
return _viewport;
}
+ ///
+ /// Gets the output buffers format (R11G11B10 or R16G16B16A16 depending on UseAlpha property).
+ ///
+ API_PROPERTY() PixelFormat GetOutputFormat() const;
+
+ ///
+ /// True if support alpha output in the rendering buffers and pass-though alpha mask of the scene during rendering (at cost of reduced performance).
+ ///
+ API_PROPERTY() bool GetUseAlpha() const;
+
+ ///
+ /// True if support alpha output in the rendering buffers and pass-though alpha mask of the scene during rendering (at cost of reduced performance).
+ ///
+ API_PROPERTY() void SetUseAlpha(bool value);
+
const CustomBuffer* FindCustomBuffer(const StringView& name) const;
template
diff --git a/Source/Engine/Renderer/AntiAliasing/FXAA.cpp b/Source/Engine/Renderer/AntiAliasing/FXAA.cpp
index d1098e9e3..f4a9092e7 100644
--- a/Source/Engine/Renderer/AntiAliasing/FXAA.cpp
+++ b/Source/Engine/Renderer/AntiAliasing/FXAA.cpp
@@ -7,12 +7,19 @@
#include "Engine/Graphics/Graphics.h"
#include "Engine/Graphics/RenderTask.h"
+PACK_STRUCT(struct Data
+ {
+ Float4 ScreenSize;
+ });
+
+String FXAA::ToString() const
+{
+ return TEXT("FXAA");
+}
+
bool FXAA::Init()
{
- // Create pipeline state
_psFXAA.CreatePipelineStates();
-
- // Load shader
_shader = Content::LoadAsyncInternal(TEXT("Shaders/FXAA"));
if (_shader == nullptr)
return true;
@@ -25,21 +32,17 @@ bool FXAA::Init()
bool FXAA::setupResources()
{
- // Check shader
if (!_shader->IsLoaded())
{
return true;
}
const auto shader = _shader->GetShader();
-
- // Validate shader constant buffer size
if (shader->GetCB(0)->GetSize() != sizeof(Data))
{
REPORT_INVALID_SHADER_PASS_CB_SIZE(shader, 0, Data);
return true;
}
- // Create pipeline state
GPUPipelineState::Description psDesc;
if (!_psFXAA.IsValid())
{
@@ -56,7 +59,6 @@ void FXAA::Dispose()
// Base
RendererPass::Dispose();
- // Cleanup
_psFXAA.Delete();
_shader = nullptr;
}
@@ -64,9 +66,6 @@ void FXAA::Dispose()
void FXAA::Render(RenderContext& renderContext, GPUTexture* input, GPUTextureView* output)
{
auto context = GPUDevice::Instance->GetMainContext();
- const auto qualityLevel = Math::Clamp(static_cast(Graphics::AAQuality), 0, static_cast(Quality::MAX) - 1);
-
- // Ensure to have valid data
if (checkIfSkipPass())
{
// Resources are missing. Do not perform rendering, just copy input frame.
@@ -74,7 +73,6 @@ void FXAA::Render(RenderContext& renderContext, GPUTexture* input, GPUTextureVie
context->Draw(input);
return;
}
-
PROFILE_GPU_CPU("Fast Approximate Antialiasing");
// Bind input
@@ -87,6 +85,7 @@ void FXAA::Render(RenderContext& renderContext, GPUTexture* input, GPUTextureVie
// Render
context->SetRenderTarget(output);
+ const auto qualityLevel = Math::Clamp(static_cast(Graphics::AAQuality), 0, static_cast(Quality::MAX) - 1);
context->SetState(_psFXAA.Get(qualityLevel));
context->DrawFullscreenTriangle();
}
diff --git a/Source/Engine/Renderer/AntiAliasing/FXAA.h b/Source/Engine/Renderer/AntiAliasing/FXAA.h
index a6e6c449c..f151c397d 100644
--- a/Source/Engine/Renderer/AntiAliasing/FXAA.h
+++ b/Source/Engine/Renderer/AntiAliasing/FXAA.h
@@ -11,17 +11,10 @@
class FXAA : public RendererPass
{
private:
-
- PACK_STRUCT(struct Data
- {
- Float4 ScreenSize;
- });
-
AssetReference _shader;
GPUPipelineStatePermutationsPs(Quality::MAX)> _psFXAA;
public:
-
///
/// Performs AA pass rendering for the input task.
///
@@ -31,7 +24,6 @@ public:
void Render(RenderContext& renderContext, GPUTexture* input, GPUTextureView* output);
private:
-
#if COMPILE_WITH_DEV_ENV
void OnShaderReloading(Asset* obj)
{
@@ -41,18 +33,12 @@ private:
#endif
public:
-
// [RendererPass]
- String ToString() const override
- {
- return TEXT("FXAA");
- }
-
+ String ToString() const override;
bool Init() override;
void Dispose() override;
protected:
-
// [RendererPass]
bool setupResources() override;
};
diff --git a/Source/Engine/Renderer/DepthOfFieldPass.cpp b/Source/Engine/Renderer/DepthOfFieldPass.cpp
index 69c39eaa7..01d370256 100644
--- a/Source/Engine/Renderer/DepthOfFieldPass.cpp
+++ b/Source/Engine/Renderer/DepthOfFieldPass.cpp
@@ -20,6 +20,7 @@
#define DOF_GRID_SIZE 450
#define DOF_APRON_SIZE DOF_MAX_SAMPLE_RADIUS
#define DOF_THREAD_GROUP_SIZE (DOF_GRID_SIZE + (DOF_APRON_SIZE * 2))
+#define DOF_DEPTH_BLUR_FORMAT PixelFormat::R16G16_Float
DepthOfFieldPass::DepthOfFieldPass()
{
@@ -320,7 +321,8 @@ GPUTexture* DepthOfFieldPass::Render(RenderContext& renderContext, GPUTexture* i
}
// Peek temporary render target for dof pass
- tempDesc = GPUTextureDescription::New2D(dofWidth, dofHeight, DOF_RT_FORMAT);
+ auto dofFormat = renderContext.Buffers->GetOutputFormat();
+ tempDesc = GPUTextureDescription::New2D(dofWidth, dofHeight, dofFormat);
GPUTexture* dofInput = RenderTargetPool::Get(tempDesc);
// Do the bokeh point generation, or just do a copy if disabled
@@ -374,7 +376,7 @@ GPUTexture* DepthOfFieldPass::Render(RenderContext& renderContext, GPUTexture* i
context->FlushState();
{
// Peek temporary targets for two blur passes
- tempDesc = GPUTextureDescription::New2D(dofWidth, dofHeight, DOF_RT_FORMAT, GPUTextureFlags::ShaderResource | GPUTextureFlags::RenderTarget | GPUTextureFlags::UnorderedAccess);
+ tempDesc = GPUTextureDescription::New2D(dofWidth, dofHeight, dofFormat, GPUTextureFlags::ShaderResource | GPUTextureFlags::RenderTarget | GPUTextureFlags::UnorderedAccess);
auto dofTargetH = RenderTargetPool::Get(tempDesc);
auto dofTargetV = RenderTargetPool::Get(tempDesc);
@@ -421,7 +423,7 @@ GPUTexture* DepthOfFieldPass::Render(RenderContext& renderContext, GPUTexture* i
// Render the bokeh points
if (isBokehGenerationEnabled)
{
- tempDesc = GPUTextureDescription::New2D(bokehTargetWidth, bokehTargetHeight, DOF_RT_FORMAT);
+ tempDesc = GPUTextureDescription::New2D(bokehTargetWidth, bokehTargetHeight, dofFormat);
auto bokehTarget = RenderTargetPool::Get(tempDesc);
context->Clear(*bokehTarget, Color::Black);
@@ -444,7 +446,7 @@ GPUTexture* DepthOfFieldPass::Render(RenderContext& renderContext, GPUTexture* i
}
// Composite the bokeh rendering results with the depth of field result
- tempDesc = GPUTextureDescription::New2D(dofWidth, dofHeight, DOF_RT_FORMAT);
+ tempDesc = GPUTextureDescription::New2D(dofWidth, dofHeight, dofFormat);
auto compositeTarget = RenderTargetPool::Get(tempDesc);
context->BindSR(0, bokehTarget);
context->BindSR(1, dofOutput);
diff --git a/Source/Engine/Renderer/DepthOfFieldPass.h b/Source/Engine/Renderer/DepthOfFieldPass.h
index 8b3d9074f..c633f56be 100644
--- a/Source/Engine/Renderer/DepthOfFieldPass.h
+++ b/Source/Engine/Renderer/DepthOfFieldPass.h
@@ -5,9 +5,6 @@
#include "RendererPass.h"
#include "Engine/Graphics/PostProcessSettings.h"
-#define DOF_DEPTH_BLUR_FORMAT PixelFormat::R16G16_Float
-#define DOF_RT_FORMAT PixelFormat::R11G11B10_Float
-
///
/// Depth of Field rendering
///
diff --git a/Source/Engine/Renderer/GI/GlobalSurfaceAtlasPass.cpp b/Source/Engine/Renderer/GI/GlobalSurfaceAtlasPass.cpp
index f80673654..d9b77d978 100644
--- a/Source/Engine/Renderer/GI/GlobalSurfaceAtlasPass.cpp
+++ b/Source/Engine/Renderer/GI/GlobalSurfaceAtlasPass.cpp
@@ -397,11 +397,11 @@ bool GlobalSurfaceAtlasPass::Render(RenderContext& renderContext, GPUContext* co
uint64 memUsage = 0;
// TODO: try using BC4/BC5/BC7 block compression for Surface Atlas (eg. for Tiles material properties)
#define INIT_ATLAS_TEXTURE(texture, format) desc.Format = format; surfaceAtlasData.texture = RenderTargetPool::Get(desc); if (!surfaceAtlasData.texture) return true; memUsage += surfaceAtlasData.texture->GetMemoryUsage()
- INIT_ATLAS_TEXTURE(AtlasEmissive, LIGHT_BUFFER_FORMAT);
+ INIT_ATLAS_TEXTURE(AtlasEmissive, PixelFormat::R11G11B10_Float);
INIT_ATLAS_TEXTURE(AtlasGBuffer0, GBUFFER0_FORMAT);
INIT_ATLAS_TEXTURE(AtlasGBuffer1, GBUFFER1_FORMAT);
INIT_ATLAS_TEXTURE(AtlasGBuffer2, GBUFFER2_FORMAT);
- INIT_ATLAS_TEXTURE(AtlasLighting, LIGHT_BUFFER_FORMAT);
+ INIT_ATLAS_TEXTURE(AtlasLighting, PixelFormat::R11G11B10_Float);
desc.Flags = GPUTextureFlags::DepthStencil | GPUTextureFlags::ShaderResource;
INIT_ATLAS_TEXTURE(AtlasDepth, PixelFormat::D16_UNorm);
#undef INIT_ATLAS_TEXTURE
diff --git a/Source/Engine/Renderer/Renderer.cpp b/Source/Engine/Renderer/Renderer.cpp
index ee7efd05f..e0055f19b 100644
--- a/Source/Engine/Renderer/Renderer.cpp
+++ b/Source/Engine/Renderer/Renderer.cpp
@@ -330,7 +330,8 @@ void RenderInner(SceneRenderTask* task, RenderContext& renderContext)
renderContext.List->SortDrawCalls(renderContext, false, DrawCallsListType::Distortion);
// Get the light accumulation buffer
- auto tempDesc = GPUTextureDescription::New2D(renderContext.Buffers->GetWidth(), renderContext.Buffers->GetHeight(), LIGHT_BUFFER_FORMAT);
+ auto outputFormat = renderContext.Buffers->GetOutputFormat();
+ auto tempDesc = GPUTextureDescription::New2D(renderContext.Buffers->GetWidth(), renderContext.Buffers->GetHeight(), outputFormat);
auto lightBuffer = RenderTargetPool::Get(tempDesc);
#if USE_EDITOR
diff --git a/Source/Shaders/DepthOfField.shader b/Source/Shaders/DepthOfField.shader
index 422268448..b035eb10f 100644
--- a/Source/Shaders/DepthOfField.shader
+++ b/Source/Shaders/DepthOfField.shader
@@ -156,10 +156,10 @@ void CS_DepthOfFieldH(uint3 groupID : SV_GroupID, uint3 groupThreadID : SV_Group
float2 sampleCoord = saturate(samplePos / float2(textureSize));
#endif
#if USE_CS_LINEAR_SAMPLING
- float3 color = Input0.SampleLevel(SamplerLinearClamp, sampleCoord, 0.0f).xyz;
+ float4 color = Input0.SampleLevel(SamplerLinearClamp, sampleCoord, 0.0f).rgba;
float2 depthBlur = Input1.SampleLevel(SamplerLinearClamp, sampleCoord, 0.0f).xy;
#else
- float3 color = Input0.SampleLevel(SamplerPointClamp, sampleCoord, 0.0f).xyz;
+ float4 color = Input0.SampleLevel(SamplerPointClamp, sampleCoord, 0.0f).rgba;
float2 depthBlur = Input1.SampleLevel(SamplerPointClamp, sampleCoord, 0.0f).xy;
#endif
float depth = depthBlur.x;
@@ -167,7 +167,7 @@ void CS_DepthOfFieldH(uint3 groupID : SV_GroupID, uint3 groupThreadID : SV_Group
float cocSize = blur * DOF_MAX_SAMPLE_RADIUS;
// Store in shared memory
- Samples[groupThreadID.x].Color = color;
+ Samples[groupThreadID.x].Color = color.rgb;
Samples[groupThreadID.x].Depth = depth;
Samples[groupThreadID.x].Blur = blur;
@@ -203,11 +203,11 @@ void CS_DepthOfFieldH(uint3 groupID : SV_GroupID, uint3 groupThreadID : SV_Group
// Write out the result
outputColor /= totalContribution;
- OutputTexture[samplePos] = float4(max(outputColor, 0), 1.0f);
+ OutputTexture[samplePos] = float4(max(outputColor, 0), color.a);
}
else
{
- OutputTexture[samplePos] = float4(color, 1.0f);
+ OutputTexture[samplePos] = color;
}
}
}
@@ -237,10 +237,10 @@ void CS_DepthOfFieldV(uint3 groupID : SV_GroupID, uint3 groupThreadID : SV_Group
float2 sampleCoord = saturate(samplePos / float2(textureSize));
#endif
#if USE_CS_LINEAR_SAMPLING
- float3 color = Input0.SampleLevel(SamplerLinearClamp, sampleCoord, 0.0f).xyz;
+ float4 color = Input0.SampleLevel(SamplerLinearClamp, sampleCoord, 0.0f).rgba;
float2 depthBlur = Input1.SampleLevel(SamplerLinearClamp, sampleCoord, 0.0f).xy;
#else
- float3 color = Input0.SampleLevel(SamplerPointClamp, sampleCoord, 0.0f).xyz;
+ float4 color = Input0.SampleLevel(SamplerPointClamp, sampleCoord, 0.0f).rgba;
float2 depthBlur = Input1.SampleLevel(SamplerPointClamp, sampleCoord, 0.0f).xy;
#endif
float depth = depthBlur.x;
@@ -248,7 +248,7 @@ void CS_DepthOfFieldV(uint3 groupID : SV_GroupID, uint3 groupThreadID : SV_Group
float cocSize = blur * DOF_MAX_SAMPLE_RADIUS;
// Store in shared memory
- Samples[groupThreadID.y].Color = color;
+ Samples[groupThreadID.y].Color = color.rgb;
Samples[groupThreadID.y].Depth = depth;
Samples[groupThreadID.y].Blur = blur;
@@ -284,11 +284,11 @@ void CS_DepthOfFieldV(uint3 groupID : SV_GroupID, uint3 groupThreadID : SV_Group
// Write out the result
outputColor /= totalContribution;
- OutputTexture[samplePos] = float4(max(outputColor, 0), 1.0f);
+ OutputTexture[samplePos] = float4(max(outputColor, 0), color.a);
}
else
{
- OutputTexture[samplePos] = float4(color, 1.0f);
+ OutputTexture[samplePos] = color;
}
}
}
@@ -456,11 +456,10 @@ META_PS(true, FEATURE_LEVEL_SM5)
float4 PS_GenerateBokeh(Quad_VS2PS input) : SV_Target
{
#if FEATURE_LEVEL >= FEATURE_LEVEL_SM5
-
- float2 centerCoord = input.TexCoord;
-
// Start with center sample color
- float3 centerColor = Input0.Sample(SamplerPointClamp, centerCoord).rgb;
+ float2 centerCoord = input.TexCoord;
+ float4 centerSample = Input0.Sample(SamplerPointClamp, centerCoord);
+ float3 centerColor = centerSample.rgb;
float3 colorSum = centerColor;
float totalContribution = 1.0f;
@@ -505,12 +504,9 @@ float4 PS_GenerateBokeh(Quad_VS2PS input) : SV_Target
centerColor = 0.0f;
}
- return float4(centerColor, 1.0f);
-
+ return float4(centerColor, centerSample.a);
#else
-
return float4(0, 0, 0, 1.0f);
-
#endif
}
@@ -520,10 +516,10 @@ float4 PS_GenerateBokeh(Quad_VS2PS input) : SV_Target
META_PS(true, FEATURE_LEVEL_SM5)
float4 PS_DoNotGenerateBokeh(Quad_VS2PS input) : SV_Target
{
- float2 centerCoord = input.TexCoord;
-
// Start with center sample color
- float3 centerColor = Input0.Sample(SamplerPointClamp, centerCoord).rgb;
+ float2 centerCoord = input.TexCoord;
+ float4 centerSample = Input0.Sample(SamplerPointClamp, centerCoord);
+ float3 centerColor = centerSample.rgb;
float3 colorSum = centerColor;
float totalContribution = 1.0f;
@@ -561,7 +557,7 @@ float4 PS_DoNotGenerateBokeh(Quad_VS2PS input) : SV_Target
centerColor = 0.0f;
}
- return float4(centerColor, 1.0f);
+ return float4(centerColor, centerSample.a);
}
#else
@@ -642,10 +638,8 @@ float4 PS_BokehComposite(in Quad_VS2PS input) : SV_Target
{
float4 bokehSample = Input0.Sample(SamplerLinearClamp, input.TexCoord);
float4 dofSample = Input1.Sample(SamplerPointClamp, input.TexCoord);
-
float3 composite = bokehSample.rgb + dofSample.rgb;
-
- return float4(composite, 1.0f);
+ return float4(composite, dofSample.a);
}
#endif
diff --git a/Source/Shaders/EyeAdaptation.shader b/Source/Shaders/EyeAdaptation.shader
index 1c1dd29d2..7f8e9a58b 100644
--- a/Source/Shaders/EyeAdaptation.shader
+++ b/Source/Shaders/EyeAdaptation.shader
@@ -90,7 +90,7 @@ float4 PS_ApplyLuminance(Quad_VS2PS input) : SV_Target
{
float averageLuminance = AverageLuminance.Load(int3(0, 0, 0)).x;
float exposure = 1.0f / averageLuminance;
- return (PreExposure * exposure).xxxx;
+ return float4((PreExposure * exposure).xxx, 1);
}
#endif
diff --git a/Source/Shaders/FXAA.shader b/Source/Shaders/FXAA.shader
index 6516598bd..3500e46c0 100644
--- a/Source/Shaders/FXAA.shader
+++ b/Source/Shaders/FXAA.shader
@@ -18,6 +18,8 @@
#include "./Flax/Common.hlsl"
+#define FXAA_ALPHA_PASSTHROUGH 1
+
Texture2D Source : register(t0);
#define SAMPLE_TEXTURE_LEVEL(texture, uv, level) texture.SampleLevel(SamplerLinearClamp, uv, level)
@@ -67,6 +69,9 @@ FXAA_DEBUG_OFFSET - Red/blue for -/+ x, gold/skyblue for -/+ y.
#ifndef FXAA_DEBUG_OFFSET
#define FXAA_DEBUG_OFFSET 0
#endif
+#ifndef FXAA_ALPHA_PASSTHROUGH
+ #define FXAA_ALPHA_PASSTHROUGH 0
+#endif
#if FXAA_DEBUG_PASSTHROUGH || FXAA_DEBUG_HORZVERT || FXAA_DEBUG_PAIR
#define FXAA_DEBUG 1
@@ -232,14 +237,18 @@ float FxaaLuma(float3 rgb)
}
// Support any extra filtering before returning color
-float4 FxaaFilterReturn(float3 rgb)
+float4 FxaaFilterReturn(float3 rgb, float4 source)
{
#if FXAA_SRGB_ROP
// Do sRGB encoded value to linear conversion
float3 b = rgb > FxaaToFloat3(0.04045);
rgb = rgb * FxaaToFloat3(1.0/12.92) * !b + pow(rgb * FxaaToFloat3(1.0/1.055) + FxaaToFloat3(0.055/1.055), FxaaToFloat3(2.4)) * b;
#endif
+#if FXAA_ALPHA_PASSTHROUGH
+ return float4(rgb, source.a);
+#else
return float4(rgb, 1);
+#endif
}
META_CB_BEGIN(0, Data)
@@ -277,9 +286,10 @@ then the shader early exits (no visible aliasing).
This threshold is clamped at a minimum value ("FXAA_EDGE_THRESHOLD_MIN")
to avoid processing in really dark areas.
*/
+ float4 source = SAMPLE_TEXTURE_OFFSET(Source, input.TexCoord, 0.0, int2( 0, 0));
float3 rgbN = SAMPLE_TEXTURE_OFFSET(Source, input.TexCoord, 0.0, int2( 0,-1)).xyz;
float3 rgbW = SAMPLE_TEXTURE_OFFSET(Source, input.TexCoord, 0.0, int2(-1, 0)).xyz;
- float3 rgbM = SAMPLE_TEXTURE_OFFSET(Source, input.TexCoord, 0.0, int2( 0, 0)).xyz;
+ float3 rgbM = source.xyz;
float3 rgbE = SAMPLE_TEXTURE_OFFSET(Source, input.TexCoord, 0.0, int2( 1, 0)).xyz;
float3 rgbS = SAMPLE_TEXTURE_OFFSET(Source, input.TexCoord, 0.0, int2( 0, 1)).xyz;
float lumaN = FxaaLuma(rgbN);
@@ -295,9 +305,9 @@ to avoid processing in really dark areas.
#endif
if(range < max(FXAA_EDGE_THRESHOLD_MIN, rangeMax * FXAA_EDGE_THRESHOLD)) {
#if FXAA_DEBUG
- return FxaaFilterReturn(FxaaToFloat3(lumaO));
+ return FxaaFilterReturn(FxaaToFloat3(lumaO), source);
#endif
- return FxaaFilterReturn(rgbM); }
+ return FxaaFilterReturn(rgbM, source); }
#if FXAA_SUBPIX > 0
#if FXAA_SUBPIX_FASTER
float3 rgbL = (rgbN + rgbW + rgbE + rgbS + rgbM) * FxaaToFloat3(1.0/5.0);
@@ -334,7 +344,7 @@ of a lowpass value (computed in the next section) to the final result.
#if FXAA_SUBPIX == 0
float blendL = 0.0;
#endif
- return FxaaFilterReturn(float3(1.0, blendL/FXAA_SUBPIX_CAP, 0.0));
+ return FxaaFilterReturn(float3(1.0, blendL/FXAA_SUBPIX_CAP, 0.0), source);
#endif
/*
CHOOSE VERTICAL OR HORIZONTAL SEARCH
@@ -379,8 +389,8 @@ flow in parallel (reusing the horizontal variables).
abs((0.25 * lumaNE) + (-0.5 * lumaE) + (0.25 * lumaSE));
bool horzSpan = edgeHorz >= edgeVert;
#if FXAA_DEBUG_HORZVERT
- if(horzSpan) return FxaaFilterReturn(float3(1.0, 0.75, 0.0));
- else return FxaaFilterReturn(float3(0.0, 0.50, 1.0));
+ if(horzSpan) return FxaaFilterReturn(float3(1.0, 0.75, 0.0), source);
+ else return FxaaFilterReturn(float3(0.0, 0.50, 1.0), source);
#endif
float lengthSign = horzSpan ? -ScreenHeightInv : -ScreenWidthInv;
if(!horzSpan) lumaN = lumaW;
@@ -410,8 +420,8 @@ until edge status changes
*/
bool pairN = gradientN >= gradientS;
#if FXAA_DEBUG_PAIR
- if(pairN) return FxaaFilterReturn(float3(0.0, 0.0, 1.0));
- else return FxaaFilterReturn(float3(0.0, 1.0, 0.0));
+ if(pairN) return FxaaFilterReturn(float3(0.0, 0.0, 1.0), source);
+ else return FxaaFilterReturn(float3(0.0, 1.0, 0.0), source);
#endif
if(!pairN) lumaN = lumaS;
if(!pairN) gradientN = gradientS;
@@ -498,8 +508,8 @@ On negative side if dstN < dstP,
float dstP = horzSpan ? posP.x - input.TexCoord.x : posP.y - input.TexCoord.y;
bool directionN = dstN < dstP;
#if FXAA_DEBUG_NEGPOS
- if(directionN) return FxaaFilterReturn(float3(1.0, 0.0, 0.0));
- else return FxaaFilterReturn(float3(0.0, 0.0, 1.0));
+ if(directionN) return FxaaFilterReturn(float3(1.0, 0.0, 0.0), source);
+ else return FxaaFilterReturn(float3(0.0, 0.0, 1.0), source);
#endif
lumaEndN = directionN ? lumaEndN : lumaEndP;
@@ -627,19 +637,19 @@ Position on span is used to compute sub-pixel filter offset using simple ramp,
float ox = horzSpan ? 0.0 : subPixelOffset * 2.0 / ScreenWidthInv;
float oy = horzSpan ? subPixelOffset * 2.0 / ScreenHeightInv : 0.0;
if(ox < 0.0)
- return FxaaFilterReturn(lerp(float3(1.0, 0.0, 0.0), FxaaToFloat3(lumaO), -ox));
+ return FxaaFilterReturn(lerp(float3(1.0, 0.0, 0.0), FxaaToFloat3(lumaO), -ox), source);
if(ox > 0.0)
- return FxaaFilterReturn(lerp(float3(0.0, 0.0, 1.0), FxaaToFloat3(lumaO), ox));
+ return FxaaFilterReturn(lerp(float3(0.0, 0.0, 1.0), FxaaToFloat3(lumaO), ox), source);
if(oy < 0.0)
- return FxaaFilterReturn(lerp(float3(1.0, 0.6, 0.2), FxaaToFloat3(lumaO), -oy));
+ return FxaaFilterReturn(lerp(float3(1.0, 0.6, 0.2), FxaaToFloat3(lumaO), -oy), source);
if(oy > 0.0)
- return FxaaFilterReturn(lerp(float3(0.2, 0.6, 1.0), FxaaToFloat3(lumaO), oy));
- return FxaaFilterReturn(float3(lumaO, lumaO, lumaO));
+ return FxaaFilterReturn(lerp(float3(0.2, 0.6, 1.0), FxaaToFloat3(lumaO), oy), source);
+ return FxaaFilterReturn(float3(lumaO, lumaO, lumaO), source);
#endif
float3 rgbF = SAMPLE_TEXTURE_LEVEL(Source, input.TexCoord + float2(horzSpan ? 0.0 : subPixelOffset, horzSpan ? subPixelOffset : 0.0), 0.0).xyz;
#if FXAA_SUBPIX == 0
- return FxaaFilterReturn(rgbF);
+ return FxaaFilterReturn(rgbF, source);
#else
- return FxaaFilterReturn(lerp(rgbF, rgbL, blendL));
+ return FxaaFilterReturn(lerp(rgbF, rgbL, blendL), source);
#endif
}
diff --git a/Source/Shaders/PostProcessing.shader b/Source/Shaders/PostProcessing.shader
index 26c699c5f..250173108 100644
--- a/Source/Shaders/PostProcessing.shader
+++ b/Source/Shaders/PostProcessing.shader
@@ -416,7 +416,7 @@ float4 PS_Composite(Quad_VS2PS input) : SV_Target
{
float2 uv = input.TexCoord;
float3 lensLight = 0;
- float3 color = 0;
+ float4 color;
// Chromatic Abberation
if (ChromaticDistortion > 0)
@@ -434,22 +434,22 @@ float4 PS_Composite(Quad_VS2PS input) : SV_Target
float rnd = nrand(uv + Time);
float t = rnd * stepsiz;
- float3 sumcol = 0;
- float3 sumw = 0;
+ float4 sumcol = 0;
+ float4 sumw = 0;
for (int i = 0; i < iterations; i++)
{
- float3 w = spectrum_offset(t);
+ float4 w = float4(spectrum_offset(t), 1);
sumw += w;
float2 uvd = distort(uv, t, min_distort, max_distort);
- sumcol += Input0.Sample(SamplerLinearClamp, uvd).rgb * w;
+ sumcol += Input0.Sample(SamplerLinearClamp, uvd) * w;
t += stepsiz;
}
- sumcol.rgb /= sumw;
- color = sumcol.rgb + (rnd / 255.0);
+ sumcol /= sumw;
+ color = sumcol + (rnd / 255.0);
}
else
{
- color = Input0.Sample(SamplerLinearClamp, uv).rgb;
+ color = Input0.Sample(SamplerLinearClamp, uv);
}
// Lens Flares
@@ -468,7 +468,7 @@ float4 PS_Composite(Quad_VS2PS input) : SV_Target
// Accumulate final lens flares lght
lensLight += lensFlares * 1.5f;
- color += lensFlares;
+ color.rgb += lensFlares;
}
// Bloom
@@ -481,19 +481,19 @@ float4 PS_Composite(Quad_VS2PS input) : SV_Target
// Accumulate final bloom lght
lensLight += max(0, bloom * 3.0f + (- 1.0f * 3.0f));
- color += bloom;
+ color.rgb += bloom;
}
// Lens Dirt
float3 lensDirt = LensDirt.SampleLevel(SamplerLinearClamp, uv, 0).rgb;
- color += lensDirt * (lensLight * LensDirtIntensity);
+ color.rgb += lensDirt * (lensLight * LensDirtIntensity);
// Eye Adaptation post exposure
- color *= PostExposure;
+ color.rgb *= PostExposure;
// Color Grading and Tone Mapping
#if !NO_GRADING_LUT
- color = ColorLookupTable(color);
+ color.rgb = ColorLookupTable(color.rgb);
#endif
// Film Grain
@@ -505,12 +505,12 @@ float4 PS_Composite(Quad_VS2PS input) : SV_Target
float noise = pnoise2D(rotCoordsR * (InputSize / GrainParticleSize), GrainTime);
// Noisiness response curve based on scene luminance
- float luminance = Luminance(saturate(color));
+ float luminance = Luminance(saturate(color.rgb));
luminance += smoothstep(0.2, 0.0, luminance);
// Add noise to the final color
noise = lerp(noise, 0, min(pow(luminance, 4.0), 100));
- color += noise * GrainAmount;
+ color.rgb += noise * GrainAmount;
}
// Vignette
@@ -520,15 +520,15 @@ float4 PS_Composite(Quad_VS2PS input) : SV_Target
float2 uvCircle = uv * (1 - uv);
float uvCircleScale = uvCircle.x * uvCircle.y * 16.0f;
float mask = lerp(1, pow(uvCircleScale, VignetteShapeFactor), VignetteIntensity);
- color = lerp(VignetteColor, color, mask);
+ color.rgb = lerp(VignetteColor, color.rgb, mask);
}
// Screen fade
- color = lerp(color, ScreenFadeColor.rgb, ScreenFadeColor.a);
+ color.rgb = lerp(color.rgb, ScreenFadeColor.rgb, ScreenFadeColor.a);
// Saturate color since it will be rendered to the screen
- color = saturate(color);
+ color.rgb = saturate(color.rgb);
- // Return final pixel color
- return float4(color, 1.0f);
+ // Return final pixel color (preserve input alpha)
+ return color;
}