Skip to content
This repository was archived by the owner on Nov 30, 2020. It is now read-only.

Commit cebe5aa

Browse files
authored
Merge pull request #259 from Unity-Technologies/xr_taa
XR Support for TAA
2 parents a873192 + fe29932 commit cebe5aa

File tree

8 files changed

+287
-45
lines changed

8 files changed

+287
-45
lines changed

PostProcessing/Editor/PostProcessLayerEditor.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ void DoAntialiasing()
176176
if (m_AntialiasingMode.intValue == (int)PostProcessLayer.Antialiasing.TemporalAntialiasing)
177177
{
178178
if (RuntimeUtilities.isSinglePassStereoEnabled)
179-
EditorGUILayout.HelpBox("TAA doesn't work with Single-pass stereo rendering.", MessageType.Warning);
179+
EditorGUILayout.HelpBox("TAA requires Unity 2017.3+ for Single-pass stereo rendering support.", MessageType.Warning);
180180

181181
EditorGUILayout.PropertyField(m_TaaJitterSpread);
182182
EditorGUILayout.PropertyField(m_TaaStationaryBlending);

PostProcessing/Runtime/Effects/TemporalAntialiasing.cs

Lines changed: 83 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -41,15 +41,26 @@ enum Pass
4141

4242
// Ping-pong between two history textures as we can't read & write the same target in the
4343
// same pass
44-
readonly RenderTexture[] m_HistoryTextures = new RenderTexture[2];
45-
int m_HistoryPingPong;
44+
const int k_NumEyes = 2;
45+
const int k_NumHistoryTextures = 2;
46+
readonly RenderTexture[][] m_HistoryTextures = new RenderTexture[k_NumEyes][];
47+
48+
int[] m_HistoryPingPong = new int [k_NumEyes];
49+
50+
public TemporalAntialiasing()
51+
{
52+
m_HistoryTextures[(int)Camera.StereoscopicEye.Left] = new RenderTexture[k_NumHistoryTextures];
53+
m_HistoryTextures[(int)Camera.StereoscopicEye.Right] = new RenderTexture[k_NumHistoryTextures];
54+
}
4655

4756
public bool IsSupported()
4857
{
4958
return SystemInfo.supportedRenderTargetCount >= 2
5059
&& SystemInfo.supportsMotionVectors
51-
&& SystemInfo.graphicsDeviceType != GraphicsDeviceType.OpenGLES2
52-
&& !RuntimeUtilities.isSinglePassStereoEnabled;
60+
#if !UNITY_2017_3_OR_NEWER
61+
&& !RuntimeUtilities.isVREnabled
62+
#endif
63+
&& SystemInfo.graphicsDeviceType != GraphicsDeviceType.OpenGLES2;
5364
}
5465

5566
internal DepthTextureMode GetCameraFlags()
@@ -96,18 +107,70 @@ public Matrix4x4 GetJitteredProjectionMatrix(Camera camera)
96107
return cameraProj;
97108
}
98109

