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.

295 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 VelocityBuffer : EffectBase
{
#if UNITY_PS4
private const RenderTextureFormat velocityFormat = RenderTextureFormat.RGHalf;
#else
private const RenderTextureFormat velocityFormat = RenderTextureFormat.RGFloat;
#endif
private Camera _camera;
private FrustumJitter _frustumJitter;
public Shader velocityShader;
private Material velocityMaterial;
private RenderTexture[] velocityBuffer;
private RenderTexture[] velocityNeighborMax;
private bool[] paramInitialized;
private Vector4[] paramProjectionExtents;
private Matrix4x4[] paramCurrV;
private Matrix4x4[] paramCurrVP;
private Matrix4x4[] paramPrevVP;
private Matrix4x4[] paramPrevVP_NoFlip;
private int activeEyeIndex = -1;
public RenderTexture activeVelocityBuffer { get { return (activeEyeIndex != -1) ? velocityBuffer[activeEyeIndex] : null; } }
public RenderTexture activeVelocityNeighborMax { get { return (activeEyeIndex != -1) ? velocityNeighborMax[activeEyeIndex] : null; } }
public enum NeighborMaxSupport
{
TileSize10,
TileSize20,
TileSize40,
};
public bool neighborMaxGen = false;
public NeighborMaxSupport neighborMaxSupport = NeighborMaxSupport.TileSize20;
// private float timeScaleNextFrame;
// public float timeScale { get; private set; }
#if UNITY_EDITOR
[Header("Stats")]
public int numResident = 0;
public int numRendered = 0;
public int numDrawCalls = 0;
#endif
void Reset()
{
_camera = GetComponent<Camera>();
_frustumJitter = GetComponent<FrustumJitter>();
}
void Clear()
{
EnsureArray(ref paramInitialized, 2);
paramInitialized[0] = false;
paramInitialized[1] = false;
}
void OnEnable()
{
//field not assigned when added by code from Fog Volume. So:
velocityShader = Shader.Find("Hidden/VelocityBuffer");
Reset();
}
void Awake()
{
Reset();
Clear();
}
//void Start()
//{
// timeScaleNextFrame = Time.timeScale;
//}
void OnPreRender()
{
// EnsureDepthTexture(_camera);
}
//void OnPostRender()
public void GenerateVelocityBuffer()
{
EnsureArray(ref velocityBuffer, 2);
EnsureArray(ref velocityNeighborMax, 2);
EnsureArray(ref paramInitialized, 2, initialValue: false);
EnsureArray(ref paramProjectionExtents, 2);
EnsureArray(ref paramCurrV, 2);
EnsureArray(ref paramCurrVP, 2);
EnsureArray(ref paramPrevVP, 2);
EnsureArray(ref paramPrevVP_NoFlip, 2);
EnsureMaterial(ref velocityMaterial, velocityShader);
if (velocityMaterial == null)
return;
//timeScale = timeScaleNextFrame;
//timeScaleNextFrame = (Time.timeScale == 0.0f) ? timeScaleNextFrame : Time.timeScale;
if (_camera == null) _camera = GetComponent<Camera>();
if (_frustumJitter == null) _frustumJitter = GetComponent<FrustumJitter>();
#if SUPPORT_STEREO
int eyeIndex = 0;
eyeIndex =(_camera.stereoActiveEye
== Camera.MonoOrStereoscopicEye.Right) ? 1 : 0;
#else
int eyeIndex = 0;
#endif
int bufferW = _camera.pixelWidth;
int bufferH = _camera.pixelHeight;
if (EnsureRenderTarget(ref velocityBuffer[eyeIndex], bufferW, bufferH, velocityFormat, FilterMode.Point, depthBits: 16))
Clear();
EnsureKeyword(velocityMaterial, "CAMERA_PERSPECTIVE", !_camera.orthographic);
EnsureKeyword(velocityMaterial, "CAMERA_ORTHOGRAPHIC", _camera.orthographic);
EnsureKeyword(velocityMaterial, "TILESIZE_10", neighborMaxSupport == NeighborMaxSupport.TileSize10);
EnsureKeyword(velocityMaterial, "TILESIZE_20", neighborMaxSupport == NeighborMaxSupport.TileSize20);
EnsureKeyword(velocityMaterial, "TILESIZE_40", neighborMaxSupport == NeighborMaxSupport.TileSize40);
#if SUPPORT_STEREO
if (_camera.stereoEnabled)
{
for (int i = 0; i != 2; i++)
{
Camera.StereoscopicEye eye = (Camera.StereoscopicEye)i;
Matrix4x4 currV = _camera.GetStereoViewMatrix(eye);
Matrix4x4 currP = GL.GetGPUProjectionMatrix(_camera.GetStereoProjectionMatrix(eye), true);
Matrix4x4 currP_NoFlip = GL.GetGPUProjectionMatrix(_camera.GetStereoProjectionMatrix(eye), false);
Matrix4x4 prevV = paramInitialized[i] ? paramCurrV[i] : currV;
paramInitialized[i] = true;
paramProjectionExtents[i] = _camera.GetProjectionExtents(eye);
paramCurrV[i] = currV;
paramCurrVP[i] = currP * currV;
paramPrevVP[i] = currP * prevV;
paramPrevVP_NoFlip[i] = currP_NoFlip * prevV;
}
}
else
#endif
{
Matrix4x4 currV = _camera.worldToCameraMatrix;
Matrix4x4 currP = GL.GetGPUProjectionMatrix(_camera.projectionMatrix, true);
Matrix4x4 currP_NoFlip = GL.GetGPUProjectionMatrix(_camera.projectionMatrix, false);
Matrix4x4 prevV = paramInitialized[0] ? paramCurrV[0] : currV;
paramInitialized[0] = true;
paramProjectionExtents[0] = _frustumJitter.enabled ? _camera.GetProjectionExtents(_frustumJitter.activeSample.x, _frustumJitter.activeSample.y) : _camera.GetProjectionExtents();
paramCurrV[0] = currV;
paramCurrVP[0] = currP * currV;
paramPrevVP[0] = currP * prevV;
paramPrevVP_NoFlip[0] = currP_NoFlip * prevV;
}
RenderTexture activeRT = RenderTexture.active;
RenderTexture.active = velocityBuffer[eyeIndex];
{
GL.Clear(true, true, Color.black);
const int kPrepass = 0;
// const int kVertices = 1;
//const int kVerticesSkinned = 2;
const int kTileMax = 3;
const int kNeighborMax = 4;
// 0: prepass
#if SUPPORT_STEREO
velocityMaterial.SetVectorArray("_ProjectionExtents", paramProjectionExtents);
velocityMaterial.SetMatrixArray("_CurrV", paramCurrV);
velocityMaterial.SetMatrixArray("_CurrVP", paramCurrVP);
velocityMaterial.SetMatrixArray("_PrevVP", paramPrevVP);
velocityMaterial.SetMatrixArray("_PrevVP_NoFlip", paramPrevVP_NoFlip);
#else
velocityMaterial.SetVector("_ProjectionExtents", paramProjectionExtents[0]);
velocityMaterial.SetMatrix("_CurrV", paramCurrV[0]);
velocityMaterial.SetMatrix("_CurrVP", paramCurrVP[0]);
velocityMaterial.SetMatrix("_PrevVP", paramPrevVP[0]);
velocityMaterial.SetMatrix("_PrevVP_NoFlip", paramPrevVP_NoFlip[0]);
#endif
velocityMaterial.SetPass(kPrepass);
DrawFullscreenQuad();
// 1 + 2: vertices + vertices skinned
// var obs = VelocityBufferTag.activeObjects;
//#if UNITY_EDITOR
// numResident = obs.Count;
// numRendered = 0;
// numDrawCalls = 0;
//#endif
// for (int i = 0, n = obs.Count; i != n; i++)
// {
// var ob = obs[i];
// if (ob != null && ob.rendering && ob.mesh != null)
// {
// velocityMaterial.SetMatrix("_CurrM", ob.localToWorldCurr);
// velocityMaterial.SetMatrix("_PrevM", ob.localToWorldPrev);
// velocityMaterial.SetPass(ob.meshSmrActive ? kVerticesSkinned : kVertices);
// for (int j = 0; j != ob.mesh.subMeshCount; j++)
// {
// Graphics.DrawMeshNow(ob.mesh, Matrix4x4.identity, j);
//#if UNITY_EDITOR
// numDrawCalls++;
//#endif
// }
//#if UNITY_EDITOR
// numRendered++;
//#endif
// }
// }
// 3 + 4: tilemax + neighbormax
if (neighborMaxGen)
{
int tileSize = 1;
switch (neighborMaxSupport)
{
case NeighborMaxSupport.TileSize10: tileSize = 10; break;
case NeighborMaxSupport.TileSize20: tileSize = 20; break;
case NeighborMaxSupport.TileSize40: tileSize = 40; break;
}
int neighborMaxW = bufferW / tileSize;
int neighborMaxH = bufferH / tileSize;
EnsureRenderTarget(ref velocityNeighborMax[eyeIndex], neighborMaxW, neighborMaxH, velocityFormat, FilterMode.Bilinear);
// tilemax
RenderTexture tileMax = RenderTexture.GetTemporary(neighborMaxW, neighborMaxH, 0, velocityFormat);
RenderTexture.active = tileMax;
{
velocityMaterial.SetTexture("_VelocityTex", velocityBuffer[eyeIndex]);
velocityMaterial.SetVector("_VelocityTex_TexelSize", new Vector4(1.0f / bufferW, 1.0f / bufferH, 0.0f, 0.0f));
velocityMaterial.SetPass(kTileMax);
DrawFullscreenQuad();
}
// neighbormax
RenderTexture.active = velocityNeighborMax[eyeIndex];
{
velocityMaterial.SetTexture("_VelocityTex", tileMax);
velocityMaterial.SetVector("_VelocityTex_TexelSize", new Vector4(1.0f / neighborMaxW, 1.0f / neighborMaxH, 0.0f, 0.0f));
velocityMaterial.SetPass(kNeighborMax);
DrawFullscreenQuad();
}
RenderTexture.ReleaseTemporary(tileMax);
}
else
{
ReleaseRenderTarget(ref velocityNeighborMax[0]);
ReleaseRenderTarget(ref velocityNeighborMax[1]);
}
}
RenderTexture.active = activeRT;
activeEyeIndex = eyeIndex;
}
void OnDisable()
{
if (velocityBuffer != null)
{
ReleaseRenderTarget(ref velocityBuffer[0]);
ReleaseRenderTarget(ref velocityBuffer[1]);
}
if (velocityNeighborMax != null)
{
ReleaseRenderTarget(ref velocityNeighborMax[0]);
ReleaseRenderTarget(ref velocityNeighborMax[1]);
}
}
}
}