CaptureFromCamera.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384
  1. #if UNITY_5_4_OR_NEWER || UNITY_5
  2. #define AVPRO_MOVIECAPTURE_DEFERREDSHADING
  3. #endif
  4. using UnityEngine;
  5. //-----------------------------------------------------------------------------
  6. // Copyright 2012-2017 RenderHeads Ltd. All rights reserved.
  7. //-----------------------------------------------------------------------------
  8. namespace RenderHeads.Media.AVProMovieCapture
  9. {
  10. /// <summary>
  11. /// Capture from a specific Unity camera. This component re-renders the camera manually, so it does add extra draw calls.
  12. /// </summary>
  13. //[RequireComponent(typeof(Camera))]
  14. [AddComponentMenu("AVPro Movie Capture/Capture From Camera", 1)]
  15. public class CaptureFromCamera : CaptureBase
  16. {
  17. [SerializeField]
  18. private Camera _lastCamera;
  19. [SerializeField]
  20. private Camera[] _contribCameras;
  21. [SerializeField]
  22. private bool _useContributingCameras = true;
  23. private RenderTexture _target;
  24. private System.IntPtr _targetNativePointer = System.IntPtr.Zero;
  25. public bool UseContributingCameras
  26. {
  27. get { return _useContributingCameras; }
  28. set { _useContributingCameras = value; }
  29. }
  30. public void SetCamera(Camera mainCamera, bool useContributingCameras = true)
  31. {
  32. _lastCamera = mainCamera;
  33. _contribCameras = null;
  34. _useContributingCameras = useContributingCameras;
  35. if (_useContributingCameras && _lastCamera != null)
  36. {
  37. if (Utils.HasContributingCameras(_lastCamera))
  38. {
  39. _contribCameras = Utils.FindContributingCameras(mainCamera);
  40. }
  41. }
  42. }
  43. public void SetCamera(Camera mainCamera, Camera[] contributingCameras)
  44. {
  45. _lastCamera = mainCamera;
  46. _contribCameras = contributingCameras;
  47. }
  48. private bool HasCamera()
  49. {
  50. return (_lastCamera != null);
  51. }
  52. private bool HasContributingCameras()
  53. {
  54. return (_useContributingCameras && _contribCameras != null && _contribCameras.Length > 0);
  55. }
  56. // If we're forcing a resolution or AA change then we have to render the camera again to the new target
  57. // If we try to just set the targetTexture of the camera and grab it in OnRenderImage we can't render it to the screen as before :(
  58. public override void UpdateFrame()
  59. {
  60. TickFrameTimer();
  61. if (_capturing && !_paused && HasCamera())
  62. {
  63. bool canGrab = true;
  64. if (IsUsingMotionBlur())
  65. {
  66. // If the motion blur is still accumulating, don't grab this frame
  67. canGrab = _motionBlur.IsFrameAccumulated;
  68. }
  69. if (canGrab)
  70. {
  71. /*while (_handle >= 0 && !AVProMovieCapturePlugin.IsNewFrameDue(_handle))
  72. {
  73. System.Threading.Thread.Sleep(1);
  74. }*/
  75. if (_handle >= 0 && CanOutputFrame())
  76. {
  77. // Render the camera(s)
  78. if (!IsUsingMotionBlur())
  79. {
  80. // Render a single camera
  81. if (!HasContributingCameras())
  82. {
  83. RenderTexture prev = _lastCamera.targetTexture;
  84. // Reset the viewport rect as we're rendering to a texture captures the full viewport
  85. Rect prevRect = _lastCamera.rect;
  86. CameraClearFlags prevClear = _lastCamera.clearFlags;
  87. Color prevColor = _lastCamera.backgroundColor;
  88. bool clearChanged = false;
  89. if (_lastCamera.clearFlags == CameraClearFlags.Nothing || _lastCamera.clearFlags == CameraClearFlags.Depth)
  90. {
  91. clearChanged = true;
  92. _lastCamera.clearFlags = CameraClearFlags.SolidColor;
  93. if (!_supportAlpha)
  94. {
  95. _lastCamera.backgroundColor = Color.black;
  96. }
  97. else
  98. {
  99. _lastCamera.backgroundColor = new Color(0f, 0f, 0f, 0f);
  100. }
  101. }
  102. // Render
  103. _lastCamera.rect = new Rect(0f, 0f, 1f, 1f);
  104. _lastCamera.targetTexture = _target;
  105. _lastCamera.Render();
  106. // Restore camera
  107. {
  108. _lastCamera.rect = prevRect;
  109. if (clearChanged)
  110. {
  111. _lastCamera.clearFlags = prevClear;
  112. _lastCamera.backgroundColor = prevColor;
  113. }
  114. _lastCamera.targetTexture = prev;
  115. }
  116. }
  117. // Render the camera chain
  118. else
  119. {
  120. // First render contributing cameras
  121. for (int cameraIndex = 0; cameraIndex < _contribCameras.Length; cameraIndex++)
  122. {
  123. Camera camera = _contribCameras[cameraIndex];
  124. if (camera != null)
  125. {
  126. RenderTexture prev = camera.targetTexture;
  127. camera.targetTexture = _target;
  128. camera.Render();
  129. camera.targetTexture = prev;
  130. }
  131. }
  132. // Finally render the last camera
  133. if (_lastCamera != null)
  134. {
  135. RenderTexture prev = _lastCamera.targetTexture;
  136. _lastCamera.targetTexture = _target;
  137. _lastCamera.Render();
  138. _lastCamera.targetTexture = prev;
  139. }
  140. }
  141. }
  142. else
  143. {
  144. // Just grab the last result of the motion blur
  145. Graphics.Blit(_motionBlur.FinalTexture, _target);
  146. }
  147. if (_supportTextureRecreate)
  148. {
  149. // NOTE: If support for captures to survive through alt-tab events, or window resizes where the GPU resources are recreated
  150. // is required, then this line is needed. It is very expensive though as it does a sync with the rendering thread.
  151. _targetNativePointer = _target.GetNativeTexturePtr();
  152. }
  153. NativePlugin.SetTexturePointer(_handle, _targetNativePointer);
  154. RenderThreadEvent(NativePlugin.PluginEvent.CaptureFrameBuffer);
  155. if (IsRecordingUnityAudio())
  156. {
  157. int audioDataLength = 0;
  158. System.IntPtr audioDataPtr = _audioCapture.ReadData(out audioDataLength);
  159. if (audioDataLength > 0)
  160. {
  161. NativePlugin.EncodeAudio(_handle, audioDataPtr, (uint)audioDataLength);
  162. }
  163. }
  164. UpdateFPS();
  165. }
  166. }
  167. }
  168. base.UpdateFrame();
  169. RenormTimer();
  170. }
  171. #if false
  172. // NOTE: This is old code based on OnRenderImage...may be revived at some point
  173. private void OnRenderImage(RenderTexture source, RenderTexture dest)
  174. {
  175. if (_capturing && !_paused)
  176. {
  177. #if true
  178. while (_handle >= 0 && !NativePlugin.IsNewFrameDue(_handle))
  179. {
  180. System.Threading.Thread.Sleep(1);
  181. }
  182. if (_handle >= 0)
  183. {
  184. if (_audioCapture && _audioDeviceIndex < 0 && !_noAudio && _isRealTime)
  185. {
  186. int audioDataLength = 0;
  187. System.IntPtr audioDataPtr = _audioCapture.ReadData(out audioDataLength);
  188. if (audioDataLength > 0)
  189. {
  190. NativePlugin.EncodeAudio(_handle, audioDataPtr, (uint)audioDataLength);
  191. }
  192. }
  193. // In Direct3D the RT can be flipped vertically
  194. /*if (source.texelSize.y < 0)
  195. {
  196. }*/
  197. Graphics.Blit(source, dest);
  198. _lastSource = source;
  199. _lastDest = dest;
  200. if (dest != _originalTarget)
  201. {
  202. Graphics.Blit(dest, _originalTarget);
  203. }
  204. #if AVPRO_MOVIECAPTURE_GLISSUEEVENT_52
  205. GL.IssuePluginEvent(NativePlugin.GetRenderEventFunc(), NativePlugin.PluginID | (int)NativePlugin.PluginEvent.CaptureFrameBuffer | _handle);
  206. #else
  207. GL.IssuePluginEvent(NativePlugin.PluginID | (int)NativePlugin.PluginEvent.CaptureFrameBuffer | _handle);
  208. #endif
  209. GL.InvalidateState();
  210. UpdateFPS();
  211. return;
  212. }
  213. #endif
  214. }
  215. // Pass-through
  216. Graphics.Blit(source, dest);
  217. _lastSource = source;
  218. _lastDest = dest;
  219. }
  220. #endif
  221. public override void UnprepareCapture()
  222. {
  223. NativePlugin.SetTexturePointer(_handle, System.IntPtr.Zero);
  224. if (_target != null)
  225. {
  226. _target.DiscardContents();
  227. }
  228. base.UnprepareCapture();
  229. }
  230. public override Texture GetPreviewTexture()
  231. {
  232. return _target;
  233. }
  234. public override bool PrepareCapture()
  235. {
  236. if (_capturing)
  237. {
  238. return false;
  239. }
  240. if (SystemInfo.graphicsDeviceVersion.StartsWith("OpenGL") && !SystemInfo.graphicsDeviceVersion.Contains("emulated"))
  241. {
  242. Debug.LogError("[AVProMovieCapture] OpenGL not yet supported for CaptureFromCamera component, please use Direct3D11 instead. You may need to switch your build platform to Windows.");
  243. return false;
  244. }
  245. // Setup material
  246. _pixelFormat = NativePlugin.PixelFormat.RGBA32;
  247. _isTopDown = true;
  248. if (!HasCamera())
  249. {
  250. _lastCamera = this.GetComponent<Camera>();
  251. if (!HasCamera())
  252. {
  253. _lastCamera = Camera.main;
  254. }
  255. if (!HasCamera())
  256. {
  257. Debug.LogError("[AVProMovieCapture] No camera assigned to CaptureFromCamera");
  258. return false;
  259. }
  260. }
  261. if (!HasContributingCameras() && (_lastCamera.clearFlags == CameraClearFlags.Depth || _lastCamera.clearFlags == CameraClearFlags.Nothing))
  262. {
  263. Debug.LogWarning("[AVProMovieCapture] This camera doesn't clear, consider setting contributing cameras");
  264. }
  265. int width = Mathf.FloorToInt(_lastCamera.pixelRect.width);
  266. int height = Mathf.FloorToInt(_lastCamera.pixelRect.height);
  267. // Setup rendering a different render target if we're overriding resolution or anti-aliasing
  268. //if (_renderResolution != Resolution.Original || (_renderAntiAliasing > 0 && _renderAntiAliasing != QualitySettings.antiAliasing))
  269. {
  270. if (_renderResolution == Resolution.Custom)
  271. {
  272. width = (int)_renderSize.x;
  273. height = (int)_renderSize.y;
  274. }
  275. else if (_renderResolution != Resolution.Original)
  276. {
  277. GetResolution(_renderResolution, ref width, ref height);
  278. }
  279. int aaLevel = GetCameraAntiAliasingLevel(_lastCamera);
  280. // Create the render target
  281. if (_target != null)
  282. {
  283. _target.DiscardContents();
  284. if (_target.width != width || _target.height != height || _target.antiAliasing != aaLevel)
  285. {
  286. _targetNativePointer = System.IntPtr.Zero;
  287. RenderTexture.ReleaseTemporary(_target);
  288. _target = null;
  289. }
  290. }
  291. if (_target == null)
  292. {
  293. _target = RenderTexture.GetTemporary(width, height, 24, RenderTextureFormat.Default, RenderTextureReadWrite.Default, aaLevel);
  294. _target.name = "[AVProMovieCapture] Camera Target";
  295. _target.Create();
  296. _targetNativePointer = _target.GetNativeTexturePtr();
  297. }
  298. //camera.targetTexture = _target;
  299. // Adjust size for camera rectangle
  300. /*if (camera.rect.width < 1f || camera.rect.height < 1f)
  301. {
  302. float rectWidth = Mathf.Clamp01(camera.rect.width + camera.rect.x) - Mathf.Clamp01(camera.rect.x);
  303. float rectHeight = Mathf.Clamp01(camera.rect.height + camera.rect.y) - Mathf.Clamp01(camera.rect.y);
  304. width = Mathf.FloorToInt(width * rectWidth);
  305. height = Mathf.FloorToInt(height * rectHeight);
  306. }*/
  307. if (_useMotionBlur)
  308. {
  309. _motionBlurCameras = new Camera[1];
  310. _motionBlurCameras[0] = _lastCamera;
  311. }
  312. }
  313. SelectRecordingResolution(width, height);
  314. GenerateFilename();
  315. return base.PrepareCapture();
  316. }
  317. public override void OnDestroy()
  318. {
  319. if (_target != null)
  320. {
  321. _targetNativePointer = System.IntPtr.Zero;
  322. RenderTexture.ReleaseTemporary(_target);
  323. _target = null;
  324. }
  325. base.OnDestroy();
  326. }
  327. }
  328. }