using System.Collections; using FidelityFX; using UnityEngine; using UnityEngine.Rendering; [RequireComponent(typeof(Camera))] public class SubsampleTest : MonoBehaviour // TODO: rename this to Fsr2Controller { private Camera _renderCamera; private GameObject _displayCameraObject; private Camera _displayCamera; [SerializeField] private Fsr2.QualityMode qualityMode; private Fsr2Controller _fsr2Controller; private float _renderScale; private Fsr2.QualityMode _prevQualityMode; private Vector2Int _prevScreenSize; private CommandBuffer _opaqueOnlyCommandBuffer; private CommandBuffer _reactiveCommandBuffer; private void OnEnable() { _renderScale = 1.0f / Fsr2.GetUpscaleRatioFromQualityMode(qualityMode); _renderCamera = GetComponent(); if (_displayCameraObject == null) { _displayCameraObject = new GameObject("FSR2 Camera Object"); _displayCameraObject.transform.SetParent(transform); _displayCameraObject.transform.SetPositionAndRotation(Vector3.zero, Quaternion.identity); //outputCameraObject.transform.hideFlags = HideFlags.HideInHierarchy | HideFlags.HideInInspector; // Create a camera that does nothing except output the upscaled image _displayCamera = _displayCameraObject.AddComponent(); _displayCamera.backgroundColor = Color.clear; _displayCamera.clearFlags = CameraClearFlags.Nothing; _displayCamera.eventMask = 0; _displayCamera.cullingMask = 0; _displayCamera.useOcclusionCulling = false; _displayCamera.orthographic = true; _displayCamera.allowMSAA = false; _displayCamera.renderingPath = RenderingPath.Forward; _fsr2Controller = _displayCameraObject.AddComponent(); } _fsr2Controller.renderCamera = _renderCamera; _fsr2Controller.renderScale = _renderScale; _fsr2Controller.enabled = true; Fsr2.GetRenderResolutionFromQualityMode(out var renderWidth, out var renderHeight, Screen.width, Screen.height, qualityMode); // TODO: check if the camera doesn't already have a target texture _renderCamera.targetTexture = new RenderTexture( renderWidth, renderHeight, 24, // Can we copy depth value from original camera? RenderTextureFormat.ARGBHalf); // Can we copy format from original camera? Or renderer quality settings? _renderCamera.depthTextureMode |= DepthTextureMode.Depth | DepthTextureMode.MotionVectors; _renderCamera.targetTexture.name = "FSR2 Input Texture"; _renderCamera.targetTexture.Create(); _opaqueOnlyCommandBuffer = new CommandBuffer { name = "FSR2 Opaque Input" }; // TODO: may need to copy the opaque-only render buffer to a temp RT here, in which case we'll need an additional CommandBuffer to release the temp RT again _opaqueOnlyCommandBuffer.SetGlobalTexture(Fsr2Pipeline.SrvOpaqueOnly, BuiltinRenderTextureType.CameraTarget, RenderTextureSubElement.Color); _renderCamera.AddCommandBuffer(CameraEvent.BeforeImageEffectsOpaque, _opaqueOnlyCommandBuffer); _reactiveCommandBuffer = new CommandBuffer { name = "FSR2 Inputs" }; _reactiveCommandBuffer.SetGlobalTexture(Fsr2Pipeline.SrvInputColor, BuiltinRenderTextureType.CameraTarget, RenderTextureSubElement.Color); _reactiveCommandBuffer.SetGlobalTexture(Fsr2Pipeline.SrvInputDepth, BuiltinRenderTextureType.CameraTarget, RenderTextureSubElement.Depth); _reactiveCommandBuffer.SetGlobalTexture(Fsr2Pipeline.SrvInputMotionVectors, BuiltinRenderTextureType.MotionVectors); _renderCamera.AddCommandBuffer(CameraEvent.BeforeImageEffects, _reactiveCommandBuffer); // Adjust texture mipmap LOD bias by log2(renderResolution/displayResolution) - 1.0; // May need to leave this to the game dev, as we don't know which textures do and don't belong to the 3D scene float biasOffset = Fsr2.GetMipmapBiasOffset(_renderScale); Fsr2.GlobalCallbacks.ApplyMipmapBias(biasOffset); _prevScreenSize = new Vector2Int(Screen.width, Screen.height); _prevQualityMode = qualityMode; } private void OnDisable() { float biasOffset = Fsr2.GetMipmapBiasOffset(_renderScale); Fsr2.GlobalCallbacks.ApplyMipmapBias(-biasOffset); _renderCamera.RemoveCommandBuffer(CameraEvent.BeforeImageEffectsOpaque, _opaqueOnlyCommandBuffer); _opaqueOnlyCommandBuffer.Release(); _opaqueOnlyCommandBuffer = null; _renderCamera.RemoveCommandBuffer(CameraEvent.BeforeImageEffects, _reactiveCommandBuffer); _reactiveCommandBuffer.Release(); _reactiveCommandBuffer = null; _renderCamera.targetTexture.Release(); _renderCamera.targetTexture = null; _fsr2Controller.enabled = false; _displayCamera.enabled = false; } private void Update() { _displayCamera.enabled = _renderCamera.enabled; if (Screen.width != _prevScreenSize.x || Screen.height != _prevScreenSize.y || qualityMode != _prevQualityMode) { // Force all resources to be destroyed and recreated with the new settings OnDisable(); OnEnable(); } } private Rect _tempRect; private void OnPreRender() { _tempRect = _renderCamera.rect; _renderCamera.aspect = (Screen.width * _tempRect.width) / (Screen.height * _tempRect.height); _renderCamera.rect = new Rect(0, 0, 1, 1); // Perform custom jittering of the camera's projection matrix according to FSR2's instructions int jitterPhaseCount = Fsr2.GetJitterPhaseCount(_renderCamera.targetTexture.width, Screen.width); Fsr2.GetJitterOffset(out float jitterX, out float jitterY, Time.frameCount, jitterPhaseCount); _fsr2Controller.SetJitterOffset(new Vector2(jitterX, jitterY)); var targetTexture = _renderCamera.targetTexture; jitterX = 2.0f * jitterX / targetTexture.width; jitterY = 2.0f * jitterY / targetTexture.height; var jitterTranslationMatrix = Matrix4x4.Translate(new Vector3(jitterX, jitterY, 0)); _renderCamera.projectionMatrix = jitterTranslationMatrix * _renderCamera.nonJitteredProjectionMatrix; } private void OnPostRender() { _renderCamera.rect = _tempRect; _renderCamera.ResetProjectionMatrix(); } }