393 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			C#
		
	
	
	
			
		
		
	
	
			393 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			C#
		
	
	
	
| #if UNITY_EDITOR || UNITY_STANDALONE_OSX || UNITY_STANDALONE_WIN
 | |
| 	#define UNITY_PLATFORM_SUPPORTS_LINEAR
 | |
| #elif UNITY_IOS || UNITY_ANDROID
 | |
| 	#if UNITY_5_5_OR_NEWER || (UNITY_5 && !UNITY_5_0 && !UNITY_5_1 && !UNITY_5_2 && !UNITY_5_3 && !UNITY_5_4)
 | |
| 		#define UNITY_PLATFORM_SUPPORTS_LINEAR
 | |
| 	#endif
 | |
| #endif
 | |
| #if UNITY_5_4_OR_NEWER || (UNITY_5 && !UNITY_5_0)
 | |
| 	#define UNITY_HELPATTRIB
 | |
| #endif
 | |
| 
 | |
| using UnityEngine;
 | |
| 
 | |
| //-----------------------------------------------------------------------------
 | |
| // Copyright 2015-2018 RenderHeads Ltd.  All rights reserverd.
 | |
| //-----------------------------------------------------------------------------
 | |
| 
 | |
| namespace RenderHeads.Media.AVProVideo
 | |
