Browse Source

Added support for the experimental automatic Transparency, Compostion & Reactive masks generation pass.

hdrp
Nico de Poel 3 years ago
parent
commit
234bd4e163
  1. 33
      Assets/Resources/FSR2/ffx_fsr2_tcr_autogen_pass.compute
  2. 8
      Assets/Resources/FSR2/ffx_fsr2_tcr_autogen_pass.compute.meta
  3. 250
      Assets/Resources/FSR2/shaders/ffx_fsr2_tcr_autogen.h
  4. 27
      Assets/Resources/FSR2/shaders/ffx_fsr2_tcr_autogen.h.meta
  5. 114
      Assets/Resources/FSR2/shaders/ffx_fsr2_tcr_autogen_pass.hlsl
  6. 7
      Assets/Resources/FSR2/shaders/ffx_fsr2_tcr_autogen_pass.hlsl.meta
  7. 6
      Assets/Scenes/SampleScene.unity
  8. 17
      Assets/Scripts/Core/Fsr2.cs
  9. 47
      Assets/Scripts/Core/Fsr2Context.cs
  10. 44
      Assets/Scripts/Core/Fsr2Pipeline.cs
  11. 31
      Assets/Scripts/Core/Fsr2Resources.cs
  12. 5
      Assets/Scripts/Core/Fsr2ShaderIDs.cs
  13. 42
      Assets/Scripts/Fsr2ImageEffect.cs

33
Assets/Resources/FSR2/ffx_fsr2_tcr_autogen_pass.compute

@ -0,0 +1,33 @@
// Copyright (c) 2023 Nico de Poel
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#pragma kernel CS
#pragma multi_compile_local __ FFX_HALF
#pragma multi_compile_local __ FFX_FSR2_OPTION_REPROJECT_USE_LANCZOS_TYPE
#pragma multi_compile_local __ FFX_FSR2_OPTION_HDR_COLOR_INPUT
#pragma multi_compile_local __ FFX_FSR2_OPTION_LOW_RESOLUTION_MOTION_VECTORS
#pragma multi_compile_local __ FFX_FSR2_OPTION_JITTERED_MOTION_VECTORS
#pragma multi_compile_local __ FFX_FSR2_OPTION_INVERTED_DEPTH
#pragma multi_compile_local __ FFX_FSR2_OPTION_APPLY_SHARPENING
#include "ffx_fsr2_unity_common.cginc"
#include "shaders/ffx_fsr2_tcr_autogen_pass.hlsl"

8
Assets/Resources/FSR2/ffx_fsr2_tcr_autogen_pass.compute.meta

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: b478fba0a6a87b44b8be7c35deb5f0dc
ComputeShaderImporter:
externalObjects: {}
preprocessorOverride: 0
userData:
assetBundleName:
assetBundleVariant:

250
Assets/Resources/FSR2/shaders/ffx_fsr2_tcr_autogen.h

