You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
327 lines
11 KiB
C#
327 lines
11 KiB
C#
// Copyright (c) <2015> <Playdead>
|
|
// This file is subject to the MIT License as seen in the root of this folder structure (LICENSE.TXT)
|
|
// AUTHOR: Lasse Jon Fuglsang Pedersen <lasse@playdead.com>
|
|
|
|
#if UNITY_5_5_OR_NEWER
|
|
#define SUPPORT_STEREO
|
|
#endif
|
|
|
|
using UnityEngine;
|
|
namespace FogVolumePlaydeadTAA
|
|
{
|
|
public class FrustumJitter : MonoBehaviour
|
|
{
|
|
#region Static point data
|
|
private static float[] points_Still = new float[] {
|
|
0.5f, 0.5f,
|
|
};
|
|
private static float[] points_Uniform2 = new float[] {
|
|
-0.25f, -0.25f,//ll
|
|
0.25f, 0.25f,//ur
|
|
};
|
|
private static float[] points_Uniform4 = new float[] {
|
|
-0.25f, -0.25f,//ll
|
|
0.25f, -0.25f,//lr
|
|
0.25f, 0.25f,//ur
|
|
-0.25f, 0.25f,//ul
|
|
};
|
|
private static float[] points_Uniform4_Helix = new float[] {
|
|
-0.25f, -0.25f,//ll 3 1
|
|
0.25f, 0.25f,//ur \/|
|
|
0.25f, -0.25f,//lr /\|
|
|
-0.25f, 0.25f,//ul 0 2
|
|
};
|
|
private static float[] points_Uniform4_DoubleHelix = new float[] {
|
|
-0.25f, -0.25f,//ll 3 1
|
|
0.25f, 0.25f,//ur \/|
|
|
0.25f, -0.25f,//lr /\|
|
|
-0.25f, 0.25f,//ul 0 2
|
|
-0.25f, -0.25f,//ll 6--7
|
|
0.25f, -0.25f,//lr \
|
|
-0.25f, 0.25f,//ul \
|
|
0.25f, 0.25f,//ur 4--5
|
|
};
|
|
private static float[] points_SkewButterfly = new float[] {
|
|
-0.250f, -0.250f,
|
|
0.250f, 0.250f,
|
|
0.125f, -0.125f,
|
|
-0.125f, 0.125f,
|
|
};
|
|
private static float[] points_Rotated4 = new float[] {
|
|
-0.125f, -0.375f,//ll
|
|
0.375f, -0.125f,//lr
|
|
0.125f, 0.375f,//ur
|
|
-0.375f, 0.125f,//ul
|
|
};
|
|
private static float[] points_Rotated4_Helix = new float[] {
|
|
-0.125f, -0.375f,//ll 3 1
|
|
0.125f, 0.375f,//ur \/|
|
|
0.375f, -0.125f,//lr /\|
|
|
-0.375f, 0.125f,//ul 0 2
|
|
};
|
|
private static float[] points_Rotated4_Helix2 = new float[] {
|
|
-0.125f, -0.375f,//ll 2--1
|
|
0.125f, 0.375f,//ur \/
|
|
-0.375f, 0.125f,//ul /\
|
|
0.375f, -0.125f,//lr 0 3
|
|
};
|
|
private static float[] points_Poisson10 = new float[] {
|
|
-0.16795960f*0.25f, 0.65544910f*0.25f,
|
|
-0.69096030f*0.25f, 0.59015970f*0.25f,
|
|
0.49843820f*0.25f, 0.83099720f*0.25f,
|
|
0.17230150f*0.25f, -0.03882703f*0.25f,
|
|
-0.60772670f*0.25f, -0.06013587f*0.25f,
|
|
0.65606390f*0.25f, 0.24007600f*0.25f,
|
|
0.80348370f*0.25f, -0.48096900f*0.25f,
|
|
0.33436540f*0.25f, -0.73007030f*0.25f,
|
|
-0.47839520f*0.25f, -0.56005300f*0.25f,
|
|
-0.12388120f*0.25f, -0.96633990f*0.25f,
|
|
};
|
|
private static float[] points_Pentagram = new float[] {
|
|
0.000000f*0.5f, 0.525731f*0.5f,// head
|
|
-0.309017f*0.5f, -0.425325f*0.5f,// lleg
|
|
0.500000f*0.5f, 0.162460f*0.5f,// rarm
|
|
-0.500000f*0.5f, 0.162460f*0.5f,// larm
|
|
0.309017f*0.5f, -0.425325f*0.5f,// rleg
|
|
};
|
|
private static float[] points_Halton_2_3_x8 = new float[8 * 2];
|
|
private static float[] points_Halton_2_3_x16 = new float[16 * 2];
|
|
private static float[] points_Halton_2_3_x32 = new float[32 * 2];
|
|
private static float[] points_Halton_2_3_x256 = new float[256 * 2];
|
|
private static float[] points_MotionPerp2 = new float[] {
|
|
0.00f, -0.25f,
|
|
0.00f, 0.25f,
|
|
};
|
|
#endregion
|
|
|
|
#region Static point data, static initialization
|
|
private static void TransformPattern(float[] seq, float theta, float scale)
|
|
{
|
|
float cs = Mathf.Cos(theta);
|
|
float sn = Mathf.Sin(theta);
|
|
for (int i = 0, j = 1, n = seq.Length; i != n; i += 2, j += 2)
|
|
{
|
|
float x = scale * seq[i];
|
|
float y = scale * seq[j];
|
|
seq[i] = x * cs - y * sn;
|
|
seq[j] = x * sn + y * cs;
|
|
}
|
|
}
|
|
|
|
// http://en.wikipedia.org/wiki/Halton_sequence
|
|
private static float HaltonSeq(int prime, int index = 1/* NOT! zero-based */)
|
|
{
|
|
float r = 0.0f;
|
|
float f = 1.0f;
|
|
int i = index;
|
|
while (i > 0)
|
|
{
|
|
f /= prime;
|
|
r += f * (i % prime);
|
|
i = (int)Mathf.Floor(i / (float)prime);
|
|
}
|
|
return r;
|
|
}
|
|
|
|
private static void InitializeHalton_2_3(float[] seq)
|
|
{
|
|
for (int i = 0, n = seq.Length / 2; i != n; i++)
|
|
{
|
|
float u = HaltonSeq(2, i + 1) - 0.5f;
|
|
float v = HaltonSeq(3, i + 1) - 0.5f;
|
|
seq[2 * i + 0] = u;
|
|
seq[2 * i + 1] = v;
|
|
}
|
|
}
|
|
|
|
static FrustumJitter()
|
|
{
|
|
// points_Pentagram
|
|
Vector2 vh = new Vector2(points_Pentagram[0] - points_Pentagram[2], points_Pentagram[1] - points_Pentagram[3]);
|
|
Vector2 vu = new Vector2(0.0f, 1.0f);
|
|
TransformPattern(points_Pentagram, Mathf.Deg2Rad * (0.5f * Vector2.Angle(vu, vh)), 1.0f);
|
|
|
|
// points_Halton_2_3_xN
|
|
InitializeHalton_2_3(points_Halton_2_3_x8);
|
|
InitializeHalton_2_3(points_Halton_2_3_x16);
|
|
InitializeHalton_2_3(points_Halton_2_3_x32);
|
|
InitializeHalton_2_3(points_Halton_2_3_x256);
|
|
}
|
|
#endregion
|
|
|
|
#region Static point data accessors
|
|
public enum Pattern
|
|
{
|
|
Still,
|
|
Uniform2,
|
|
Uniform4,
|
|
Uniform4_Helix,
|
|
Uniform4_DoubleHelix,
|
|
SkewButterfly,
|
|
Rotated4,
|
|
Rotated4_Helix,
|
|
Rotated4_Helix2,
|
|
Poisson10,
|
|
Pentagram,
|
|
Halton_2_3_X8,
|
|
Halton_2_3_X16,
|
|
Halton_2_3_X32,
|
|
Halton_2_3_X256,
|
|
MotionPerp2,
|
|
};
|
|
|
|
private static float[] AccessPointData(Pattern pattern)
|
|
{
|
|
switch (pattern)
|
|
{
|
|
case Pattern.Still:
|
|
return points_Still;
|
|
case Pattern.Uniform2:
|
|
return points_Uniform2;
|
|
case Pattern.Uniform4:
|
|
return points_Uniform4;
|
|
case Pattern.Uniform4_Helix:
|
|
return points_Uniform4_Helix;
|
|
case Pattern.Uniform4_DoubleHelix:
|
|
return points_Uniform4_DoubleHelix;
|
|
case Pattern.SkewButterfly:
|
|
return points_SkewButterfly;
|
|
case Pattern.Rotated4:
|
|
return points_Rotated4;
|
|
case Pattern.Rotated4_Helix:
|
|
return points_Rotated4_Helix;
|
|
case Pattern.Rotated4_Helix2:
|
|
return points_Rotated4_Helix2;
|
|
case Pattern.Poisson10:
|
|
return points_Poisson10;
|
|
case Pattern.Pentagram:
|
|
return points_Pentagram;
|
|
case Pattern.Halton_2_3_X8:
|
|
return points_Halton_2_3_x8;
|
|
case Pattern.Halton_2_3_X16:
|
|
return points_Halton_2_3_x16;
|
|
case Pattern.Halton_2_3_X32:
|
|
return points_Halton_2_3_x32;
|
|
case Pattern.Halton_2_3_X256:
|
|
return points_Halton_2_3_x256;
|
|
case Pattern.MotionPerp2:
|
|
return points_MotionPerp2;
|
|
default:
|
|
Debug.LogError("missing point distribution");
|
|
return points_Halton_2_3_x16;
|
|
}
|
|
}
|
|
|
|
public static int AccessLength(Pattern pattern)
|
|
{
|
|
return AccessPointData(pattern).Length / 2;
|
|
}
|
|
|
|
public Vector2 Sample(Pattern pattern, int index)
|
|
{
|
|
float[] points = AccessPointData(pattern);
|
|
int n = points.Length / 2;
|
|
int i = index % n;
|
|
|
|
float x = patternScale * points[2 * i + 0];
|
|
float y = patternScale * points[2 * i + 1];
|
|
|
|
if (pattern != Pattern.MotionPerp2)
|
|
return new Vector2(x, y);
|
|
else
|
|
return new Vector2(x, y).Rotate(Vector2.right.SignedAngle(focalMotionDir));
|
|
}
|
|
#endregion
|
|
|
|
private Camera _camera;
|
|
|
|
private Vector3 focalMotionPos = Vector3.zero;
|
|
private Vector3 focalMotionDir = Vector3.right;
|
|
|
|
public Pattern pattern = Pattern.Halton_2_3_X16;
|
|
public float patternScale = .2f;
|
|
|
|
public Vector4 activeSample = Vector4.zero;// xy = current sample, zw = previous sample
|
|
public int activeIndex = -2;
|
|
|
|
void Reset()
|
|
{
|
|
_camera = GetComponent<Camera>();
|
|
}
|
|
|
|
void Clear()
|
|
{
|
|
_camera.ResetProjectionMatrix();
|
|
|
|
activeSample = Vector4.zero;
|
|
activeIndex = -2;
|
|
}
|
|
|
|
void Awake()
|
|
{
|
|
Reset();
|
|
Clear();
|
|
}
|
|
|
|
void OnPreCull()
|
|
{
|
|
// update motion dir
|
|
{
|
|
Vector3 oldWorld = focalMotionPos;
|
|
Vector3 newWorld = _camera.transform.TransformVector(_camera.nearClipPlane * Vector3.forward);
|
|
|
|
Vector3 oldPoint = (_camera.worldToCameraMatrix * oldWorld);
|
|
Vector3 newPoint = (_camera.worldToCameraMatrix * newWorld);
|
|
Vector3 newDelta = (newPoint - oldPoint).WithZ(0.0f);
|
|
|
|
var mag = newDelta.magnitude;
|
|
if (mag != 0.0f)
|
|
{
|
|
var dir = newDelta / mag;// yes, apparently this is necessary instead of newDelta.normalized... because facepalm
|
|
if (dir.sqrMagnitude != 0.0f)
|
|
{
|
|
focalMotionPos = newWorld;
|
|
focalMotionDir = Vector3.Slerp(focalMotionDir, dir, 0.2f);
|
|
//Debug.Log("CHANGE focalMotionDir " + focalMotionDir.ToString("G4") + " delta was " + newDelta.ToString("G4") + " delta.mag " + newDelta.magnitude);
|
|
}
|
|
}
|
|
}
|
|
|
|
// update jitter
|
|
#if SUPPORT_STEREO
|
|
if (_camera.stereoEnabled)
|
|
{
|
|
Clear();
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
if (activeIndex == -2)
|
|
{
|
|
activeSample = Vector4.zero;
|
|
activeIndex += 1;
|
|
|
|
_camera.projectionMatrix = _camera.GetProjectionMatrix();
|
|
}
|
|
else
|
|
{
|
|
activeIndex += 1;
|
|
activeIndex %= AccessLength(pattern);
|
|
|
|
Vector2 sample = Sample(pattern, activeIndex);
|
|
activeSample.z = activeSample.x;
|
|
activeSample.w = activeSample.y;
|
|
activeSample.x = sample.x;
|
|
activeSample.y = sample.y;
|
|
|
|
_camera.projectionMatrix = _camera.GetProjectionMatrix(sample.x, sample.y);
|
|
}
|
|
}
|
|
}
|
|
|
|
void OnDisable()
|
|
{
|
|
Clear();
|
|
}
|
|
}
|
|
} |