You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
191 lines
7.6 KiB
191 lines
7.6 KiB
#if UNITY_POST_PROCESSING_STACK_V2
|
|
using System;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
using UnityEngine.Rendering.PostProcessing;
|
|
|
|
namespace FidelityFX
|
|
{
|
|
[Serializable]
|
|
[PostProcess(typeof(Fsr2PostProcessRenderer), PostProcessEvent.BeforeStack, "FidelityFX/FSR 2", false)]
|
|
public class Fsr2PostProcessEffect : PostProcessEffectSettings
|
|
{
|
|
public Fsr2QualityModeParameter qualityMode = new Fsr2QualityModeParameter() { value = Fsr2.QualityMode.Quality };
|
|
|
|
public BoolParameter performSharpenPass = new BoolParameter() { value = true };
|
|
[Range(0, 1)] public FloatParameter sharpness = new FloatParameter() { value = 0.8f };
|
|
|
|
[Tooltip("Allow the use of half precision compute operations, potentially improving performance")]
|
|
public BoolParameter enableFP16 = new BoolParameter() { value = false };
|
|
|
|
[Header("Exposure")]
|
|
public BoolParameter enableAutoExposure = new BoolParameter() { value = true };
|
|
public FloatParameter preExposure = new FloatParameter() { value = 1.0f };
|
|
|
|
[Header("Reactivity, Transparency & Composition")]
|
|
public BoolParameter autoGenerateReactiveMask = new BoolParameter() { value = true };
|
|
|
|
public override bool IsEnabledAndSupported(PostProcessRenderContext context)
|
|
{
|
|
return base.IsEnabledAndSupported(context) && SystemInfo.supportsComputeShaders;
|
|
}
|
|
}
|
|
|
|
[Serializable]
|
|
public class Fsr2QualityModeParameter : ParameterOverride<Fsr2.QualityMode>
|
|
{
|
|
}
|
|
|
|
public class Fsr2PostProcessRenderer : PostProcessEffectRenderer<Fsr2PostProcessEffect>
|
|
{
|
|
private Fsr2Context _fsrContext;
|
|
private Fsr2PostProcessHelper _helper;
|
|
|
|
private Vector2Int _displaySize;
|
|
private Vector2Int _renderSize;
|
|
|
|
private Fsr2.QualityMode _prevQualityMode;
|
|
|
|
public override void Init()
|
|
{
|
|
base.Init();
|
|
|
|
Debug.Log($"Initializing FSR2 post-process effect, quality = {settings.qualityMode.value}");
|
|
}
|
|
|
|
public override void Release()
|
|
{
|
|
Debug.Log("Releasing FSR2 post-process effect");
|
|
|
|
base.Release();
|
|
}
|
|
|
|
public override DepthTextureMode GetCameraFlags()
|
|
{
|
|
return DepthTextureMode.Depth | DepthTextureMode.MotionVectors;
|
|
}
|
|
|
|
public override void Render(PostProcessRenderContext context)
|
|
{
|
|
var cmd = context.command;
|
|
|
|
if (!Application.isPlaying)
|
|
{
|
|
// We don't want this effect to start injecting scripts in edit mode, so just blit and skip the rest entirely
|
|
cmd.BlitFullscreenTriangle(context.source, context.destination);
|
|
return;
|
|
}
|
|
|
|
// Monitor for any resolution changes and recreate the FSR2 context if necessary
|
|
// We can't create an FSR2 context without info from the post-processing context, so delay the initial setup until here
|
|
if (_fsrContext == null || context.screenWidth != _displaySize.x || context.screenHeight != _displaySize.y || settings.qualityMode != _prevQualityMode)
|
|
{
|
|
DestroyFsrContext();
|
|
CreateFsrContext(context);
|
|
|
|
_prevQualityMode = settings.qualityMode;
|
|
}
|
|
|
|
// Ensure that the helper script exists and is enabled
|
|
if (_helper == null || !_helper.enabled)
|
|
{
|
|
if (_helper == null)
|
|
Inject(context);
|
|
|
|
_helper.enabled = settings.IsEnabledAndSupported(context);
|
|
|
|
// The injected script won't come into effect until the next frame, so just do a simple blit this frame
|
|
cmd.BlitFullscreenTriangle(context.source, context.destination);
|
|
return;
|
|
}
|
|
|
|
//Debug.Log("[FSR2] Render, where am I being called from?"); // In OnPreCull... OH
|
|
// TODO: executing in OnPreCull means we can do jittering in here, at least. Rect manipulation should still happen before PPV2 entirely.
|
|
ApplyJitter(context.camera);
|
|
|
|
cmd.BlitFullscreenTriangle(context.source, context.destination);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Inject ourselves into the camera's render loop at points where PPV2 normally wouldn't allow us.
|
|
/// This also sets up PPV2's own stack to use FSR2's upscaled output as its source.
|
|
/// </summary>
|
|
private void Inject(PostProcessRenderContext context)
|
|
{
|
|
var go = context.camera.gameObject;
|
|
_helper = go.AddComponent<Fsr2PostProcessHelper>();
|
|
|
|
_helper.Settings = settings;
|
|
// TODO: create output RT, set it as PPV2's post-transparency stack source
|
|
}
|
|
|
|
private void CreateFsrContext(PostProcessRenderContext context)
|
|
{
|
|
_displaySize = new Vector2Int(context.screenWidth, context.screenHeight);
|
|
Fsr2.GetRenderResolutionFromQualityMode(out var renderWidth, out var renderHeight, _displaySize.x, _displaySize.y, settings.qualityMode);
|
|
_renderSize = new Vector2Int(renderWidth, renderHeight);
|
|
|
|
Fsr2.InitializationFlags flags = 0;
|
|
if (context.camera.allowHDR) flags |= Fsr2.InitializationFlags.EnableHighDynamicRange;
|
|
if (settings.enableFP16) flags |= Fsr2.InitializationFlags.EnableFP16Usage;
|
|
if (settings.enableAutoExposure) flags |= Fsr2.InitializationFlags.EnableAutoExposure;
|
|
|
|
#if UNITY_EDITOR || DEVELOPMENT_BUILD
|
|
flags |= Fsr2.InitializationFlags.EnableDebugChecking;
|
|
#endif
|
|
|
|
_fsrContext = Fsr2.CreateContext(_displaySize, _renderSize, flags);
|
|
}
|
|
|
|
private void DestroyFsrContext()
|
|
{
|
|
if (_fsrContext != null)
|
|
{
|
|
_fsrContext.Destroy();
|
|
_fsrContext = null;
|
|
}
|
|
}
|
|
|
|
private void ApplyJitter(Camera camera)
|
|
{
|
|
// Perform custom jittering of the camera's projection matrix according to FSR2's recipe
|
|
int jitterPhaseCount = Fsr2.GetJitterPhaseCount(_renderSize.x, _displaySize.x);
|
|
Fsr2.GetJitterOffset(out float jitterX, out float jitterY, Time.frameCount, jitterPhaseCount);
|
|
|
|
jitterX = 2.0f * jitterX / _renderSize.x;
|
|
jitterY = 2.0f * jitterY / _renderSize.y;
|
|
|
|
var jitterTranslationMatrix = Matrix4x4.Translate(new Vector3(jitterX, jitterY, 0));
|
|
camera.nonJitteredProjectionMatrix = camera.projectionMatrix;
|
|
camera.projectionMatrix = jitterTranslationMatrix * camera.nonJitteredProjectionMatrix;
|
|
camera.useJitteredProjectionMatrixForTransparentRendering = true;
|
|
}
|
|
}
|
|
|
|
internal class Fsr2PostProcessHelper : MonoBehaviour
|
|
{
|
|
internal Fsr2PostProcessEffect Settings;
|
|
|
|
private Camera _camera;
|
|
|
|
private void Awake()
|
|
{
|
|
_camera = GetComponent<Camera>();
|
|
// TODO: inject opaque-only command buffer & anything else?
|
|
}
|
|
|
|
private void OnPreCull() // TODO: may need to do this in LateUpdate instead? So we execute before PPV2's OnPreCull
|
|
{
|
|
// TODO: check if FSR2 is still enabled; if not: reset PPV2 source texture & disable self
|
|
// TODO: fiddle with the camera parameters, rect, jitter, etc
|
|
// Debug.Log("[FSR2] OnPreCull");
|
|
}
|
|
|
|
private void OnPostRender()
|
|
{
|
|
_camera.ResetProjectionMatrix();
|
|
}
|
|
}
|
|
}
|
|
#endif // UNITY_POST_PROCESSING_STACK_V2
|