| {
 | |
| 	/// <summary>
 | |
| 	/// Builds a cube mesh for displaying a 360 degree "Cubemap 3x2 facebook layout" texture in VR
 | |
| 	/// </summary>
 | |
| 	[RequireComponent(typeof(MeshRenderer))]
 | |
| 	[RequireComponent(typeof(MeshFilter))]
 | |
| 	//[ExecuteInEditMode]
 | |
| 	[AddComponentMenu("AVPro Video/Cubemap Cube (VR)", 400)]
 | |
| #if UNITY_HELPATTRIB
 | |
| 	[HelpURL("http://renderheads.com/product/avpro-video/")]
 | |
| #endif
 | |
| 	public class CubemapCube : MonoBehaviour
 | |
| 	{
 | |
| 		public enum Layout
 | |
| 		{
 | |
| 			FacebookTransform32,	// Layout for Facebooks FFMPEG Transform plugin with 3:2 layout
 | |
| 			Facebook360Capture,		// Layout for Facebooks 360-Capture-SDK
 | |
| 		}
 | |
| 
 | |
| 		private Mesh _mesh;
 | |
|         protected MeshRenderer _renderer;
 | |
| 
 | |
|         [SerializeField]
 | |
|         protected Material _material = null;
 | |
| 
 | |
|         [SerializeField]
 | |
|         private MediaPlayer _mediaPlayer = null;
 | |
| 
 | |
| 		// This value comes from the facebook transform ffmpeg filter and is used to prevent seams appearing along the edges due to bilinear filtering
 | |
| 		[SerializeField]
 | |
| 		private float expansion_coeff = 1.01f;
 | |
| 
 | |
| 		[SerializeField]
 | |
| 		private Layout _layout = Layout.FacebookTransform32;
 | |
| 
 | |
| 		private Texture _texture;
 | |
| 		private bool _verticalFlip;
 | |
| 		private int _textureWidth;
 | |
| 		private int _textureHeight;
 | |
| 		private static int _propApplyGamma;
 | |
| 
 | |
| 		private static int _propUseYpCbCr;
 | |
| 		private const string PropChromaTexName = "_ChromaTex";
 | |
| 		private static int _propChromaTex;
 | |
| 
 | |
| 		public MediaPlayer Player
 | |
| 		{
 | |
| 			set { _mediaPlayer = value; }
 | |
| 			get { return _mediaPlayer; }
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 		void Awake()
 | |
| 		{
 | |
| 			if (_propApplyGamma == 0)
 | |
| 			{
 | |
| 				_propApplyGamma = Shader.PropertyToID("_ApplyGamma");
 | |
| 			}
 | |
| 			if (_propUseYpCbCr == 0)
 | |
| 				_propUseYpCbCr = Shader.PropertyToID("_UseYpCbCr");
 | |
| 			if (_propChromaTex == 0)
 | |
| 				_propChromaTex = Shader.PropertyToID(PropChromaTexName);
 | |
| 		}
 | |
| 
 | |
| 		void Start()
 | |
| 		{
 | |
| 			if (_mesh == null)
 | |
| 			{
 | |
| 				_mesh = new Mesh();
 | |
| 				_mesh.MarkDynamic();
 | |
| 				MeshFilter filter = this.GetComponent<MeshFilter>();
 | |
| 				if (filter != null)
 | |
| 				{
 | |
| 					filter.mesh = _mesh;
 | |
| 				}
 | |
| 				_renderer = this.GetComponent<MeshRenderer>();
 | |
| 				if (_renderer != null)
 | |
| 				{
 | |
| 					_renderer.material = _material;
 | |
| 				}
 | |
| 				BuildMesh();
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		void OnDestroy()
 | |
| 		{
 | |
| 			if (_mesh != null)
 | |
| 			{
 | |
| 				MeshFilter filter = this.GetComponent<MeshFilter>();
 | |
| 				if (filter != null)
 | |
| 				{
 | |
| 					filter.mesh = null;
 | |
| 				}
 | |
| 
 | |
| #if UNITY_EDITOR
 | |
| 				Mesh.DestroyImmediate(_mesh);
 | |
| #else
 | |
| 				Mesh.Destroy(_mesh);
 | |
| #endif
 | |
| 				_mesh = null;
 | |
| 			}
 | |
| 
 | |
| 			if (_renderer != null)
 | |
| 			{
 | |
| 				_renderer.material = null;
 | |
| 				_renderer = null;
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		// We do a LateUpdate() to allow for any changes in the texture that may have happened in Update()
 | |
| 		void LateUpdate()
 | |
| 		{
 | |
| 			if (Application.isPlaying)
 | |
| 			{
 | |
| 				Texture texture = null;
 | |
| 				bool requiresVerticalFlip = false;
 | |
| 				if (_mediaPlayer != null && _mediaPlayer.Control != null)
 | |
| 				{
 | |
| 					if (_mediaPlayer.TextureProducer != null)
 | |
| 					{
 | |
| 						Texture resamplerTex = _mediaPlayer.FrameResampler == null || _mediaPlayer.FrameResampler.OutputTexture == null ? null : _mediaPlayer.FrameResampler.OutputTexture[0];
 | |
| 						texture = _mediaPlayer.m_Resample ? resamplerTex : _mediaPlayer.TextureProducer.GetTexture();
 | |
| 						requiresVerticalFlip = _mediaPlayer.TextureProducer.RequiresVerticalFlip();
 | |
| 
 | |
| 						// Detect changes that we need to apply to the material/mesh
 | |
| 						if (_texture != texture || 
 | |
| 							_verticalFlip != requiresVerticalFlip ||
 | |
| 							(texture != null && (_textureWidth != texture.width || _textureHeight != texture.height))
 | |
| 							)
 | |
| 						{
 | |
| 							_texture = texture;
 | |
| 							if (texture != null)
 | |
| 							{
 | |
| 								UpdateMeshUV(texture.width, texture.height, requiresVerticalFlip);
 | |
| 							}
 | |
| 						}
 | |
| 
 | |
| #if UNITY_PLATFORM_SUPPORTS_LINEAR
 | |
| 						// Apply gamma
 | |
| 						if (_renderer.material.HasProperty(_propApplyGamma) && _mediaPlayer.Info != null)
 | |
| 						{
 | |
| 							Helper.SetupGammaMaterial(_renderer.material, _mediaPlayer.Info.PlayerSupportsLinearColorSpace());
 | |
| 						}
 | |
| #endif
 | |
| 						if (_renderer.material.HasProperty(_propUseYpCbCr) && _mediaPlayer.TextureProducer.GetTextureCount() == 2)
 | |
| 						{
 | |
| 							_renderer.material.EnableKeyword("USE_YPCBCR");
 | |
| 							Texture resamplerTexYCRCB = _mediaPlayer.FrameResampler == null || _mediaPlayer.FrameResampler.OutputTexture == null ? null : _mediaPlayer.FrameResampler.OutputTexture[1];
 | |
| 							_renderer.material.SetTexture(_propChromaTex, _mediaPlayer.m_Resample ? resamplerTexYCRCB : _mediaPlayer.TextureProducer.GetTexture(1));
 | |
| 						}
 | |
| 					}
 | |
| 
 | |
| 					_renderer.material.mainTexture = _texture;
 | |
| 				}
 | |
| 				else
 | |
| 				{
 | |
| 					_renderer.material.mainTexture = null;
 | |
| 				}
 | |
| 			}
 | |
| 		}	
 | |
| 
 | |
| 		private void BuildMesh()
 | |
| 		{
 | |
| 			Vector3 offset = new Vector3(-0.5f, -0.5f, -0.5f);
 | |
| 			Vector3[] v = new Vector3[]
 | |
| 			{
 | |
| 				// Left
 | |
| 				new Vector3(0f,-1f,0f) - offset,
 | |
| 				new Vector3(0f,0f,0f) - offset,
 | |
| 				new Vector3(0f,0f,-1f) - offset,
 | |
| 				new Vector3(0f,-1f,-1f) - offset,
 | |
| 				// Front
 | |
| 				new Vector3(0f,0f,0f) - offset,
 | |
| 				new Vector3(-1f,0f,0f) - offset,
 | |
| 				new Vector3(-1f,0f,-1f) - offset,
 | |
| 				new Vector3(0f,0f,-1f) - offset,
 | |
| 				// Right
 | |
| 				new Vector3(-1f,0f,0f) - offset,
 | |
| 				new Vector3(-1f,-1f,0f) - offset,
 | |
| 				new Vector3(-1f,-1f,-1f) - offset,
 | |
| 				new Vector3(-1f,0f,-1f) - offset,
 | |
| 				// Back
 | |
| 				new Vector3(-1f,-1f,0f) - offset,
 | |
| 				new Vector3(0f,-1f,0f) - offset,
 | |
| 				new Vector3(0f,-1f,-1f) - offset,
 | |
| 				new Vector3(-1f,-1f,-1f) - offset,
 | |
| 				// Bottom
 | |
| 				new Vector3(0f,-1f,-1f) - offset,
 | |
| 				new Vector3(0f,0f,-1f) - offset,
 | |
| 				new Vector3(-1f,0f,-1f) - offset,
 | |
| 				new Vector3(-1f,-1f,-1f) - offset,
 | |
| 				// Top
 | |
| 				new Vector3(-1f,-1f,0f) - offset,
 | |
| 				new Vector3(-1f,0f,0f) - offset,
 | |
| 				new Vector3(0f,0f,0f) - offset,
 | |
| 				new Vector3(0f,-1f,0f) - offset,
 | |
| 			};
 | |
| 
 | |
| 			Matrix4x4 rot = Matrix4x4.TRS(Vector3.zero, Quaternion.AngleAxis(-90f, Vector3.right), Vector3.one);
 | |
| 			for (int i = 0; i < v.Length; i++)
 | |
| 			{
 | |
| 				v[i] = rot.MultiplyPoint(v[i]);
 | |
| 			}
 | |
| 
 | |
| 			_mesh.vertices = v;
 | |
| 
 | |
| 			_mesh.triangles = new int[]
 | |
| 			{
 | |
| 				0,1,2,
 | |
| 				0,2,3,
 | |
| 				4,5,6,
 | |
| 				4,6,7,
 | |
| 				8,9,10,
 | |
| 				8,10,11,
 | |
| 				12,13,14,
 | |
| 				12,14,15,
 | |
| 				16,17,18,
 | |
| 				16,18,19,
 | |
| 				20,21,22,
 | |
| 				20,22,23,
 | |
| 			};
 | |
| 
 | |
| 			_mesh.normals = new Vector3[]
 | |
| 			{
 | |
| 				// Left
 | |
| 				new Vector3(-1f,0f,0f),
 | |
| 				new Vector3(-1f,0f,0f),
 | |
| 				new Vector3(-1f,0f,0f),
 | |
| 				new Vector3(-1f,0f,0f),
 | |
| 				// Front
 | |
| 				new Vector3(0f,-1f,0f),
 | |
| 				new Vector3(0f,-1f,0f),
 | |
| 				new Vector3(0f,-1f,0f),
 | |
| 				new Vector3(0f,-1f,0f),
 | |
| 				// Right
 | |
| 				new Vector3(1f,0f,0f),
 | |
| 				new Vector3(1f,0f,0f),
 | |
| 				new Vector3(1f,0f,0f),
 | |
| 				new Vector3(1f,0f,0f),
 | |
| 				// Back
 | |
| 				new Vector3(0f,1f,0f),
 | |
| 				new Vector3(0f,1f,0f),
 | |
| 				new Vector3(0f,1f,0f),
 | |
| 				new Vector3(0f,1f,0f),
 | |
| 				// Bottom
 | |
| 				new Vector3(0f,0f,1f),
 | |
| 				new Vector3(0f,0f,1f),
 | |
| 				new Vector3(0f,0f,1f),
 | |
| 				new Vector3(0f,0f,1f),
 | |
| 				// Top
 | |
| 				new Vector3(0f,0f,-1f),
 | |
| 				new Vector3(0f,0f,-1f),
 | |
| 				new Vector3(0f,0f,-1f),
 | |
| 				new Vector3(0f,0f,-1f)
 | |
| 			};
 | |
| 
 | |
| 			UpdateMeshUV(512, 512, false);
 | |
| 		}
 | |
| 
 | |
| 		private void UpdateMeshUV(int textureWidth, int textureHeight, bool flipY)
 | |
| 		{
 | |
| 			_textureWidth = textureWidth;
 | |
| 			_textureHeight = textureHeight;
 | |
| 			_verticalFlip = flipY;
 | |
| 
 | |
| 			float texWidth = textureWidth;
 | |
| 			float texHeight = textureHeight;
 | |
| 
 | |
| 			float blockWidth = texWidth / 3f;
 | |
| 			float pixelOffset = Mathf.Floor(((expansion_coeff * blockWidth) - blockWidth) / 2f);
 | |
| 
 | |
| 			float wO = pixelOffset / texWidth;
 | |
| 			float hO = pixelOffset / texHeight;
 | |
| 
 | |
| 			const float third = 1f / 3f;
 | |
| 			const float half = 0.5f;
 | |
| 
 | |
| 			Vector2[] uv = null;
 | |
| 			if (_layout == Layout.Facebook360Capture)
 | |
| 			{
 | |
| 				uv = new Vector2[]
 | |
| 				{
 | |
| 					//front (texture middle top) correct left
 | |
| 					new Vector2(third+wO, half-hO),
 | |
| 					new Vector2((third*2f)-wO, half-hO),
 | |
| 					new Vector2((third*2f)-wO, 0f+hO),
 | |
| 					new Vector2(third+wO, 0f+hO),
 | |
| 				
 | |
| 					//left (texture middle bottom) correct front
 | |
| 					new Vector2(third+wO,1f-hO),
 | |
| 					new Vector2((third*2f)-wO, 1f-hO),
 | |
| 					new Vector2((third*2f)-wO, half+hO),
 | |
| 					new Vector2(third+wO, half+hO),
 | |
| 
 | |
| 					//bottom (texture left top) correct right
 | |
| 					new Vector2(0f+wO, half-hO),
 | |
| 					new Vector2(third-wO, half-hO),
 | |
| 					new Vector2(third-wO, 0f+hO),
 | |
| 					new Vector2(0f+wO, 0f+hO),
 | |
| 
 | |
| 					//top (texture right top) correct rear
 | |
| 					new Vector2((third*2f)+wO, 1f-hO),
 | |
| 					new Vector2(1f-wO, 1f-hO),
 | |
| 					new Vector2(1f-wO, half+hO),
 | |
| 					new Vector2((third*2f)+wO, half+hO),
 | |
| 
 | |
| 					//back (texture right bottom) correct ground
 | |
| 					new Vector2((third*2f)+wO, 0f+hO),
 | |
| 					new Vector2((third*2f)+wO, half-hO),
 | |
| 					new Vector2(1f-wO, half-hO),
 | |
| 					new Vector2(1f-wO, 0f+hO),
 | |
| 
 | |
| 					//right (texture left bottom) correct sky
 | |
| 					new Vector2(third-wO, 1f-hO),
 | |
| 					new Vector2(third-wO, half+hO),
 | |
| 					new Vector2(0f+wO, half+hO),
 | |
| 					new Vector2(0f+wO, 1f-hO),
 | |
| 				};
 | |
| 			}
 | |
| 			else if (_layout == Layout.FacebookTransform32)
 | |
| 			{
 | |
| 				uv = new Vector2[]
 | |
| 				{
 | |
| 					//left
 | |
| 					new Vector2(third+wO,1f-hO),
 | |
| 					new Vector2((third*2f)-wO, 1f-hO),
 | |
| 					new Vector2((third*2f)-wO, half+hO),
 | |
| 					new Vector2(third+wO, half+hO),
 | |
| 
 | |
| 					//front
 | |
| 					new Vector2(third+wO, half-hO),
 | |
| 					new Vector2((third*2f)-wO, half-hO),
 | |
| 					new Vector2((third*2f)-wO, 0f+hO),
 | |
| 					new Vector2(third+wO, 0f+hO),
 | |
| 
 | |
| 					//right
 | |
| 					new Vector2(0f+wO, 1f-hO),
 | |
| 					new Vector2(third-wO, 1f-hO),
 | |
| 					new Vector2(third-wO, half+hO),
 | |
| 					new Vector2(0f+wO, half+hO),
 | |
| 
 | |
| 					//back
 | |
| 					new Vector2((third*2f)+wO, half-hO),
 | |
| 					new Vector2(1f-wO, half-hO),
 | |
| 					new Vector2(1f-wO, 0f+hO),
 | |
| 					new Vector2((third*2f)+wO, 0f+hO),
 | |
| 
 | |
| 					//bottom
 | |
| 					new Vector2(0f+wO, 0f+hO),
 | |
| 					new Vector2(0f+wO, half-hO),
 | |
| 					new Vector2(third-wO, half-hO),
 | |
| 					new Vector2(third-wO, 0f+hO),
 | |
| 
 | |
| 					//top
 | |
| 					new Vector2(1f-wO, 1f-hO),
 | |
| 					new Vector2(1f-wO, half+hO),
 | |
| 					new Vector2((third*2f)+wO, half+hO),
 | |
| 					new Vector2((third*2f)+wO, 1f-hO)
 | |
| 				};
 | |
| 			}
 | |
| 			
 | |
| 			if (flipY)
 | |
| 			{
 | |
| 				for (int i = 0; i < uv.Length; i++)
 | |
| 				{
 | |
| 					uv[i].y = 1f - uv[i].y;
 | |
| 				}
 | |
| 			}
 | |
| 
 | |
| 			_mesh.uv = uv;
 | |
| 			_mesh.UploadMeshData(false);
 | |
| 		}
 | |
| 	}
 | |
| }
 |