417 lines
18 KiB
C#
417 lines
18 KiB
C#
using System;
|
|
using System.Reflection;
|
|
using UnityEngine;
|
|
using UnityEngine.Rendering;
|
|
using UnityEngine.Rendering.Universal;
|
|
using UnityEngine.Experimental.Rendering;
|
|
using System.Collections.Generic;
|
|
using System.Runtime.InteropServices;
|
|
using FidelityFX;
|
|
|
|
namespace AEG.FSR
|
|
{
|
|
[RequireComponent(typeof(Camera))]
|
|
public class FSR3_URP : FSR3_BASE
|
|
{
|
|
//Rendertextures
|
|
private RTHandleSystem RTHandleS;
|
|
public RTHandle m_opaqueOnlyColorBuffer;
|
|
public RTHandle m_afterOpaqueOnlyColorBuffer;
|
|
public RTHandle m_reactiveMaskOutput;
|
|
//public RTHandle m_colorBuffer;
|
|
public RTHandle m_fsrOutput;
|
|
public bool m_autoHDR;
|
|
|
|
|
|
private List<FSRScriptableRenderFeature> fsrScriptableRenderFeature;
|
|
private bool containsRenderFeature = false;
|
|
|
|
private Matrix4x4 m_jitterMatrix;
|
|
private Matrix4x4 m_projectionMatrix;
|
|
|
|
//UniversalRenderPipelineAsset
|
|
private UniversalRenderPipelineAsset UniversalRenderPipelineAsset;
|
|
private UniversalAdditionalCameraData m_cameraData;
|
|
|
|
private GraphicsFormat m_graphicsFormat = GraphicsFormat.R16G16B16A16_SFloat;
|
|
public GraphicsFormat m_prevGraphicsFormat;
|
|
|
|
public readonly Fsr3.DispatchDescription m_dispatchDescription = new Fsr3.DispatchDescription();
|
|
public readonly Fsr3.GenerateReactiveDescription m_genReactiveDescription = new Fsr3.GenerateReactiveDescription();
|
|
private IFsr3Callbacks Callbacks { get; set; } = new Fsr3CallbacksBase();
|
|
public Fsr3Context m_context;
|
|
|
|
public bool m_cameraStacking = false;
|
|
public Camera m_topCamera;
|
|
private int m_prevCameraStackCount;
|
|
private bool m_isBaseCamera;
|
|
private List<FSR3_URP> m_prevCameraStack = new List<FSR3_URP>();
|
|
private FSR_Quality m_prevStackQuality = (FSR_Quality)(-1);
|
|
|
|
protected override void InitializeFSR() {
|
|
base.InitializeFSR();
|
|
m_mainCamera.depthTextureMode = DepthTextureMode.Depth | DepthTextureMode.MotionVectors;
|
|
|
|
SetupResolution();
|
|
|
|
if(!m_fsrInitialized) {
|
|
RenderPipelineManager.beginCameraRendering += PreRenderCamera;
|
|
RenderPipelineManager.endCameraRendering += PostRenderCamera;
|
|
}
|
|
|
|
if(m_cameraData == null) {
|
|
m_cameraData = m_mainCamera.GetUniversalAdditionalCameraData();
|
|
if(m_cameraData != null) {
|
|
if(m_cameraData.renderType == CameraRenderType.Base) {
|
|
m_isBaseCamera = true;
|
|
// delete by james
|
|
//SetupCameraStacking();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Sets up the buffers, initializes the fsr context, and sets up the command buffer
|
|
/// Must be recalled whenever the display resolution changes
|
|
/// </summary>
|
|
private void SetupCommandBuffer() {
|
|
if(m_fsrOutput != null) {
|
|
m_fsrOutput.Release();
|
|
if(m_opaqueOnlyColorBuffer != null) {
|
|
m_opaqueOnlyColorBuffer.Release();
|
|
m_afterOpaqueOnlyColorBuffer.Release();
|
|
m_reactiveMaskOutput.Release();
|
|
}
|
|
|
|
if(m_genReactiveDescription.ColorOpaqueOnly != null) {
|
|
m_genReactiveDescription.ColorOpaqueOnly = null;
|
|
m_genReactiveDescription.ColorPreUpscale = null;
|
|
m_genReactiveDescription.OutReactive = null;
|
|
m_dispatchDescription.Reactive = null;
|
|
}
|
|
}
|
|
|
|
if(fsrScriptableRenderFeature != null) {
|
|
for(int i = 0; i < fsrScriptableRenderFeature.Count; i++) {
|
|
fsrScriptableRenderFeature[i].OnDispose();
|
|
}
|
|
} else {
|
|
containsRenderFeature = GetRenderFeature();
|
|
}
|
|
SetDynamicResolution(m_scaleFactor);
|
|
|
|
m_renderWidth = (int)(m_mainCamera.pixelWidth / m_scaleFactor);
|
|
m_renderHeight = (int)(m_mainCamera.pixelHeight / m_scaleFactor);
|
|
|
|
m_fsrOutput = RTHandleS.Alloc(m_mainCamera.pixelWidth, m_mainCamera.pixelHeight, enableRandomWrite: true, colorFormat: m_graphicsFormat, msaaSamples: MSAASamples.None, name: "FSR OUTPUT");
|
|
|
|
m_dispatchDescription.InputResourceSize = new Vector2Int(m_renderWidth, m_renderHeight);
|
|
m_dispatchDescription.Output = m_fsrOutput;
|
|
|
|
if(generateReactiveMask) {
|
|
m_opaqueOnlyColorBuffer = RTHandleS.Alloc(m_renderWidth, m_renderHeight, enableRandomWrite: false, colorFormat: m_graphicsFormat, msaaSamples: MSAASamples.None, name: "OPAQUE ONLY BUFFER");
|
|
m_afterOpaqueOnlyColorBuffer = RTHandleS.Alloc(m_renderWidth, m_renderHeight, enableRandomWrite: false, colorFormat: m_graphicsFormat, msaaSamples: MSAASamples.None, name: "AFTER OPAQUE ONLY BUFFER");
|
|
m_reactiveMaskOutput = RTHandleS.Alloc(m_renderWidth, m_renderHeight, enableRandomWrite: true, colorFormat: m_graphicsFormat, msaaSamples: MSAASamples.None, name: "FSR REACTIVE MASK OUTPUT");
|
|
|
|
m_genReactiveDescription.ColorOpaqueOnly = m_opaqueOnlyColorBuffer;
|
|
m_genReactiveDescription.ColorPreUpscale = m_afterOpaqueOnlyColorBuffer;
|
|
m_genReactiveDescription.OutReactive = m_reactiveMaskOutput;
|
|
m_dispatchDescription.Reactive = m_genReactiveDescription.OutReactive;
|
|
}
|
|
|
|
if(!containsRenderFeature) {
|
|
Debug.LogError("Current Universal Render Data is missing the 'FSR Scriptable Render Pass URP' Rendering Feature");
|
|
} else {
|
|
for(int i = 0; i < fsrScriptableRenderFeature.Count; i++) {
|
|
fsrScriptableRenderFeature[i].OnSetReference(this);
|
|
}
|
|
}
|
|
for(int i = 0; i < fsrScriptableRenderFeature.Count; i++) {
|
|
fsrScriptableRenderFeature[i].IsEnabled = true;
|
|
}
|
|
}
|
|
|
|
|
|
private bool GetRenderFeature() {
|
|
fsrScriptableRenderFeature = new List<FSRScriptableRenderFeature>();
|
|
|
|
UniversalRenderPipelineAsset = GraphicsSettings.currentRenderPipeline as UniversalRenderPipelineAsset;
|
|
bool fsrScriptableRenderFeatureFound = false;
|
|
if(UniversalRenderPipelineAsset != null) {
|
|
UniversalRenderPipelineAsset.upscalingFilter = UpscalingFilterSelection.Linear;
|
|
UniversalRenderPipelineAsset.msaaSampleCount = (int)MsaaQuality.Disabled;
|
|
|
|
var type = UniversalRenderPipelineAsset.GetType();
|
|
var propertyInfo = type.GetField("m_RendererDataList", BindingFlags.Instance | BindingFlags.NonPublic);
|
|
|
|
if(propertyInfo != null) {
|
|
var scriptableRenderData = (ScriptableRendererData[])propertyInfo.GetValue(UniversalRenderPipelineAsset);
|
|
|
|
|
|
|
|
if(scriptableRenderData != null && scriptableRenderData.Length > 0) {
|
|
foreach(var renderData in scriptableRenderData) {
|
|
|
|
foreach(var rendererFeature in renderData.rendererFeatures) {
|
|
|
|
FSRScriptableRenderFeature _renderFeature = rendererFeature as FSRScriptableRenderFeature;
|
|
if(_renderFeature != null) {
|
|
fsrScriptableRenderFeature.Add(rendererFeature as FSRScriptableRenderFeature);
|
|
fsrScriptableRenderFeatureFound = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
Debug.LogError("FSR 2: Can't find UniversalRenderPipelineAsset");
|
|
}
|
|
|
|
return fsrScriptableRenderFeatureFound;
|
|
}
|
|
|
|
void PreRenderCamera(ScriptableRenderContext context, Camera cameras) {
|
|
|
|
if(cameras != m_mainCamera) {
|
|
return;
|
|
}
|
|
|
|
// Set up the parameters to auto-generate a reactive mask
|
|
if(generateReactiveMask) {
|
|
m_genReactiveDescription.RenderSize = new Vector2Int(m_renderWidth, m_renderHeight);
|
|
m_genReactiveDescription.Scale = autoReactiveScale;
|
|
m_genReactiveDescription.CutoffThreshold = autoTcThreshold;
|
|
m_genReactiveDescription.BinaryValue = autoReactiveBinaryValue;
|
|
|
|
m_genReactiveDescription.Flags = reactiveFlags;
|
|
}
|
|
|
|
m_dispatchDescription.Exposure = null;
|
|
m_dispatchDescription.PreExposure = 1;
|
|
m_dispatchDescription.EnableSharpening = sharpening;
|
|
m_dispatchDescription.Sharpness = sharpness;
|
|
m_dispatchDescription.MotionVectorScale.x = -m_renderWidth;
|
|
m_dispatchDescription.MotionVectorScale.y = -m_renderHeight;
|
|
m_dispatchDescription.RenderSize = new Vector2Int(m_renderWidth, m_renderHeight);
|
|
m_dispatchDescription.FrameTimeDelta = Time.deltaTime;
|
|
m_dispatchDescription.CameraNear = m_mainCamera.nearClipPlane;
|
|
m_dispatchDescription.CameraFar = m_mainCamera.farClipPlane;
|
|
m_dispatchDescription.CameraFovAngleVertical = m_mainCamera.fieldOfView * Mathf.Deg2Rad;
|
|
m_dispatchDescription.ViewSpaceToMetersFactor = 1.0f;
|
|
m_dispatchDescription.Reset = m_resetCamera;
|
|
m_resetCamera = false;
|
|
|
|
if(SystemInfo.usesReversedZBuffer) {
|
|
// Swap the near and far clip plane distances as FSR2 expects this when using inverted depth
|
|
(m_dispatchDescription.CameraNear, m_dispatchDescription.CameraFar) = (m_dispatchDescription.CameraFar, m_dispatchDescription.CameraNear);
|
|
}
|
|
|
|
JitterCameraMatrix();
|
|
|
|
if(UniversalRenderPipelineAsset != GraphicsSettings.currentRenderPipeline as UniversalRenderPipelineAsset) {
|
|
for(int i = 0; i < fsrScriptableRenderFeature.Count; i++) {
|
|
fsrScriptableRenderFeature[i].OnDispose();
|
|
}
|
|
fsrScriptableRenderFeature = null;
|
|
OnSetQuality(FSRQuality);
|
|
SetupCommandBuffer();
|
|
}
|
|
|
|
//Check if display resolution has changed
|
|
if(m_displayWidth != m_mainCamera.pixelWidth || m_displayHeight != m_mainCamera.pixelHeight || m_previousHDR != m_autoHDR || m_prevGraphicsFormat != m_graphicsFormat) {
|
|
SetupResolution();
|
|
}
|
|
|
|
if(m_previousScaleFactor != m_scaleFactor || m_previousReactiveMask != generateReactiveMask || m_previousTCMask != generateTCMask || m_previousRenderingPath != m_mainCamera.actualRenderingPath) {
|
|
SetupFrameBuffers();
|
|
}
|
|
|
|
//Camera Stacking
|
|
// delete by james
|
|
//if (m_isBaseCamera)
|
|
//{
|
|
// if (m_cameraData != null)
|
|
// {
|
|
// if (m_cameraData.cameraStack.Count > 0)
|
|
// {
|
|
// try
|
|
// {
|
|
// if (m_topCamera != m_cameraData.cameraStack[m_cameraData.cameraStack.Count - 1] || m_prevCameraStackCount != m_cameraData.cameraStack.Count || m_prevStackQuality != FSRQuality)
|
|
// {
|
|
// SetupCameraStacking();
|
|
// }
|
|
// }
|
|
// catch { }
|
|
// }
|
|
// }
|
|
//}
|
|
}
|
|
|
|
void PostRenderCamera(ScriptableRenderContext context, Camera cameras) {
|
|
if(cameras != m_mainCamera) {
|
|
return;
|
|
}
|
|
|
|
m_mainCamera.ResetProjectionMatrix();
|
|
}
|
|
|
|
/// <summary>
|
|
/// FSR TAA Jitter
|
|
/// </summary>
|
|
private void JitterCameraMatrix() {
|
|
if(fsrScriptableRenderFeature == null) {
|
|
return;
|
|
} else if(!fsrScriptableRenderFeature[0].IsEnabled) {
|
|
return;
|
|
}
|
|
|
|
|
|
int jitterPhaseCount = Fsr3.GetJitterPhaseCount(m_renderWidth, (int)(m_renderWidth * m_scaleFactor));
|
|
Fsr3.GetJitterOffset(out float jitterX, out float jitterY, Time.frameCount, jitterPhaseCount);
|
|
m_dispatchDescription.JitterOffset = new Vector2(jitterX, jitterY);
|
|
|
|
jitterX = 2.0f * jitterX / (float)m_renderWidth;
|
|
jitterY = 2.0f * jitterY / (float)m_renderHeight;
|
|
|
|
jitterX += UnityEngine.Random.Range(-0.0001f * antiGhosting, 0.0001f * antiGhosting);
|
|
jitterY += UnityEngine.Random.Range(-0.0001f * antiGhosting, 0.0001f * antiGhosting);
|
|
|
|
m_jitterMatrix = Matrix4x4.Translate(new Vector2(jitterX, jitterY));
|
|
m_projectionMatrix = m_mainCamera.projectionMatrix;
|
|
m_mainCamera.nonJitteredProjectionMatrix = m_projectionMatrix;
|
|
m_mainCamera.projectionMatrix = m_jitterMatrix * m_projectionMatrix;
|
|
m_mainCamera.useJitteredProjectionMatrixForTransparentRendering = true;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Handle Dynamic Scaling
|
|
/// </summary>
|
|
/// <param name="_value"></param>
|
|
public void SetDynamicResolution(float _value) {
|
|
if(UniversalRenderPipelineAsset != null) {
|
|
UniversalRenderPipelineAsset.renderScale = 1 / _value;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates new buffers and sends them to the plugin
|
|
/// </summary>
|
|
private void SetupFrameBuffers() {
|
|
m_previousScaleFactor = m_scaleFactor;
|
|
m_previousReactiveMask = generateReactiveMask;
|
|
|
|
SetupCommandBuffer();
|
|
|
|
m_previousRenderingPath = m_mainCamera.actualRenderingPath;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates new buffers, sends them to the plugin, and reintilized FSR to adjust the display size
|
|
/// </summary>
|
|
private void SetupResolution() {
|
|
m_displayWidth = m_mainCamera.pixelWidth;
|
|
m_displayHeight = m_mainCamera.pixelHeight;
|
|
m_previousHDR = m_autoHDR;
|
|
|
|
m_prevGraphicsFormat = m_graphicsFormat;
|
|
|
|
RTHandleS = new RTHandleSystem();
|
|
RTHandleS.Initialize(m_mainCamera.pixelWidth, m_mainCamera.pixelHeight);
|
|
|
|
Fsr3.InitializationFlags flags = Fsr3.InitializationFlags.EnableMotionVectorsJitterCancellation
|
|
| Fsr3.InitializationFlags.EnableHighDynamicRange
|
|
| Fsr3.InitializationFlags.EnableAutoExposure;
|
|
if(enableF16)
|
|
flags |= Fsr3.InitializationFlags.EnableFP16Usage;
|
|
|
|
if(m_context != null) {
|
|
m_context.Destroy();
|
|
m_context = null;
|
|
}
|
|
m_context = Fsr3.CreateContext(new Vector2Int(m_displayWidth, m_displayHeight), new Vector2Int((int)(m_displayWidth), (int)(m_displayHeight)), Callbacks, flags);
|
|
|
|
SetupFrameBuffers();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Automatically Setup camera stacking
|
|
/// </summary>
|
|
private void SetupCameraStacking() {
|
|
m_prevCameraStackCount = m_cameraData.cameraStack.Count;
|
|
if(m_cameraData.renderType == CameraRenderType.Base) {
|
|
m_isBaseCamera = true;
|
|
|
|
m_cameraStacking = m_cameraData.cameraStack.Count > 0;
|
|
if(m_cameraStacking) {
|
|
CleanupOverlayCameras();
|
|
m_prevStackQuality = FSRQuality;
|
|
|
|
m_topCamera = m_cameraData.cameraStack[m_cameraData.cameraStack.Count - 1];
|
|
|
|
for(int i = 0; i < m_cameraData.cameraStack.Count; i++) {
|
|
FSR3_URP stackedCamera = m_cameraData.cameraStack[i].gameObject.GetComponent<FSR3_URP>();
|
|
if(stackedCamera == null) {
|
|
stackedCamera = m_cameraData.cameraStack[i].gameObject.AddComponent<FSR3_URP>();
|
|
}
|
|
m_prevCameraStack.Add(m_cameraData.cameraStack[i].gameObject.GetComponent<FSR3_URP>());
|
|
|
|
//stackedCamera.hideFlags = HideFlags.HideInInspector;
|
|
stackedCamera.m_cameraStacking = true;
|
|
stackedCamera.m_topCamera = m_topCamera;
|
|
|
|
stackedCamera.OnSetQuality(FSRQuality);
|
|
|
|
stackedCamera.sharpening = sharpening;
|
|
stackedCamera.sharpness = sharpness;
|
|
stackedCamera.generateReactiveMask = generateReactiveMask;
|
|
stackedCamera.autoReactiveScale = autoReactiveScale;
|
|
stackedCamera.autoReactiveThreshold = autoReactiveThreshold;
|
|
stackedCamera.autoReactiveBinaryValue = autoReactiveBinaryValue;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private void CleanupOverlayCameras() {
|
|
for(int i = 0; i < m_prevCameraStack.Count; i++) {
|
|
if(!m_prevCameraStack[i].m_isBaseCamera)
|
|
DestroyImmediate(m_prevCameraStack[i]);
|
|
}
|
|
m_prevCameraStack = new List<FSR3_URP>();
|
|
}
|
|
|
|
protected override void DisableFSR() {
|
|
base.DisableFSR();
|
|
|
|
RenderPipelineManager.beginCameraRendering -= PreRenderCamera;
|
|
RenderPipelineManager.endCameraRendering -= PostRenderCamera;
|
|
|
|
SetDynamicResolution(1);
|
|
if(fsrScriptableRenderFeature != null) {
|
|
for(int i = 0; i < fsrScriptableRenderFeature.Count; i++) {
|
|
fsrScriptableRenderFeature[i].IsEnabled = false;
|
|
}
|
|
}
|
|
CleanupOverlayCameras();
|
|
m_previousScaleFactor = -1;
|
|
m_prevStackQuality = (FSR_Quality)(-1);
|
|
|
|
if(m_fsrOutput != null) {
|
|
m_fsrOutput.Release();
|
|
|
|
if(m_opaqueOnlyColorBuffer != null) {
|
|
m_opaqueOnlyColorBuffer.Release();
|
|
m_afterOpaqueOnlyColorBuffer.Release();
|
|
m_reactiveMaskOutput.Release();
|
|
}
|
|
}
|
|
|
|
if(m_context != null) {
|
|
m_context.Destroy();
|
|
m_context = null;
|
|
}
|
|
}
|
|
}
|
|
}
|