Neodroid  0.2.0
Machine Learning Environment Prototyping Tool
UberCamera.cs
Go to the documentation of this file.
1 using System;
2 using System.Linq;
3 using UnityEngine;
4 using UnityEngine.Rendering;
5 
6 namespace droid.Runtime.Utilities.GameObjects.NeodroidCamera.Experimental {
10  [RequireComponent(typeof(Camera))]
11  [ExecuteInEditMode]
12  public class UberCamera : MonoBehaviour {
13  #region fields
14 
15  [SerializeField] Shader copy_shader = null;
16  [SerializeField] Material _copy_material = null;
17  [SerializeField] Material _off_screen_mat = null;
18  [SerializeField] Camera _camera = null;
19  [SerializeField] Boolean _debugging = true;
20  [SerializeField] GUISkin gui_style = null;
21 
22  CommandBuffer[] _copy_cbs = null;
23  CommandBuffer _copy_fb_cb = null;
24  CommandBuffer _copy_gb_cb = null;
25  CommandBuffer _clear_gb_cb = null;
26  CommandBuffer _copy_velocity_cb = null;
27  RenderTexture[] _fb_rts = null;
28  RenderTexture[] _gb_rts = null;
29  Mesh _quad_mesh = null;
30 
31  RenderTargetIdentifier[] _m_rt_fb_ids = null;
32  RenderTargetIdentifier[] _m_rt_gb_ids = null;
33  int _tmp_texture_id = Shader.PropertyToID("_TmpFrameBuffer");
34  static readonly int _clear_color = Shader.PropertyToID("_ClearColor");
35 
36  static readonly Tuple<Int32, Int32> _texture_wh = new Tuple<int, int>(256, 256);
37 
38  const int _preview_size = 100;
39  const int _preview_margin = 20;
40 
41  #endregion
42 
46  public Boolean Debugging { get { return this._debugging; } set { this._debugging = value; } }
47 
48  protected Tuple<int, int> GetCaptureResolutionFromCamera() {
49  var w = this._camera.pixelWidth;
50  var h = this._camera.pixelHeight;
51  var aspect = (float)h / w;
52  w = _texture_wh.Item1;
53  h = (int)(w * aspect);
54  return new Tuple<int, int>(w, h);
55  }
56 
57  void Update() {
58  if (_texture_wh.Item1 == Screen.width && _texture_wh.Item2 == Screen.height) {
59  return;
60  }
61 
62  var xw = _texture_wh.Item1;
63  var yh = _texture_wh.Item2;
64 
65  var x = Screen.width / 2 - xw / 2;
66  var y = Screen.height / 2 - yh / 2;
67 
68  this._camera.pixelRect = new Rect(x, y, xw, yh);
69  }
70 
71  void Awake() {
72  if (!this.gui_style) {
73  this.gui_style = Resources.FindObjectsOfTypeAll<GUISkin>().First(a => a.name == "BoundingBox");
74  }
75 
76  if (!this._copy_material) {
77  this._copy_material = new Material(this.copy_shader);
78  }
79 
80  if (!this._quad_mesh) {
81  this._quad_mesh = CreateFullscreenQuad();
82  }
83 
84  if (!this._camera) {
85  this._camera = this.GetComponent<Camera>();
86  }
87 
88  this.Dispose();
89 
90  if (this._fb_rts == null || this._fb_rts.Length != 2) {
91  this._fb_rts = new RenderTexture[2];
92  for (var i = 0; i < this._fb_rts.Length; ++i) {
93  this._fb_rts[i] =
94  new RenderTexture(_texture_wh.Item1, _texture_wh.Item2, 0, RenderTextureFormat.ARGBHalf) {
95  filterMode
96  = FilterMode
97  .Point,
98  name
99  = $"rt_fb{i}"
100  };
101  this._fb_rts[i].Create();
102  }
103  }
104 
105  this._m_rt_gb_ids = new RenderTargetIdentifier[] {this._fb_rts[0], this._fb_rts[1]};
106 
107  if (this._gb_rts == null || this._gb_rts.Length != 8) {
108  /*
109  half4 albedo : SV_Target0;
110  half4 occlusion : SV_Target1;
111  half4 specular : SV_Target2;
112  half4 smoothness : SV_Target3;
113  half4 normal : SV_Target4;
114  half4 emission : SV_Target5;
115  half4 depth : SV_Target6;
116  */
117  var names = new[] {
118  "albedo",
119  "occlusion",
120  "specular",
121  "smoothness",
122  "normal",
123  "emission",
124  "depth",
125  "velocity"
126  };
127  this._gb_rts = new RenderTexture[8];
128  for (var i = 0; i < this._gb_rts.Length; ++i) {
129  this._gb_rts[i] =
130  new RenderTexture(_texture_wh.Item1, _texture_wh.Item2, 0, RenderTextureFormat.ARGBHalf) {
131  filterMode
132  = FilterMode
133  .Point,
134  name
135  = $"{names[i]}"
136  };
137  this._gb_rts[i].Create();
138  }
139  }
140 
141  this._m_rt_fb_ids = new RenderTargetIdentifier[] {
142  this._gb_rts[0],
143  this._gb_rts[1],
144  this._gb_rts[2],
145  this._gb_rts[3],
146  this._gb_rts[4],
147  this._gb_rts[5],
148  this._gb_rts[6]
149  };
150 
151  this.Setup();
152  }
153 
158  public static Mesh CreateFullscreenQuad() {
159  var r = new Mesh {
160  vertices = new[] {
161  new Vector3(1.0f, 1.0f, 0.0f),
162  new Vector3(-1.0f, 1.0f, 0.0f),
163  new Vector3(-1.0f, -1.0f, 0.0f),
164  new Vector3(1.0f, -1.0f, 0.0f)
165  },
166  triangles = new[] {0, 1, 2, 2, 3, 0}
167  };
168  r.UploadMeshData(true);
169  return r;
170  }
171 
174  void Setup() {
175  if (this.copy_shader == null) {
176  Debug.LogError("Copy shader is missing!");
177  return;
178  }
179 
180  if (this._off_screen_mat != null) {
181  if (this._camera.targetTexture != null) {
182  this._off_screen_mat.EnableKeyword("OFFSCREEN");
183  } else {
184  this._off_screen_mat.DisableKeyword("OFFSCREEN");
185  }
186  }
187 
188  this._copy_fb_cb = new CommandBuffer {name = "Copy FrameBuffer"};
189  this._copy_fb_cb.GetTemporaryRT(this._tmp_texture_id, -1, -1, 0, FilterMode.Point);
190  this._copy_fb_cb.Blit(BuiltinRenderTextureType.CurrentActive, this._tmp_texture_id);
191  this._copy_fb_cb.SetRenderTarget(this._m_rt_gb_ids, this._fb_rts[0]);
192  this._copy_fb_cb.DrawMesh(this._quad_mesh, Matrix4x4.identity, this._copy_material, 0, 0);
193  this._copy_fb_cb.ReleaseTemporaryRT(this._tmp_texture_id);
194  this._camera.AddCommandBuffer(CameraEvent.AfterEverything, this._copy_fb_cb);
195 
196  this._clear_gb_cb = new CommandBuffer {
197  name = "Cleanup GBuffer"
198  }; // clear gbuffer (Unity doesn't clear emission buffer - it is not needed usually)
199  if (this._camera.allowHDR) {
200  this._clear_gb_cb.SetRenderTarget(BuiltinRenderTextureType.CameraTarget);
201  } else {
202  this._clear_gb_cb.SetRenderTarget(BuiltinRenderTextureType.GBuffer3);
203  }
204 
205  this._clear_gb_cb.DrawMesh(this._quad_mesh, Matrix4x4.identity, this._copy_material, 0, 3);
206  this._copy_material.SetColor(_clear_color, this._camera.backgroundColor);
207 
208  this._copy_gb_cb = new CommandBuffer {name = "Copy GBuffer"}; // copy gbuffer
209  this._copy_gb_cb.SetRenderTarget(this._m_rt_fb_ids, this._gb_rts[0]);
210  this._copy_gb_cb.DrawMesh(this._quad_mesh, Matrix4x4.identity, this._copy_material, 0, 2);
211  this._camera.AddCommandBuffer(CameraEvent.BeforeGBuffer, this._clear_gb_cb);
212  this._camera.AddCommandBuffer(CameraEvent.BeforeLighting, this._copy_gb_cb);
213 
214  this._copy_velocity_cb = new CommandBuffer {name = "Copy Velocity"};
215  this._copy_velocity_cb.SetRenderTarget(this._gb_rts[7]);
216  this._copy_velocity_cb.DrawMesh(this._quad_mesh, Matrix4x4.identity, this._copy_material, 0, 4);
217  this._camera.AddCommandBuffer(CameraEvent.BeforeImageEffectsOpaque, this._copy_velocity_cb);
218  this._camera.depthTextureMode = DepthTextureMode.Depth | DepthTextureMode.MotionVectors;
219 
220  this._copy_cbs = new[] {this._copy_fb_cb, this._clear_gb_cb, this._copy_gb_cb, this._copy_velocity_cb};
221  }
222 
223  void OnGUI() {
224  if (this._debugging) {
225  var index = 0;
226 
227  if (this._gb_rts != null) {
228  foreach (var pass in this._gb_rts) {
229  var xi = (_preview_size + _preview_margin) * index++;
230  var x = xi % (Screen.width - _preview_size);
231  var y = (_preview_size + _preview_margin) * (xi / (Screen.width - _preview_size));
232  var r = new Rect(_preview_margin + x, _preview_margin + y, _preview_size, _preview_size);
233  //this._asf?.Flip(pass._RenderTexture);
234 
235  GUI.DrawTexture(r, pass, ScaleMode.ScaleToFit);
236  GUI.TextField(r, pass.name, this.gui_style.box);
237  }
238  }
239 
240  if (this._fb_rts != null) {
241  foreach (var pass in this._fb_rts) {
242  var xi = (_preview_size + _preview_margin) * index++;
243  var x = xi % (Screen.width - _preview_size);
244  var y = (_preview_size + _preview_margin) * (xi / (Screen.width - _preview_size));
245  var r = new Rect(_preview_margin + x, _preview_margin + y, _preview_size, _preview_size);
246  //this._asf?.Flip(pass._RenderTexture);
247 
248  GUI.DrawTexture(r, pass, ScaleMode.ScaleToFit);
249  GUI.TextField(r, pass.name, this.gui_style.box);
250  }
251  }
252  }
253  }
254 
255  void OnDestroy() {
256  //this.Dispose();
257  }
258 
259  void Dispose() {
260  this._camera.RemoveAllCommandBuffers(); // cleanup capturing camera
261 
262  if (this._copy_fb_cb != null) {
263  this._camera.RemoveCommandBuffer(CameraEvent.AfterEverything, this._copy_fb_cb);
264  this._copy_fb_cb.Release();
265  this._copy_fb_cb = null;
266  }
267 
268  if (this._clear_gb_cb != null) {
269  this._camera.RemoveCommandBuffer(CameraEvent.BeforeGBuffer, this._clear_gb_cb);
270  this._clear_gb_cb.Release();
271  this._clear_gb_cb = null;
272  }
273 
274  if (this._copy_gb_cb != null) {
275  this._camera.RemoveCommandBuffer(CameraEvent.BeforeLighting, this._copy_gb_cb);
276  this._copy_gb_cb.Release();
277  this._copy_gb_cb = null;
278  }
279 
280  if (this._copy_velocity_cb != null) {
281  this._camera.RemoveCommandBuffer(CameraEvent.BeforeImageEffectsOpaque, this._copy_velocity_cb);
282  this._copy_velocity_cb.Release();
283  this._copy_velocity_cb = null;
284  }
285 
286  if (this._fb_rts != null) {
287  foreach (var rt in this._fb_rts) {
288  rt.Release();
289  }
290 
291  this._fb_rts = null;
292  }
293 
294  if (this._gb_rts != null) {
295  foreach (var rt in this._gb_rts) {
296  rt.Release();
297  }
298 
299  this._gb_rts = null;
300  }
301  }
302  }
303 }