110+
public void ConfigureJitteredProjectionMatrix(PostProcessRenderContext context)
111+
{
112+
var camera = context.camera;
113+
camera.nonJitteredProjectionMatrix = camera.projectionMatrix;
114+
camera.projectionMatrix = GetJitteredProjectionMatrix(camera);
115+
camera.useJitteredProjectionMatrixForTransparentRendering = false;
116+
}
117+
118+
// TODO: We'll probably need to isolate most of this for SRPs
119+
public void ConfigureStereoJitteredProjectionMatrices(PostProcessRenderContext context)
120+
{
121+
#if UNITY_2017_3_OR_NEWER
122+
var camera = context.camera;
123+
jitter = GenerateRandomOffset();
124+
jitter *= jitterSpread;
125+
126+
for (var eye = Camera.StereoscopicEye.Left; eye <= Camera.StereoscopicEye.Right; eye++)
127+
{
128+
// This saves off the device generated projection matrices as non-jittered
129+
context.camera.CopyStereoDeviceProjectionMatrixToNonJittered(eye);
130+
var originalProj = context.camera.GetStereoNonJitteredProjectionMatrix(eye);
131+
132+
// Currently no support for custom jitter func, as VR devices would need to provide
133+
// original projection matrix as input along with jitter
134+
var jitteredMatrix = RuntimeUtilities.GenerateJitteredProjectionMatrixFromOriginal(context, originalProj, jitter);
135+
context.camera.SetStereoProjectionMatrix(eye, jitteredMatrix);
136+
}
137+
138+
// jitter has to be scaled for the actual eye texture size, not just the intermediate texture size
139+
// which could be double-wide in certain stereo rendering scenarios
140+
jitter = new Vector2(jitter.x / context.xrSingleEyeWidth, jitter.y / context.height);
141+
camera.useJitteredProjectionMatrixForTransparentRendering = false;
142+
#endif
143+
}
144+
145+
void GenerateHistoryName(RenderTexture rt, int id, PostProcessRenderContext context)
146+
{
147+
rt.name = "Temporal Anti-aliasing History id #" + id;
148+
149+
bool vrDeviceActive = false;
150+
151+
#if UNITY_2017_2_OR_NEWER
152+
vrDeviceActive = XR.XRSettings.isDeviceActive;
153+
#else
154+
vrDeviceActive = VR.VRSettings.isDeviceActive;
155+
#endif
156+
157+
if (vrDeviceActive)
158+
rt.name += " for eye " + context.xrActiveEye;
159+
}
160+
99161
RenderTexture CheckHistory(int id, PostProcessRenderContext context)
100162
{
101-
var rt = m_HistoryTextures[id];
163+
var rt = m_HistoryTextures[context.xrActiveEye][id];
102164

103165
if (m_ResetHistory || rt == null || !rt.IsCreated())
104166
{
105167
RenderTexture.ReleaseTemporary(rt);
106168

107169
rt = RenderTexture.GetTemporary(context.width, context.height, 0, context.sourceFormat);
108-
rt.name = "Temporal Anti-aliasing History";
170+
GenerateHistoryName(rt, id, context);
171+
109172
rt.filterMode = FilterMode.Bilinear;
110-
m_HistoryTextures[id] = rt;
173+
m_HistoryTextures[context.xrActiveEye][id] = rt;
111174

112175
context.command.BlitFullscreenTriangle(context.source, rt);
113176
}
@@ -116,15 +179,16 @@ RenderTexture CheckHistory(int id, PostProcessRenderContext context)
116179
// On size change, simply copy the old history to the new one. This looks better
117180
// than completely discarding the history and seeing a few aliased frames.
118181
var rt2 = RenderTexture.GetTemporary(context.width, context.height, 0, context.sourceFormat);
119-
rt2.name = "Temporal Anti-aliasing History";
182+
GenerateHistoryName(rt2, id, context);
183+
120184
rt2.filterMode = FilterMode.Bilinear;
121-
m_HistoryTextures[id] = rt2;
185+
m_HistoryTextures[context.xrActiveEye][id] = rt2;
122186

123187
context.command.BlitFullscreenTriangle(rt, rt2);
124188
RenderTexture.ReleaseTemporary(rt);
125189
}
126190

127-
return m_HistoryTextures[id];
191+
return m_HistoryTextures[context.xrActiveEye][id];
128192
}
129193

130194
internal void Render(PostProcessRenderContext context)
@@ -134,10 +198,10 @@ internal void Render(PostProcessRenderContext context)
134198
var cmd = context.command;
135199
cmd.BeginSample("TemporalAntialiasing");
136200

137-
int pp = m_HistoryPingPong;
201+
int pp = m_HistoryPingPong[context.xrActiveEye];
138202
var historyRead = CheckHistory(++pp % 2, context);
139203
var historyWrite = CheckHistory(++pp % 2, context);
140-
m_HistoryPingPong = ++pp % 2;
204+
m_HistoryPingPong[context.xrActiveEye] = ++pp % 2;
141205

142206
const float kMotionAmplification = 100f * 60f;
143207
sheet.properties.SetVector(ShaderIDs.Jitter, jitter);
@@ -159,12 +223,17 @@ internal void Release()
159223
{
160224
for (int i = 0; i < m_HistoryTextures.Length; i++)
161225
{
162-
RenderTexture.ReleaseTemporary(m_HistoryTextures[i]);
226+
for (int j = 0; j < m_HistoryTextures[i].Length; j++)
227+
{
228+
RenderTexture.ReleaseTemporary(m_HistoryTextures[i][j]);
229+
m_HistoryTextures[i][j] = null;
230+
}
163231
m_HistoryTextures[i] = null;
164232
}
165233

166234
m_SampleIndex = 0;
167-
m_HistoryPingPong = 0;
235+
m_HistoryPingPong[0] = 0;
236+
m_HistoryPingPong[1] = 0;
168237

169238
ResetHistory();
170239
}

