123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585 |
- #if UNITY_5_4_OR_NEWER || (UNITY_5 && !UNITY_5_0 && !UNITY_5_1 && !UNITY_5_2 && !UNITY_5_3)
- #define AVPRO_MOVIECAPTURE_RENDERTEXTUREDIMENSIONS_54
- #endif
- #if UNITY_5_6_0 || UNITY_5_6_1
- #define AVPRO_MOVIECAPTURE_UNITYBUG_RENDERTOCUBEMAP_56
- #endif
- using UnityEngine;
- //-----------------------------------------------------------------------------
- // Copyright 2012-2017 RenderHeads Ltd. All rights reserved.
- //-----------------------------------------------------------------------------
- namespace RenderHeads.Media.AVProMovieCapture
- {
- /// <summary>
- /// Capture a camera view in 360 equi-rectangular format.
- /// The camera is rendered into a cubemap, so the scene is rendered an extra 6 times.
- /// Finally the cubemap is converted to equi-rectangular format and encoded.
- /// </summary>
- //[RequireComponent(typeof(Camera))]
- [AddComponentMenu("AVPro Movie Capture/Capture From Camera 360 (VR)", 100)]
- public class CaptureFromCamera360 : CaptureBase
- {
- // Cube map options
- [SerializeField]
- public int _cubemapResolution = 2048;
- [SerializeField]
- public int _cubemapDepth = 24;
- [SerializeField]
- public bool _supportGUI = true;
- [SerializeField]
- public bool _supportCameraRotation = true;
- [SerializeField]
- public StereoPacking _stereoRendering = StereoPacking.None;
- [SerializeField]
- [Tooltip("Makes assumption that 1 Unity unit is 1m")]
- public float _ipd = 0.064f;
- [SerializeField]
- private Camera _camera;
- // State
- private RenderTexture _faceTarget;
- private Material _blitMaterial;
- private Material _cubemapToEquirectangularMaterial;
- private RenderTexture _cubeTarget;
- private RenderTexture _finalTarget;
- private System.IntPtr _targetNativePointer = System.IntPtr.Zero;
- private int _propFlipX;
- public CaptureFromCamera360()
- {
- // Override the default values to match more common use cases for this capture component
- _renderResolution = Resolution.POW2_2048x2048;
- }
- protected bool IsManualCubemapRendering()
- {
- return (_supportGUI || _supportCameraRotation || _stereoRendering != StereoPacking.None);
- }
- public void SetCamera(Camera camera)
- {
- _camera = camera;
- }
- #if false
- private void OnRenderImage(RenderTexture source, RenderTexture dest)
- {
- #if false
- if (_capturing && !_paused)
- {
- while (_handle >= 0 && !NativePlugin.IsNewFrameDue(_handle))
- {
- System.Threading.Thread.Sleep(1);
- }
- if (_handle >= 0)
- {
- if (_audioCapture && _audioDeviceIndex < 0 && !_noAudio)
- {
- uint bufferLength = (uint)_audioCapture.BufferLength;
- if (bufferLength > 0)
- {
- NativePlugin.EncodeAudio(_handle, _audioCapture.BufferPtr, bufferLength);
- _audioCapture.FlushBuffer();
- }
- }
- // In Direct3D the RT can be flipped vertically
- /*if (source.texelSize.y < 0)
- {
- }*/
- Graphics.Blit(_cubeTarget, _target, _cubemapToEquirectangularMaterial);
- RenderThreadEvent(NativePlugin.PluginEvent.CaptureFrameBuffer);
- GL.InvalidateState();
-
- UpdateFPS();
- }
- }
- #endif
- // Pass-through
- if (_cubeTarget != null)
- {
- Graphics.Blit(_cubeTarget, dest, _cubemapToEquirectangularMaterial);
- }
- else
- {
- Graphics.Blit(source, dest);
- }
- }
- #endif
- public override void UpdateFrame()
- {
- TickFrameTimer();
- if (_capturing && !_paused)
- {
- if (_cubeTarget != null && _camera != null)
- {
- bool canGrab = true;
- if (IsUsingMotionBlur())
- {
- // TODO: fix motion blur
- //this._motionBlur.RenderImage()
- // If the motion blur is still accumulating, don't grab this frame
- canGrab = _motionBlur.IsFrameAccumulated;
- }
- if (canGrab && CanOutputFrame())
- {
- if (IsRecordingUnityAudio())
- {
- int audioDataLength = 0;
- System.IntPtr audioDataPtr = _audioCapture.ReadData(out audioDataLength);
- if (audioDataLength > 0)
- {
- NativePlugin.EncodeAudio(_handle, audioDataPtr, (uint)audioDataLength);
- }
- }
- RenderTexture finalTexture = _finalTarget;
- if (!IsUsingMotionBlur())
- {
- UpdateTexture();
- }
- else
- {
- finalTexture = _motionBlur.FinalTexture;
- }
- if (_targetNativePointer == System.IntPtr.Zero || _supportTextureRecreate)
- {
- // NOTE: If support for captures to survive through alt-tab events, or window resizes where the GPU resources are recreated
- // is required, then this line is needed. It is very expensive though as it does a sync with the rendering thread.
- _targetNativePointer = finalTexture.GetNativeTexturePtr();
- }
- NativePlugin.SetTexturePointer(_handle, _targetNativePointer);
- RenderThreadEvent(NativePlugin.PluginEvent.CaptureFrameBuffer);
- GL.InvalidateState();
- UpdateFPS();
- }
- }
- }
- base.UpdateFrame();
- RenormTimer();
- }
- private static void ClearCubemap(RenderTexture texture, Color color)
- {
- // TODO: Find a better way to do this?
- bool clearDepth = (texture.depth != 0);
- Graphics.SetRenderTarget(texture, 0, CubemapFace.PositiveX);
- GL.Clear(true, clearDepth, color);
- Graphics.SetRenderTarget(texture, 0, CubemapFace.PositiveY);
- GL.Clear(true, clearDepth, color);
- Graphics.SetRenderTarget(texture, 0, CubemapFace.PositiveZ);
- GL.Clear(true, clearDepth, color);
- Graphics.SetRenderTarget(texture, 0, CubemapFace.NegativeX);
- GL.Clear(true, clearDepth, color);
- Graphics.SetRenderTarget(texture, 0, CubemapFace.NegativeY);
- GL.Clear(true, clearDepth, color);
- Graphics.SetRenderTarget(texture, 0, CubemapFace.NegativeZ);
- GL.Clear(true, clearDepth, color);
- Graphics.SetRenderTarget(null);
- }
- private void UpdateTexture()
- {
- // In Direct3D the RT can be flipped vertically
- /*if (source.texelSize.y < 0)
- {
- }*/
- //_cubeCamera.transform.position = _camera.transform.position;
- //_cubeCamera.transform.rotation = _camera.transform.rotation;
- Camera camera = _camera;
- _cubeTarget.DiscardContents();
- if (_stereoRendering == StereoPacking.None)
- {
- if (!IsManualCubemapRendering())
- {
- #if AVPRO_MOVIECAPTURE_UNITYBUG_RENDERTOCUBEMAP_56
- RenderTexture prev = camera.targetTexture;
- #endif
- // Note: Camera.RenderToCubemap() doesn't support camera rotation
- camera.RenderToCubemap(_cubeTarget, 63);
- #if AVPRO_MOVIECAPTURE_UNITYBUG_RENDERTOCUBEMAP_56
- // NOTE: We need this to clean up the state in at least Unity 5.6.0 - 5.6.1p1
- camera.targetTexture = prev;
- #endif
- }
- else
- {
- RenderCameraToCubemap(camera, _cubeTarget);
- }
- _finalTarget.DiscardContents();
- Graphics.Blit(_cubeTarget, _finalTarget, _cubemapToEquirectangularMaterial);
- }
- else
- {
- // Save camera state
- Vector3 cameraPosition = camera.transform.localPosition;
- //Left eye
- camera.transform.Translate(new Vector3(-_ipd / 2f, 0f, 0f), Space.Self);
- RenderCameraToCubemap(camera, _cubeTarget);
- if (_stereoRendering == StereoPacking.TopBottom)
- {
- _cubemapToEquirectangularMaterial.DisableKeyword("STEREOPACK_BOTTOM");
- _cubemapToEquirectangularMaterial.EnableKeyword("STEREOPACK_TOP");
- }
- else if (_stereoRendering == StereoPacking.LeftRight)
- {
- _cubemapToEquirectangularMaterial.DisableKeyword("STEREOPACK_RIGHT");
- _cubemapToEquirectangularMaterial.EnableKeyword("STEREOPACK_LEFT");
- }
- _finalTarget.DiscardContents();
- Graphics.Blit(_cubeTarget, _finalTarget, _cubemapToEquirectangularMaterial);
- // Right eye
- camera.transform.localPosition = cameraPosition;
- camera.transform.Translate(new Vector3(_ipd / 2f, 0f, 0f), Space.Self);
- _cubeTarget.DiscardContents();
- RenderCameraToCubemap(camera, _cubeTarget);
- if (_stereoRendering == StereoPacking.TopBottom)
- {
- _cubemapToEquirectangularMaterial.DisableKeyword("STEREOPACK_TOP");
- _cubemapToEquirectangularMaterial.EnableKeyword("STEREOPACK_BOTTOM");
- }
- else if (_stereoRendering == StereoPacking.LeftRight)
- {
- _cubemapToEquirectangularMaterial.DisableKeyword("STEREOPACK_LEFT");
- _cubemapToEquirectangularMaterial.EnableKeyword("STEREOPACK_RIGHT");
- }
- _finalTarget.DiscardContents();
- Graphics.Blit(_cubeTarget, _finalTarget, _cubemapToEquirectangularMaterial);
- // Restore camera state
- camera.transform.localPosition = cameraPosition;
- }
- }
- private void RenderCameraToCubemap(Camera camera, RenderTexture cubemapTarget)
- {
- // Cache old camera values
- float prevFieldOfView = camera.fieldOfView;
- RenderTexture prevtarget = camera.targetTexture;
- Quaternion prevRotation = camera.transform.rotation;
- // Ignore the camera rotation
- Quaternion xform = camera.transform.rotation;
- if (!_supportCameraRotation)
- {
- xform = Quaternion.identity;
- }
- // 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
- camera.targetTexture = _faceTarget;
- camera.fieldOfView = 90f;
- camera.transform.rotation = xform * Quaternion.LookRotation(Vector3.forward, Vector3.down);
- _faceTarget.DiscardContents();
- camera.Render();
- Graphics.SetRenderTarget(cubemapTarget, 0, CubemapFace.PositiveZ);
- Graphics.Blit(_faceTarget, _blitMaterial);
- camera.transform.rotation = xform * Quaternion.LookRotation(Vector3.back, Vector3.down);
- _faceTarget.DiscardContents();
- camera.Render();
- Graphics.SetRenderTarget(cubemapTarget, 0, CubemapFace.NegativeZ);
- Graphics.Blit(_faceTarget, _blitMaterial);
- camera.transform.rotation = xform * Quaternion.LookRotation(Vector3.right, Vector3.down);
- _faceTarget.DiscardContents();
- camera.Render();
- Graphics.SetRenderTarget(cubemapTarget, 0, CubemapFace.NegativeX);
- Graphics.Blit(_faceTarget, _blitMaterial);
- camera.transform.rotation = xform * Quaternion.LookRotation(Vector3.left, Vector3.down);
- _faceTarget.DiscardContents();
- camera.Render();
- Graphics.SetRenderTarget(cubemapTarget, 0, CubemapFace.PositiveX);
- Graphics.Blit(_faceTarget, _blitMaterial);
- camera.transform.rotation = xform * Quaternion.LookRotation(Vector3.up, Vector3.forward);
- _faceTarget.DiscardContents();
- camera.Render();
- Graphics.SetRenderTarget(cubemapTarget, 0, CubemapFace.PositiveY);
- Graphics.Blit(_faceTarget, _blitMaterial);
- camera.transform.rotation = xform * Quaternion.LookRotation(Vector3.down, Vector3.back);
- _faceTarget.DiscardContents();
- camera.Render();
- Graphics.SetRenderTarget(cubemapTarget, 0, CubemapFace.NegativeY);
- Graphics.Blit(_faceTarget, _blitMaterial);
- Graphics.SetRenderTarget(null);
- // Restore camera values
- camera.transform.rotation = prevRotation;
- camera.fieldOfView = prevFieldOfView;
- camera.targetTexture = prevtarget;
- }
- private void LateUpdate()
- {
- if (_motionBlur != null)
- {
- if (_capturing && !_paused && _handle >= 0)
- {
- UpdateTexture();
- _motionBlur.Accumulate(_finalTarget);
- }
- }
- }
- public override bool PrepareCapture()
- {
- if (_capturing)
- {
- return false;
- }
- if (SystemInfo.graphicsDeviceVersion.StartsWith("OpenGL") && !SystemInfo.graphicsDeviceVersion.Contains("emulated"))
- {
- Debug.LogError("[AVProMovieCapture] OpenGL not yet supported for CaptureFromCamera360 component, please use Direct3D11 instead. You may need to switch your build platform to Windows.");
- return false;
- }
- // Setup material
- _pixelFormat = NativePlugin.PixelFormat.RGBA32;
- _isTopDown = true;
- if (_camera == null)
- {
- _camera = this.GetComponent<Camera>();
- }
- if (_camera == null)
- {
- Debug.LogError("[AVProMovieCapture] No camera assigned to CaptureFromCamera360");
- return false;
- }
- // Resolution
- int finalWidth = Mathf.FloorToInt(_camera.pixelRect.width);
- int finalHeight = Mathf.FloorToInt(_camera.pixelRect.height);
- if (_renderResolution == Resolution.Custom)
- {
- finalWidth = (int)_renderSize.x;
- finalHeight = (int)_renderSize.y;
- }
- else if (_renderResolution != Resolution.Original)
- {
- GetResolution(_renderResolution, ref finalWidth, ref finalHeight);
- }
- // Setup rendering a different render target if we're overriding resolution or anti-aliasing
- //if (_renderResolution != Resolution.Original || _renderAntiAliasing != QualitySettings.antiAliasing)
- {
- int aaLevel = GetCameraAntiAliasingLevel(_camera);
- if (!Mathf.IsPowerOfTwo(_cubemapResolution))
- {
- _cubemapResolution = Mathf.ClosestPowerOfTwo(_cubemapResolution);
- Debug.LogWarning("[AVProMovieCapture] Cubemap must be power-of-2 dimensions, resizing to closest = " + _cubemapResolution);
- }
- // Create the final render target
- _targetNativePointer = System.IntPtr.Zero;
- if (_finalTarget != null)
- {
- _finalTarget.DiscardContents();
- if (_finalTarget.width != finalWidth || _finalTarget.height != finalHeight)
- {
- RenderTexture.ReleaseTemporary(_finalTarget);
- _finalTarget = null;
- }
- }
- if (_finalTarget == null)
- {
- _finalTarget = RenderTexture.GetTemporary(finalWidth, finalHeight, 0, RenderTextureFormat.Default, RenderTextureReadWrite.Default, 1);
- _finalTarget.name = "[AVProMovieCapture] 360 Final Target";
- }
- // Create the per-face render target (only when need to support GUI rendering)
- if (_faceTarget != null)
- {
- _faceTarget.DiscardContents();
- if (_faceTarget.width != _cubemapResolution || _faceTarget.height != _cubemapResolution || _faceTarget.depth != _cubemapDepth || aaLevel != _faceTarget.antiAliasing)
- {
- RenderTexture.Destroy(_faceTarget);
- _faceTarget = null;
- }
- }
- if (IsManualCubemapRendering())
- {
- if (_faceTarget == null)
- {
- _faceTarget = new RenderTexture(_cubemapResolution, _cubemapResolution, _cubemapDepth, RenderTextureFormat.Default, RenderTextureReadWrite.Default);
- _faceTarget.name = "[AVProMovieCapture] 360 Face Target";
- _faceTarget.isPowerOfTwo = true;
- _faceTarget.wrapMode = TextureWrapMode.Clamp;
- _faceTarget.filterMode = FilterMode.Bilinear;
- _faceTarget.autoGenerateMips = false;
- _faceTarget.antiAliasing = aaLevel;
- }
- _cubemapToEquirectangularMaterial.SetFloat(_propFlipX, 0.0f);
- }
- else
- {
- // Unity's RenderToCubemap result needs flipping
- _cubemapToEquirectangularMaterial.SetFloat(_propFlipX, 1.0f);
- }
- _cubemapToEquirectangularMaterial.DisableKeyword("STEREOPACK_TOP");
- _cubemapToEquirectangularMaterial.DisableKeyword("STEREOPACK_BOTTOM");
- _cubemapToEquirectangularMaterial.DisableKeyword("STEREOPACK_LEFT");
- _cubemapToEquirectangularMaterial.DisableKeyword("STEREOPACK_RIGHT");
- // Create the cube render target
- int cubeDepth = 0;
- if (!IsManualCubemapRendering())
- {
- cubeDepth = _cubemapDepth;
- }
- int cubeAA = 1;
- if (!IsManualCubemapRendering())
- {
- cubeAA = aaLevel;
- }
- if (_cubeTarget != null)
- {
- _cubeTarget.DiscardContents();
- if (_cubeTarget.width != _cubemapResolution || _cubeTarget.height != _cubemapResolution || _cubeTarget.depth != cubeDepth || cubeAA != _cubeTarget.antiAliasing)
- {
- RenderTexture.Destroy(_cubeTarget);
- _cubeTarget = null;
- }
- }
- if (_cubeTarget == null)
- {
- _cubeTarget = new RenderTexture(_cubemapResolution, _cubemapResolution, cubeDepth, RenderTextureFormat.Default, RenderTextureReadWrite.Default);
- _cubeTarget.name = "[AVProMovieCapture] 360 Cube Target";
- _cubeTarget.isPowerOfTwo = true;
- #if AVPRO_MOVIECAPTURE_RENDERTEXTUREDIMENSIONS_54
- _cubeTarget.dimension = UnityEngine.Rendering.TextureDimension.Cube;
- #else
- _cubeTarget.isCubemap = true;
- #endif
- _cubeTarget.useMipMap = false;
- _cubeTarget.autoGenerateMips = false;
- _cubeTarget.antiAliasing = cubeAA;
- _cubeTarget.wrapMode = TextureWrapMode.Clamp;
- _cubeTarget.filterMode = FilterMode.Bilinear;
- }
- if (_useMotionBlur)
- {
- _motionBlurCameras = new Camera[1];
- _motionBlurCameras[0] = _camera;
- }
- }
- SelectRecordingResolution(finalWidth, finalHeight);
- GenerateFilename();
- return base.PrepareCapture();
- }
- public override Texture GetPreviewTexture()
- {
- if (IsUsingMotionBlur())
- {
- return _motionBlur.FinalTexture;
- }
- return _finalTarget;
- }
- public override void Start()
- {
- Shader shader = Resources.Load<Shader>("CubemapToEquirectangular");
- if (shader != null)
- {
- _cubemapToEquirectangularMaterial = new Material(shader);
- }
- else
- {
- Debug.LogError("[AVProMovieCapture] Can't find CubemapToEquirectangular shader");
- }
- Shader blitShader = Shader.Find("Hidden/BlitCopy");
- if (blitShader != null)
- {
- _blitMaterial = new Material(blitShader);
- }
- else
- {
- Debug.LogError("[AVProMovieCapture] Can't find Hidden/BlitCopy shader");
- }
- _propFlipX = Shader.PropertyToID("_FlipX");
- base.Start();
- }
- public override void OnDestroy()
- {
- _targetNativePointer = System.IntPtr.Zero;
- if (_blitMaterial != null)
- {
- Material.Destroy(_blitMaterial);
- _blitMaterial = null;
- }
- if (_faceTarget != null)
- {
- RenderTexture.Destroy(_faceTarget);
- _faceTarget = null;
- }
- if (_cubeTarget != null)
- {
- RenderTexture.Destroy(_cubeTarget);
- _cubeTarget = null;
- }
- if (_finalTarget != null)
- {
- RenderTexture.ReleaseTemporary(_finalTarget);
- _finalTarget = null;
- }
- base.OnDestroy();
- }
- }
- }
|