CaptureFromCamera360.cs 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981
  1. #if UNITY_5_6_0 || UNITY_5_6_1
  2. #define AVPRO_MOVIECAPTURE_UNITYBUG_RENDERTOCUBEMAP_56
  3. #endif
  4. #if UNITY_2018_1_OR_NEWER
  5. // Unity 2018.1 introduces stereo cubemap render methods, but with no camera rotation
  6. #define AVPRO_MOVIECAPTURE_UNITY_STEREOCUBEMAP_RENDER
  7. #if UNITY_2018_2_OR_NEWER || UNITY_2018_1_9
  8. // Unity 2018.2 adds camera rotation
  9. #define AVPRO_MOVIECAPTURE_UNITY_STEREOCUBEMAP_RENDER_WITHROTATION
  10. #endif
  11. #endif
  12. using UnityEngine;
  13. using UnityEngine.Rendering;
  14. using System.Collections;
  15. //-----------------------------------------------------------------------------
  16. // Copyright 2012-2022 RenderHeads Ltd. All rights reserved.
  17. //-----------------------------------------------------------------------------
  18. namespace RenderHeads.Media.AVProMovieCapture
  19. {
  20. /// <summary>
  21. /// Capture a camera view in 360 equi-rectangular format.
  22. /// The camera is rendered into a cubemap, so the scene is rendered an extra 6 times.
  23. /// Finally the cubemap is converted to equi-rectangular format and encoded.
  24. /// </summary>
  25. //[RequireComponent(typeof(Camera))]
  26. [AddComponentMenu("AVPro Movie Capture/Capture From Camera 360 (VR)", 100)]
  27. public class CaptureFromCamera360 : CaptureBase
  28. {
  29. [SerializeField] CameraSelector _cameraSelector = null;
  30. public CameraSelector CameraSelector
  31. {
  32. get { return _cameraSelector; }
  33. set { _cameraSelector = value; }
  34. }
  35. [SerializeField] Camera _camera = null;
  36. [SerializeField] CubemapResolution _cubemapResolution = CubemapResolution.POW2_2048;
  37. [SerializeField] CubemapDepth _cubemapDepth = CubemapDepth.Depth_24;
  38. public CubemapResolution CubemapFaceResolution
  39. {
  40. get { return _cubemapResolution; }
  41. set { _cubemapResolution = value; }
  42. }
  43. public CubemapDepth CubemapDepthResolution
  44. {
  45. get { return _cubemapDepth; }
  46. set { _cubemapDepth = value; }
  47. }
  48. [SerializeField] bool _supportGUI = false;
  49. [SerializeField] bool _supportCameraRotation = false;
  50. [SerializeField] bool _onlyLeftRightRotation = false;
  51. public bool SupportGUI
  52. {
  53. get { return _supportGUI; }
  54. set { _supportGUI = value; }
  55. }
  56. public bool SupportCameraRotation
  57. {
  58. get { return _supportCameraRotation; }
  59. set { _supportCameraRotation = value; }
  60. }
  61. public bool OnlyLeftRightRotation
  62. {
  63. get { return _onlyLeftRightRotation; }
  64. set { _onlyLeftRightRotation = value; }
  65. }
  66. [Tooltip("Render 180 degree equirectangular instead of 360 degrees")]
  67. [SerializeField] bool _render180Degrees = false;
  68. [SerializeField] StereoPacking _stereoRendering = StereoPacking.None;
  69. public bool Render180Degrees
  70. {
  71. get { return _render180Degrees; }
  72. set { _render180Degrees = value; }
  73. }
  74. public StereoPacking StereoRendering
  75. {
  76. get { return _stereoRendering; }
  77. set { _stereoRendering = value; }
  78. }
  79. [Tooltip("Makes assumption that 1 Unity unit is 1m")]
  80. [SerializeField] float _ipd = 0.064f;
  81. public float IPD
  82. {
  83. get { return _ipd; }
  84. set { _ipd = value; }
  85. }
  86. [Tooltip("Percentage cube faces are overdrawn each edge then blended to alleviate screen space FX seams")]
  87. [SerializeField] float _blendOverlapPercent = 0.0f;
  88. // State
  89. private RenderTexture _faceTarget;
  90. // RJT TODO: Texture array?
  91. private RenderTexture[] _faceTargets = new RenderTexture[6];
  92. private Material _blitMaterial;
  93. private Material _cubemapToEquirectangularMaterial;
  94. private RenderTexture _cubeTarget;
  95. private RenderTexture _finalTarget;
  96. private System.IntPtr _targetNativePointer = System.IntPtr.Zero;
  97. private int _propFlipX;
  98. #if SUPPORT_SHADER_ROTATION
  99. private int _propRotation;
  100. #endif
  101. private enum CubemapRenderMethod
  102. {
  103. Manual, // Manually render the cubemaps - supports world space GUI, camera rotation, but is slow and doesn't give correct stereo
  104. Unity, // No stereo, no world space GUI, no camera rotation
  105. Unity2018, // Good fast stereo, no world space GUI, camera rotation only in 2018.2 and above
  106. }
  107. public CaptureFromCamera360()
  108. {
  109. // Override the default values to match more common use cases for this capture component
  110. _renderResolution = Resolution.POW2_2048x2048;
  111. }
  112. private CubemapRenderMethod GetCubemapRenderingMethod()
  113. {
  114. if (_supportGUI)
  115. {
  116. return CubemapRenderMethod.Manual;
  117. }
  118. if (_supportCameraRotation)
  119. {
  120. #if AVPRO_MOVIECAPTURE_UNITY_STEREOCUBEMAP_RENDER_WITHROTATION
  121. return CubemapRenderMethod.Unity2018;
  122. #else
  123. return CubemapRenderMethod.Manual;
  124. #endif
  125. }
  126. if (_stereoRendering == StereoPacking.None)
  127. {
  128. #if AVPRO_MOVIECAPTURE_UNITY_STEREOCUBEMAP_RENDER_WITHROTATION
  129. return CubemapRenderMethod.Unity2018;
  130. #else
  131. return CubemapRenderMethod.Unity;
  132. #endif
  133. }
  134. else
  135. {
  136. #if AVPRO_MOVIECAPTURE_UNITY_STEREOCUBEMAP_RENDER
  137. return CubemapRenderMethod.Unity2018;
  138. #else
  139. return CubemapRenderMethod.Manual;
  140. #endif
  141. }
  142. }
  143. public void SetCamera(Camera camera)
  144. {
  145. _camera = camera;
  146. }
  147. #if false
  148. private void OnRenderImage(RenderTexture source, RenderTexture dest)
  149. {
  150. #if false
  151. if (_capturing && !_paused)
  152. {
  153. while (_handle >= 0 && !NativePlugin.IsNewFrameDue(_handle))
  154. {
  155. System.Threading.Thread.Sleep(1);
  156. }
  157. if (_handle >= 0)
  158. {
  159. if (_audioCapture && _audioDeviceIndex < 0 && !_noAudio)
  160. {
  161. uint bufferLength = (uint)_audioCapture.BufferLength;
  162. if (bufferLength > 0)
  163. {
  164. NativePlugin.EncodeAudio(_handle, _audioCapture.BufferPtr, bufferLength);
  165. _audioCapture.FlushBuffer();
  166. }
  167. }
  168. // In Direct3D the RT can be flipped vertically
  169. /*if (source.texelSize.y < 0)
  170. {
  171. }*/
  172. Graphics.Blit(_cubeTarget, _target, _cubemapToEquirectangularMaterial);
  173. RenderThreadEvent(NativePlugin.PluginEvent.CaptureFrameBuffer);
  174. GL.InvalidateState();
  175. UpdateFPS();
  176. }
  177. }
  178. #endif
  179. // Pass-through
  180. if (_cubeTarget != null)
  181. {
  182. Graphics.Blit(_cubeTarget, dest, _cubemapToEquirectangularMaterial);
  183. }
  184. else
  185. {
  186. Graphics.Blit(source, dest);
  187. }
  188. }
  189. #endif
  190. public override void UpdateFrame()
  191. {
  192. if (_cameraSelector != null)
  193. {
  194. if (_camera != _cameraSelector.Camera)
  195. {
  196. SetCamera(_cameraSelector.Camera);
  197. }
  198. }
  199. if (_useWaitForEndOfFrame)
  200. {
  201. if (_capturing && !_paused)
  202. {
  203. StartCoroutine(FinalRenderCapture());
  204. }
  205. }
  206. else
  207. {
  208. Capture();
  209. }
  210. base.UpdateFrame();
  211. }
  212. private IEnumerator FinalRenderCapture()
  213. {
  214. yield return _waitForEndOfFrame;
  215. Capture();
  216. }
  217. private void Capture()
  218. {
  219. TickFrameTimer();
  220. AccumulateMotionBlur();
  221. if (_capturing && !_paused)
  222. {
  223. if (
  224. ((_cubeTarget != null) || (_faceTargets[0] != null)) &&
  225. (_camera != null)
  226. )
  227. {
  228. bool canGrab = true;
  229. if (IsUsingMotionBlur())
  230. {
  231. // TODO: fix motion blur
  232. //this._motionBlur.RenderImage()
  233. // If the motion blur is still accumulating, don't grab this frame
  234. canGrab = _motionBlur.IsFrameAccumulated;
  235. }
  236. if (canGrab && CanOutputFrame())
  237. {
  238. EncodeUnityAudio();
  239. RenderTexture finalTexture = _finalTarget;
  240. if (!IsUsingMotionBlur())
  241. {
  242. UpdateTexture();
  243. }
  244. else
  245. {
  246. finalTexture = _motionBlur.FinalTexture;
  247. }
  248. // Side-by-side transparency
  249. RenderTexture newSourceTexture = UpdateForSideBySideTransparency( finalTexture );
  250. if (newSourceTexture)
  251. {
  252. finalTexture = newSourceTexture;
  253. }
  254. if (_targetNativePointer == System.IntPtr.Zero || _supportTextureRecreate)
  255. {
  256. // NOTE: If support for captures to survive through alt-tab events, or window resizes where the GPU resources are recreated
  257. // is required, then this line is needed. It is very expensive though as it does a sync with the rendering thread.
  258. _targetNativePointer = finalTexture.GetNativeTexturePtr();
  259. }
  260. NativePlugin.SetTexturePointer(_handle, _targetNativePointer);
  261. RenderThreadEvent(NativePlugin.PluginEvent.CaptureFrameBuffer);
  262. // ADG NOTE: Causes screen flickering under D3D12, even if we're not doing any rendering at native level
  263. // And also seems to cause GL.sRGBWrite to be set to false, which causes screen darkening in Linear mode
  264. if (SystemInfo.graphicsDeviceType != GraphicsDeviceType.Direct3D12)
  265. {
  266. GL.InvalidateState();
  267. }
  268. UpdateFPS();
  269. }
  270. }
  271. }
  272. RenormTimer();
  273. }
  274. private static void ClearCubemap(RenderTexture texture, Color color)
  275. {
  276. // TODO: Find a better way to do this?
  277. bool clearDepth = (texture.depth != 0);
  278. Graphics.SetRenderTarget(texture, 0, CubemapFace.PositiveX);
  279. GL.Clear(true, clearDepth, color);
  280. Graphics.SetRenderTarget(texture, 0, CubemapFace.PositiveY);
  281. GL.Clear(true, clearDepth, color);
  282. Graphics.SetRenderTarget(texture, 0, CubemapFace.PositiveZ);
  283. GL.Clear(true, clearDepth, color);
  284. Graphics.SetRenderTarget(texture, 0, CubemapFace.NegativeX);
  285. GL.Clear(true, clearDepth, color);
  286. Graphics.SetRenderTarget(texture, 0, CubemapFace.NegativeY);
  287. GL.Clear(true, clearDepth, color);
  288. Graphics.SetRenderTarget(texture, 0, CubemapFace.NegativeZ);
  289. GL.Clear(true, clearDepth, color);
  290. Graphics.SetRenderTarget(null);
  291. }
  292. private void RenderCubemapToEquiRect(RenderTexture cubemap, RenderTexture target, bool supportRotation, Quaternion rotation, bool isEyeLeft)
  293. {
  294. #if SUPPORT_SHADER_ROTATION
  295. if (supportRotation)
  296. {
  297. // Note: Because Unity's Camera.RenderCubemap() doesn't support rotated cameras, we apply the rotation matrix in the cubemap lookup
  298. _cubemapToEquirectangularMaterial.EnableKeyword("USE_ROTATION");
  299. Matrix4x4 rotationMatrix = Matrix4x4.TRS(Vector3.zero, rotation, Vector3.one);
  300. _cubemapToEquirectangularMaterial.SetMatrix(_propRotation, rotationMatrix);
  301. }
  302. else
  303. {
  304. _cubemapToEquirectangularMaterial.DisableKeyword("USE_ROTATION");
  305. }
  306. #endif
  307. if (_stereoRendering == StereoPacking.TopBottom)
  308. {
  309. if (isEyeLeft)
  310. {
  311. // Render to top
  312. _cubemapToEquirectangularMaterial.DisableKeyword("STEREOPACK_BOTTOM");
  313. _cubemapToEquirectangularMaterial.EnableKeyword("STEREOPACK_TOP");
  314. }
  315. else
  316. {
  317. // Render to bottom
  318. _cubemapToEquirectangularMaterial.DisableKeyword("STEREOPACK_TOP");
  319. _cubemapToEquirectangularMaterial.EnableKeyword("STEREOPACK_BOTTOM");
  320. }
  321. }
  322. else if (_stereoRendering == StereoPacking.LeftRight)
  323. {
  324. if (isEyeLeft)
  325. {
  326. // Render to left
  327. _cubemapToEquirectangularMaterial.DisableKeyword("STEREOPACK_RIGHT");
  328. _cubemapToEquirectangularMaterial.EnableKeyword("STEREOPACK_LEFT");
  329. }
  330. else
  331. {
  332. // Render to right
  333. _cubemapToEquirectangularMaterial.DisableKeyword("STEREOPACK_LEFT");
  334. _cubemapToEquirectangularMaterial.EnableKeyword("STEREOPACK_RIGHT");
  335. }
  336. }
  337. // Between Unity 2018.1.0 and 2018.3.0 Unity doesn't seem to set the correct sRGBWrite state and keeps it as false
  338. #if (UNITY_2018_1_OR_NEWER && !UNITY_2018_3_OR_NEWER)
  339. bool sRGBWritePrev = GL.sRGBWrite;
  340. GL.sRGBWrite = target.sRGB;
  341. #endif
  342. // Blending?
  343. if (_blendOverlapPercent > 0.0f)
  344. {
  345. _cubemapToEquirectangularMaterial.EnableKeyword("USE_BLENDING");
  346. _cubemapToEquirectangularMaterial.SetTexture("_Face_Left", _faceTargets[0]);
  347. _cubemapToEquirectangularMaterial.SetTexture("_Face_Right", _faceTargets[1]);
  348. _cubemapToEquirectangularMaterial.SetTexture("_Face_Up", _faceTargets[2]);
  349. _cubemapToEquirectangularMaterial.SetTexture("_Face_Down", _faceTargets[3]);
  350. _cubemapToEquirectangularMaterial.SetTexture("_Face_Front", _faceTargets[4]);
  351. _cubemapToEquirectangularMaterial.SetTexture("_Face_Back", _faceTargets[5]);
  352. _cubemapToEquirectangularMaterial.SetFloat("_inverseOverlap", (1.0f / (1.0f + (_blendOverlapPercent * 0.01f))));
  353. }
  354. else { _cubemapToEquirectangularMaterial.DisableKeyword("USE_BLENDING"); }
  355. // Render
  356. Graphics.Blit(cubemap, target, _cubemapToEquirectangularMaterial);
  357. #if (UNITY_2018_1_OR_NEWER && !UNITY_2018_3_OR_NEWER)
  358. GL.sRGBWrite = sRGBWritePrev;
  359. #endif
  360. }
  361. private void UpdateTexture()
  362. {
  363. // Between Unity 2018.1.0 and 2018.3.0 Unity doesn't seem to set the correct sRGBWrite state and keeps it as false
  364. #if (UNITY_2018_1_OR_NEWER && !UNITY_2018_3_OR_NEWER)
  365. bool sRGBWritePrev = GL.sRGBWrite;
  366. GL.sRGBWrite = _cubeTarget.sRGB;
  367. #endif
  368. // In Direct3D the RT can be flipped vertically
  369. /*if (source.texelSize.y < 0)
  370. {
  371. }*/
  372. //_cubeCamera.transform.position = _camera.transform.position;
  373. //_cubeCamera.transform.rotation = _camera.transform.rotation;
  374. Camera camera = _camera;
  375. Rect prevRect = camera.rect;
  376. camera.rect = new Rect(0f, 0f, 1f, 1f); // NOTE: the Scene View camera will change it's rect when being interacted with, so we need to make sure it's overridden
  377. CubemapRenderMethod cubemapRenderMethod = GetCubemapRenderingMethod();
  378. if (_stereoRendering == StereoPacking.None)
  379. {
  380. if (cubemapRenderMethod == CubemapRenderMethod.Unity)
  381. {
  382. #if AVPRO_MOVIECAPTURE_UNITYBUG_RENDERTOCUBEMAP_56
  383. RenderTexture prev = camera.targetTexture;
  384. #endif
  385. // Note: Camera.RenderToCubemap() doesn't support camera rotation
  386. camera.RenderToCubemap(_cubeTarget, 63);
  387. #if AVPRO_MOVIECAPTURE_UNITYBUG_RENDERTOCUBEMAP_56
  388. // NOTE: We need this to clean up the state in at least Unity 5.6.0 - 5.6.1p1
  389. camera.targetTexture = prev;
  390. #endif
  391. }
  392. #if AVPRO_MOVIECAPTURE_UNITY_STEREOCUBEMAP_RENDER
  393. else if (cubemapRenderMethod == CubemapRenderMethod.Unity2018)
  394. {
  395. // Note: If we use Mono instead of Left then rotation isn't supported
  396. if (this.transform.rotation == Quaternion.identity)
  397. {
  398. camera.RenderToCubemap(_cubeTarget, 63, Camera.MonoOrStereoscopicEye.Mono);
  399. }
  400. else
  401. {
  402. camera.stereoSeparation = 0f;
  403. camera.RenderToCubemap(_cubeTarget, 63, Camera.MonoOrStereoscopicEye.Left);
  404. }
  405. }
  406. #endif
  407. else if (cubemapRenderMethod == CubemapRenderMethod.Manual)
  408. {
  409. RenderCameraToCubemap(camera, _cubeTarget);
  410. }
  411. RenderCubemapToEquiRect(_cubeTarget, _finalTarget, false, Quaternion.identity, true);
  412. }
  413. else
  414. {
  415. #if AVPRO_MOVIECAPTURE_UNITY_STEREOCUBEMAP_RENDER
  416. if (cubemapRenderMethod == CubemapRenderMethod.Unity2018)
  417. {
  418. //Left eye
  419. camera.stereoSeparation = _ipd;
  420. camera.RenderToCubemap(_cubeTarget, 63, Camera.MonoOrStereoscopicEye.Left);
  421. RenderCubemapToEquiRect(_cubeTarget, _finalTarget, false, camera.transform.rotation, true);
  422. // Right eye
  423. _cubeTarget.DiscardContents();
  424. camera.RenderToCubemap(_cubeTarget, 63, Camera.MonoOrStereoscopicEye.Right);
  425. RenderCubemapToEquiRect(_cubeTarget, _finalTarget, false, camera.transform.rotation, false);
  426. } else
  427. #endif
  428. if (cubemapRenderMethod == CubemapRenderMethod.Manual)
  429. {
  430. // Save camera state
  431. Vector3 cameraPosition = camera.transform.localPosition;
  432. // Left eye
  433. camera.transform.Translate(new Vector3(-_ipd / 2f, 0f, 0f), Space.Self);
  434. RenderCameraToCubemap(camera, _cubeTarget);
  435. RenderCubemapToEquiRect(_cubeTarget, _finalTarget, false, Quaternion.identity, true);
  436. // Right eye
  437. camera.transform.localPosition = cameraPosition;
  438. camera.transform.Translate(new Vector3(_ipd / 2f, 0f, 0f), Space.Self);
  439. RenderCameraToCubemap(camera, _cubeTarget);
  440. RenderCubemapToEquiRect(_cubeTarget, _finalTarget, false, Quaternion.identity, false);
  441. // Restore camera state
  442. camera.transform.localPosition = cameraPosition;
  443. }
  444. }
  445. camera.rect = prevRect;
  446. #if (UNITY_2018_1_OR_NEWER && !UNITY_2018_3_OR_NEWER)
  447. GL.sRGBWrite = sRGBWritePrev;
  448. #endif
  449. }
  450. private void RenderCameraToCubemap(Camera camera, RenderTexture cubemapTarget)
  451. {
  452. RenderTexture prevRT = RenderTexture.active;
  453. // Cache old camera values
  454. float prevFieldOfView = camera.fieldOfView;
  455. RenderTexture prevtarget = camera.targetTexture;
  456. Quaternion prevRotation = camera.transform.rotation;
  457. // Ignore the camera rotation
  458. Quaternion xform = camera.transform.rotation;
  459. if (!_supportCameraRotation)
  460. {
  461. xform = Quaternion.identity;
  462. }
  463. else if (_onlyLeftRightRotation)
  464. {
  465. xform = Quaternion.Euler(0f, camera.transform.eulerAngles.y, 0f);
  466. }
  467. if (_blendOverlapPercent > 0.0f)
  468. {
  469. // Adjust FOV for overlap percentage (each each)
  470. camera.fieldOfView = (Mathf.Atan(1.0f + (_blendOverlapPercent * 0.01f)) * 2.0f * Mathf.Rad2Deg);
  471. // RJT TODO: LUT/loop
  472. // Left
  473. camera.transform.rotation = xform * Quaternion.LookRotation(Vector3.right, Vector3.down);
  474. camera.targetTexture = _faceTargets[0];
  475. camera.Render();
  476. // Right
  477. camera.transform.rotation = xform * Quaternion.LookRotation(Vector3.left, Vector3.down);
  478. camera.targetTexture = _faceTargets[1];
  479. camera.Render();
  480. // Up
  481. camera.transform.rotation = xform * Quaternion.LookRotation(Vector3.up, Vector3.forward);
  482. camera.targetTexture = _faceTargets[2];
  483. camera.Render();
  484. // Down
  485. camera.transform.rotation = xform * Quaternion.LookRotation(Vector3.down, Vector3.back);
  486. camera.targetTexture = _faceTargets[3];
  487. camera.Render();
  488. // Front
  489. camera.transform.rotation = xform * Quaternion.LookRotation(Vector3.forward, Vector3.down);
  490. camera.targetTexture = _faceTargets[4];
  491. camera.Render();
  492. // Back
  493. camera.transform.rotation = xform * Quaternion.LookRotation(Vector3.back, Vector3.down);
  494. camera.targetTexture = _faceTargets[5];
  495. camera.Render();
  496. }
  497. else
  498. {
  499. // NOTE: There is a bug in Unity 2017.1.0f3 to at least 2017.2beta7 which causes deferred rendering mode to always clear the cubemap target to white
  500. camera.fieldOfView = 90f;
  501. camera.targetTexture = _faceTarget;
  502. // Front
  503. camera.transform.rotation = xform * Quaternion.LookRotation(Vector3.forward, Vector3.down);
  504. _faceTarget.DiscardContents();
  505. camera.Render();
  506. Graphics.SetRenderTarget(cubemapTarget, 0, CubemapFace.PositiveZ);
  507. Graphics.Blit(_faceTarget, _blitMaterial);
  508. // Back
  509. camera.transform.rotation = xform * Quaternion.LookRotation(Vector3.back, Vector3.down);
  510. _faceTarget.DiscardContents();
  511. camera.Render();
  512. Graphics.SetRenderTarget(cubemapTarget, 0, CubemapFace.NegativeZ);
  513. Graphics.Blit(_faceTarget, _blitMaterial);
  514. // Right
  515. camera.transform.rotation = xform * Quaternion.LookRotation(Vector3.right, Vector3.down);
  516. _faceTarget.DiscardContents();
  517. camera.Render();
  518. Graphics.SetRenderTarget(cubemapTarget, 0, CubemapFace.NegativeX);
  519. Graphics.Blit(_faceTarget, _blitMaterial);
  520. // Left
  521. camera.transform.rotation = xform * Quaternion.LookRotation(Vector3.left, Vector3.down);
  522. _faceTarget.DiscardContents();
  523. camera.Render();
  524. Graphics.SetRenderTarget(cubemapTarget, 0, CubemapFace.PositiveX);
  525. Graphics.Blit(_faceTarget, _blitMaterial);
  526. // Up
  527. camera.transform.rotation = xform * Quaternion.LookRotation(Vector3.up, Vector3.forward);
  528. _faceTarget.DiscardContents();
  529. camera.Render();
  530. Graphics.SetRenderTarget(cubemapTarget, 0, CubemapFace.PositiveY);
  531. Graphics.Blit(_faceTarget, _blitMaterial);
  532. // Down
  533. camera.transform.rotation = xform * Quaternion.LookRotation(Vector3.down, Vector3.back);
  534. _faceTarget.DiscardContents();
  535. camera.Render();
  536. Graphics.SetRenderTarget(cubemapTarget, 0, CubemapFace.NegativeY);
  537. Graphics.Blit(_faceTarget, _blitMaterial);
  538. Graphics.SetRenderTarget(prevRT);
  539. }
  540. // Restore camera values
  541. camera.transform.rotation = prevRotation;
  542. camera.fieldOfView = prevFieldOfView;
  543. camera.targetTexture = prevtarget;
  544. }
  545. private void AccumulateMotionBlur()
  546. {
  547. if (_motionBlur != null)
  548. {
  549. if (_capturing && !_paused)
  550. {
  551. if (_camera != null && _handle >= 0)
  552. {
  553. UpdateTexture();
  554. _motionBlur.Accumulate(_finalTarget);
  555. }
  556. }
  557. }
  558. }
  559. public override bool PrepareCapture()
  560. {
  561. if (_capturing)
  562. {
  563. return false;
  564. }
  565. #if UNITY_EDITOR_WIN || (!UNITY_EDITOR && UNITY_STANDALONE_WIN)
  566. if (SystemInfo.graphicsDeviceVersion.StartsWith("Direct3D 9"))
  567. {
  568. Debug.LogError("[AVProMovieCapture] Direct3D9 not yet supported, please use Direct3D11 instead.");
  569. return false;
  570. }
  571. else if (SystemInfo.graphicsDeviceVersion.StartsWith("OpenGL") && !SystemInfo.graphicsDeviceVersion.Contains("emulated"))
  572. {
  573. Debug.LogError("[AVProMovieCapture] OpenGL not yet supported for CaptureFromCamera360 component, please use Direct3D11 instead. You may need to switch your build platform to Windows.");
  574. return false;
  575. }
  576. #endif
  577. // Check cubemap resolution support
  578. int cubemapResolution = (int)_cubemapResolution;
  579. if (_blendOverlapPercent > 0.0f)
  580. {
  581. // Adjust resolution for overlap percentage (each edge)
  582. cubemapResolution = (int)(((float)cubemapResolution * (1.0f + ((_blendOverlapPercent * 0.01f) * 2.0f))) + 0.5f);
  583. }
  584. if (cubemapResolution > SystemInfo.maxCubemapSize)
  585. {
  586. cubemapResolution = SystemInfo.maxCubemapSize;
  587. Debug.LogWarning("[AVProMovieCapture] Reducing cubemap size to system max: " + cubemapResolution);
  588. }
  589. // Setup material
  590. _pixelFormat = NativePlugin.PixelFormat.RGBA32;
  591. _isTopDown = true;
  592. if (_cameraSelector != null)
  593. {
  594. //if (_camera != _cameraSelector.Camera)
  595. {
  596. SetCamera(_cameraSelector.Camera);
  597. }
  598. }
  599. if (_camera == null)
  600. {
  601. SetCamera(this.GetComponent<Camera>());
  602. }
  603. if (_camera == null)
  604. {
  605. Debug.LogError("[AVProMovieCapture] No camera assigned to CaptureFromCamera360");
  606. return false;
  607. }
  608. // Resolution
  609. int finalWidth = Mathf.FloorToInt(_camera.pixelRect.width);
  610. int finalHeight = Mathf.FloorToInt(_camera.pixelRect.height);
  611. if (_renderResolution == Resolution.Custom)
  612. {
  613. finalWidth = (int)_renderSize.x;
  614. finalHeight = (int)_renderSize.y;
  615. }
  616. else if (_renderResolution != Resolution.Original)
  617. {
  618. GetResolution(_renderResolution, ref finalWidth, ref finalHeight);
  619. }
  620. // Setup rendering a different render target if we're overriding resolution or anti-aliasing
  621. //if (_renderResolution != Resolution.Original || _renderAntiAliasing != QualitySettings.antiAliasing)
  622. {
  623. int aaLevel = GetCameraAntiAliasingLevel(_camera);
  624. CubemapRenderMethod cubemapRenderMethod = GetCubemapRenderingMethod();
  625. Debug.Log("[AVProMovieCapture] Using cubemap render method: " + cubemapRenderMethod.ToString());
  626. // Create the final render target
  627. _targetNativePointer = System.IntPtr.Zero;
  628. if (_finalTarget != null)
  629. {
  630. _finalTarget.DiscardContents();
  631. if (_finalTarget.width != finalWidth || _finalTarget.height != finalHeight)
  632. {
  633. RenderTexture.ReleaseTemporary(_finalTarget);
  634. _finalTarget = null;
  635. }
  636. }
  637. if (_finalTarget == null)
  638. {
  639. _finalTarget = RenderTexture.GetTemporary(finalWidth, finalHeight, 0, RenderTextureFormat.Default, RenderTextureReadWrite.Default, 1);
  640. _finalTarget.name = "[AVProMovieCapture] 360 Final Target";
  641. }
  642. // Create the per-face render target (only when need to support GUI rendering)
  643. if (_faceTarget != null)
  644. {
  645. _faceTarget.DiscardContents();
  646. if (_faceTarget.width != (int)cubemapResolution ||
  647. _faceTarget.height != (int)cubemapResolution ||
  648. _faceTarget.depth != (int)_cubemapDepth ||
  649. _faceTarget.antiAliasing != aaLevel)
  650. {
  651. RenderTexture.Destroy(_faceTarget);
  652. _faceTarget = null;
  653. }
  654. }
  655. if (_faceTargets[0] != null)
  656. {
  657. for (int i = 0; i < 6; ++i )
  658. {
  659. _faceTargets[i].DiscardContents();
  660. }
  661. if (_faceTargets[0].width != cubemapResolution ||
  662. _faceTargets[0].height != cubemapResolution ||
  663. _faceTargets[0].depth != (int)_cubemapDepth ||
  664. _faceTargets[0].antiAliasing != aaLevel)
  665. {
  666. for (int i = 0; i < 6; ++i )
  667. {
  668. RenderTexture.Destroy(_faceTargets[i]);
  669. _faceTargets[i] = null;
  670. }
  671. }
  672. }
  673. RenderTextureFormat renderTextureFormat = RenderTextureFormat.Default;
  674. #if USING_URP
  675. renderTextureFormat = RenderTextureFormat.ARGBHalf;//ARGBFloat;
  676. #endif
  677. if (cubemapRenderMethod == CubemapRenderMethod.Manual)
  678. {
  679. if ((_blendOverlapPercent > 0.0f) && (_faceTargets[0] == null))
  680. {
  681. for (int i = 0; i < 6; ++i )
  682. {
  683. _faceTargets[i] = new RenderTexture(cubemapResolution, cubemapResolution, (int)_cubemapDepth, renderTextureFormat, RenderTextureReadWrite.Default);
  684. _faceTargets[i].name = "[AVProMovieCapture] 360 Face Target";
  685. _faceTargets[i].isPowerOfTwo = Mathf.IsPowerOfTwo(cubemapResolution);
  686. _faceTargets[i].wrapMode = TextureWrapMode.Clamp;
  687. _faceTargets[i].filterMode = FilterMode.Bilinear;
  688. _faceTargets[i].autoGenerateMips = false;
  689. _faceTargets[i].antiAliasing = aaLevel;
  690. }
  691. }
  692. else if (_faceTarget == null)
  693. {
  694. _faceTarget = new RenderTexture((int)cubemapResolution, (int)cubemapResolution, (int)_cubemapDepth, RenderTextureFormat.Default, RenderTextureReadWrite.Default);
  695. _faceTarget.name = "[AVProMovieCapture] 360 Face Target";
  696. _faceTarget.isPowerOfTwo = true;
  697. _faceTarget.wrapMode = TextureWrapMode.Clamp;
  698. _faceTarget.filterMode = FilterMode.Bilinear;
  699. _faceTarget.autoGenerateMips = false;
  700. _faceTarget.antiAliasing = aaLevel;
  701. }
  702. _cubemapToEquirectangularMaterial.SetFloat(_propFlipX, 0.0f);
  703. }
  704. else
  705. {
  706. // Unity's RenderToCubemap result needs flipping
  707. _cubemapToEquirectangularMaterial.SetFloat(_propFlipX, 1.0f);
  708. }
  709. _cubemapToEquirectangularMaterial.DisableKeyword("USE_ROTATION");
  710. _cubemapToEquirectangularMaterial.DisableKeyword("STEREOPACK_TOP");
  711. _cubemapToEquirectangularMaterial.DisableKeyword("STEREOPACK_BOTTOM");
  712. _cubemapToEquirectangularMaterial.DisableKeyword("STEREOPACK_LEFT");
  713. _cubemapToEquirectangularMaterial.DisableKeyword("STEREOPACK_RIGHT");
  714. if (_render180Degrees)
  715. {
  716. _cubemapToEquirectangularMaterial.DisableKeyword("LAYOUT_EQUIRECT360");
  717. _cubemapToEquirectangularMaterial.EnableKeyword("LAYOUT_EQUIRECT180");
  718. }
  719. else
  720. {
  721. _cubemapToEquirectangularMaterial.DisableKeyword("LAYOUT_EQUIRECT180");
  722. _cubemapToEquirectangularMaterial.EnableKeyword("LAYOUT_EQUIRECT360");
  723. }
  724. if (_blendOverlapPercent == 0.0f)
  725. {
  726. // Create the cube render target
  727. int cubeDepth = 0;
  728. if (cubemapRenderMethod != CubemapRenderMethod.Manual)
  729. {
  730. cubeDepth = (int)_cubemapDepth;
  731. }
  732. int cubeAA = 1;
  733. if (cubemapRenderMethod != CubemapRenderMethod.Manual)
  734. {
  735. cubeAA = aaLevel;
  736. }
  737. if (_cubeTarget != null)
  738. {
  739. _cubeTarget.DiscardContents();
  740. if (_cubeTarget.width != cubemapResolution ||
  741. _cubeTarget.height != cubemapResolution ||
  742. _cubeTarget.depth != cubeDepth ||
  743. _cubeTarget.antiAliasing != cubeAA)
  744. {
  745. RenderTexture.Destroy(_cubeTarget);
  746. _cubeTarget = null;
  747. }
  748. }
  749. if (_cubeTarget == null)
  750. {
  751. _cubeTarget = new RenderTexture(cubemapResolution, cubemapResolution, cubeDepth, renderTextureFormat, RenderTextureReadWrite.Default);
  752. _cubeTarget.name = "[AVProMovieCapture] 360 Cube Target";
  753. _cubeTarget.isPowerOfTwo = true;
  754. _cubeTarget.dimension = UnityEngine.Rendering.TextureDimension.Cube;
  755. _cubeTarget.useMipMap = false;
  756. _cubeTarget.autoGenerateMips = false;
  757. _cubeTarget.antiAliasing = cubeAA;
  758. _cubeTarget.wrapMode = TextureWrapMode.Clamp;
  759. _cubeTarget.filterMode = FilterMode.Bilinear;
  760. }
  761. }
  762. if (_useMotionBlur)
  763. {
  764. _motionBlurCameras = new Camera[1];
  765. _motionBlurCameras[0] = _camera;
  766. }
  767. }
  768. _Transparency = Transparency.None;
  769. if ( !NativePlugin.IsBasicEdition() )
  770. {
  771. if( (_outputTarget == OutputTarget.VideoFile || _outputTarget == OutputTarget.NamedPipe) && GetEncoderHints().videoHints.transparency != Transparency.None )
  772. {
  773. _Transparency = GetEncoderHints().videoHints.transparency;
  774. }
  775. else if( _outputTarget == OutputTarget.ImageSequence && GetEncoderHints().imageHints.transparency != Transparency.None )
  776. {
  777. _Transparency = GetEncoderHints().imageHints.transparency;
  778. }
  779. //
  780. if( _Transparency == Transparency.TopBottom || _Transparency == Transparency.LeftRight )
  781. {
  782. InitialiseSideBySideTransparency( finalWidth, finalHeight );
  783. }
  784. switch ( _Transparency )
  785. {
  786. case Transparency.TopBottom: finalHeight *= 2; break;
  787. case Transparency.LeftRight: finalWidth *= 2; break;
  788. }
  789. }
  790. SelectRecordingResolution(finalWidth, finalHeight);
  791. GenerateFilename();
  792. if (base.PrepareCapture())
  793. {
  794. UpdateInjectionOptions(_stereoRendering, _render180Degrees?SphericalVideoLayout.Equirectangular180:SphericalVideoLayout.Equirectangular360);
  795. return true;
  796. }
  797. return false;
  798. }
  799. public override Texture GetPreviewTexture()
  800. {
  801. if (IsUsingMotionBlur())
  802. {
  803. return _motionBlur.FinalTexture;
  804. }
  805. return _finalTarget;
  806. }
  807. public override void Start()
  808. {
  809. Shader shader = Resources.Load<Shader>("CubemapToEquirectangular");
  810. if (shader != null)
  811. {
  812. _cubemapToEquirectangularMaterial = new Material(shader);
  813. }
  814. else
  815. {
  816. Debug.LogError("[AVProMovieCapture] Can't find CubemapToEquirectangular shader");
  817. }
  818. Shader blitShader = Shader.Find("Hidden/BlitCopy");
  819. if (blitShader != null)
  820. {
  821. _blitMaterial = new Material(blitShader);
  822. }
  823. else
  824. {
  825. Debug.LogError("[AVProMovieCapture] Can't find Hidden/BlitCopy shader");
  826. }
  827. _propFlipX = Shader.PropertyToID("_FlipX");
  828. #if SUPPORT_SHADER_ROTATION
  829. _propRotation = Shader.PropertyToID("_RotationMatrix");
  830. #endif
  831. base.Start();
  832. }
  833. public override void OnDestroy()
  834. {
  835. _targetNativePointer = System.IntPtr.Zero;
  836. if (_blitMaterial != null)
  837. {
  838. Material.Destroy(_blitMaterial);
  839. _blitMaterial = null;
  840. }
  841. if (_faceTarget != null)
  842. {
  843. RenderTexture.Destroy(_faceTarget);
  844. _faceTarget = null;
  845. }
  846. if (_faceTargets[0] != null)
  847. {
  848. for (int i = 0; i < 6; ++i)
  849. {
  850. RenderTexture.Destroy(_faceTargets[i]);
  851. _faceTargets[i] = null;
  852. }
  853. }
  854. if (_cubeTarget != null)
  855. {
  856. RenderTexture.Destroy(_cubeTarget);
  857. _cubeTarget = null;
  858. }
  859. if (_finalTarget != null)
  860. {
  861. RenderTexture.ReleaseTemporary(_finalTarget);
  862. _finalTarget = null;
  863. }
  864. base.OnDestroy();
  865. }
  866. }
  867. }