Remove TAA and Motion Blur implementations

This commit is contained in:
Wojtek Figat
2020-12-22 18:07:53 +01:00
parent 4fe91d57b7
commit cf0aeb79bf
9 changed files with 26 additions and 827 deletions

BIN
Content/Shaders/MotionBlur.flax (Stored with Git LFS)

Binary file not shown.

BIN
Content/Shaders/TAA.flax (Stored with Git LFS)

Binary file not shown.

View File

@@ -12,7 +12,7 @@
bool TAA::Init()
{
// Create pipeline state
_psTAA.CreatePipelineStates();
//_psTAA.CreatePipelineStates();
// Load shader
_shader = Content::LoadAsyncInternal<Shader>(TEXT("Shaders/TAA"));
@@ -34,22 +34,6 @@ bool TAA::setupResources()
}
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 (!_psTAA.IsValid())
{
psDesc = GPUPipelineState::Description::DefaultFullscreenTriangle;
if (_psTAA.Create(psDesc, shader, "PS"))
return true;
}
return false;
}
@@ -58,10 +42,7 @@ void TAA::Dispose()
// Base
RendererPass::Dispose();
// Delete pipeline state
_psTAA.Delete();
// Release asset
_psTAA = nullptr;
_shader.Unlink();
}
@@ -75,7 +56,7 @@ void TAA::Render(RenderContext& renderContext, GPUTexture* input, GPUTextureView
auto context = GPUDevice::Instance->GetMainContext();
// Ensure to have valid data
if (checkIfSkipPass())
//if (checkIfSkipPass())
{
// Resources are missing. Do not perform rendering, just copy source frame.
context->SetRenderTarget(output);
@@ -119,32 +100,5 @@ void TAA::Render(RenderContext& renderContext, GPUTexture* input, GPUTextureView
blendStrength = 0.0f;
}
// Bind input
Data data;
data.ScreenSize = renderContext.View.ScreenSize;
data.TaaJitterStrength.X = renderContext.View.TemporalAAJitter.X;
data.TaaJitterStrength.Y = renderContext.View.TemporalAAJitter.Y;
data.TaaJitterStrength.Z = data.TaaJitterStrength.X / tempDesc.Width;
data.TaaJitterStrength.W = data.TaaJitterStrength.Y / tempDesc.Height;
data.FinalBlendParameters.X = settings.TAA_StationaryBlending * blendStrength;
data.FinalBlendParameters.Y = settings.TAA_MotionBlending * blendStrength;
data.FinalBlendParameters.Z = 100.0f * 60.0f;
data.FinalBlendParameters.W = settings.TAA_Sharpness;
const auto cb = _shader->GetShader()->GetCB(0);
context->UpdateCB(cb, &data);
context->BindCB(0, cb);
context->BindSR(0, input);
context->BindSR(1, inputHistory);
context->BindSR(2, renderContext.Buffers->MotionVectors);
context->BindSR(3, renderContext.Buffers->DepthBuffer);
// Render
GPUTextureView* rts[] = { output, outputHistory->View() };
context->SetRenderTarget(nullptr, ToSpan(rts, ARRAY_COUNT(rts)));
context->SetState(_psTAA.Get(renderContext.View.IsOrthographicProjection() ? 1 : 0));
context->DrawFullscreenTriangle();
// Swap the history
RenderTargetPool::Release(inputHistory);
renderContext.Buffers->TemporalAA = outputHistory;
// ...
}

View File

@@ -12,15 +12,8 @@ class TAA : public RendererPass<TAA>
{
private:
PACK_STRUCT(struct Data
{
Vector4 ScreenSize;
Vector4 TaaJitterStrength;
Vector4 FinalBlendParameters;
});
AssetReference<Shader> _shader;
GPUPipelineStatePermutationsPs<2> _psTAA;
GPUPipelineState* _psTAA;
public:
@@ -44,7 +37,7 @@ private:
#if COMPILE_WITH_DEV_ENV
void OnShaderReloading(Asset* obj)
{
_psTAA.Release();
_psTAA = nullptr;
invalidateResources();
}
#endif

View File

@@ -11,19 +11,16 @@
#include "Engine/Graphics/RenderTargetPool.h"
#include "Engine/Graphics/RenderBuffers.h"
PACK_STRUCT(struct Data {
GBufferData GBuffer;
Matrix CurrentVP;
Matrix PreviousVP;
Vector4 TemporalAAJitter;
});
MotionBlurPass::MotionBlurPass()
: _motionVectorsFormat(PixelFormat::Unknown)
, _velocityFormat(PixelFormat::Unknown)
, _psCameraMotionVectors(nullptr)
, _psMotionVectorsDebug(nullptr)
, _psMotionVectorsDebugArrow(nullptr)
, _psVelocitySetup(nullptr)
, _psTileMax1(nullptr)
, _psTileMax2(nullptr)
, _psTileMax4(nullptr)
, _psTileMaxV(nullptr)
, _psNeighborMax(nullptr)
, _psReconstruction(nullptr)
{
}
@@ -36,15 +33,6 @@ bool MotionBlurPass::Init()
{
// Create pipeline state
_psCameraMotionVectors = GPUDevice::Instance->CreatePipelineState();
_psMotionVectorsDebug = GPUDevice::Instance->CreatePipelineState();
_psMotionVectorsDebugArrow = GPUDevice::Instance->CreatePipelineState();
_psVelocitySetup = GPUDevice::Instance->CreatePipelineState();
_psTileMax1 = GPUDevice::Instance->CreatePipelineState();
_psTileMax2 = GPUDevice::Instance->CreatePipelineState();
_psTileMax4 = GPUDevice::Instance->CreatePipelineState();
_psTileMaxV = GPUDevice::Instance->CreatePipelineState();
_psNeighborMax = GPUDevice::Instance->CreatePipelineState();
_psReconstruction = GPUDevice::Instance->CreatePipelineState();
// Load shader
_shader = Content::LoadAsyncInternal<Shader>(TEXT("Shaders/MotionBlur"));
@@ -98,62 +86,6 @@ bool MotionBlurPass::setupResources()
if (_psCameraMotionVectors->Init(psDesc))
return true;
}
if (!_psVelocitySetup->IsValid())
{
psDesc.PS = shader->GetPS("PS_VelocitySetup");
if (_psVelocitySetup->Init(psDesc))
return true;
}
if (!_psTileMax1->IsValid())
{
psDesc.PS = shader->GetPS("PS_TileMax1");
if (_psTileMax1->Init(psDesc))
return true;
}
if (!_psTileMax2->IsValid())
{
psDesc.PS = shader->GetPS("PS_TileMax2");
if (_psTileMax2->Init(psDesc))
return true;
}
if (!_psTileMax4->IsValid())
{
psDesc.PS = shader->GetPS("PS_TileMax4");
if (_psTileMax4->Init(psDesc))
return true;
}
if (!_psTileMaxV->IsValid())
{
psDesc.PS = shader->GetPS("PS_TileMaxV");
if (_psTileMaxV->Init(psDesc))
return true;
}
if (!_psNeighborMax->IsValid())
{
psDesc.PS = shader->GetPS("PS_NeighborMax");
if (_psNeighborMax->Init(psDesc))
return true;
}
if (!_psReconstruction->IsValid())
{
psDesc.PS = shader->GetPS("PS_Reconstruction");
if (_psReconstruction->Init(psDesc))
return true;
}
if (!_psMotionVectorsDebug->IsValid())
{
psDesc.PS = shader->GetPS("PS_MotionVectorsDebug");
if (_psMotionVectorsDebug->Init(psDesc))
return true;
}
if (!_psMotionVectorsDebugArrow->IsValid())
{
psDesc.PrimitiveTopologyType = PrimitiveTopologyType::Line;
psDesc.VS = shader->GetVS("VS_DebugArrow");
psDesc.PS = shader->GetPS("PS_DebugArrow");
if (_psMotionVectorsDebugArrow->Init(psDesc))
return true;
}
return false;
}
@@ -165,15 +97,6 @@ void MotionBlurPass::Dispose()
// Delete pipeline state
SAFE_DELETE_GPU_RESOURCE(_psCameraMotionVectors);
SAFE_DELETE_GPU_RESOURCE(_psMotionVectorsDebug);
SAFE_DELETE_GPU_RESOURCE(_psMotionVectorsDebugArrow);
SAFE_DELETE_GPU_RESOURCE(_psVelocitySetup);
SAFE_DELETE_GPU_RESOURCE(_psTileMax1);
SAFE_DELETE_GPU_RESOURCE(_psTileMax2);
SAFE_DELETE_GPU_RESOURCE(_psTileMax4);
SAFE_DELETE_GPU_RESOURCE(_psTileMaxV);
SAFE_DELETE_GPU_RESOURCE(_psNeighborMax);
SAFE_DELETE_GPU_RESOURCE(_psReconstruction);
// Release asset
_shader.Unlink();
@@ -275,39 +198,13 @@ void MotionBlurPass::RenderDebug(RenderContext& renderContext, GPUTextureView* f
{
auto context = GPUDevice::Instance->GetMainContext();
const auto motionVectors = renderContext.Buffers->MotionVectors;
if (!motionVectors->IsAllocated() || setupResources())
//if (!motionVectors->IsAllocated() || setupResources())
{
context->Draw(frame);
return;
}
PROFILE_GPU_CPU("Motion Vectors Debug");
// Bind input
Data data;
GBufferPass::SetInputs(renderContext.View, data.GBuffer);
const float rows = 16.0f;
const float cols = rows * renderContext.Buffers->GetWidth() / renderContext.Buffers->GetHeight();
data.DebugBlend = 0.7f;
data.DebugAmplitude = 2.0f;
data.DebugRowCount = static_cast<int32>(rows);
data.DebugColumnCount = static_cast<int32>(cols);
auto cb = _shader->GetShader()->GetCB(0);
context->UpdateCB(cb, &data);
context->BindCB(0, cb);
context->BindSR(0, frame);
context->BindSR(1, renderContext.Buffers->MotionVectors);
// Draw motion gradient
context->SetState(_psMotionVectorsDebug);
context->DrawFullscreenTriangle();
// Draw arrows
context->SetState(_psMotionVectorsDebugArrow);
context->Draw(0, static_cast<uint32>(cols * rows * 6));
// Cleanup
context->ResetSR();
// ..
}
void MotionBlurPass::Render(RenderContext& renderContext, GPUTexture*& input, GPUTexture*& output)
@@ -335,128 +232,5 @@ void MotionBlurPass::Render(RenderContext& renderContext, GPUTexture*& input, GP
return;
}
// Need to have valid motion vectors created and rendered before
ASSERT(motionVectors->IsAllocated());
PROFILE_GPU_CPU("Motion Blur");
// Calculate the maximum blur radius in pixels
const float maxBlurRadius = 5.0f;
const int32 maxBlurPixels = static_cast<int32>(maxBlurRadius * motionVectorsHeight / 100.0f);
// Calculate the TileMax size (it should be a multiple of 8 and larger than maxBlur)
const int32 tileSize = ((maxBlurPixels - 1) / 8 + 1) * 8;
// Bind input
Data data;
GBufferPass::SetInputs(renderContext.View, data.GBuffer);
Matrix::Transpose(renderContext.View.ViewProjection(), data.CurrentVP);
Matrix::Transpose(renderContext.View.PrevViewProjection, data.PreviousVP);
data.TemporalAAJitter = renderContext.View.TemporalAAJitter;
data.VelocityScale = settings.Scale;
data.MaxBlurRadius = static_cast<float>(maxBlurPixels);
data.RcpMaxBlurRadius = 1.0f / maxBlurPixels;
data.TileMaxOffs = Vector2::One * (tileSize / 8.0f - 1.0f) * -0.5f;
data.TileMaxLoop = static_cast<int32>(tileSize / 8.0f);
data.LoopCount = Math::Clamp(settings.SampleCount / 2.0f, 1.0f, 64.0f);
const float invWidth = 1.0f / motionVectorsWidth;
const float invHeight = 1.0f / motionVectorsHeight;
data.TexelSize1 = Vector2(invWidth, invHeight);
data.TexelSize2 = Vector2(invWidth * 2.0f, invHeight * 2.0f);
data.TexelSize4 = Vector2(invWidth * 4.0f, invHeight * 4.0f);
data.TexelSizeV = Vector2(invWidth * 8.0f, invHeight * 8.0f);
data.TexelSizeNM = Vector2(invWidth * tileSize, invHeight * tileSize);
data.MotionVectorsTexelSize = Vector2(1.0f / motionVectorsWidth, invHeight * tileSize);
auto cb = _shader->GetShader()->GetCB(0);
context->UpdateCB(cb, &data);
context->BindCB(0, cb);
context->BindSR(0, renderContext.Buffers->DepthBuffer);
auto rtDesc = GPUTextureDescription::New2D(motionVectorsWidth, motionVectorsHeight, _velocityFormat);
// Pass 1 - Velocity/depth packing
auto vBuffer = RenderTargetPool::Get(rtDesc);
context->SetRenderTarget(*vBuffer);
context->SetViewportAndScissors((float)rtDesc.Width, (float)rtDesc.Height);
context->BindSR(0, motionVectors->View());
context->BindSR(1, renderContext.Buffers->DepthBuffer->View());
context->SetState(_psVelocitySetup);
context->DrawFullscreenTriangle();
context->UnBindSR(1);
// Pass 2 - First TileMax filter (1/2 downsize)
rtDesc.Format = _motionVectorsFormat;
rtDesc.Width = motionVectorsWidth / 2;
rtDesc.Height = motionVectorsHeight / 2;
auto tile2 = RenderTargetPool::Get(rtDesc);
context->ResetRenderTarget();
context->SetRenderTarget(tile2->View());
context->SetViewportAndScissors((float)rtDesc.Width, (float)rtDesc.Height);
context->BindSR(0, vBuffer->View());
context->SetState(_psTileMax1);
context->DrawFullscreenTriangle();
// Pass 3 - Second TileMax filter (1/4 downsize)
rtDesc.Width = motionVectorsWidth / 4;
rtDesc.Height = motionVectorsHeight / 4;
auto tile4 = RenderTargetPool::Get(rtDesc);
context->ResetRenderTarget();
context->SetRenderTarget(tile4->View());
context->SetViewportAndScissors((float)rtDesc.Width, (float)rtDesc.Height);
context->BindSR(0, tile2->View());
context->SetState(_psTileMax2);
context->DrawFullscreenTriangle();
RenderTargetPool::Release(tile2);
// Pass 4 - Third TileMax filter (1/8 downsize)
rtDesc.Width = motionVectorsWidth / 8;
rtDesc.Height = motionVectorsHeight / 8;
auto tile8 = RenderTargetPool::Get(rtDesc);
context->ResetRenderTarget();
context->SetRenderTarget(tile8->View());
context->SetViewportAndScissors((float)rtDesc.Width, (float)rtDesc.Height);
context->BindSR(0, tile4->View());
context->SetState(_psTileMax4);
context->DrawFullscreenTriangle();
RenderTargetPool::Release(tile4);
// Pass 5 - Fourth TileMax filter (reduce to tileSize)
rtDesc.Width = motionVectorsWidth / tileSize;
rtDesc.Height = motionVectorsHeight / tileSize;
auto tile = RenderTargetPool::Get(rtDesc);
context->ResetRenderTarget();
context->SetRenderTarget(tile->View());
context->SetViewportAndScissors((float)rtDesc.Width, (float)rtDesc.Height);
context->BindSR(0, tile8->View());
context->SetState(_psTileMaxV);
context->DrawFullscreenTriangle();
RenderTargetPool::Release(tile8);
// Pass 6 - NeighborMax filter
rtDesc.Width = motionVectorsWidth / tileSize;
rtDesc.Height = motionVectorsHeight / tileSize;
auto neighborMax = RenderTargetPool::Get(rtDesc);
context->ResetRenderTarget();
context->SetRenderTarget(neighborMax->View());
context->SetViewportAndScissors((float)rtDesc.Width, (float)rtDesc.Height);
context->BindSR(0, tile->View());
context->SetState(_psNeighborMax);
context->DrawFullscreenTriangle();
RenderTargetPool::Release(tile);
// Pass 7 - Reconstruction pass
context->ResetRenderTarget();
context->SetRenderTarget(*output);
context->SetViewportAndScissors((float)screenWidth, (float)screenHeight);
context->BindSR(0, input->View());
context->BindSR(1, vBuffer->View());
context->BindSR(2, neighborMax->View());
context->SetState(_psReconstruction);
context->DrawFullscreenTriangle();
// Cleanup
context->ResetSR();
context->ResetRenderTarget();
RenderTargetPool::Release(vBuffer);
RenderTargetPool::Release(neighborMax);
Swap(output, input);
// ..
}

View File

@@ -10,43 +10,11 @@
class MotionBlurPass : public RendererPass<MotionBlurPass>
{
private:
PACK_STRUCT(struct Data {
GBufferData GBuffer;
Matrix CurrentVP;
Matrix PreviousVP;
Vector4 TemporalAAJitter;
Vector2 TileMaxOffs;
float VelocityScale;
int32 TileMaxLoop;
float MaxBlurRadius;
float RcpMaxBlurRadius;
Vector2 TexelSize1;
Vector2 TexelSize2;
Vector2 TexelSize4;
Vector2 TexelSizeV;
Vector2 TexelSizeNM;
float LoopCount;
float Dummy0;
Vector2 MotionVectorsTexelSize;
float DebugBlend;
float DebugAmplitude;
int32 DebugColumnCount;
int32 DebugRowCount;
});
PixelFormat _motionVectorsFormat;
PixelFormat _velocityFormat;
AssetReference<Shader> _shader;
GPUPipelineState* _psCameraMotionVectors;
GPUPipelineState* _psMotionVectorsDebug;
GPUPipelineState* _psMotionVectorsDebugArrow;
GPUPipelineState* _psVelocitySetup;
GPUPipelineState* _psTileMax1;
GPUPipelineState* _psTileMax2;
GPUPipelineState* _psTileMax4;
GPUPipelineState* _psTileMaxV;
GPUPipelineState* _psNeighborMax;
GPUPipelineState* _psReconstruction;
GPUPipelineState* _psCameraMotionVectors = nullptr;
public:
@@ -84,15 +52,6 @@ private:
void OnShaderReloading(Asset* obj)
{
_psCameraMotionVectors->ReleaseGPU();
_psMotionVectorsDebug->ReleaseGPU();
_psMotionVectorsDebugArrow->ReleaseGPU();
_psVelocitySetup->ReleaseGPU();
_psTileMax1->ReleaseGPU();
_psTileMax2->ReleaseGPU();
_psTileMax4->ReleaseGPU();
_psTileMaxV->ReleaseGPU();
_psNeighborMax->ReleaseGPU();
_psReconstruction->ReleaseGPU();
invalidateResources();
}
#endif

View File

@@ -306,6 +306,7 @@ void RenderInner(SceneRenderTask* task, RenderContext& renderContext)
#endif
renderContext.List->Settings.AntiAliasing.Mode = aaMode;
// Prepare
renderContext.View.Prepare(renderContext);
renderContext.Buffers->Prepare();
@@ -484,7 +485,8 @@ void RenderInner(SceneRenderTask* task, RenderContext& renderContext)
context->ResetRenderTarget();
context->SetRenderTarget(task->GetOutputView());
context->SetViewportAndScissors((float)renderContext.Buffers->GetWidth(), (float)renderContext.Buffers->GetHeight());
MotionBlurPass::Instance()->RenderDebug(renderContext, frameBuffer->View());
context->Clear(frameBuffer->View(), Color::Black);
//MotionBlurPass::Instance()->RenderDebug(renderContext, frameBuffer->View());
return;
}

View File

@@ -14,27 +14,6 @@ float4x4 CurrentVP;
float4x4 PreviousVP;
float4 TemporalAAJitter;
// Motion Blur
float2 TileMaxOffs;
float VelocityScale;
int TileMaxLoop;
float MaxBlurRadius;
float RcpMaxBlurRadius;
float2 TexelSize1;
float2 TexelSize2;
float2 TexelSize4;
float2 TexelSizeV;
float2 TexelSizeNM;
float LoopCount;
float Dummy0;
float2 MotionVectorsTexelSize;
// Motion Vectors Debug Parameters
float DebugBlend;
float DebugAmplitude;
int DebugColumnCount;
int DebugRowCount;
META_CB_END
DECLARE_GBUFFERDATA_ACCESS(GBuffer)
@@ -43,106 +22,6 @@ Texture2D Input0 : register(t0);
Texture2D Input1 : register(t1);
Texture2D Input2 : register(t2);
// Calculates the color for the a motion vector debugging
float4 VectorToColor(float2 motionVector)
{
float phi = atan2(motionVector.x, motionVector.y);
float hue = (phi / PI + 1) * 0.5;
float r = abs(hue * 6 - 3) - 1;
float g = 2 - abs(hue * 6 - 2);
float b = 2 - abs(hue * 6 - 4);
float a = length(motionVector);
return saturate(float4(r, g, b, a));
}
// Pixel shader for motion vectors debug view
META_PS(true, FEATURE_LEVEL_ES2)
float4 PS_MotionVectorsDebug(Quad_VS2PS input) : SV_Target
{
float4 color = SAMPLE_RT(Input0, input.TexCoord);
float2 motionVector = SAMPLE_RT(Input1, input.TexCoord).rg * (DebugAmplitude * 5.0f);
float4 motionColor = VectorToColor(motionVector);
float colorRation = saturate(2 - DebugBlend * 2);
float motionColorRatio = saturate(DebugBlend * 2);
color.rgb = lerp(color.rgb * colorRation, motionColor.rgb, motionColor.a * motionColorRatio);
return color;
}
// Motion vector arrow data from VS to PS
struct ArrowVaryings
{
float4 Position : SV_POSITION;
float2 ScreenUV : TEXCOORD;
float4 Color : COLOR;
};
META_VS(true, FEATURE_LEVEL_ES2)
ArrowVaryings VS_DebugArrow(uint VertexId : SV_VertexID)
{
// Screen aspect ratio
float aspect = GBuffer.ScreenSize.x * GBuffer.ScreenSize.w;
float aspectInv = GBuffer.ScreenSize.y * GBuffer.ScreenSize.z;
// Vertex IDs
uint arrowId = VertexId / 6;
uint pointId = VertexId - arrowId * 6;
// Column and row number of the arrow
uint row = arrowId / DebugColumnCount;
uint col = arrowId - row * DebugColumnCount;
// Get the motion vector
float2 uv = float2((col + 0.5) / DebugColumnCount, (row + 0.5) / DebugRowCount);
float2 motionVector = SAMPLE_RT(Input1, uv).rg * DebugAmplitude;
// Arrow color
float4 color = VectorToColor(motionVector);
// Arrow transformation
float isEnd = pointId > 0;
float2 direction = normalize(motionVector * float2(aspect, 1));
float2x2 rotation = float2x2(direction.y, direction.x, -direction.x, direction.y);
float offsetStart = pointId == 3 ? -1 : (pointId == 5 ? 1 : 0);
offsetStart *= isEnd * 0.3f * saturate(length(motionVector) * DebugRowCount);
float2 offset = float2(offsetStart, -abs(offsetStart));
offset = mul(rotation, offset) * float2(aspectInv, 1);
// Vertex position in the clip space
float2 pos = motionVector * isEnd + offset * 2 / DebugRowCount + uv * 2.0f - 1.0f;
// Convert to the screen coordinates
float2 posSS = (pos + 1) * 0.5f * GBuffer.ScreenSize.xy;
posSS = round(posSS);
// Bring back to the clip space
pos = (posSS + 0.5f) * GBuffer.ScreenSize.zw * 2.0f - 1.0f;
pos.y *= -1;
// Color tweaks
color.rgb = lerp(color.rgb, 1, 0.5f);
color.a = DebugBlend;
// Output
ArrowVaryings output;
output.Position = float4(pos, 0, 1);
output.ScreenUV = posSS;
output.Color = color;
return output;
}
META_PS(true, FEATURE_LEVEL_ES2)
float4 PS_DebugArrow(ArrowVaryings input) : SV_Target
{
// Pseudo anti-aliasing
float aa = length(frac(input.ScreenUV) - 0.5f) / 0.707f;
aa *= (aa * (aa * 0.305306011f + 0.682171111f) + 0.012522878f);
return float4(input.Color.rgb, input.Color.a * aa);
}
// Pixel shader for camera motion vectors
META_PS(true, FEATURE_LEVEL_ES2)
float4 PS_CameraMotionVectors(Quad_VS2PS input) : SV_Target
@@ -169,224 +48,3 @@ float4 PS_CameraMotionVectors(Quad_VS2PS input) : SV_Target
return float4(vPosCur - vPosPrev, 0, 1);
}
// Pixel Shader for velocity texture setup
META_PS(true, FEATURE_LEVEL_ES2)
float4 PS_VelocitySetup(Quad_VS2PS input) : SV_Target
{
// Sample the motion vector
float2 v = SAMPLE_RT(Input0, input.TexCoord).rg;
// Apply the exposure time and convert to the pixel space
v *= (VelocityScale * 0.5f) * GBuffer.ScreenSize.xy;
// Clamp the vector with the maximum blur radius
v /= max(1.0f, length(v) * RcpMaxBlurRadius);
// Sample the depth of the pixel
float depth = SAMPLE_RT(Input1, input.TexCoord).r;
GBufferData gBufferData = GetGBufferData();
depth = LinearizeZ(gBufferData, depth);
// Pack into 10/10/10/2 format
return float4((v * RcpMaxBlurRadius + 1.0f) * 0.5f, depth, 0.0f);
}
float2 MaxV(float2 v1, float2 v2)
{
return dot(v1, v1) < dot(v2, v2) ? v2 : v1;
}
// Pixel Shader for TileMax filter (2 pixel width with normalization)
META_PS(true, FEATURE_LEVEL_ES2)
float4 PS_TileMax1(Quad_VS2PS input) : SV_Target
{
float4 d = TexelSize1.xyxy * float4(-0.5, -0.5, 0.5, 0.5);
float2 v1 = SAMPLE_RT(Input0, input.TexCoord + d.xy).rg;
float2 v2 = SAMPLE_RT(Input0, input.TexCoord + d.zy).rg;
float2 v3 = SAMPLE_RT(Input0, input.TexCoord + d.xw).rg;
float2 v4 = SAMPLE_RT(Input0, input.TexCoord + d.zw).rg;
v1 = (v1 * 2.0f - 1.0f) * MaxBlurRadius;
v2 = (v2 * 2.0f - 1.0f) * MaxBlurRadius;
v3 = (v3 * 2.0f - 1.0f) * MaxBlurRadius;
v4 = (v4 * 2.0f - 1.0f) * MaxBlurRadius;
return float4(MaxV(MaxV(MaxV(v1, v2), v3), v4), 0.0f, 0.0f);
}
// Pixel Shader for TileMax filter (2 pixel width)
META_PS(true, FEATURE_LEVEL_ES2)
float4 PS_TileMax2(Quad_VS2PS input) : SV_Target
{
float4 d = TexelSize2.xyxy * float4(-0.5f, -0.5f, 0.5f, 0.5f);
float2 v1 = SAMPLE_RT(Input0, input.TexCoord + d.xy).rg;
float2 v2 = SAMPLE_RT(Input0, input.TexCoord + d.zy).rg;
float2 v3 = SAMPLE_RT(Input0, input.TexCoord + d.xw).rg;
float2 v4 = SAMPLE_RT(Input0, input.TexCoord + d.zw).rg;
return float4(MaxV(MaxV(MaxV(v1, v2), v3), v4), 0.0f, 0.0f);
}
// Pixel Shader for TileMax filter (2 pixel width)
META_PS(true, FEATURE_LEVEL_ES2)
float4 PS_TileMax4(Quad_VS2PS input) : SV_Target
{
float4 d = TexelSize4.xyxy * float4(-0.5f, -0.5f, 0.5f, 0.5f);
float2 v1 = SAMPLE_RT(Input0, input.TexCoord + d.xy).rg;
float2 v2 = SAMPLE_RT(Input0, input.TexCoord + d.zy).rg;
float2 v3 = SAMPLE_RT(Input0, input.TexCoord + d.xw).rg;
float2 v4 = SAMPLE_RT(Input0, input.TexCoord + d.zw).rg;
return float4(MaxV(MaxV(MaxV(v1, v2), v3), v4), 0.0f, 0.0f);
}
// Pixel Shader for TileMax filter (variable width)
META_PS(true, FEATURE_LEVEL_ES2)
float4 PS_TileMaxV(Quad_VS2PS input) : SV_Target
{
float2 uv0 = input.TexCoord + TexelSizeV.xy * TileMaxOffs.xy;
float2 du = float2(TexelSizeV.x, 0.0);
float2 dv = float2(0.0, TexelSizeV.y);
float2 vo = 0.0;
LOOP
for (int x = 0; x < TileMaxLoop; x++)
{
LOOP
for (int y = 0; y < TileMaxLoop; y++)
{
float2 uv = uv0 + du * x + dv * y;
vo = MaxV(vo, SAMPLE_RT(Input0, uv).rg);
}
}
return float4(vo, 0.0, 0.0);
}
// Pixel Shader for NeighborMax filter
META_PS(true, FEATURE_LEVEL_ES2)
float4 PS_NeighborMax(Quad_VS2PS input) : SV_Target
{
// Center weight tweak
const float cw = 1.01;
float4 d = TexelSizeNM.xyxy * float4(1.0, 1.0, -1.0, 0.0);
float2 v1 = SAMPLE_RT(Input0, input.TexCoord - d.xy).rg;
float2 v2 = SAMPLE_RT(Input0, input.TexCoord - d.wy).rg;
float2 v3 = SAMPLE_RT(Input0, input.TexCoord - d.zy).rg;
float2 v4 = SAMPLE_RT(Input0, input.TexCoord - d.xw).rg;
float2 v5 = SAMPLE_RT(Input0, input.TexCoord).rg * cw;
float2 v6 = SAMPLE_RT(Input0, input.TexCoord + d.xw).rg;
float2 v7 = SAMPLE_RT(Input0, input.TexCoord + d.zy).rg;
float2 v8 = SAMPLE_RT(Input0, input.TexCoord + d.wy).rg;
float2 v9 = SAMPLE_RT(Input0, input.TexCoord + d.xy).rg;
float2 va = MaxV(v1, MaxV(v2, v3));
float2 vb = MaxV(v4, MaxV(v5, v6));
float2 vc = MaxV(v7, MaxV(v8, v9));
return float4(MaxV(va, MaxV(vb, vc)) * (1.0f / cw), 0.0f, 0.0f);
}
// Interleaved gradient function from Jimenez 2014
// http://www.iryoku.com/next-generation-post-processing-in-call-of-duty-advanced-warfare
float GradientNoise(float2 uv)
{
uv = floor(uv * GBuffer.ScreenSize.xy);
float f = dot(float2(0.06711056f, 0.00583715f), uv);
return frac(52.9829189f * frac(f));
}
// Returns true or false with a given interval
bool Interval(float phase, float interval)
{
return frac(phase / interval) > 0.499;
}
// Jitter function for tile lookup
float2 JitterTile(float2 uv)
{
float rx, ry;
sincos(GradientNoise(uv + float2(2.0f, 0.0f)) * (2.0f * PI), ry, rx);
return float2(rx, ry) * TexelSizeNM.xy * 0.25f;
}
// Velocity sampling function
float3 SampleVelocity(float2 uv)
{
float3 v = SAMPLE_RT(Input1, uv).xyz;
return float3((v.xy * 2.0f - 1.0f) * MaxBlurRadius, v.z);
}
// Pixel Shader for reconstruction filter (applies the motion blur to the frame)
META_PS(true, FEATURE_LEVEL_ES2)
float4 PS_Reconstruction(Quad_VS2PS input) : SV_Target
{
// Sample at the current location
const float4 color = SAMPLE_RT(Input0, input.TexCoord);
const float3 velocity = SampleVelocity(input.TexCoord);
const float velocityLen = max(length(velocity.xy), 0.5);
const float depthInv = 1.0 / velocity.z;
const float2 velocityMax = SAMPLE_RT(Input2, input.TexCoord + JitterTile(input.TexCoord)).xy;
const float velocityMaxLength = length(velocityMax);
if (velocityMaxLength < 2.0f)
return color;
const float2 velocityWeighted = (velocityLen * 2.0f > velocityMaxLength) ? velocity.xy * (velocityMaxLength / velocityLen) : velocityMax;
// Calculate the amount of samples
const float sc = floor(min(LoopCount, velocityMaxLength * 0.5f));
// Accumlation loop
float backgroudVelocity = max(velocityLen, 1.0f);
const float dt = 1.0f / sc;
const float offsetNoise = (GradientNoise(input.TexCoord) - 0.5f) * dt;
float t = 1.0f - dt * 0.5f;
float count = 0.0f;
float4 sum = 0.0f;
LOOP
while (t > dt * 0.25)
{
// Sampling direction (switched per every two samples)
const float2 sampleVelocity = Interval(count, 4.0) ? velocityWeighted : velocityMax;
// Sample position (inverted per every sample)
const float samplePosition = (Interval(count, 2.0) ? -t : t) + offsetNoise;
// Calculate UVs for the sample position
const float2 sampleUV = input.TexCoord + sampleVelocity * samplePosition * GBuffer.ScreenSize.zw;
// Sample color and velocity with depth
const float3 c = SAMPLE_RT(Input0, sampleUV).rgb;
const float3 velocityDepth = SampleVelocity(sampleUV);
// Length of the velocity vector
const float foreground = saturate((velocity.z - velocityDepth.z) * 20.0f * depthInv);
const float sampleVelocityLength = lerp(backgroudVelocity, length(velocityDepth.xy), foreground);
// Apply color accumulation
float weight = saturate(sampleVelocityLength - (velocityMaxLength * abs(samplePosition))) / sampleVelocityLength * (1.2f - t);
sum += float4(c, 1.0) * weight;
// Calculate the background velocity
backgroudVelocity = max(backgroudVelocity, sampleVelocityLength);
// Move to the next sample
t = Interval(count, 2.0f) ? t - dt : t;
count += 1.0f;
}
// Add the center sample
sum += float4(color.rgb, 1.0f) * (1.2f / (backgroudVelocity * sc * 2.0f));
return float4(sum.rgb / sum.a, color.a);
}

