using System; using System.Collections; using System.Collections.Generic; using UnityEngine; [RequireComponent(typeof(Camera))] public class SubsampleTest : MonoBehaviour { private Camera gameCamera; private GameObject outputCameraObject; private Camera outputCamera; [SerializeField] private float renderScale = 0.5f; [SerializeField] private bool enableJitter; private FSR2Thing fsr2Thing; private void OnEnable() { gameCamera = GetComponent(); if (outputCameraObject == null) { outputCameraObject = new GameObject("FSR2 Camera Object"); outputCameraObject.transform.SetParent(transform); outputCameraObject.transform.SetPositionAndRotation(Vector3.zero, Quaternion.identity); //outputCameraObject.transform.hideFlags = HideFlags.HideInHierarchy | HideFlags.HideInInspector; outputCamera = outputCameraObject.AddComponent(); outputCamera.eventMask = 0; fsr2Thing = outputCameraObject.AddComponent(); fsr2Thing.gameCamera = gameCamera; fsr2Thing.outputCamera = outputCamera; fsr2Thing.renderScale = renderScale; fsr2Thing.enabled = true; //outputCamera.CopyFrom(gameCamera); outputCamera.cullingMask = 0; outputCamera.clearFlags = CameraClearFlags.Nothing; } else { fsr2Thing.enabled = true; } gameCamera.targetTexture = new RenderTexture( (int)(Screen.width * renderScale), (int)(Screen.height * renderScale), 24, // Can we copy depth value from original camera? RenderTextureFormat.ARGBHalf); // Can we copy format from original camera? Or renderer quality settings? gameCamera.depthTextureMode = DepthTextureMode.Depth | DepthTextureMode.DepthNormals | DepthTextureMode.MotionVectors; gameCamera.targetTexture.name = "FSR2 Source Texture"; gameCamera.targetTexture.Create(); // 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 // TODO: add to Callbacks class/interface (ApplyMipmapBias) float biasOffset = GetMipmapBiasOffset(); foreach (var tex in Resources.FindObjectsOfTypeAll()) { tex.mipMapBias += biasOffset; } } private void OnDisable() { float biasOffset = GetMipmapBiasOffset(); foreach (var tex in Resources.FindObjectsOfTypeAll()) { tex.mipMapBias -= biasOffset; } gameCamera.targetTexture.Release(); gameCamera.targetTexture = null; fsr2Thing.enabled = false; outputCamera.enabled = false; } public float GetMipmapBiasOffset() { return Mathf.Log(renderScale) - 1.0f; } private void Update() { outputCamera.enabled = gameCamera.enabled; //outputCamera.CopyFrom(gameCamera); outputCamera.clearFlags = CameraClearFlags.Color; } private Rect tempRect; private void OnPreRender() { gameCamera.aspect = (Screen.width * gameCamera.rect.width) / (Screen.height * gameCamera.rect.height); tempRect = gameCamera.rect; gameCamera.rect = new Rect(0, 0, 1, 1); if (enableJitter) { // Perform custom jittering of the camera's projection matrix according to FSR2's instructions // Unity already does jittering behind the scenes for certain post-effects, so can we perhaps integrate with that? int jitterPhaseCount = GetJitterPhaseCount(gameCamera.targetTexture.width, Screen.width); GetJitterOffset(out float jitterX, out float jitterY, Time.frameCount, jitterPhaseCount); jitterX = 2.0f * jitterX / gameCamera.targetTexture.width; jitterY = -2.0f * jitterY / gameCamera.targetTexture.height; var jitterTranslationMatrix = Matrix4x4.Translate(new Vector3(jitterX, jitterY, 0)); gameCamera.projectionMatrix = jitterTranslationMatrix * gameCamera.nonJitteredProjectionMatrix; } } private void OnPostRender() { gameCamera.rect = tempRect; gameCamera.ResetProjectionMatrix(); } private static int GetJitterPhaseCount(int renderWidth, int displayWidth) { const float basePhaseCount = 8.0f; int jitterPhaseCount = (int)(basePhaseCount * Mathf.Pow((float)displayWidth / renderWidth, 2.0f)); return jitterPhaseCount; } private static void GetJitterOffset(out float outX, out float outY, int index, int phaseCount) { outX = Halton((index % phaseCount) + 1, 2) - 0.5f; outY = Halton((index % phaseCount) + 1, 3) - 0.5f; } // Calculate halton number for index and base. private static float Halton(int index, int @base) { float f = 1.0f, result = 0.0f; for (int currentIndex = index; currentIndex > 0;) { f /= @base; result += f * (currentIndex % @base); currentIndex = (int)Mathf.Floor((float)currentIndex / @base); } return result; } }