PostProcessing/Runtime/PostProcessLayer.cs

Lines changed: 48 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,12 @@
55

66
namespace UnityEngine.Rendering.PostProcessing
77
{
8+
#if UNITY_2017_2_OR_NEWER
9+
using XRSettings = UnityEngine.XR.XRSettings;
10+
#elif UNITY_5_6_OR_NEWER
11+
using XRSettings = UnityEngine.VR.VRSettings;
12+
#endif
13+
814
// TODO: XMLDoc everything (?)
915
[DisallowMultipleComponent, ExecuteInEditMode, ImageEffectAllowedInSceneView]
1016
[AddComponentMenu("Rendering/Post-process Layer", -1)]
@@ -256,20 +262,40 @@ void OnPreCull()
256262
if (RuntimeUtilities.scriptableRenderPipelineActive)
257263
return;
258264

259-
var context = m_CurrentContext;
260-
var sourceFormat = m_Camera.allowHDR ? RenderTextureFormat.DefaultHDR : RenderTextureFormat.Default;
261-
262265
// Resets the projection matrix from previous frame in case TAA was enabled.
263266
// We also need to force reset the non-jittered projection matrix here as it's not done
264267
// when ResetProjectionMatrix() is called and will break transparent rendering if TAA
265268
// is switched off and the FOV or any other camera property changes.
266269
m_Camera.ResetProjectionMatrix();
267270
m_Camera.nonJitteredProjectionMatrix = m_Camera.projectionMatrix;
268271

272+
if (XRSettings.isDeviceActive)
273+
m_Camera.ResetStereoProjectionMatrices();
274+
275+
BuildCommandBuffers();
276+
}
277+
278+
void OnPreRender()
279+
{
280+
// Unused in scriptable render pipelines
281+
// Only needed for multi-pass stereo right eye
282+
if (RuntimeUtilities.scriptableRenderPipelineActive ||
283+
(m_Camera.stereoActiveEye != Camera.MonoOrStereoscopicEye.Right))
284+
return;
285+
286+
BuildCommandBuffers();
287+
}
288+
289+
void BuildCommandBuffers()
290+
{
291+
var context = m_CurrentContext;
292+
var sourceFormat = m_Camera.allowHDR ? RenderTextureFormat.DefaultHDR : RenderTextureFormat.Default;
293+
269294
context.Reset();
270295
context.camera = m_Camera;
271296
context.sourceFormat = sourceFormat;
272297

298+
// TODO: Investigate retaining command buffers on XR multi-pass right eye
273299
m_LegacyCmdBufferBeforeReflections.Clear();
274300
m_LegacyCmdBufferBeforeLighting.Clear();
275301
m_LegacyCmdBufferOpaque.Clear();
@@ -321,6 +347,7 @@ void OnPreCull()
321347
opaqueOnlyEffects += isFogActive ? 1 : 0;
322348
opaqueOnlyEffects += hasCustomOpaqueOnlyEffects ? 1 : 0;
323349

350+
// This works on right eye because it is resolved/populated at runtime
324351
var cameraTarget = new RenderTargetIdentifier(BuiltinRenderTextureType.CameraTarget);
325352

326353
if (opaqueOnlyEffects > 0)
@@ -394,7 +421,15 @@ void OnPostRender()
394421
return;
395422

396423
if (m_CurrentContext.IsTemporalAntialiasingActive())
424+
{
397425
m_Camera.ResetProjectionMatrix();
426+
427+
if (XRSettings.isDeviceActive)
428+
{
429+
if (RuntimeUtilities.isSinglePassStereoEnabled || m_Camera.stereoActiveEye == Camera.MonoOrStereoscopicEye.Right)
430+
m_Camera.ResetStereoProjectionMatrices();
431+
}
432+
}
398433
}
399434

