317 lines
8.5 KiB
C#
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();
|
|
}
|
|
}
|
|
}
|