@ -0,0 +1,250 @@
// This file is part of the FidelityFX SDK.
//
// Copyright (c) 2022-2023 Advanced Micro Devices, Inc. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#define USE_YCOCG 1
#define fAutogenEpsilon 0.01f
// EXPERIMENTAL
FFX_MIN16_F ComputeAutoTC_01(FFX_MIN16_I2 uDispatchThreadId, FFX_MIN16_I2 iPrevIdx)
{
FfxFloat32x3 colorPreAlpha = LoadOpaqueOnly(uDispatchThreadId);
FfxFloat32x3 colorPostAlpha = LoadInputColor(uDispatchThreadId);
FfxFloat32x3 colorPrevPreAlpha = LoadPrevPreAlpha(iPrevIdx);
FfxFloat32x3 colorPrevPostAlpha = LoadPrevPostAlpha(iPrevIdx);
#if USE_YCOCG
colorPreAlpha = RGBToYCoCg(colorPreAlpha);
colorPostAlpha = RGBToYCoCg(colorPostAlpha);
colorPrevPreAlpha = RGBToYCoCg(colorPrevPreAlpha);
colorPrevPostAlpha = RGBToYCoCg(colorPrevPostAlpha);
#endif
FfxFloat32x3 colorDeltaCurr = colorPostAlpha - colorPreAlpha;
FfxFloat32x3 colorDeltaPrev = colorPrevPostAlpha - colorPrevPreAlpha;
bool hasAlpha = any(FFX_GREATER_THAN(abs(colorDeltaCurr), FfxFloat32x3(fAutogenEpsilon, fAutogenEpsilon, fAutogenEpsilon)));
bool hadAlpha = any(FFX_GREATER_THAN(abs(colorDeltaPrev), FfxFloat32x3(fAutogenEpsilon, fAutogenEpsilon, fAutogenEpsilon)));
FfxFloat32x3 X = colorPreAlpha;
FfxFloat32x3 Y = colorPostAlpha;
FfxFloat32x3 Z = colorPrevPreAlpha;
FfxFloat32x3 W = colorPrevPostAlpha;
FFX_MIN16_F retVal = FFX_MIN16_F(ffxSaturate(dot(abs(abs(Y - X) - abs(W - Z)), FfxFloat32x3(1, 1, 1))));
// cleanup very small values
retVal = (retVal < getTcThreshold()) ? FFX_MIN16_F(0.0f) : FFX_MIN16_F(1.f);
return retVal;
}
// works ok: thin edges
FFX_MIN16_F ComputeAutoTC_02(FFX_MIN16_I2 uDispatchThreadId, FFX_MIN16_I2 iPrevIdx)
{
FfxFloat32x3 colorPreAlpha = LoadOpaqueOnly(uDispatchThreadId);
FfxFloat32x3 colorPostAlpha = LoadInputColor(uDispatchThreadId);
FfxFloat32x3 colorPrevPreAlpha = LoadPrevPreAlpha(iPrevIdx);
FfxFloat32x3 colorPrevPostAlpha = LoadPrevPostAlpha(iPrevIdx);
#if USE_YCOCG
colorPreAlpha = RGBToYCoCg(colorPreAlpha);
colorPostAlpha = RGBToYCoCg(colorPostAlpha);
colorPrevPreAlpha = RGBToYCoCg(colorPrevPreAlpha);
colorPrevPostAlpha = RGBToYCoCg(colorPrevPostAlpha);
#endif
FfxFloat32x3 colorDelta = colorPostAlpha - colorPreAlpha;
FfxFloat32x3 colorPrevDelta = colorPrevPostAlpha - colorPrevPreAlpha;
bool hasAlpha = any(FFX_GREATER_THAN(abs(colorDelta), FfxFloat32x3(fAutogenEpsilon, fAutogenEpsilon, fAutogenEpsilon)));
bool hadAlpha = any(FFX_GREATER_THAN(abs(colorPrevDelta), FfxFloat32x3(fAutogenEpsilon, fAutogenEpsilon, fAutogenEpsilon)));
FfxFloat32x3 delta = colorPostAlpha - colorPreAlpha; //prev+1*d = post => d = color, alpha =
FfxFloat32x3 deltaPrev = colorPrevPostAlpha - colorPrevPreAlpha;
FfxFloat32x3 X = colorPrevPreAlpha;
FfxFloat32x3 N = colorPreAlpha - colorPrevPreAlpha;
FfxFloat32x3 YAminusXA = colorPrevPostAlpha - colorPrevPreAlpha;
FfxFloat32x3 NminusNA = colorPostAlpha - colorPrevPostAlpha;
FfxFloat32x3 A = (hasAlpha || hadAlpha) ? NminusNA / max(FfxFloat32x3(fAutogenEpsilon, fAutogenEpsilon, fAutogenEpsilon), N) : FfxFloat32x3(0, 0, 0);
FFX_MIN16_F retVal = FFX_MIN16_F( max(max(A.x, A.y), A.z) );
// only pixels that have significantly changed in color shuold be considered
retVal = ffxSaturate(retVal * FFX_MIN16_F(length(colorPostAlpha - colorPrevPostAlpha)) );
return retVal;
}
// This function computes the TransparencyAndComposition mask:
// This mask indicates pixels that should discard locks and apply color clamping.
//
// Typically this is the case for translucent pixels (that don't write depth values) or pixels where the correctness of
// the MVs can not be guaranteed (e.g. procedutal movement or vegetation that does not have MVs to reduce the cost during rasterization)
// Also, large changes in color due to changed lighting should be marked to remove locks on pixels with "old" lighting.
//
// This function takes a opaque only and a final texture and uses internal copies of those textures from the last frame.
// The function tries to determine where the color changes between opaque only and final image to determine the pixels that use transparency.
// Also it uses the previous frames and detects where the use of transparency changed to mark those pixels.
// Additionally it marks pixels where the color changed significantly in the opaque only image, e.g. due to lighting or texture animation.
//
// In the final step it stores the current textures in internal textures for the next frame
FFX_MIN16_F ComputeTransparencyAndComposition(FFX_MIN16_I2 uDispatchThreadId, FFX_MIN16_I2 iPrevIdx)
{
FFX_MIN16_F retVal = ComputeAutoTC_02(uDispatchThreadId, iPrevIdx);
// [branch]
if (retVal > FFX_MIN16_F(0.01f))
{
retVal = ComputeAutoTC_01(uDispatchThreadId, iPrevIdx);
}
return retVal;
}
float computeSolidEdge(FFX_MIN16_I2 curPos, FFX_MIN16_I2 prevPos)
{
float lum[9];
int i = 0;
for (int y = -1; y < 2; ++y)
{
for (int x = -1; x < 2; ++x)
{
FfxFloat32x3 curCol = LoadOpaqueOnly(curPos + FFX_MIN16_I2(x, y)).rgb;
FfxFloat32x3 prevCol = LoadPrevPreAlpha(prevPos + FFX_MIN16_I2(x, y)).rgb;
lum[i++] = length(curCol - prevCol);
}
}
//float gradX = abs(lum[3] - lum[4]) + abs(lum[5] - lum[4]);
//float gradY = abs(lum[1] - lum[4]) + abs(lum[7] - lum[4]);
//return sqrt(gradX * gradX + gradY * gradY);
float gradX = abs(lum[3] - lum[4]) * abs(lum[5] - lum[4]);
float gradY = abs(lum[1] - lum[4]) * abs(lum[7] - lum[4]);
return sqrt(sqrt(gradX * gradY));
}
float computeAlphaEdge(FFX_MIN16_I2 curPos, FFX_MIN16_I2 prevPos)
{
float lum[9];
int i = 0;
for (int y = -1; y < 2; ++y)
{
for (int x = -1; x < 2; ++x)
{
FfxFloat32x3 curCol = abs(LoadInputColor(curPos + FFX_MIN16_I2(x, y)).rgb - LoadOpaqueOnly(curPos + FFX_MIN16_I2(x, y)).rgb);
FfxFloat32x3 prevCol = abs(LoadPrevPostAlpha(prevPos + FFX_MIN16_I2(x, y)).rgb - LoadPrevPreAlpha(prevPos + FFX_MIN16_I2(x, y)).rgb);
lum[i++] = length(curCol - prevCol);
}
}
//float gradX = abs(lum[3] - lum[4]) + abs(lum[5] - lum[4]);
//float gradY = abs(lum[1] - lum[4]) + abs(lum[7] - lum[4]);
//return sqrt(gradX * gradX + gradY * gradY);
float gradX = abs(lum[3] - lum[4]) * abs(lum[5] - lum[4]);
float gradY = abs(lum[1] - lum[4]) * abs(lum[7] - lum[4]);
return sqrt(sqrt(gradX * gradY));
}
FFX_MIN16_F ComputeAabbOverlap(FFX_MIN16_I2 uDispatchThreadId, FFX_MIN16_I2 iPrevIdx)
{
FFX_MIN16_F retVal = FFX_MIN16_F(0.f);
FfxFloat32x2 fMotionVector = LoadInputMotionVector(uDispatchThreadId);
FfxFloat32x3 colorPreAlpha = LoadOpaqueOnly(uDispatchThreadId);
FfxFloat32x3 colorPostAlpha = LoadInputColor(uDispatchThreadId);
FfxFloat32x3 colorPrevPreAlpha = LoadPrevPreAlpha(iPrevIdx);
FfxFloat32x3 colorPrevPostAlpha = LoadPrevPostAlpha(iPrevIdx);
#if USE_YCOCG
colorPreAlpha = RGBToYCoCg(colorPreAlpha);
colorPostAlpha = RGBToYCoCg(colorPostAlpha);
colorPrevPreAlpha = RGBToYCoCg(colorPrevPreAlpha);
colorPrevPostAlpha = RGBToYCoCg(colorPrevPostAlpha);
#endif
FfxFloat32x3 minPrev = FFX_MIN16_F3(+1000.f, +1000.f, +1000.f);
FfxFloat32x3 maxPrev = FFX_MIN16_F3(-1000.f, -1000.f, -1000.f);
for (int y = -1; y < 2; ++y)
{
for (int x = -1; x < 2; ++x)
{
FfxFloat32x3 W = LoadPrevPostAlpha(iPrevIdx + FFX_MIN16_I2(x, y));
#if USE_YCOCG
W = RGBToYCoCg(W);
#endif
minPrev = min(minPrev, W);
maxPrev = max(maxPrev, W);
}
}
// instead of computing the overlap: simply count how many samples are outside
// set reactive based on that
FFX_MIN16_F count = FFX_MIN16_F(0.f);
for (int y = -1; y < 2; ++y)
{
for (int x = -1; x < 2; ++x)
{
FfxFloat32x3 Y = LoadInputColor(uDispatchThreadId + FFX_MIN16_I2(x, y));
#if USE_YCOCG
Y = RGBToYCoCg(Y);
#endif
count += ((Y.x < minPrev.x) || (Y.x > maxPrev.x)) ? FFX_MIN16_F(1.f) : FFX_MIN16_F(0.f);
count += ((Y.y < minPrev.y) || (Y.y > maxPrev.y)) ? FFX_MIN16_F(1.f) : FFX_MIN16_F(0.f);
count += ((Y.z < minPrev.z) || (Y.z > maxPrev.z)) ? FFX_MIN16_F(1.f) : FFX_MIN16_F(0.f);
}
}
retVal = count / FFX_MIN16_F(27.f);
return retVal;
}
// This function computes the Reactive mask:
// We want pixels marked where the alpha portion of the frame changes a lot between neighbours
// Those pixels are expected to change quickly between frames, too. (e.g. small particles, reflections on curved surfaces...)
// As a result history would not be trustworthy.
// On the other hand we don't want pixels marked where pre-alpha has a large differnce, since those would profit from accumulation
// For mirrors we may assume the pre-alpha is pretty uniform color.
//
// This works well generally, but also marks edge pixels
FFX_MIN16_F ComputeReactive(FFX_MIN16_I2 uDispatchThreadId, FFX_MIN16_I2 iPrevIdx)
{
// we only get here if alpha has a significant contribution and has changed since last frame.
FFX_MIN16_F retVal = FFX_MIN16_F(0.f);
// mark pixels with huge variance in alpha as reactive
FFX_MIN16_F alphaEdge = FFX_MIN16_F(computeAlphaEdge(uDispatchThreadId, iPrevIdx));
FFX_MIN16_F opaqueEdge = FFX_MIN16_F(computeSolidEdge(uDispatchThreadId, iPrevIdx));
retVal = ffxSaturate(alphaEdge - opaqueEdge);
// the above also marks edge pixels due to jitter, so we need to cancel those out
return retVal;
}