400435
PostProcessBundle GetBundle<T>()
@@ -573,10 +608,16 @@ public void Render(PostProcessRenderContext context)
573608
{
574609
if (!RuntimeUtilities.scriptableRenderPipelineActive)
575610
{
576-
var camera = context.camera;
577-
camera.nonJitteredProjectionMatrix = camera.projectionMatrix;
578-
camera.projectionMatrix = temporalAntialiasing.GetJitteredProjectionMatrix(camera);
579-
camera.useJitteredProjectionMatrixForTransparentRendering = false;
611+
if (XRSettings.isDeviceActive)
612+
{
613+
// We only need to configure all of this once for stereo, during OnPreCull
614+
if (context.camera.stereoActiveEye != Camera.MonoOrStereoscopicEye.Right)
615+
temporalAntialiasing.ConfigureStereoJitteredProjectionMatrices(context);
616+
}
617+
else
618+
{
619+
temporalAntialiasing.ConfigureJitteredProjectionMatrix(context);
620+
}
580621
}
581622

582623
var taaTarget = m_TargetPool.Get();

PostProcessing/Runtime/PostProcessRenderContext.cs

Lines changed: 59 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,52 @@
11
namespace UnityEngine.Rendering.PostProcessing
22
{
3+
#if UNITY_2017_2_OR_NEWER
4+
using XRSettings = UnityEngine.XR.XRSettings;
5+
#elif UNITY_5_6_OR_NEWER
6+
using XRSettings = UnityEngine.VR.VRSettings;
7+
#endif
8+
39
// Context object passed around all post-fx in a frame
410
public sealed class PostProcessRenderContext
511
{
612
// -----------------------------------------------------------------------------------------
713
// The following should be filled by the render pipeline
814

915
// Camera currently rendering
10-
public Camera camera { get; set; }
16+
Camera m_Camera;
17+
public Camera camera
18+
{
19+
get { return m_Camera; }
20+
set
21+
{
22+
m_Camera = value;
23+
24+
if (XRSettings.isDeviceActive)
25+
{
26+
#if UNITY_2017_2_OR_NEWER
27+
RenderTextureDescriptor xrDesc = XRSettings.eyeTextureDesc;
28+
width = xrDesc.width;
29+
height = xrDesc.height;
30+
#else
31+
width = XRSettings.eyeTextureWidth; // double this for single-pass when we can't query eyeTextureDesc
32+
height = XRSettings.eyeTextureHeight;
33+
#endif
34+
35+
if (camera.stereoActiveEye == Camera.MonoOrStereoscopicEye.Right)
36+
xrActiveEye = (int)Camera.StereoscopicEye.Right;
37+
38+
xrSingleEyeWidth = XRSettings.eyeTextureWidth;
39+
xrSingleEyeHeight = XRSettings.eyeTextureHeight;
40+
}
41+
else
42+
{
43+
width = m_Camera.pixelWidth;
44+
height = m_Camera.pixelHeight;
45+
xrSingleEyeWidth = width;
46+
}
47+
}
48+
}
49+
1150

1251
// The command buffer to fill in
1352
public CommandBuffer command { get; set; }
@@ -45,16 +84,19 @@ public sealed class PostProcessRenderContext
4584
public PostProcessDebugLayer debugLayer { get; internal set; }
4685

4786
// Current camera width in pixels
48-
public int width
49-
{
50-
get { return camera.pixelWidth; }
51-
}
87+
public int width { get; private set; }
5288

5389
// Current camera height in pixels
54-
public int height
55-
{
56-
get { return camera.pixelHeight; }
57-
}
90+
public int height { get; private set; }
91+
92+
// Current active rendering eye (for XR)
93+
public int xrActiveEye { get; private set; }
94+
95+
// Current single eye width in pixels (for XR)
96+
public int xrSingleEyeWidth { get; private set; }
97+
98+
// Current single eye height in pixels (for XR)
99+
public int xrSingleEyeHeight { get; private set; }
58100

59101
// Are we currently rendering in the scene view?
60102
public bool isSceneView { get; internal set; }
@@ -68,7 +110,14 @@ public int height
68110

69111
public void Reset()
70112
{
71-
camera = null;
113+
m_Camera = null;
114+
width = 0;
115+
height = 0;
116+
117+
xrActiveEye = (int)Camera.StereoscopicEye.Left;
118+
xrSingleEyeWidth = 0;
119+
xrSingleEyeHeight = 0;
120+
72121
command = null;
73122
source = 0;
74123
destination = 0;

0 commit comments

Comments
 (0)