View File

@@ -1,151 +1,10 @@
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
#include "./Flax/Common.hlsl"
#include "./Flax/GammaCorrectionCommon.hlsl"
#define USE_TONEMAP 0
META_CB_BEGIN(0, Data)
float4 ScreenSize;// x-width, y-height, z-1/width, w-1/height
float4 TaaJitterStrength; // x, y, x/width, y/height
float4 FinalBlendParameters; // x: static, y: dynamic, z: motion amplification, w; sharpness
META_CB_END
Texture2D Input : register(t0);
Texture2D InputHistory : register(t1);
Texture2D MotionVectors : register(t2);
Texture2D Depth : register(t3);
float3 Fetch(Texture2D tex, float2 coords)
{
return tex.SampleLevel(SamplerLinearClamp, coords, 0).rgb;
}
float3 Map(float3 x)
{
#if USE_TONEMAP
return FastTonemap(x);
#else
return x;
#endif
}
float3 Unmap(float3 x)
{
#if USE_TONEMAP
return FastTonemapInvert(x);
#else
return x;
#endif
}
float3 ClipToAABB(float3 color, float3 minimum, float3 maximum)
{
// Note: only clips towards aabb center (but fast!)
float3 center = 0.5 * (maximum + minimum);
float3 extents = 0.5 * (maximum - minimum);
// This is actually `distance`, however the keyword is reserved
float3 offset = color - center;
float3 ts = abs(extents / max(offset, 0.0001));
float t = saturate(min(min(ts.x, ts.y), ts.z));
return center + offset * t;
}
float2 GetClosestFragment(float2 uv)
{
const float2 k = ScreenSize.zw;
const float4 neighborhood = float4(
SAMPLE_RT(Depth, uv - k).r,
SAMPLE_RT(Depth, uv + float2(k.x, -k.y)).r,
SAMPLE_RT(Depth, uv + float2(-k.x, k.y)).r,
SAMPLE_RT(Depth, uv + k).r
);
#if defined(REVERSED_Z)
#define COMPARE_DEPTH(a, b) step(b, a)
#else
#define COMPARE_DEPTH(a, b) step(a, b)
#endif
float3 result = float3(0.0, 0.0, SAMPLE_RT(Depth, uv).r);
result = lerp(result, float3(-1.0, -1.0, neighborhood.x), COMPARE_DEPTH(neighborhood.x, result.z));
result = lerp(result, float3( 1.0, -1.0, neighborhood.y), COMPARE_DEPTH(neighborhood.y, result.z));
result = lerp(result, float3(-1.0, 1.0, neighborhood.z), COMPARE_DEPTH(neighborhood.z, result.z));
result = lerp(result, float3( 1.0, 1.0, neighborhood.w), COMPARE_DEPTH(neighborhood.w, result.z));
return (uv + result.xy * k);
}
// Pixel Shader for Temporal Anti-Aliasing
META_PS(true, FEATURE_LEVEL_ES2)
META_PERMUTATION_1(IS_ORTHO=0)
META_PERMUTATION_1(IS_ORTHO=1)
void PS(Quad_VS2PS input, out float4 output : SV_Target0, out float4 outputHistory : SV_Target1)
float4 PS(Quad_VS2PS input) : SV_Target0
{
float2 jitter = TaaJitterStrength.zw;
float2 texcoord = input.TexCoord;
const float2 k = ScreenSize.zw;
#if IS_ORTHO
float2 closest = texcoord;
#else
float2 closest = GetClosestFragment(texcoord);
#endif
// Sample velocity
float2 velocity = MotionVectors.SampleLevel(SamplerLinearClamp, closest, 0).xy;
// Sample color and surround
float2 uv = texcoord - jitter;
float3 color = Fetch(Input, uv);
float3 topLeft = Fetch(Input, uv - k);
float3 bottomRight = Fetch(Input, uv + k);
float3 topRight = Fetch(Input, uv + float2(k.x, -k.y));
float3 bottomLeft = Fetch(Input, uv + float2(-k.x, k.y));
float3 corners = 4.0 * (topLeft + bottomRight) - 2.0 * color;
// Sharpen output
float sharpness = FinalBlendParameters.w;
float3 blur = (topLeft + topRight + bottomLeft + bottomRight) * 0.25;
color += (color - blur) * sharpness;
color = clamp(color, 0.0, HDR_CLAMP_MAX);
// Tonemap color
float3 average = Map((corners + color) / 7.0);
topLeft = Map(topLeft);
bottomRight = Map(bottomRight);
color = Map(color);
// Sample history
float3 history = Fetch(InputHistory, texcoord - velocity);
history = Map(history);
float colorLuma = Luminance(color);
float averageLuma = Luminance(average);
float velocityLength = length(velocity);
float nudge = lerp(4.0, 0.25, velocityLength * 100.0) * abs(averageLuma - colorLuma);
float3 minimum = min(bottomRight, topLeft) - nudge;
float3 maximum = max(topLeft, bottomRight) + nudge;
// Clip history sample
history = ClipToAABB(history, minimum, maximum);
// Blend color with history
//float historyLuma = Luminance(history);
//float weight = 1.0f - saturate(abs(colorLuma - historyLuma) / max(max(colorLuma, historyLuma), 0.2));
float weight = saturate(velocityLength * FinalBlendParameters.z);
float feedback = lerp(FinalBlendParameters.x, FinalBlendParameters.y, weight * weight);
//feedback = lerp(feedback, 0.02, velocityWeight);
color = Unmap(lerp(color, history, feedback));
color = clamp(color, 0.0, HDR_CLAMP_MAX);
output = float4(color, 1);
outputHistory = output;
//output = float4(1, 0, 0, 1) * feedback;
return float4(0, 0, 0, 0);
}