#if UNITY_5_6_0 || UNITY_5_6_1
#define AVPRO_MOVIECAPTURE_UNITYBUG_RENDERTOCUBEMAP_56
#endif
#if UNITY_2018_1_OR_NEWER
// Unity 2018.1 introduces stereo cubemap render methods, but with no camera rotation
#define AVPRO_MOVIECAPTURE_UNITY_STEREOCUBEMAP_RENDER
#if UNITY_2018_2_OR_NEWER || UNITY_2018_1_9
// Unity 2018.2 adds camera rotation
#define AVPRO_MOVIECAPTURE_UNITY_STEREOCUBEMAP_RENDER_WITHROTATION
#endif
#endif
using UnityEngine;
using UnityEngine.Rendering;
using System.Collections;
//-----------------------------------------------------------------------------
// Copyright 2012-2022 RenderHeads Ltd. All rights reserved.
//-----------------------------------------------------------------------------
namespace RenderHeads.Media.AVProMovieCapture
{
///
/// 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.
///
//[RequireComponent(typeof(Camera))]
[AddComponentMenu("AVPro Movie Capture/Capture From Camera 360 (VR)", 100)]
public class CaptureFromCamera360 : CaptureBase
{
[SerializeField] CameraSelector _cameraSelector = null;
public CameraSelector CameraSelector
{
get { return _cameraSelector; }
set { _cameraSelector = value; }
}
[SerializeField] Camera _camera = null;
[SerializeField] CubemapResolution _cubemapResolution = CubemapResolution.POW2_2048;
[SerializeField] CubemapDepth _cubemapDepth = CubemapDepth.Depth_24;
public CubemapResolution CubemapFaceResolution
{
get { return _cubemapResolution; }
set { _cubemapResolution = value; }
}
public CubemapDepth CubemapDepthResolution
{
get { return _cubemapDepth; }
set { _cubemapDepth = value; }
}
[SerializeField] bool _supportGUI = false;
[SerializeField] bool _supportCameraRotation = false;
[SerializeField] bool _onlyLeftRightRotation = false;
public bool SupportGUI
{
get { return _supportGUI; }
set { _supportGUI = value; }
}
public bool SupportCameraRotation
{
get { return _supportCameraRotation; }
set { _supportCameraRotation = value; }
}
public bool OnlyLeftRightRotation
{
get { return _onlyLeftRightRotation; }
set { _onlyLeftRightRotation = value; }
}
[Tooltip("Render 180 degree equirectangular instead of 360 degrees")]
[SerializeField] bool _render180Degrees = false;
[SerializeField] StereoPacking _stereoRendering = StereoPacking.None;
public bool Render180Degrees
{
get { return _render180Degrees; }
set { _render180Degrees = value; }
}
public StereoPacking StereoRendering
{
get { return _stereoRendering; }
set { _stereoRendering = value; }
}
[Tooltip("Makes assumption that 1 Unity unit is 1m")]
[SerializeField] float _ipd = 0.064f;
public float IPD
{
get { return _ipd; }
set { _ipd = value; }
}
[Tooltip("Percentage cube faces are overdrawn each edge then blended to alleviate screen space FX seams")]
[SerializeField] float _blendOverlapPercent = 0.0f;
// State
private RenderTexture _faceTarget;
// RJT TODO: Texture array?
private RenderTexture[] _faceTargets = new RenderTexture[6];
private Material _blitMaterial;
private Material _cubemapToEquirectangularMaterial;
private RenderTexture _cubeTarget;
private RenderTexture _finalTarget;
private System.IntPtr _targetNativePointer = System.IntPtr.Zero;
private int _propFlipX;
#if SUPPORT_SHADER_ROTATION
private int _propRotation;
#endif
private enum CubemapRenderMethod
{
Manual, // Manually render the cubemaps - supports world space GUI, camera rotation, but is slow and doesn't give correct stereo
Unity, // No stereo, no world space GUI, no camera rotation
Unity2018, // Good fast stereo, no world space GUI, camera rotation only in 2018.2 and above
}
public CaptureFromCamera360()
{
// Override the default values to match more common use cases for this capture component
_renderResolution = Resolution.POW2_2048x2048;
}
private CubemapRenderMethod GetCubemapRenderingMethod()
{
if (_supportGUI)
{
return CubemapRenderMethod.Manual;
}
if (_supportCameraRotation)
{
#if AVPRO_MOVIECAPTURE_UNITY_STEREOCUBEMAP_RENDER_WITHROTATION
return CubemapRenderMethod.Unity2018;
#else
return CubemapRenderMethod.Manual;
#endif
}
if (_stereoRendering == StereoPacking.None)
{
#if AVPRO_MOVIECAPTURE_UNITY_STEREOCUBEMAP_RENDER_WITHROTATION
return CubemapRenderMethod.Unity2018;
#else
return CubemapRenderMethod.Unity;
#endif
}
else
{
#if AVPRO_MOVIECAPTURE_UNITY_STEREOCUBEMAP_RENDER
return CubemapRenderMethod.Unity2018;
#else
return CubemapRenderMethod.Manual;
#endif
}
}
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()
{
if (_cameraSelector != null)
{
if (_camera != _cameraSelector.Camera)
{
SetCamera(_cameraSelector.Camera);
}
}
if (_useWaitForEndOfFrame)
{
if (_capturing && !_paused)
{
StartCoroutine(FinalRenderCapture());
}
}
else
{
Capture();
}
base.UpdateFrame();
}
private IEnumerator FinalRenderCapture()
{
yield return _waitForEndOfFrame;
Capture();
}
private void Capture()
{
TickFrameTimer();
AccumulateMotionBlur();
if (_capturing && !_paused)
{
if (
((_cubeTarget != null) || (_faceTargets[0] != 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())
{
EncodeUnityAudio();
RenderTexture finalTexture = _finalTarget;
if (!IsUsingMotionBlur())
{
UpdateTexture();
}
else
{
finalTexture = _motionBlur.FinalTexture;
}
// Side-by-side transparency
RenderTexture newSourceTexture = UpdateForSideBySideTransparency( finalTexture );
if (newSourceTexture)
{
finalTexture = newSourceTexture;
}
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);
// ADG NOTE: Causes screen flickering under D3D12, even if we're not doing any rendering at native level
// And also seems to cause GL.sRGBWrite to be set to false, which causes screen darkening in Linear mode
if (SystemInfo.graphicsDeviceType != GraphicsDeviceType.Direct3D12)
{
GL.InvalidateState();
}
UpdateFPS();
}
}
}
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 RenderCubemapToEquiRect(RenderTexture cubemap, RenderTexture target, bool supportRotation, Quaternion rotation, bool isEyeLeft)
{
#if SUPPORT_SHADER_ROTATION
if (supportRotation)
{
// Note: Because Unity's Camera.RenderCubemap() doesn't support rotated cameras, we apply the rotation matrix in the cubemap lookup
_cubemapToEquirectangularMaterial.EnableKeyword("USE_ROTATION");
Matrix4x4 rotationMatrix = Matrix4x4.TRS(Vector3.zero, rotation, Vector3.one);
_cubemapToEquirectangularMaterial.SetMatrix(_propRotation, rotationMatrix);
}
else
{
_cubemapToEquirectangularMaterial.DisableKeyword("USE_ROTATION");
}
#endif
if (_stereoRendering == StereoPacking.TopBottom)
{
if (isEyeLeft)
{
// Render to top
_cubemapToEquirectangularMaterial.DisableKeyword("STEREOPACK_BOTTOM");
_cubemapToEquirectangularMaterial.EnableKeyword("STEREOPACK_TOP");
}
else
{
// Render to bottom
_cubemapToEquirectangularMaterial.DisableKeyword("STEREOPACK_TOP");
_cubemapToEquirectangularMaterial.EnableKeyword("STEREOPACK_BOTTOM");
}
}
else if (_stereoRendering == StereoPacking.LeftRight)
{
if (isEyeLeft)
{
// Render to left
_cubemapToEquirectangularMaterial.DisableKeyword("STEREOPACK_RIGHT");
_cubemapToEquirectangularMaterial.EnableKeyword("STEREOPACK_LEFT");
}
else
{
// Render to right
_cubemapToEquirectangularMaterial.DisableKeyword("STEREOPACK_LEFT");
_cubemapToEquirectangularMaterial.EnableKeyword("STEREOPACK_RIGHT");
}
}
// Between Unity 2018.1.0 and 2018.3.0 Unity doesn't seem to set the correct sRGBWrite state and keeps it as false
#if (UNITY_2018_1_OR_NEWER && !UNITY_2018_3_OR_NEWER)
bool sRGBWritePrev = GL.sRGBWrite;
GL.sRGBWrite = target.sRGB;
#endif
// Blending?
if (_blendOverlapPercent > 0.0f)
{
_cubemapToEquirectangularMaterial.EnableKeyword("USE_BLENDING");
_cubemapToEquirectangularMaterial.SetTexture("_Face_Left", _faceTargets[0]);
_cubemapToEquirectangularMaterial.SetTexture("_Face_Right", _faceTargets[1]);
_cubemapToEquirectangularMaterial.SetTexture("_Face_Up", _faceTargets[2]);
_cubemapToEquirectangularMaterial.SetTexture("_Face_Down", _faceTargets[3]);
_cubemapToEquirectangularMaterial.SetTexture("_Face_Front", _faceTargets[4]);
_cubemapToEquirectangularMaterial.SetTexture("_Face_Back", _faceTargets[5]);
_cubemapToEquirectangularMaterial.SetFloat("_inverseOverlap", (1.0f / (1.0f + (_blendOverlapPercent * 0.01f))));
}
else { _cubemapToEquirectangularMaterial.DisableKeyword("USE_BLENDING"); }
// Render
Graphics.Blit(cubemap, target, _cubemapToEquirectangularMaterial);
#if (UNITY_2018_1_OR_NEWER && !UNITY_2018_3_OR_NEWER)
GL.sRGBWrite = sRGBWritePrev;
#endif
}
private void UpdateTexture()
{
// Between Unity 2018.1.0 and 2018.3.0 Unity doesn't seem to set the correct sRGBWrite state and keeps it as false
#if (UNITY_2018_1_OR_NEWER && !UNITY_2018_3_OR_NEWER)
bool sRGBWritePrev = GL.sRGBWrite;
GL.sRGBWrite = _cubeTarget.sRGB;
#endif
// 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;
Rect prevRect = camera.rect;
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
CubemapRenderMethod cubemapRenderMethod = GetCubemapRenderingMethod();
if (_stereoRendering == StereoPacking.None)
{
if (cubemapRenderMethod == CubemapRenderMethod.Unity)
{
#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
}
#if AVPRO_MOVIECAPTURE_UNITY_STEREOCUBEMAP_RENDER
else if (cubemapRenderMethod == CubemapRenderMethod.Unity2018)
{
// Note: If we use Mono instead of Left then rotation isn't supported
if (this.transform.rotation == Quaternion.identity)
{
camera.RenderToCubemap(_cubeTarget, 63, Camera.MonoOrStereoscopicEye.Mono);
}
else
{
camera.stereoSeparation = 0f;
camera.RenderToCubemap(_cubeTarget, 63, Camera.MonoOrStereoscopicEye.Left);
}
}
#endif
else if (cubemapRenderMethod == CubemapRenderMethod.Manual)
{
RenderCameraToCubemap(camera, _cubeTarget);
}
RenderCubemapToEquiRect(_cubeTarget, _finalTarget, false, Quaternion.identity, true);
}
else
{
#if AVPRO_MOVIECAPTURE_UNITY_STEREOCUBEMAP_RENDER
if (cubemapRenderMethod == CubemapRenderMethod.Unity2018)
{
//Left eye
camera.stereoSeparation = _ipd;
camera.RenderToCubemap(_cubeTarget, 63, Camera.MonoOrStereoscopicEye.Left);
RenderCubemapToEquiRect(_cubeTarget, _finalTarget, false, camera.transform.rotation, true);
// Right eye
_cubeTarget.DiscardContents();
camera.RenderToCubemap(_cubeTarget, 63, Camera.MonoOrStereoscopicEye.Right);
RenderCubemapToEquiRect(_cubeTarget, _finalTarget, false, camera.transform.rotation, false);
} else
#endif
if (cubemapRenderMethod == CubemapRenderMethod.Manual)
{
// Save camera state
Vector3 cameraPosition = camera.transform.localPosition;
// Left eye
camera.transform.Translate(new Vector3(-_ipd / 2f, 0f, 0f), Space.Self);
RenderCameraToCubemap(camera, _cubeTarget);
RenderCubemapToEquiRect(_cubeTarget, _finalTarget, false, Quaternion.identity, true);
// Right eye
camera.transform.localPosition = cameraPosition;
camera.transform.Translate(new Vector3(_ipd / 2f, 0f, 0f), Space.Self);
RenderCameraToCubemap(camera, _cubeTarget);
RenderCubemapToEquiRect(_cubeTarget, _finalTarget, false, Quaternion.identity, false);
// Restore camera state
camera.transform.localPosition = cameraPosition;
}
}
camera.rect = prevRect;
#if (UNITY_2018_1_OR_NEWER && !UNITY_2018_3_OR_NEWER)
GL.sRGBWrite = sRGBWritePrev;
#endif
}
private void RenderCameraToCubemap(Camera camera, RenderTexture cubemapTarget)
{
RenderTexture prevRT = RenderTexture.active;
// 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;
}
else if (_onlyLeftRightRotation)
{
xform = Quaternion.Euler(0f, camera.transform.eulerAngles.y, 0f);
}
if (_blendOverlapPercent > 0.0f)
{
// Adjust FOV for overlap percentage (each each)
camera.fieldOfView = (Mathf.Atan(1.0f + (_blendOverlapPercent * 0.01f)) * 2.0f * Mathf.Rad2Deg);
// RJT TODO: LUT/loop
// Left
camera.transform.rotation = xform * Quaternion.LookRotation(Vector3.right, Vector3.down);
camera.targetTexture = _faceTargets[0];
camera.Render();
// Right
camera.transform.rotation = xform * Quaternion.LookRotation(Vector3.left, Vector3.down);
camera.targetTexture = _faceTargets[1];
camera.Render();
// Up
camera.transform.rotation = xform * Quaternion.LookRotation(Vector3.up, Vector3.forward);
camera.targetTexture = _faceTargets[2];
camera.Render();
// Down
camera.transform.rotation = xform * Quaternion.LookRotation(Vector3.down, Vector3.back);
camera.targetTexture = _faceTargets[3];
camera.Render();
// Front
camera.transform.rotation = xform * Quaternion.LookRotation(Vector3.forward, Vector3.down);
camera.targetTexture = _faceTargets[4];
camera.Render();
// Back
camera.transform.rotation = xform * Quaternion.LookRotation(Vector3.back, Vector3.down);
camera.targetTexture = _faceTargets[5];
camera.Render();
}
else
{
// 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.fieldOfView = 90f;
camera.targetTexture = _faceTarget;
// Front
camera.transform.rotation = xform * Quaternion.LookRotation(Vector3.forward, Vector3.down);
_faceTarget.DiscardContents();
camera.Render();
Graphics.SetRenderTarget(cubemapTarget, 0, CubemapFace.PositiveZ);
Graphics.Blit(_faceTarget, _blitMaterial);
// Back
camera.transform.rotation = xform * Quaternion.LookRotation(Vector3.back, Vector3.down);
_faceTarget.DiscardContents();
camera.Render();
Graphics.SetRenderTarget(cubemapTarget, 0, CubemapFace.NegativeZ);
Graphics.Blit(_faceTarget, _blitMaterial);
// Right
camera.transform.rotation = xform * Quaternion.LookRotation(Vector3.right, Vector3.down);
_faceTarget.DiscardContents();
camera.Render();
Graphics.SetRenderTarget(cubemapTarget, 0, CubemapFace.NegativeX);
Graphics.Blit(_faceTarget, _blitMaterial);
// Left
camera.transform.rotation = xform * Quaternion.LookRotation(Vector3.left, Vector3.down);
_faceTarget.DiscardContents();
camera.Render();
Graphics.SetRenderTarget(cubemapTarget, 0, CubemapFace.PositiveX);
Graphics.Blit(_faceTarget, _blitMaterial);
// Up
camera.transform.rotation = xform * Quaternion.LookRotation(Vector3.up, Vector3.forward);
_faceTarget.DiscardContents();
camera.Render();
Graphics.SetRenderTarget(cubemapTarget, 0, CubemapFace.PositiveY);
Graphics.Blit(_faceTarget, _blitMaterial);
// Down
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(prevRT);
}
// Restore camera values
camera.transform.rotation = prevRotation;
camera.fieldOfView = prevFieldOfView;
camera.targetTexture = prevtarget;
}
private void AccumulateMotionBlur()
{
if (_motionBlur != null)
{
if (_capturing && !_paused)
{
if (_camera != null && _handle >= 0)
{
UpdateTexture();
_motionBlur.Accumulate(_finalTarget);
}
}
}
}
public override bool PrepareCapture()
{
if (_capturing)
{
return false;
}
#if UNITY_EDITOR_WIN || (!UNITY_EDITOR && UNITY_STANDALONE_WIN)
if (SystemInfo.graphicsDeviceVersion.StartsWith("Direct3D 9"))
{
Debug.LogError("[AVProMovieCapture] Direct3D9 not yet supported, please use Direct3D11 instead.");
return false;
}
else 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;
}
#endif
// Check cubemap resolution support
int cubemapResolution = (int)_cubemapResolution;
if (_blendOverlapPercent > 0.0f)
{
// Adjust resolution for overlap percentage (each edge)
cubemapResolution = (int)(((float)cubemapResolution * (1.0f + ((_blendOverlapPercent * 0.01f) * 2.0f))) + 0.5f);
}
if (cubemapResolution > SystemInfo.maxCubemapSize)
{
cubemapResolution = SystemInfo.maxCubemapSize;
Debug.LogWarning("[AVProMovieCapture] Reducing cubemap size to system max: " + cubemapResolution);
}
// Setup material
_pixelFormat = NativePlugin.PixelFormat.RGBA32;
_isTopDown = true;
if (_cameraSelector != null)
{
//if (_camera != _cameraSelector.Camera)
{
SetCamera(_cameraSelector.Camera);
}
}
if (_camera == null)
{
SetCamera(this.GetComponent());
}
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);
CubemapRenderMethod cubemapRenderMethod = GetCubemapRenderingMethod();
Debug.Log("[AVProMovieCapture] Using cubemap render method: " + cubemapRenderMethod.ToString());
// 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 != (int)cubemapResolution ||
_faceTarget.height != (int)cubemapResolution ||
_faceTarget.depth != (int)_cubemapDepth ||
_faceTarget.antiAliasing != aaLevel)
{
RenderTexture.Destroy(_faceTarget);
_faceTarget = null;
}
}
if (_faceTargets[0] != null)
{
for (int i = 0; i < 6; ++i )
{
_faceTargets[i].DiscardContents();
}
if (_faceTargets[0].width != cubemapResolution ||
_faceTargets[0].height != cubemapResolution ||
_faceTargets[0].depth != (int)_cubemapDepth ||
_faceTargets[0].antiAliasing != aaLevel)
{
for (int i = 0; i < 6; ++i )
{
RenderTexture.Destroy(_faceTargets[i]);
_faceTargets[i] = null;
}
}
}
RenderTextureFormat renderTextureFormat = RenderTextureFormat.Default;
#if USING_URP
renderTextureFormat = RenderTextureFormat.ARGBHalf;//ARGBFloat;
#endif
if (cubemapRenderMethod == CubemapRenderMethod.Manual)
{
if ((_blendOverlapPercent > 0.0f) && (_faceTargets[0] == null))
{
for (int i = 0; i < 6; ++i )
{
_faceTargets[i] = new RenderTexture(cubemapResolution, cubemapResolution, (int)_cubemapDepth, renderTextureFormat, RenderTextureReadWrite.Default);
_faceTargets[i].name = "[AVProMovieCapture] 360 Face Target";
_faceTargets[i].isPowerOfTwo = Mathf.IsPowerOfTwo(cubemapResolution);
_faceTargets[i].wrapMode = TextureWrapMode.Clamp;
_faceTargets[i].filterMode = FilterMode.Bilinear;
_faceTargets[i].autoGenerateMips = false;
_faceTargets[i].antiAliasing = aaLevel;
}
}
else if (_faceTarget == null)
{
_faceTarget = new RenderTexture((int)cubemapResolution, (int)cubemapResolution, (int)_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("USE_ROTATION");
_cubemapToEquirectangularMaterial.DisableKeyword("STEREOPACK_TOP");
_cubemapToEquirectangularMaterial.DisableKeyword("STEREOPACK_BOTTOM");
_cubemapToEquirectangularMaterial.DisableKeyword("STEREOPACK_LEFT");
_cubemapToEquirectangularMaterial.DisableKeyword("STEREOPACK_RIGHT");
if (_render180Degrees)
{
_cubemapToEquirectangularMaterial.DisableKeyword("LAYOUT_EQUIRECT360");
_cubemapToEquirectangularMaterial.EnableKeyword("LAYOUT_EQUIRECT180");
}
else
{
_cubemapToEquirectangularMaterial.DisableKeyword("LAYOUT_EQUIRECT180");
_cubemapToEquirectangularMaterial.EnableKeyword("LAYOUT_EQUIRECT360");
}
if (_blendOverlapPercent == 0.0f)
{
// Create the cube render target
int cubeDepth = 0;
if (cubemapRenderMethod != CubemapRenderMethod.Manual)
{
cubeDepth = (int)_cubemapDepth;
}
int cubeAA = 1;
if (cubemapRenderMethod != CubemapRenderMethod.Manual)
{
cubeAA = aaLevel;
}
if (_cubeTarget != null)
{
_cubeTarget.DiscardContents();
if (_cubeTarget.width != cubemapResolution ||
_cubeTarget.height != cubemapResolution ||
_cubeTarget.depth != cubeDepth ||
_cubeTarget.antiAliasing != cubeAA)
{
RenderTexture.Destroy(_cubeTarget);
_cubeTarget = null;
}
}
if (_cubeTarget == null)
{
_cubeTarget = new RenderTexture(cubemapResolution, cubemapResolution, cubeDepth, renderTextureFormat, RenderTextureReadWrite.Default);
_cubeTarget.name = "[AVProMovieCapture] 360 Cube Target";
_cubeTarget.isPowerOfTwo = true;
_cubeTarget.dimension = UnityEngine.Rendering.TextureDimension.Cube;
_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;
}
}
_Transparency = Transparency.None;
if ( !NativePlugin.IsBasicEdition() )
{
if( (_outputTarget == OutputTarget.VideoFile || _outputTarget == OutputTarget.NamedPipe) && GetEncoderHints().videoHints.transparency != Transparency.None )
{
_Transparency = GetEncoderHints().videoHints.transparency;
}
else if( _outputTarget == OutputTarget.ImageSequence && GetEncoderHints().imageHints.transparency != Transparency.None )
{
_Transparency = GetEncoderHints().imageHints.transparency;
}
//
if( _Transparency == Transparency.TopBottom || _Transparency == Transparency.LeftRight )
{
InitialiseSideBySideTransparency( finalWidth, finalHeight );
}
switch ( _Transparency )
{
case Transparency.TopBottom: finalHeight *= 2; break;
case Transparency.LeftRight: finalWidth *= 2; break;
}
}
SelectRecordingResolution(finalWidth, finalHeight);
GenerateFilename();
if (base.PrepareCapture())
{
UpdateInjectionOptions(_stereoRendering, _render180Degrees?SphericalVideoLayout.Equirectangular180:SphericalVideoLayout.Equirectangular360);
return true;
}
return false;
}
public override Texture GetPreviewTexture()
{
if (IsUsingMotionBlur())
{
return _motionBlur.FinalTexture;
}
return _finalTarget;
}
public override void Start()
{
Shader shader = Resources.Load("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");
#if SUPPORT_SHADER_ROTATION
_propRotation = Shader.PropertyToID("_RotationMatrix");
#endif
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 (_faceTargets[0] != null)
{
for (int i = 0; i < 6; ++i)
{
RenderTexture.Destroy(_faceTargets[i]);
_faceTargets[i] = null;
}
}
if (_cubeTarget != null)
{
RenderTexture.Destroy(_cubeTarget);
_cubeTarget = null;
}
if (_finalTarget != null)
{
RenderTexture.ReleaseTemporary(_finalTarget);
_finalTarget = null;
}
base.OnDestroy();
}
}
}