123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473 |
- #if UNITY_5_5_OR_NEWER
- #define AVPRO_MOVIECAPTURE_UNITYPROFILER_55
- #endif
- using System.Collections;
- using System.Collections.Generic;
- using UnityEngine;
- //-----------------------------------------------------------------------------
- // Copyright 2012-2017 RenderHeads Ltd. All rights reserved.
- //-----------------------------------------------------------------------------
- namespace RenderHeads.Media.AVProMovieCapture
- {
- /// <summary>
- /// Capture to a stereo 360 view from camera in equi-rectangular format.
- /// Based on Google's Omni-direction Stereo paper: https://developers.google.com/vr/jump/rendering-ods-content.pdf
- /// </summary>
- [AddComponentMenu("AVPro Movie Capture/Capture From Camera 360 Stereo ODS (VR)", 101)]
- public class CaptureFromCamera360ODS : CaptureBase
- {
- [System.Serializable]
- public class Settings
- {
- [SerializeField]
- public Camera camera;
- [SerializeField]
- [Tooltip("Makes assumption that 1 Unity unit is 1m")]
- public float ipd = 0.064f;
- [SerializeField]
- [Tooltip("Higher value meant less slices to render, but can affect quality.")]
- public int pixelSliceSize = 1;
- [SerializeField]
- [Range(1, 31)]
- [Tooltip("May need to be increased to work with some post image effects. Value is in pixels.")]
- public int paddingSize = 1;
- [SerializeField]
- public CameraClearFlags cameraClearMode = CameraClearFlags.Color;
- [SerializeField]
- public Color cameraClearColor = Color.black;
- [SerializeField]
- public Behaviour[] cameraImageEffects;
- }
- [SerializeField]
- private Settings _settings = new Settings();
- public Settings Setup
- {
- get { return _settings; }
- }
- // State
- private int _eyeWidth = 1920;
- private int _eyeHeight = 1080;
- private Transform _cameraGroup;
- private Camera _leftCameraTop;
- private Camera _leftCameraBot;
- private Camera _rightCameraTop;
- private Camera _rightCameraBot;
- private RenderTexture _final;
- private System.IntPtr _targetNativePointer = System.IntPtr.Zero;
- private Material _finalMaterial;
- private int _propSliceCenter;
- public CaptureFromCamera360ODS()
- {
- // Override the default values to match more common use cases for this capture component
- _isRealTime = false;
- _renderResolution = Resolution.POW2_4096x4096;
- /*_settings.camera = this.GetComponent<Camera>();
- if (_settings.camera != null)
- {
- _settings.cameraClearMode = _settings.camera.clearFlags;
- _settings.cameraClearColor = _settings.camera.backgroundColor;
- }*/
- }
- public void SetCamera(Camera camera)
- {
- _settings.camera = camera;
- // TODO: add support for camera chains
- }
- public override void Start()
- {
- Shader mergeShader = Shader.Find("Hidden/AVProMovieCapture/ODSMerge");
- if (mergeShader != null)
- {
- _finalMaterial = new Material(mergeShader);
- }
- else
- {
- Debug.LogError("[AVProMovieCapture] Can't find Hidden/AVProMovieCapture/ODSMerge shader");
- }
- _propSliceCenter = Shader.PropertyToID("_sliceCenter");
- base.Start();
- }
- private Camera CreateEye(Camera camera, string gameObjectName, float yRot, float xOffset, int cameraTargetHeight, int cullingMask, float fov, float aspect, int aalevel)
- {
- bool isCreated = false;
- if (camera == null)
- {
- GameObject eye = new GameObject(gameObjectName);
- eye.transform.parent = _cameraGroup;
- eye.transform.rotation = Quaternion.AngleAxis(-yRot, Vector3.right);
- eye.transform.localPosition = new Vector3(xOffset, 0f, 0f);
- camera = eye.AddComponent<Camera>();
- isCreated = true;
- }
- camera.fieldOfView = fov;
- camera.aspect = aspect;
- camera.clearFlags = _settings.cameraClearMode;
- camera.backgroundColor = _settings.cameraClearColor;
- camera.cullingMask = cullingMask;
- camera.useOcclusionCulling = _settings.camera.useOcclusionCulling;
- camera.renderingPath = _settings.camera.renderingPath;
- #if UNITY_5_6_OR_NEWER
- camera.allowHDR = _settings.camera.allowHDR;
- camera.allowMSAA = _settings.camera.allowMSAA;
- if (camera.renderingPath == RenderingPath.DeferredShading
- #if AVPRO_MOVIECAPTURE_DEFERREDSHADING
- || camera.renderingPath == RenderingPath.DeferredLighting
- #endif
- )
- {
- camera.allowMSAA = false;
- }
- #endif
- {
- int textureWidth = _settings.pixelSliceSize + 2 * _settings.paddingSize;
- int textureHeight = cameraTargetHeight;
- if (camera.targetTexture != null)
- {
- camera.targetTexture.DiscardContents();
- if (camera.targetTexture.width != textureWidth || camera.targetTexture.height != textureHeight || camera.targetTexture.antiAliasing != aalevel)
- {
- RenderTexture.ReleaseTemporary(camera.targetTexture);
- camera.targetTexture = null;
- }
- }
- if (camera.targetTexture == null)
- {
- camera.targetTexture = RenderTexture.GetTemporary(textureWidth, textureHeight, 24, RenderTextureFormat.Default, RenderTextureReadWrite.Default, aalevel);
- }
- }
- camera.enabled = false;
- // TODO: make it so the components can be added/updated each time if they have changed
- if (isCreated)
- {
- if (_settings.cameraImageEffects != null)
- {
- for (int i = 0; i < _settings.cameraImageEffects.Length; i++)
- {
- Behaviour origComponent = _settings.cameraImageEffects[i];
- if (origComponent != null)
- {
- if (origComponent.enabled)
- {
- #if UNITY_EDITOR
- Component newComponent = camera.gameObject.AddComponent(origComponent.GetType());
- // TODO: we need to copy any post image effect component fields here via reflection? or perhaps use prefabs?
- UnityEditor.EditorUtility.CopySerialized(origComponent, newComponent);
- #endif
- }
- }
- else
- {
- Debug.LogWarning("[AVProMovieCapture] Image effect is null");
- }
- }
- }
- }
- return camera;
- }
- public override void UpdateFrame()
- {
- TickFrameTimer();
- if (_capturing && !_paused)
- {
- if (_settings.camera != null && _handle >= 0)
- {
- bool canGrab = true;
- if (IsUsingMotionBlur())
- {
- // If the motion blur is still accumulating, don't grab this frame
- canGrab = _motionBlur.IsFrameAccumulated;
- }
- if (canGrab && CanOutputFrame())
- {
- // Frame to encode either comes from rendering, or motion blur accumulation
- RenderTexture finalTexture = null;
- if (!IsUsingMotionBlur())
- {
- RenderFrame();
- finalTexture = _final;
- }
- 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 void LateUpdate()
- {
- AccumulateMotionBlur();
- }
- private void AccumulateMotionBlur()
- {
- if (_motionBlur != null)
- {
- if (_capturing && !_paused)
- {
- if (_settings.camera != null && _handle >= 0)
- {
- RenderFrame();
- _motionBlur.Accumulate(_final);
- }
- }
- }
- }
- private void RenderFrame()
- {
- _cameraGroup.position = _settings.camera.transform.position;
- Quaternion originalRot = _settings.camera.transform.rotation * Quaternion.AngleAxis(180f, Vector3.up); // Apply 180 degree correction align the front camera vector to the center of the output image
- float rotationStep = 360f / _eyeWidth;
- for (int i = 0; i < _eyeWidth / _settings.pixelSliceSize; ++i)
- {
- int step = i * _settings.pixelSliceSize;
- float v = step * rotationStep;
- _cameraGroup.rotation = originalRot * Quaternion.AngleAxis(v, Vector3.up);
- _leftCameraTop.targetTexture.DiscardContents();
- _leftCameraBot.targetTexture.DiscardContents();
- _rightCameraTop.targetTexture.DiscardContents();
- _rightCameraBot.targetTexture.DiscardContents();
- _leftCameraTop.Render();
- _leftCameraBot.Render();
- _rightCameraTop.Render();
- _rightCameraBot.Render();
- _finalMaterial.SetFloat(_propSliceCenter, step + _settings.pixelSliceSize / 2f);
- _final.DiscardContents();
- Graphics.Blit(null, _final, _finalMaterial);
- //System.GC.Collect();
- }
- }
- public override Texture GetPreviewTexture()
- {
- if (IsUsingMotionBlur())
- {
- return _motionBlur.FinalTexture;
- }
- return _final;
- }
- 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 CaptureFromCamera360ODS component, please use Direct3D11 instead. You may need to switch your build platform to Windows.");
- return false;
- }
- #if AVPRO_MOVIECAPTURE_UNITYPROFILER_55
- // This component makes the profiler use a TON of memory, so warn the user to disable it
- if (UnityEngine.Profiling.Profiler.enabled)
- {
- Debug.LogWarning("[AVProMovieCapture] Having the Unity profiler enabled while using the CaptureFromCamera360ODS component is not recommended. Too many samples are generated which can make the system run out of memory. Disable the profiler, close the window and remove the tab. A Unity restart may be required after disabling the profiler recording");
- }
- #endif
- // Setup material
- _pixelFormat = NativePlugin.PixelFormat.RGBA32;
- _isTopDown = true;
- if (_settings.camera == null)
- {
- _settings.camera = this.GetComponent<Camera>();
- }
- if (_settings.camera == null)
- {
- Debug.LogError("[AVProMovieCapture] No camera assigned to CaptureFromCamera360ODS");
- return false;
- }
- // Resolution
- int finalWidth = Mathf.FloorToInt(_settings.camera.pixelRect.width);
- int finalHeight = Mathf.FloorToInt(_settings.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);
- }
- _eyeWidth = Mathf.Clamp(finalWidth, 1, 8192);
- // NOTE: Height must be even
- _eyeHeight = Mathf.Clamp(finalHeight / 2, 1, 4096);
- _eyeHeight -= _eyeHeight & 1;
- finalWidth = _eyeWidth;
- finalHeight = _eyeHeight * 2;
- int aaLevel = GetCameraAntiAliasingLevel(_settings.camera);
- // NOTE: Pixel slice size must be divisible by the total width
- _settings.pixelSliceSize = Mathf.Clamp(_settings.pixelSliceSize, 1, _eyeWidth);
- _settings.pixelSliceSize = _settings.pixelSliceSize - (_eyeWidth % _settings.pixelSliceSize);
- _settings.paddingSize = Mathf.Clamp(_settings.paddingSize, 0, 31);
- float offset = _settings.ipd / 2f;
- float aspect = (_settings.pixelSliceSize * 2f) / _eyeHeight;
- if (_cameraGroup == null)
- {
- GameObject go = new GameObject("OdsCameraGroup");
- go.transform.parent = this.gameObject.transform;
- _cameraGroup = go.transform;
- }
- // TODO: only recreate textures if they don't already exist or size has changed
- _leftCameraTop = CreateEye(_leftCameraTop, "LeftEyeTop", 45f, -offset, _eyeHeight / 2, _settings.camera.cullingMask, 90f, aspect, aaLevel);
- _leftCameraBot = CreateEye(_leftCameraBot, "LeftEyeBot", -45f, -offset, _eyeHeight / 2, _settings.camera.cullingMask, 90f, aspect, aaLevel);
- _rightCameraTop = CreateEye(_rightCameraTop, "RightEyeTop", 45f, offset, _eyeHeight / 2, _settings.camera.cullingMask, 90f, aspect, aaLevel);
- _rightCameraBot = CreateEye(_rightCameraBot, "RightEyeBot", -45f, offset, _eyeHeight / 2, _settings.camera.cullingMask, 90f, aspect, aaLevel);
- // Create final texture (if not already created)
- _targetNativePointer = System.IntPtr.Zero;
- if (_final != null)
- {
- _final.DiscardContents();
- if (_final.width != finalWidth || _final.height != finalHeight || _final.antiAliasing != aaLevel)
- {
- RenderTexture.ReleaseTemporary(_final);
- _final = null;
- }
- _final = null;
- }
- if (_final == null)
- {
- _final = RenderTexture.GetTemporary(finalWidth, finalHeight, 0);
- }
- // Setup material
- _finalMaterial.SetTexture("_leftTopTex", _leftCameraTop.targetTexture);
- _finalMaterial.SetTexture("_leftBotTex", _leftCameraBot.targetTexture);
- _finalMaterial.SetTexture("_rightTopTex", _rightCameraTop.targetTexture);
- _finalMaterial.SetTexture("_rightBotTex", _rightCameraBot.targetTexture);
- _finalMaterial.SetFloat("_pixelSliceSize", _settings.pixelSliceSize);
- _finalMaterial.SetInt("_paddingSize", _settings.paddingSize);
- _finalMaterial.SetFloat("_targetXTexelSize", 1.0f / finalWidth);
- // Setup capture
- SelectRecordingResolution(finalWidth, finalHeight);
- GenerateFilename();
- return base.PrepareCapture();
- }
- public override void OnDestroy()
- {
- _targetNativePointer = System.IntPtr.Zero;
- if (_final != null)
- {
- RenderTexture.ReleaseTemporary(_final);
- _final = null;
- }
- if (_leftCameraTop != null)
- {
- RenderTexture.ReleaseTemporary(_leftCameraTop.targetTexture);
- GameObject.Destroy(_leftCameraTop.gameObject);
- _leftCameraTop = null;
- }
- if (_leftCameraBot != null)
- {
- RenderTexture.ReleaseTemporary(_leftCameraBot.targetTexture);
- GameObject.Destroy(_leftCameraBot.gameObject);
- _leftCameraBot = null;
- }
- if (_rightCameraTop != null)
- {
- RenderTexture.ReleaseTemporary(_rightCameraTop.targetTexture);
- GameObject.Destroy(_rightCameraTop.gameObject);
- _rightCameraTop = null;
- }
- if (_rightCameraBot != null)
- {
- RenderTexture.ReleaseTemporary(_rightCameraBot.targetTexture);
- GameObject.Destroy(_rightCameraBot.gameObject);
- _rightCameraBot = null;
- }
- if (_cameraGroup != null)
- {
- GameObject.Destroy(_cameraGroup.gameObject);
- _cameraGroup = null;
- }
- if (_finalMaterial)
- {
- Destroy(_finalMaterial);
- _finalMaterial = null;
- }
- base.OnDestroy();
- }
- }
- }
|