27
Assets/Resources/FSR2/shaders/ffx_fsr2_tcr_autogen.h.meta

@ -0,0 +1,27 @@
fileFormatVersion: 2
guid: 18b8590c99b171a4e9af68dfd2c3ff02
PluginImporter:
externalObjects: {}
serializedVersion: 2
iconMap: {}
executionOrder: {}
defineConstraints: []
isPreloaded: 0
isOverridable: 0
isExplicitlyReferenced: 0
validateReferences: 1
platformData:
- first:
Any:
second:
enabled: 1
settings: {}
- first:
Editor: Editor
second:
enabled: 0
settings:
DefaultValueInitialized: true
userData:
assetBundleName:
assetBundleVariant:

114
Assets/Resources/FSR2/shaders/ffx_fsr2_tcr_autogen_pass.hlsl

@ -0,0 +1,114 @@
// This file is part of the FidelityFX SDK.
//
// Copyright (c) 2022-2023 Advanced Micro Devices, Inc. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#define FSR2_BIND_SRV_INPUT_OPAQUE_ONLY 0
#define FSR2_BIND_SRV_INPUT_COLOR 1
#define FSR2_BIND_SRV_INPUT_MOTION_VECTORS 2
#define FSR2_BIND_SRV_PREV_PRE_ALPHA_COLOR 3
#define FSR2_BIND_SRV_PREV_POST_ALPHA_COLOR 4
#define FSR2_BIND_SRV_REACTIVE_MASK 4
#define FSR2_BIND_SRV_TRANSPARENCY_AND_COMPOSITION_MASK 5
#define FSR2_BIND_UAV_AUTOREACTIVE 0
#define FSR2_BIND_UAV_AUTOCOMPOSITION 1
#define FSR2_BIND_UAV_PREV_PRE_ALPHA_COLOR 2
#define FSR2_BIND_UAV_PREV_POST_ALPHA_COLOR 3
#define FSR2_BIND_CB_FSR2 0
#define FSR2_BIND_CB_AUTOREACTIVE 1
#include "ffx_fsr2_callbacks_hlsl.h"
#include "ffx_fsr2_common.h"
#if defined(FSR2_BIND_CB_AUTOREACTIVE)
cbuffer cbGenerateReactive : FFX_FSR2_DECLARE_CB(FSR2_BIND_CB_AUTOREACTIVE)
{
float fTcThreshold; // 0.1 is a good starting value, lower will result in more TC pixels
float fTcScale;
float fReactiveScale;
float fReactiveMax;
};
float getTcThreshold()
{
return fTcThreshold;
}
#else
#define fTcThreshold 0.05f
#define fTcScale 1.00f
#define fReactiveScale 10.0f
#define fReactiveMax 0.90f
float getTcThreshold()
{
return fTcThreshold;
}
#endif
#include "ffx_fsr2_tcr_autogen.h"
#ifndef FFX_FSR2_THREAD_GROUP_WIDTH
#define FFX_FSR2_THREAD_GROUP_WIDTH 8
#endif // #ifndef FFX_FSR2_THREAD_GROUP_WIDTH
#ifndef FFX_FSR2_THREAD_GROUP_HEIGHT
#define FFX_FSR2_THREAD_GROUP_HEIGHT 8
#endif // FFX_FSR2_THREAD_GROUP_HEIGHT
#ifndef FFX_FSR2_THREAD_GROUP_DEPTH
#define FFX_FSR2_THREAD_GROUP_DEPTH 1
#endif // #ifndef FFX_FSR2_THREAD_GROUP_DEPTH
#ifndef FFX_FSR2_NUM_THREADS
#define FFX_FSR2_NUM_THREADS [numthreads(FFX_FSR2_THREAD_GROUP_WIDTH, FFX_FSR2_THREAD_GROUP_HEIGHT, FFX_FSR2_THREAD_GROUP_DEPTH)]
#endif // #ifndef FFX_FSR2_NUM_THREADS
FFX_FSR2_NUM_THREADS
FFX_FSR2_EMBED_ROOTSIG_CONTENT
void CS(uint2 uGroupId : SV_GroupID, uint2 uGroupThreadId : SV_GroupThreadID)
{
FFX_MIN16_I2 uDispatchThreadId = FFX_MIN16_I2(uGroupId * uint2(FFX_FSR2_THREAD_GROUP_WIDTH, FFX_FSR2_THREAD_GROUP_HEIGHT) + uGroupThreadId);
// ToDo: take into account jitter (i.e. add delta of previous jitter and current jitter to previous UV
// fetch pre- and post-alpha color values
FFX_MIN16_F2 fUv = ( FFX_MIN16_F2(uDispatchThreadId) + FFX_MIN16_F2(0.5f, 0.5f) ) / FFX_MIN16_F2( RenderSize() );
FFX_MIN16_F2 fPrevUV = fUv + FFX_MIN16_F2( LoadInputMotionVector(uDispatchThreadId) );
FFX_MIN16_I2 iPrevIdx = FFX_MIN16_I2(fPrevUV * FFX_MIN16_F2(RenderSize()) - 0.5f);
FFX_MIN16_F3 colorPreAlpha = FFX_MIN16_F3( LoadOpaqueOnly( uDispatchThreadId ) );
FFX_MIN16_F3 colorPostAlpha = FFX_MIN16_F3( LoadInputColor( uDispatchThreadId ) );
FFX_MIN16_F2 outReactiveMask = 0;
outReactiveMask.y = ComputeTransparencyAndComposition(uDispatchThreadId, iPrevIdx);
if (outReactiveMask.y > 0.5f)
{
outReactiveMask.x = ComputeReactive(uDispatchThreadId, iPrevIdx);
outReactiveMask.x *= FFX_MIN16_F(fReactiveScale);
outReactiveMask.x = outReactiveMask.x < fReactiveMax ? outReactiveMask.x : FFX_MIN16_F( fReactiveMax );
}
outReactiveMask.y *= FFX_MIN16_F(fTcScale );
outReactiveMask.x = max( outReactiveMask.x, FFX_MIN16_F( LoadReactiveMask(uDispatchThreadId) ) );
outReactiveMask.y = max( outReactiveMask.y, FFX_MIN16_F( LoadTransparencyAndCompositionMask(uDispatchThreadId) ) );
StoreAutoReactive(uDispatchThreadId, outReactiveMask);
StorePrevPreAlpha(uDispatchThreadId, colorPreAlpha);
StorePrevPostAlpha(uDispatchThreadId, colorPostAlpha);
}

