-
Notifications
You must be signed in to change notification settings - Fork 2
/
BigCameraInput.cs
163 lines (135 loc) · 5.96 KB
/
BigCameraInput.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
using System.Linq;
using UnityEditor.Recorder;
using UnityEngine;
namespace UnityEditor.BigImageRecorder
{
/// <summary>
/// Recorder input that divides a camera's projection matrix and renders the tiles to individual render textures.
/// </summary>
class BigCameraInput : RecorderInput
{
public bool HasCamera => camera != null;
public BigCameraInputSettings InputSettings => settings as BigCameraInputSettings;
public RenderTexture[,] OutputRenderTextures { get; private set; }
Camera camera;
Matrix4x4[,] projectionMatrices;
protected override void BeginRecording(RecordingSession session)
{
base.BeginRecording(session);
OutputRenderTextures = CreateOutputRenderTextures(InputSettings);
camera = GetTargetCamera(InputSettings.CameraTag);
projectionMatrices = CreateProjectionMatrices(InputSettings, camera);
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
foreach (var renderTexture in OutputRenderTextures)
{
renderTexture.Release();
}
OutputRenderTextures = null;
}
protected override void NewFrameReady(RecordingSession session)
{
base.NewFrameReady(session);
if (camera == null)
{
return;
}
var originalTargetTexture = camera.targetTexture;
for (var row = 0; row < InputSettings.Rows; row++)
{
for (var column = 0; column < InputSettings.Columns; column++)
{
camera.projectionMatrix = projectionMatrices[row, column];
camera.targetTexture = OutputRenderTextures[row, column];
camera.Render();
}
}
camera.ResetProjectionMatrix();
camera.targetTexture = originalTargetTexture;
}
static RenderTexture[,] CreateOutputRenderTextures(BigCameraInputSettings inputSettings)
{
var outputRenderTextures = new RenderTexture[inputSettings.Rows, inputSettings.Columns];
for (var row = 0; row < inputSettings.Rows; row++)
{
for (var column = 0; column < inputSettings.Columns; column++)
{
var renderTexture = new RenderTexture(inputSettings.TileWidth, inputSettings.TileHeight, 0);
renderTexture.Create();
outputRenderTextures[row, column] = renderTexture;
}
}
return outputRenderTextures;
}
static Matrix4x4[,] CreateProjectionMatrices(BigCameraInputSettings inputSettings, Camera camera)
{
if (camera == null)
{
return null;
}
var projectionMatrices = new Matrix4x4[inputSettings.Rows, inputSettings.Columns];
var nearClipPlane = camera.nearClipPlane;
// Values to create the original projection matrix.
// We multiply these by a modifier from -1 to 1 to get a partial projection matrix.
//
// Say we want to split the projection matrix into vertical thirds. To get the three projection matrices:
// [ | | ]
// Left: left * 1, right * -1/3
// Center: left * 1/3, right * 1/3
// Right: left * -1/3, right * 1
var top = nearClipPlane * Mathf.Tan(camera.fieldOfView * 0.5f * Mathf.Deg2Rad);
var bottom = -top;
var left = bottom * inputSettings.AspectRatio;
var right = top * inputSettings.AspectRatio;
// How much of the final image each tile accounts for.
var horizontalTilePercent = 1f / inputSettings.Columns;
var verticalTilePercent = 1f / inputSettings.Rows;
for (var row = 0; row < inputSettings.Rows; row++)
{
var tileTop = top * (1 - 2 * verticalTilePercent * row);
var tileBottom = bottom * (-1 + 2 * verticalTilePercent * (row + 1));
for (var column = 0; column < inputSettings.Columns; column++)
{
var tileLeft = left * (1 - 2 * horizontalTilePercent * column);
var tileRight = right * (-1 + 2 * horizontalTilePercent * (column + 1));
var projectionMatrix = camera.projectionMatrix;
projectionMatrix.m00 = 2 * nearClipPlane / (tileRight - tileLeft);
projectionMatrix.m02 = (tileRight + tileLeft) / (tileRight - tileLeft);
projectionMatrix.m11 = 2 * nearClipPlane / (tileTop - tileBottom);
projectionMatrix.m12 = (tileTop + tileBottom) / (tileTop - tileBottom);
projectionMatrices[row, column] = projectionMatrix;
}
}
return projectionMatrices;
}
static Camera GetTargetCamera(string cameraTag)
{
GameObject[] gameObjectsWithTag;
try
{
gameObjectsWithTag = GameObject.FindGameObjectsWithTag(cameraTag);
}
catch (UnityException)
{
Debug.LogError($"[Big Image Recorder] Tag '{cameraTag}' does not exist.");
return null;
}
var cameras = gameObjectsWithTag
.Select(gameObject => gameObject.GetComponent<Camera>())
.Where(camera => camera != null)
.ToList();
if (cameras.Count == 0)
{
Debug.LogError($"[Big Image Recorder] Found no camera with tag '{cameraTag}'.");
return null;
}
if (cameras.Count > 1)
{
Debug.LogWarning($"[Big Image Recorder] Found more than one camera with tag '{cameraTag}'.");
}
return cameras.First();
}
}
}