Files
2026-02-21 16:45:37 +08:00

317 lines
8.5 KiB
C#

using System;
using UnityEngine;
namespace UnityStandardAssets.CinematicEffects
{
[ExecuteInEditMode]
[RequireComponent(typeof(Camera))]
[AddComponentMenu("Image Effects/Cinematic/Temporal Anti-aliasing")]
public class TemporalAntiAliasing : MonoBehaviour
{
public enum Sequence
{
Halton = 0
}
[Serializable]
public struct JitterSettings
{
[Tooltip("The sequence used to generate the points used as jitter offsets.")]
public Sequence sequence;
[Tooltip("The diameter (in texels) inside which jitter samples are spread. Smaller values result in crisper but more aliased output, while larger values result in more stable but blurrier output.")]
[Range(0.1f, 3f)]
public float spread;
[Tooltip("Number of temporal samples. A larger value results in a smoother image but takes longer to converge; whereas a smaller value converges fast but allows for less subpixel information.")]
[Range(4f, 64f)]
public int sampleCount;
}
[Serializable]
public struct SharpenFilterSettings
{
[Tooltip("Controls the amount of sharpening applied to the color buffer.")]
[Range(0f, 3f)]
public float amount;
}
[Serializable]
public struct BlendSettings
{
[Tooltip("The blend coefficient for a stationary fragment. Controls the percentage of history sample blended into the final color.")]
[Range(0f, 1f)]
public float stationary;
[Tooltip("The blend coefficient for a fragment with significant motion. Controls the percentage of history sample blended into the final color.")]
[Range(0f, 1f)]
public float moving;
[Tooltip("Amount of motion amplification in percentage. A higher value will make the final blend more sensitive to smaller motion, but might result in more aliased output; while a smaller value might desensitivize the algorithm resulting in a blurry output.")]
[Range(30f, 100f)]
public float motionAmplification;
}
[Serializable]
public struct DebugSettings
{
[Tooltip("Forces the game view to update automatically while not in play mode.")]
public bool forceRepaint;
}
[Serializable]
public class Settings
{
[AttributeUsage(AttributeTargets.Field)]
public class LayoutAttribute : PropertyAttribute
{
}
[Layout]
public JitterSettings jitterSettings;
[Layout]
public SharpenFilterSettings sharpenFilterSettings;
[Layout]
public BlendSettings blendSettings;
[Layout]
public DebugSettings debugSettings;
private static readonly Settings m_Default = new Settings
{
jitterSettings = new JitterSettings
{
sequence = Sequence.Halton,
spread = 1f,
sampleCount = 8
},
sharpenFilterSettings = new SharpenFilterSettings
{
amount = 0.25f
},
blendSettings = new BlendSettings
{
stationary = 0.98f,
moving = 0.8f,
motionAmplification = 60f
},
debugSettings = new DebugSettings
{
forceRepaint = false
}
};
public static Settings defaultSettings
{
get
{
return m_Default;
}
}
}
[SerializeField]
public Settings settings = Settings.defaultSettings;
private Shader m_Shader;
private Material m_Material;
private Camera m_Camera;
private RenderTexture m_History;
private int m_SampleIndex;
public Shader shader
{
get
{
if (m_Shader == null)
{
m_Shader = Shader.Find("Hidden/Temporal Anti-aliasing");
}
return m_Shader;
}
}
public Material material
{
get
{
if (m_Material == null)
{
if (shader == null || !shader.isSupported)
{
return null;
}
m_Material = new Material(shader);
}
return m_Material;
}
}
public Camera camera_
{
get
{
if (m_Camera == null)
{
m_Camera = GetComponent<Camera>();
}
return m_Camera;
}
}
private void RenderFullScreenQuad()
{
GL.PushMatrix();
GL.LoadOrtho();
material.SetPass(0);
GL.Begin(7);
GL.TexCoord2(0f, 0f);
GL.Vertex3(0f, 0f, 0.1f);
GL.TexCoord2(1f, 0f);
GL.Vertex3(1f, 0f, 0.1f);
GL.TexCoord2(1f, 1f);
GL.Vertex3(1f, 1f, 0.1f);
GL.TexCoord2(0f, 1f);
GL.Vertex3(0f, 1f, 0.1f);
GL.End();
GL.PopMatrix();
}
private float GetHaltonValue(int index, int radix)
{
float num = 0f;
float num2 = 1f / (float)radix;
while (index > 0)
{
num += (float)(index % radix) * num2;
index /= radix;
num2 /= (float)radix;
}
return num;
}
private Vector2 GenerateRandomOffset()
{
Vector2 result = new Vector2(GetHaltonValue(m_SampleIndex & 0x3FF, 2), GetHaltonValue(m_SampleIndex & 0x3FF, 3));
if (++m_SampleIndex >= settings.jitterSettings.sampleCount)
{
m_SampleIndex = 0;
}
return result;
}
private Matrix4x4 GetPerspectiveProjectionMatrix(Vector2 offset)
{
float num = Mathf.Tan((float)Math.PI / 360f * camera_.fieldOfView);
float num2 = num * camera_.aspect;
offset.x *= num2 / (0.5f * (float)camera_.pixelWidth);
offset.y *= num / (0.5f * (float)camera_.pixelHeight);
float num3 = (offset.x - num2) * camera_.nearClipPlane;
float num4 = (offset.x + num2) * camera_.nearClipPlane;
float num5 = (offset.y + num) * camera_.nearClipPlane;
float num6 = (offset.y - num) * camera_.nearClipPlane;
Matrix4x4 result = default(Matrix4x4);
result[0, 0] = 2f * camera_.nearClipPlane / (num4 - num3);
result[0, 1] = 0f;
result[0, 2] = (num4 + num3) / (num4 - num3);
result[0, 3] = 0f;
result[1, 0] = 0f;
result[1, 1] = 2f * camera_.nearClipPlane / (num5 - num6);
result[1, 2] = (num5 + num6) / (num5 - num6);
result[1, 3] = 0f;
result[2, 0] = 0f;
result[2, 1] = 0f;
result[2, 2] = (0f - (camera_.farClipPlane + camera_.nearClipPlane)) / (camera_.farClipPlane - camera_.nearClipPlane);
result[2, 3] = (0f - 2f * camera_.farClipPlane * camera_.nearClipPlane) / (camera_.farClipPlane - camera_.nearClipPlane);
result[3, 0] = 0f;
result[3, 1] = 0f;
result[3, 2] = -1f;
result[3, 3] = 0f;
return result;
}
private void OnEnable()
{
camera_.depthTextureMode |= DepthTextureMode.Depth | DepthTextureMode.MotionVectors;
}
private void OnDisable()
{
if (m_History != null)
{
RenderTexture.ReleaseTemporary(m_History);
m_History = null;
}
camera_.depthTextureMode &= ~DepthTextureMode.MotionVectors;
m_SampleIndex = 0;
}
private void OnPreCull()
{
Vector2 vector = GenerateRandomOffset();
vector *= settings.jitterSettings.spread;
camera_.nonJitteredProjectionMatrix = camera_.projectionMatrix;
camera_.projectionMatrix = GetPerspectiveProjectionMatrix(vector);
vector.x /= camera_.pixelWidth;
vector.y /= camera_.pixelHeight;
material.SetVector("_Jitter", vector);
}
[ImageEffectOpaque]
private void OnRenderImage(RenderTexture source, RenderTexture destination)
{
if (camera_.orthographic)
{
Graphics.Blit(source, destination);
return;
}
if (m_History == null || m_History.width != source.width || m_History.height != source.height)
{
if ((bool)m_History)
{
RenderTexture.ReleaseTemporary(m_History);
}
m_History = RenderTexture.GetTemporary(source.width, source.height, 0, source.format, RenderTextureReadWrite.Default);
m_History.filterMode = FilterMode.Bilinear;
m_History.hideFlags = HideFlags.HideAndDontSave;
Graphics.Blit(source, m_History);
}
material.SetVector("_SharpenParameters", new Vector4(settings.sharpenFilterSettings.amount, 0f, 0f, 0f));
material.SetVector("_FinalBlendParameters", new Vector4(settings.blendSettings.stationary, settings.blendSettings.moving, 100f * settings.blendSettings.motionAmplification, 0f));
material.SetTexture("_MainTex", source);
material.SetTexture("_HistoryTex", m_History);
RenderTexture temporary = RenderTexture.GetTemporary(source.width, source.height, 0, source.format, RenderTextureReadWrite.Default);
temporary.filterMode = FilterMode.Bilinear;
RenderTexture renderTexture = destination;
bool flag = false;
if (destination == null)
{
renderTexture = RenderTexture.GetTemporary(source.width, source.height, 0, source.format, RenderTextureReadWrite.Default);
renderTexture.filterMode = FilterMode.Bilinear;
flag = true;
}
Graphics.SetRenderTarget(new RenderBuffer[2] { renderTexture.colorBuffer, temporary.colorBuffer }, renderTexture.depthBuffer);
RenderFullScreenQuad();
RenderTexture.ReleaseTemporary(m_History);
m_History = temporary;
if (flag)
{
Graphics.Blit(renderTexture, destination);
RenderTexture.ReleaseTemporary(renderTexture);
}
RenderTexture.active = destination;
}
public void OnPostRender()
{
camera_.ResetProjectionMatrix();
}
}
}