7
Assets/Resources/FSR2/shaders/ffx_fsr2_tcr_autogen_pass.hlsl.meta

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 9feb1fa4d6cff5a4799298dc69b12a8e
ShaderIncludeImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

6
Assets/Scenes/SampleScene.unity

@ -329,6 +329,12 @@ MonoBehaviour:
cutoffThreshold: 0.2 cutoffThreshold: 0.2
binaryValue: 0.9 binaryValue: 0.9
flags: 13 flags: 13
autoGenerateTransparencyAndComposition: 0
generateTransparencyAndCompositionParameters:
autoTcThreshold: 0.05
autoTcScale: 1
autoReactiveScale: 5
autoReactiveMax: 0.9
outputMotionVectors: {fileID: 0} outputMotionVectors: {fileID: 0}
--- !u!1001 &1313173313 --- !u!1001 &1313173313
PrefabInstance: PrefabInstance:

17
Assets/Scripts/Core/Fsr2.cs

@ -182,6 +182,14 @@ namespace FidelityFX
public float CameraFar; public float CameraFar;
public float CameraFovAngleVertical; public float CameraFovAngleVertical;
public float ViewSpaceToMetersFactor; public float ViewSpaceToMetersFactor;
// EXPERIMENTAL reactive mask generation parameters
public bool EnableAutoReactive;
public RenderTargetIdentifier? ColorOpaqueOnly;
public float AutoTcThreshold = 0.05f;
public float AutoTcScale = 1.0f;
public float AutoReactiveScale = 5.0f;
public float AutoReactiveMax = 0.9f;
} }
/// <summary> /// <summary>
@ -253,6 +261,15 @@ namespace FidelityFX
public uint flags; public uint flags;
} }
[Serializable, StructLayout(LayoutKind.Sequential)]
internal struct GenerateReactiveConstants2
{
public float autoTcThreshold;
public float autoTcScale;
public float autoReactiveScale;
public float autoReactiveMax;
}
[Serializable, StructLayout(LayoutKind.Sequential)] [Serializable, StructLayout(LayoutKind.Sequential)]
internal struct RcasConstants internal struct RcasConstants
{ {

47
Assets/Scripts/Core/Fsr2Context.cs

@ -47,6 +47,7 @@ namespace FidelityFX
private Fsr2Pipeline _rcasPipeline; private Fsr2Pipeline _rcasPipeline;
private Fsr2Pipeline _computeLuminancePyramidPipeline; private Fsr2Pipeline _computeLuminancePyramidPipeline;
private Fsr2Pipeline _generateReactivePipeline; private Fsr2Pipeline _generateReactivePipeline;
private Fsr2Pipeline _tcrAutogeneratePipeline;
private readonly Fsr2Resources _resources = new Fsr2Resources(); private readonly Fsr2Resources _resources = new Fsr2Resources();
@ -66,6 +67,10 @@ namespace FidelityFX
private readonly Fsr2.GenerateReactiveConstants[] _generateReactiveConstantsArray = { new Fsr2.GenerateReactiveConstants() }; private readonly Fsr2.GenerateReactiveConstants[] _generateReactiveConstantsArray = { new Fsr2.GenerateReactiveConstants() };
private ref Fsr2.GenerateReactiveConstants GenReactiveConsts => ref _generateReactiveConstantsArray[0]; private ref Fsr2.GenerateReactiveConstants GenReactiveConsts => ref _generateReactiveConstantsArray[0];
private ComputeBuffer _tcrAutogenerateConstantsBuffer;
private readonly Fsr2.GenerateReactiveConstants2[] _tcrAutogenerateConstantsArray = { new Fsr2.GenerateReactiveConstants2() };
private ref Fsr2.GenerateReactiveConstants2 TcrAutoGenConsts => ref _tcrAutogenerateConstantsArray[0];
private bool _firstExecution; private bool _firstExecution;
private Vector2 _previousJitterOffset; private Vector2 _previousJitterOffset;
private int _resourceFrameIndex; private int _resourceFrameIndex;
@ -79,6 +84,7 @@ namespace FidelityFX
_spdConstantsBuffer = CreateConstantBuffer<Fsr2.SpdConstants>(); _spdConstantsBuffer = CreateConstantBuffer<Fsr2.SpdConstants>();
_rcasConstantsBuffer = CreateConstantBuffer<Fsr2.RcasConstants>(); _rcasConstantsBuffer = CreateConstantBuffer<Fsr2.RcasConstants>();
_generateReactiveConstantsBuffer = CreateConstantBuffer<Fsr2.GenerateReactiveConstants>(); _generateReactiveConstantsBuffer = CreateConstantBuffer<Fsr2.GenerateReactiveConstants>();
_tcrAutogenerateConstantsBuffer = CreateConstantBuffer<Fsr2.GenerateReactiveConstants2>();
// Set defaults // Set defaults
_firstExecution = true; _firstExecution = true;
@ -100,10 +106,12 @@ namespace FidelityFX
_accumulateSharpenPipeline = new Fsr2AccumulateSharpenPipeline(_contextDescription, _resources, _fsr2ConstantsBuffer); _accumulateSharpenPipeline = new Fsr2AccumulateSharpenPipeline(_contextDescription, _resources, _fsr2ConstantsBuffer);
_rcasPipeline = new Fsr2RcasPipeline(_contextDescription, _resources, _fsr2ConstantsBuffer, _rcasConstantsBuffer); _rcasPipeline = new Fsr2RcasPipeline(_contextDescription, _resources, _fsr2ConstantsBuffer, _rcasConstantsBuffer);
_generateReactivePipeline = new Fsr2GenerateReactivePipeline(_contextDescription, _resources, _generateReactiveConstantsBuffer); _generateReactivePipeline = new Fsr2GenerateReactivePipeline(_contextDescription, _resources, _generateReactiveConstantsBuffer);
_tcrAutogeneratePipeline = new Fsr2TcrAutogeneratePipeline(_contextDescription, _resources, _fsr2ConstantsBuffer, _tcrAutogenerateConstantsBuffer);
} }
public void Destroy() public void Destroy()
{ {
DestroyPipeline(ref _tcrAutogeneratePipeline);
DestroyPipeline(ref _generateReactivePipeline); DestroyPipeline(ref _generateReactivePipeline);
DestroyPipeline(ref _computeLuminancePyramidPipeline); DestroyPipeline(ref _computeLuminancePyramidPipeline);
DestroyPipeline(ref _rcasPipeline); DestroyPipeline(ref _rcasPipeline);
@ -115,6 +123,7 @@ namespace FidelityFX
_resources.Destroy(); _resources.Destroy();
DestroyConstantBuffer(ref _tcrAutogenerateConstantsBuffer);
DestroyConstantBuffer(ref _generateReactiveConstantsBuffer); DestroyConstantBuffer(ref _generateReactiveConstantsBuffer);
DestroyConstantBuffer(ref _rcasConstantsBuffer); DestroyConstantBuffer(ref _rcasConstantsBuffer);
DestroyConstantBuffer(ref _spdConstantsBuffer); DestroyConstantBuffer(ref _spdConstantsBuffer);
@ -156,6 +165,21 @@ namespace FidelityFX
else if (dispatchParams.Exposure == null) else if (dispatchParams.Exposure == null)
dispatchParams.Exposure = _resources.DefaultExposure; dispatchParams.Exposure = _resources.DefaultExposure;
if (dispatchParams.EnableAutoReactive)
{
// Create the auto-TCR resources only when we need them
if (_resources.AutoReactive == null)
_resources.CreateTcrAutogenResources(_contextDescription);
if (resetAccumulation)
commandBuffer.Blit(_resources.PrevPreAlpha[frameIndex ^ 1], dispatchParams.ColorOpaqueOnly ?? Fsr2ShaderIDs.SrvOpaqueOnly);
}
else if (_resources.AutoReactive != null)
{
// Destroy the auto-TCR resources if we don't use the feature
_resources.DestroyTcrAutogenResources();
}
if (dispatchParams.Reactive == null) dispatchParams.Reactive = _resources.DefaultReactive; if (dispatchParams.Reactive == null) dispatchParams.Reactive = _resources.DefaultReactive;
if (dispatchParams.TransparencyAndComposition == null) dispatchParams.TransparencyAndComposition = _resources.DefaultReactive; if (dispatchParams.TransparencyAndComposition == null) dispatchParams.TransparencyAndComposition = _resources.DefaultReactive;
Fsr2Pipeline.RegisterResources(commandBuffer, _contextDescription, dispatchParams); Fsr2Pipeline.RegisterResources(commandBuffer, _contextDescription, dispatchParams);
@ -193,6 +217,14 @@ namespace FidelityFX
_fsr2ConstantsBuffer.SetData(_fsr2ConstantsArray); _fsr2ConstantsBuffer.SetData(_fsr2ConstantsArray);
_spdConstantsBuffer.SetData(_spdConstantsArray); _spdConstantsBuffer.SetData(_spdConstantsArray);
// Auto reactive
if (dispatchParams.EnableAutoReactive)
{
GenerateTransparencyCompositionReactive(dispatchParams, commandBuffer, frameIndex);
dispatchParams.Reactive = _resources.AutoReactive;
dispatchParams.TransparencyAndComposition = _resources.AutoComposition;
}
// Compute luminance pyramid // Compute luminance pyramid
_computeLuminancePyramidPipeline.ScheduleDispatch(commandBuffer, dispatchParams, frameIndex, dispatchThreadGroupCount.x, dispatchThreadGroupCount.y); _computeLuminancePyramidPipeline.ScheduleDispatch(commandBuffer, dispatchParams, frameIndex, dispatchThreadGroupCount.x, dispatchThreadGroupCount.y);
@ -251,6 +283,21 @@ namespace FidelityFX
((Fsr2GenerateReactivePipeline)_generateReactivePipeline).ScheduleDispatch(commandBuffer, dispatchParams, dispatchSrcX, dispatchSrcY); ((Fsr2GenerateReactivePipeline)_generateReactivePipeline).ScheduleDispatch(commandBuffer, dispatchParams, dispatchSrcX, dispatchSrcY);
} }
private void GenerateTransparencyCompositionReactive(Fsr2.DispatchDescription dispatchParams, CommandBuffer commandBuffer, int frameIndex)
{
const int threadGroupWorkRegionDim = 8;
int dispatchSrcX = (dispatchParams.RenderSize.x + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim;
int dispatchSrcY = (dispatchParams.RenderSize.y + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim;
TcrAutoGenConsts.autoTcThreshold = dispatchParams.AutoTcThreshold;
TcrAutoGenConsts.autoTcScale = dispatchParams.AutoTcScale;
TcrAutoGenConsts.autoReactiveScale = dispatchParams.AutoReactiveScale;
TcrAutoGenConsts.autoReactiveMax = dispatchParams.AutoReactiveMax;
_tcrAutogenerateConstantsBuffer.SetData(_tcrAutogenerateConstantsArray);
_tcrAutogeneratePipeline.ScheduleDispatch(commandBuffer, dispatchParams, frameIndex, dispatchSrcX, dispatchSrcY);
}
private void SetupConstants(Fsr2.DispatchDescription dispatchParams, bool resetAccumulation) private void SetupConstants(Fsr2.DispatchDescription dispatchParams, bool resetAccumulation)
{ {
ref Fsr2.Fsr2Constants constants = ref Constants; ref Fsr2.Fsr2Constants constants = ref Constants;

44
Assets/Scripts/Core/Fsr2Pipeline.cs

@ -404,4 +404,48 @@ namespace FidelityFX
commandBuffer.DispatchCompute(ComputeShader, KernelIndex, dispatchX, dispatchY, 1); commandBuffer.DispatchCompute(ComputeShader, KernelIndex, dispatchX, dispatchY, 1);
} }
} }
internal class Fsr2TcrAutogeneratePipeline : Fsr2Pipeline
{
private readonly ComputeBuffer _tcrAutogenerateConstants;
public Fsr2TcrAutogeneratePipeline(Fsr2.ContextDescription contextDescription, Fsr2Resources resources, ComputeBuffer constants, ComputeBuffer tcrAutogenerateConstants)
: base(contextDescription, resources, constants)
{
_tcrAutogenerateConstants = tcrAutogenerateConstants;
LoadComputeShader("FSR2/ffx_fsr2_tcr_autogen_pass");
}
public override void ScheduleDispatch(CommandBuffer commandBuffer, Fsr2.DispatchDescription dispatchParams, int frameIndex, int dispatchX, int dispatchY)
{
if (dispatchParams.ColorOpaqueOnly.HasValue)
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvOpaqueOnly, dispatchParams.ColorOpaqueOnly.Value, 0, RenderTextureSubElement.Color);
if (dispatchParams.Color.HasValue)
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvInputColor, dispatchParams.Color.Value, 0, RenderTextureSubElement.Color);
if (dispatchParams.MotionVectors.HasValue)
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvInputMotionVectors, dispatchParams.MotionVectors.Value);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvPrevColorPreAlpha, Resources.PrevPreAlpha[frameIndex ^ 1]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvPrevColorPostAlpha, Resources.PrevPostAlpha[frameIndex ^ 1]);
if (dispatchParams.Reactive.HasValue)
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvReactiveMask, dispatchParams.Reactive.Value);
if (dispatchParams.TransparencyAndComposition.HasValue)
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvTransparencyAndCompositionMask, dispatchParams.TransparencyAndComposition.Value);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.UavAutoReactive, Resources.AutoReactive);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.UavAutoComposition, Resources.AutoComposition);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.UavPrevColorPreAlpha, Resources.PrevPreAlpha[frameIndex]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.UavPrevColorPostAlpha, Resources.PrevPostAlpha[frameIndex]);
commandBuffer.SetComputeConstantBufferParam(ComputeShader, Fsr2ShaderIDs.CbFsr2, Constants, 0, Marshal.SizeOf<Fsr2.Fsr2Constants>());
commandBuffer.SetComputeConstantBufferParam(ComputeShader, Fsr2ShaderIDs.CbGenReactive, _tcrAutogenerateConstants, 0, Marshal.SizeOf<Fsr2.GenerateReactiveConstants2>());
commandBuffer.DispatchCompute(ComputeShader, KernelIndex, dispatchX, dispatchY, 1);
}
}
} }

