using System; using System.Collections; using System.Collections.Generic; using System.Linq; using FidelityFX; using UnityEngine; using UnityEngine.Rendering; /// /// This class is responsible for hooking into various Unity events and translating them to the FSR2 subsystem. /// This includes creation and destruction of the FSR2 context, as well as dispatching commands at the right time. /// This class also exposes various FSR2 parameters to the Unity inspector. /// public class Fsr2Controller : MonoBehaviour { [SerializeField] private bool performSharpenPass = true; [SerializeField, Range(0, 1)] private float sharpness = 0.8f; [HideInInspector] public Camera gameCamera; [HideInInspector] public Camera outputCamera; [HideInInspector] public float renderScale; private Fsr2Context _context; private readonly Fsr2.DispatchDescription _dispatchDescription = new Fsr2.DispatchDescription(); private RenderTexture _upscaleRT; private RenderTexture _outputRT; private Texture2D _exposure; private Material _testMaterial; private Material TestMaterial { get { if (_testMaterial == null) { var testShader = Fsr2.GlobalCallbacks.LoadShader("Shaders/FSRTest"); _testMaterial = new Material(testShader); } return _testMaterial; } } private void OnEnable() { RenderPipelineManager.endContextRendering += OnEndContextRendering; _context = Fsr2.CreateContext(); _upscaleRT = new RenderTexture(Screen.width, Screen.height, 24, RenderTextureFormat.ARGBHalf); _upscaleRT.Create(); _outputRT = new RenderTexture(Screen.width, Screen.height, 24, RenderTextureFormat.ARGBHalf); _outputRT.enableRandomWrite = true; _outputRT.Create(); _exposure = new Texture2D(1, 1); _exposure.name = "FSR2 Exposure"; _exposure.SetPixel(0, 0, Color.white); _exposure.Apply(); } private void OnDisable() { if (_exposure != null) { Destroy(_exposure); _exposure = null; } if (_outputRT != null) { _outputRT.Release(); _outputRT = null; } if (_upscaleRT != null) { _upscaleRT.Release(); _upscaleRT = null; } if (_context != null) { _context.Destroy(); _context = null; } RenderPipelineManager.endContextRendering -= OnEndContextRendering; } // For scriptable rendering pipeline private void OnEndContextRendering(ScriptableRenderContext context, List cameras) { Debug.Log($"OnEndContentRendering, cameras = {string.Join(", ", cameras.Select(c => c.name))}"); } // For legacy built-in render pipeline private void OnRenderImage(RenderTexture src, RenderTexture dest) { // Do a dumb upscale first Graphics.Blit(gameCamera.targetTexture, _upscaleRT, TestMaterial); _dispatchDescription.Input = _upscaleRT; _dispatchDescription.Output = _outputRT; _dispatchDescription.Exposure = _exposure; _dispatchDescription.PreExposure = 1.0f; _dispatchDescription.EnableSharpening = performSharpenPass; _dispatchDescription.Sharpness = sharpness; _dispatchDescription.MotionVectorScale.x = gameCamera.pixelWidth; _dispatchDescription.MotionVectorScale.y = gameCamera.pixelHeight; _dispatchDescription.FrameTimeDelta = Time.unscaledDeltaTime; _dispatchDescription.CameraNear = gameCamera.nearClipPlane; _dispatchDescription.CameraFar = gameCamera.farClipPlane; _dispatchDescription.CameraFovAngleVertical = gameCamera.fieldOfView * Mathf.Deg2Rad; _context.Dispatch(_dispatchDescription); // Output sharpened image to screen Graphics.Blit(_outputRT, dest); } }