31
Assets/Scripts/Core/Fsr2Resources.cs

@ -36,10 +36,14 @@ namespace FidelityFX
public Texture2D MaximumBiasLut; public Texture2D MaximumBiasLut;
public RenderTexture AutoExposure; public RenderTexture AutoExposure;
public RenderTexture SceneLuminance; public RenderTexture SceneLuminance;
public RenderTexture AutoReactive;
public RenderTexture AutoComposition;
public readonly RenderTexture[] DilatedMotionVectors = new RenderTexture[2]; public readonly RenderTexture[] DilatedMotionVectors = new RenderTexture[2];
public readonly RenderTexture[] LockStatus = new RenderTexture[2]; public readonly RenderTexture[] LockStatus = new RenderTexture[2];
public readonly RenderTexture[] InternalUpscaled = new RenderTexture[2]; public readonly RenderTexture[] InternalUpscaled = new RenderTexture[2];
public readonly RenderTexture[] LumaHistory = new RenderTexture[2]; public readonly RenderTexture[] LumaHistory = new RenderTexture[2];
public readonly RenderTexture[] PrevPreAlpha = new RenderTexture[2];
public readonly RenderTexture[] PrevPostAlpha = new RenderTexture[2];
public void Create(Fsr2.ContextDescription contextDescription) public void Create(Fsr2.ContextDescription contextDescription)
{ {
@ -104,6 +108,23 @@ namespace FidelityFX
CreateDoubleBufferedResource(LumaHistory, "FSR2_LumaHistory", contextDescription.DisplaySize, GraphicsFormat.R8G8B8A8_UNorm); CreateDoubleBufferedResource(LumaHistory, "FSR2_LumaHistory", contextDescription.DisplaySize, GraphicsFormat.R8G8B8A8_UNorm);
} }
public void CreateTcrAutogenResources(Fsr2.ContextDescription contextDescription)
{
// Resource FSR2_AutoReactive: FFX_RESOURCE_USAGE_UAV, FFX_SURFACE_FORMAT_R8_UNORM, FFX_RESOURCE_FLAGS_NONE
AutoReactive = new RenderTexture(contextDescription.MaxRenderSize.x, contextDescription.MaxRenderSize.y, 0, GraphicsFormat.R8_UNorm) { name = "FSR2_AutoReactive", enableRandomWrite = true };
AutoReactive.Create();
// Resource FSR2_AutoComposition: FFX_RESOURCE_USAGE_UAV, FFX_SURFACE_FORMAT_R8_UNORM, FFX_RESOURCE_FLAGS_NONE
AutoComposition = new RenderTexture(contextDescription.MaxRenderSize.x, contextDescription.MaxRenderSize.y, 0, GraphicsFormat.R8_UNorm) { name = "FSR2_AutoComposition", enableRandomWrite = true };
AutoComposition.Create();
// Resources FSR2_PrevPreAlpha0/1: FFX_RESOURCE_USAGE_UAV, FFX_SURFACE_FORMAT_R11G11B10_FLOAT, FFX_RESOURCE_FLAGS_NONE
CreateDoubleBufferedResource(PrevPreAlpha, "FSR2_PrevPreAlpha", contextDescription.MaxRenderSize, GraphicsFormat.B10G11R11_UFloatPack32);
// Resources FSR2_PrevPostAlpha0/1: FFX_RESOURCE_USAGE_UAV, FFX_SURFACE_FORMAT_R11G11B10_FLOAT, FFX_RESOURCE_FLAGS_NONE
CreateDoubleBufferedResource(PrevPostAlpha, "FSR2_PrevPostAlpha", contextDescription.MaxRenderSize, GraphicsFormat.B10G11R11_UFloatPack32);
}
private static void CreateDoubleBufferedResource(RenderTexture[] resource, string name, Vector2Int size, GraphicsFormat format) private static void CreateDoubleBufferedResource(RenderTexture[] resource, string name, Vector2Int size, GraphicsFormat format)
{ {
for (int i = 0; i < 2; ++i) for (int i = 0; i < 2; ++i)
@ -115,6 +136,8 @@ namespace FidelityFX
public void Destroy() public void Destroy()
{ {
DestroyTcrAutogenResources();
DestroyResource(LumaHistory); DestroyResource(LumaHistory);
DestroyResource(InternalUpscaled); DestroyResource(InternalUpscaled);
DestroyResource(LockStatus); DestroyResource(LockStatus);
@ -127,6 +150,14 @@ namespace FidelityFX
DestroyResource(ref LanczosLut); DestroyResource(ref LanczosLut);
} }
public void DestroyTcrAutogenResources()
{
DestroyResource(PrevPostAlpha);
DestroyResource(PrevPreAlpha);
DestroyResource(ref AutoComposition);
DestroyResource(ref AutoReactive);
}
private static void DestroyResource(ref Texture2D resource) private static void DestroyResource(ref Texture2D resource)
{ {
if (resource == null) if (resource == null)

5
Assets/Scripts/Core/Fsr2ShaderIDs.cs

@ -47,6 +47,8 @@ namespace FidelityFX
internal static readonly int SrvSceneLuminanceMips = Shader.PropertyToID("r_imgMips"); internal static readonly int SrvSceneLuminanceMips = Shader.PropertyToID("r_imgMips");
internal static readonly int SrvUpscaleMaximumBiasLut = Shader.PropertyToID("r_upsample_maximum_bias_lut"); internal static readonly int SrvUpscaleMaximumBiasLut = Shader.PropertyToID("r_upsample_maximum_bias_lut");
internal static readonly int SrvDilatedReactiveMasks = Shader.PropertyToID("r_dilated_reactive_masks"); internal static readonly int SrvDilatedReactiveMasks = Shader.PropertyToID("r_dilated_reactive_masks");
internal static readonly int SrvPrevColorPreAlpha = Shader.PropertyToID("r_input_prev_color_pre_alpha");
internal static readonly int SrvPrevColorPostAlpha = Shader.PropertyToID("r_input_prev_color_post_alpha");
// Unordered access views, i.e. random read/write bindings // Unordered access views, i.e. random read/write bindings
internal static readonly int UavReconstructedPrevNearestDepth = Shader.PropertyToID("rw_reconstructed_previous_nearest_depth"); internal static readonly int UavReconstructedPrevNearestDepth = Shader.PropertyToID("rw_reconstructed_previous_nearest_depth");
@ -65,6 +67,9 @@ namespace FidelityFX
internal static readonly int UavAutoExposure = Shader.PropertyToID("rw_auto_exposure"); internal static readonly int UavAutoExposure = Shader.PropertyToID("rw_auto_exposure");
internal static readonly int UavSpdAtomicCount = Shader.PropertyToID("rw_spd_global_atomic"); internal static readonly int UavSpdAtomicCount = Shader.PropertyToID("rw_spd_global_atomic");
internal static readonly int UavAutoReactive = Shader.PropertyToID("rw_output_autoreactive"); internal static readonly int UavAutoReactive = Shader.PropertyToID("rw_output_autoreactive");
internal static readonly int UavAutoComposition = Shader.PropertyToID("rw_output_autocomposition");
internal static readonly int UavPrevColorPreAlpha = Shader.PropertyToID("rw_output_prev_color_pre_alpha");
internal static readonly int UavPrevColorPostAlpha = Shader.PropertyToID("rw_output_prev_color_post_alpha");
// Constant buffer bindings // Constant buffer bindings
internal static readonly int CbFsr2 = Shader.PropertyToID("cbFSR2"); internal static readonly int CbFsr2 = Shader.PropertyToID("cbFSR2");

42
Assets/Scripts/Fsr2ImageEffect.cs

@ -75,6 +75,25 @@ namespace FidelityFX
public Fsr2.GenerateReactiveFlags flags = Fsr2.GenerateReactiveFlags.ApplyTonemap | Fsr2.GenerateReactiveFlags.ApplyThreshold | Fsr2.GenerateReactiveFlags.UseComponentsMax; public Fsr2.GenerateReactiveFlags flags = Fsr2.GenerateReactiveFlags.ApplyTonemap | Fsr2.GenerateReactiveFlags.ApplyThreshold | Fsr2.GenerateReactiveFlags.UseComponentsMax;
} }
[Tooltip("(Experimental) Automatically generate and use Reactive mask and Transparency & composition mask internally.")]
public bool autoGenerateTransparencyAndComposition = false;
[Tooltip("Parameters to control the process of auto-generating transparency and composition masks.")]
[SerializeField] private GenerateTcrParameters generateTransparencyAndCompositionParameters = new GenerateTcrParameters();
public GenerateTcrParameters GenerateTcrParams => generateTransparencyAndCompositionParameters;
[Serializable]
public class GenerateTcrParameters
{
[Tooltip("Setting this value too small will cause visual instability. Larger values can cause ghosting.")]
[Range(0, 1)] public float autoTcThreshold = 0.05f;
[Tooltip("Smaller values will increase stability at hard edges of translucent objects.")]
[Range(0, 2)] public float autoTcScale = 1.0f;
[Tooltip("Larger values result in more reactive pixels.")]
[Range(0, 10)] public float autoReactiveScale = 5.0f;
[Tooltip("Maximum value reactivity can reach.")]
[Range(0, 1)] public float autoReactiveMax = 0.9f;
}
[Header("Output resources")] [Header("Output resources")]
[Tooltip("Optional render texture to copy motion vector data to, for additional post-processing after upscaling.")] [Tooltip("Optional render texture to copy motion vector data to, for additional post-processing after upscaling.")]
public RenderTexture outputMotionVectors; public RenderTexture outputMotionVectors;
@ -97,6 +116,7 @@ namespace FidelityFX
private Fsr2.QualityMode _prevQualityMode; private Fsr2.QualityMode _prevQualityMode;
private Vector2Int _prevDisplaySize; private Vector2Int _prevDisplaySize;
private bool _prevGenReactiveMask; private bool _prevGenReactiveMask;
private bool _prevGenTcrMasks;
private CommandBuffer _dispatchCommandBuffer; private CommandBuffer _dispatchCommandBuffer;
private CommandBuffer _opaqueInputCommandBuffer; private CommandBuffer _opaqueInputCommandBuffer;
@ -155,7 +175,7 @@ namespace FidelityFX
_opaqueInputCommandBuffer.GetTemporaryRT(Fsr2ShaderIDs.SrvOpaqueOnly, _renderSize.x, _renderSize.y, 0, default, GetDefaultFormat()); _opaqueInputCommandBuffer.GetTemporaryRT(Fsr2ShaderIDs.SrvOpaqueOnly, _renderSize.x, _renderSize.y, 0, default, GetDefaultFormat());
_opaqueInputCommandBuffer.Blit(BuiltinRenderTextureType.CameraTarget, Fsr2ShaderIDs.SrvOpaqueOnly); _opaqueInputCommandBuffer.Blit(BuiltinRenderTextureType.CameraTarget, Fsr2ShaderIDs.SrvOpaqueOnly);
if (autoGenerateReactiveMask)
if (autoGenerateReactiveMask || autoGenerateTransparencyAndComposition)
{ {
_renderCamera.AddCommandBuffer(CameraEvent.BeforeForwardAlpha, _opaqueInputCommandBuffer); _renderCamera.AddCommandBuffer(CameraEvent.BeforeForwardAlpha, _opaqueInputCommandBuffer);
} }
@ -165,6 +185,7 @@ namespace FidelityFX
_prevDisplaySize = _displaySize; _prevDisplaySize = _displaySize;
_prevQualityMode = qualityMode; _prevQualityMode = qualityMode;
_prevGenReactiveMask = autoGenerateReactiveMask; _prevGenReactiveMask = autoGenerateReactiveMask;
_prevGenTcrMasks = autoGenerateTransparencyAndComposition;
} }
private void OnDisable() private void OnDisable()
@ -216,14 +237,15 @@ namespace FidelityFX
OnEnable(); OnEnable();
} }
if (autoGenerateReactiveMask != _prevGenReactiveMask)
if ((autoGenerateReactiveMask || autoGenerateTransparencyAndComposition) != (_prevGenReactiveMask || _prevGenTcrMasks))
{ {
if (autoGenerateReactiveMask)
if (autoGenerateReactiveMask || autoGenerateTransparencyAndComposition)
_renderCamera.AddCommandBuffer(CameraEvent.BeforeForwardAlpha, _opaqueInputCommandBuffer); _renderCamera.AddCommandBuffer(CameraEvent.BeforeForwardAlpha, _opaqueInputCommandBuffer);
else else
_renderCamera.RemoveCommandBuffer(CameraEvent.BeforeForwardAlpha, _opaqueInputCommandBuffer); _renderCamera.RemoveCommandBuffer(CameraEvent.BeforeForwardAlpha, _opaqueInputCommandBuffer);
_prevGenReactiveMask = autoGenerateReactiveMask; _prevGenReactiveMask = autoGenerateReactiveMask;
_prevGenTcrMasks = autoGenerateTransparencyAndComposition;
} }
} }
@ -288,6 +310,15 @@ namespace FidelityFX
_dispatchDescription.Reset = _reset; _dispatchDescription.Reset = _reset;
_reset = false; _reset = false;
_dispatchDescription.EnableAutoReactive = autoGenerateTransparencyAndComposition;
if (autoGenerateTransparencyAndComposition)
{
_dispatchDescription.AutoTcThreshold = generateTransparencyAndCompositionParameters.autoTcThreshold;
_dispatchDescription.AutoTcScale = generateTransparencyAndCompositionParameters.autoTcScale;
_dispatchDescription.AutoReactiveScale = generateTransparencyAndCompositionParameters.autoReactiveScale;
_dispatchDescription.AutoReactiveMax = generateTransparencyAndCompositionParameters.autoReactiveMax;
}
if (SystemInfo.usesReversedZBuffer) if (SystemInfo.usesReversedZBuffer)
{ {
// Swap the near and far clip plane distances as FSR2 expects this when using inverted depth // Swap the near and far clip plane distances as FSR2 expects this when using inverted depth
@ -359,6 +390,11 @@ namespace FidelityFX
_dispatchCommandBuffer.ReleaseTemporaryRT(Fsr2ShaderIDs.UavAutoReactive); _dispatchCommandBuffer.ReleaseTemporaryRT(Fsr2ShaderIDs.UavAutoReactive);
} }
if (autoGenerateTransparencyAndComposition)
{
_dispatchCommandBuffer.ReleaseTemporaryRT(Fsr2ShaderIDs.SrvOpaqueOnly);
}
Graphics.ExecuteCommandBuffer(_dispatchCommandBuffer); Graphics.ExecuteCommandBuffer(_dispatchCommandBuffer);
// Shut up the Unity warning about not writing to the destination texture // Shut up the Unity warning about not writing to the destination texture

Loading…
Cancel
Save