CubemapCube.cs 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408
  1. #if UNITY_EDITOR || UNITY_STANDALONE_OSX || UNITY_STANDALONE_WIN
  2. #define UNITY_PLATFORM_SUPPORTS_LINEAR
  3. #elif UNITY_IOS || UNITY_ANDROID
  4. #if UNITY_5_5_OR_NEWER || (UNITY_5 && !UNITY_5_0 && !UNITY_5_1 && !UNITY_5_2 && !UNITY_5_3 && !UNITY_5_4)
  5. #define UNITY_PLATFORM_SUPPORTS_LINEAR
  6. #endif
  7. #endif
  8. #if UNITY_5_4_OR_NEWER || (UNITY_5 && !UNITY_5_0)
  9. #define UNITY_HELPATTRIB
  10. #endif
  11. using UnityEngine;
  12. //-----------------------------------------------------------------------------
  13. // Copyright 2015-2020 RenderHeads Ltd. All rights reserved.
  14. //-----------------------------------------------------------------------------
  15. namespace RenderHeads.Media.AVProVideo
  16. {
  17. /// <summary>
  18. /// Builds a cube mesh for displaying a 360 degree "Cubemap 3x2 facebook layout" texture in VR
  19. /// </summary>
  20. [RequireComponent(typeof(MeshRenderer))]
  21. [RequireComponent(typeof(MeshFilter))]
  22. //[ExecuteInEditMode]
  23. [AddComponentMenu("AVPro Video/Cubemap Cube (VR)", 400)]
  24. #if UNITY_HELPATTRIB
  25. [HelpURL("http://renderheads.com/products/avpro-video/")]
  26. #endif
  27. public class CubemapCube : MonoBehaviour
  28. {
  29. public enum Layout
  30. {
  31. FacebookTransform32, // Layout for Facebooks FFMPEG Transform plugin with 3:2 layout
  32. Facebook360Capture, // Layout for Facebooks 360-Capture-SDK
  33. }
  34. private Mesh _mesh;
  35. protected MeshRenderer _renderer;
  36. [SerializeField]
  37. protected Material _material = null;
  38. [SerializeField]
  39. private MediaPlayer _mediaPlayer = null;
  40. // This value comes from the facebook transform ffmpeg filter and is used to prevent seams appearing along the edges due to bilinear filtering
  41. [SerializeField]
  42. private float expansion_coeff = 1.01f;
  43. [SerializeField]
  44. private Layout _layout = Layout.FacebookTransform32;
  45. private Texture _texture;
  46. private bool _verticalFlip;
  47. private int _textureWidth;
  48. private int _textureHeight;
  49. private static int _propApplyGamma;
  50. private static int _propStereo;
  51. private static int _propUseYpCbCr;
  52. private const string PropChromaTexName = "_ChromaTex";
  53. private static int _propChromaTex;
  54. private const string PropYpCbCrTransformName = "_YpCbCrTransform";
  55. private static int _propYpCbCrTransform;
  56. public MediaPlayer Player
  57. {
  58. set { _mediaPlayer = value; }
  59. get { return _mediaPlayer; }
  60. }
  61. void Awake()
  62. {
  63. if (_propStereo == 0)
  64. {
  65. _propStereo = Shader.PropertyToID("Stereo");
  66. }
  67. if (_propApplyGamma == 0)
  68. {
  69. _propApplyGamma = Shader.PropertyToID("_ApplyGamma");
  70. }
  71. if (_propUseYpCbCr == 0)
  72. _propUseYpCbCr = Shader.PropertyToID("_UseYpCbCr");
  73. if (_propChromaTex == 0)
  74. _propChromaTex = Shader.PropertyToID(PropChromaTexName);
  75. if (_propYpCbCrTransform == 0)
  76. _propYpCbCrTransform = Shader.PropertyToID(PropYpCbCrTransformName);
  77. }
  78. void Start()
  79. {
  80. if (_mesh == null)
  81. {
  82. _mesh = new Mesh();
  83. _mesh.MarkDynamic();
  84. MeshFilter filter = this.GetComponent<MeshFilter>();
  85. if (filter != null)
  86. {
  87. filter.mesh = _mesh;
  88. }
  89. _renderer = this.GetComponent<MeshRenderer>();
  90. if (_renderer != null)
  91. {
  92. _renderer.material = _material;
  93. }
  94. BuildMesh();
  95. }
  96. }
  97. void OnDestroy()
  98. {
  99. if (_mesh != null)
  100. {
  101. MeshFilter filter = this.GetComponent<MeshFilter>();
  102. if (filter != null)
  103. {
  104. filter.mesh = null;
  105. }
  106. #if UNITY_EDITOR
  107. Mesh.DestroyImmediate(_mesh);
  108. #else
  109. Mesh.Destroy(_mesh);
  110. #endif
  111. _mesh = null;
  112. }
  113. if (_renderer != null)
  114. {
  115. _renderer.material = null;
  116. _renderer = null;
  117. }
  118. }
  119. // We do a LateUpdate() to allow for any changes in the texture that may have happened in Update()
  120. void LateUpdate()
  121. {
  122. if (Application.isPlaying)
  123. {
  124. Texture texture = null;
  125. bool requiresVerticalFlip = false;
  126. if (_mediaPlayer != null && _mediaPlayer.Control != null)
  127. {
  128. if (_mediaPlayer.TextureProducer != null)
  129. {
  130. Texture resamplerTex = _mediaPlayer.FrameResampler == null || _mediaPlayer.FrameResampler.OutputTexture == null ? null : _mediaPlayer.FrameResampler.OutputTexture[0];
  131. texture = _mediaPlayer.m_Resample ? resamplerTex : _mediaPlayer.TextureProducer.GetTexture();
  132. requiresVerticalFlip = _mediaPlayer.TextureProducer.RequiresVerticalFlip();
  133. // Detect changes that we need to apply to the material/mesh
  134. if (_texture != texture ||
  135. _verticalFlip != requiresVerticalFlip ||
  136. (texture != null && (_textureWidth != texture.width || _textureHeight != texture.height))
  137. )
  138. {
  139. _texture = texture;
  140. if (texture != null)
  141. {
  142. UpdateMeshUV(texture.width, texture.height, requiresVerticalFlip);
  143. }
  144. }
  145. #if UNITY_PLATFORM_SUPPORTS_LINEAR
  146. // Apply gamma
  147. if (_renderer.material.HasProperty(_propApplyGamma) && _mediaPlayer.Info != null)
  148. {
  149. Helper.SetupGammaMaterial(_renderer.material, _mediaPlayer.Info.PlayerSupportsLinearColorSpace());
  150. }
  151. #endif
  152. // Apply changes for stereo videos
  153. if (_renderer.material.HasProperty(_propStereo))
  154. {
  155. Helper.SetupStereoMaterial(_renderer.material, _mediaPlayer.m_StereoPacking, _mediaPlayer.m_DisplayDebugStereoColorTint);
  156. }
  157. if (_renderer.material.HasProperty(_propUseYpCbCr) && _mediaPlayer.TextureProducer.GetTextureCount() == 2)
  158. {
  159. _renderer.material.EnableKeyword("USE_YPCBCR");
  160. Texture resamplerTexYCRCB = _mediaPlayer.FrameResampler == null || _mediaPlayer.FrameResampler.OutputTexture == null ? null : _mediaPlayer.FrameResampler.OutputTexture[1];
  161. _renderer.material.SetTexture(_propChromaTex, _mediaPlayer.m_Resample ? resamplerTexYCRCB : _mediaPlayer.TextureProducer.GetTexture(1));
  162. _renderer.material.SetMatrix(_propYpCbCrTransform, _mediaPlayer.TextureProducer.GetYpCbCrTransform());
  163. }
  164. }
  165. _renderer.material.mainTexture = _texture;
  166. }
  167. else
  168. {
  169. _renderer.material.mainTexture = null;
  170. }
  171. }
  172. }
  173. private void BuildMesh()
  174. {
  175. Vector3 offset = new Vector3(-0.5f, -0.5f, -0.5f);
  176. Vector3[] v = new Vector3[]
  177. {
  178. // Left
  179. new Vector3(0f,-1f,0f) - offset,
  180. new Vector3(0f,0f,0f) - offset,
  181. new Vector3(0f,0f,-1f) - offset,
  182. new Vector3(0f,-1f,-1f) - offset,
  183. // Front
  184. new Vector3(0f,0f,0f) - offset,
  185. new Vector3(-1f,0f,0f) - offset,
  186. new Vector3(-1f,0f,-1f) - offset,
  187. new Vector3(0f,0f,-1f) - offset,
  188. // Right
  189. new Vector3(-1f,0f,0f) - offset,
  190. new Vector3(-1f,-1f,0f) - offset,
  191. new Vector3(-1f,-1f,-1f) - offset,
  192. new Vector3(-1f,0f,-1f) - offset,
  193. // Back
  194. new Vector3(-1f,-1f,0f) - offset,
  195. new Vector3(0f,-1f,0f) - offset,
  196. new Vector3(0f,-1f,-1f) - offset,
  197. new Vector3(-1f,-1f,-1f) - offset,
  198. // Bottom
  199. new Vector3(0f,-1f,-1f) - offset,
  200. new Vector3(0f,0f,-1f) - offset,
  201. new Vector3(-1f,0f,-1f) - offset,
  202. new Vector3(-1f,-1f,-1f) - offset,
  203. // Top
  204. new Vector3(-1f,-1f,0f) - offset,
  205. new Vector3(-1f,0f,0f) - offset,
  206. new Vector3(0f,0f,0f) - offset,
  207. new Vector3(0f,-1f,0f) - offset,
  208. };
  209. Matrix4x4 rot = Matrix4x4.TRS(Vector3.zero, Quaternion.AngleAxis(-90f, Vector3.right), Vector3.one);
  210. for (int i = 0; i < v.Length; i++)
  211. {
  212. v[i] = rot.MultiplyPoint(v[i]);
  213. }
  214. _mesh.vertices = v;
  215. _mesh.triangles = new int[]
  216. {
  217. 0,1,2,
  218. 0,2,3,
  219. 4,5,6,
  220. 4,6,7,
  221. 8,9,10,
  222. 8,10,11,
  223. 12,13,14,
  224. 12,14,15,
  225. 16,17,18,
  226. 16,18,19,
  227. 20,21,22,
  228. 20,22,23,
  229. };
  230. _mesh.normals = new Vector3[]
  231. {
  232. // Left
  233. new Vector3(-1f,0f,0f),
  234. new Vector3(-1f,0f,0f),
  235. new Vector3(-1f,0f,0f),
  236. new Vector3(-1f,0f,0f),
  237. // Front
  238. new Vector3(0f,-1f,0f),
  239. new Vector3(0f,-1f,0f),
  240. new Vector3(0f,-1f,0f),
  241. new Vector3(0f,-1f,0f),
  242. // Right
  243. new Vector3(1f,0f,0f),
  244. new Vector3(1f,0f,0f),
  245. new Vector3(1f,0f,0f),
  246. new Vector3(1f,0f,0f),
  247. // Back
  248. new Vector3(0f,1f,0f),
  249. new Vector3(0f,1f,0f),
  250. new Vector3(0f,1f,0f),
  251. new Vector3(0f,1f,0f),
  252. // Bottom
  253. new Vector3(0f,0f,1f),
  254. new Vector3(0f,0f,1f),
  255. new Vector3(0f,0f,1f),
  256. new Vector3(0f,0f,1f),
  257. // Top
  258. new Vector3(0f,0f,-1f),
  259. new Vector3(0f,0f,-1f),
  260. new Vector3(0f,0f,-1f),
  261. new Vector3(0f,0f,-1f)
  262. };
  263. UpdateMeshUV(512, 512, false);
  264. }
  265. private void UpdateMeshUV(int textureWidth, int textureHeight, bool flipY)
  266. {
  267. _textureWidth = textureWidth;
  268. _textureHeight = textureHeight;
  269. _verticalFlip = flipY;
  270. float texWidth = textureWidth;
  271. float texHeight = textureHeight;
  272. float blockWidth = texWidth / 3f;
  273. float pixelOffset = Mathf.Floor(((expansion_coeff * blockWidth) - blockWidth) / 2f);
  274. float wO = pixelOffset / texWidth;
  275. float hO = pixelOffset / texHeight;
  276. const float third = 1f / 3f;
  277. const float half = 0.5f;
  278. Vector2[] uv = null;
  279. if (_layout == Layout.Facebook360Capture)
  280. {
  281. uv = new Vector2[]
  282. {
  283. //front (texture middle top) correct left
  284. new Vector2(third+wO, half-hO),
  285. new Vector2((third*2f)-wO, half-hO),
  286. new Vector2((third*2f)-wO, 0f+hO),
  287. new Vector2(third+wO, 0f+hO),
  288. //left (texture middle bottom) correct front
  289. new Vector2(third+wO,1f-hO),
  290. new Vector2((third*2f)-wO, 1f-hO),
  291. new Vector2((third*2f)-wO, half+hO),
  292. new Vector2(third+wO, half+hO),
  293. //bottom (texture left top) correct right
  294. new Vector2(0f+wO, half-hO),
  295. new Vector2(third-wO, half-hO),
  296. new Vector2(third-wO, 0f+hO),
  297. new Vector2(0f+wO, 0f+hO),
  298. //top (texture right top) correct rear
  299. new Vector2((third*2f)+wO, 1f-hO),
  300. new Vector2(1f-wO, 1f-hO),
  301. new Vector2(1f-wO, half+hO),
  302. new Vector2((third*2f)+wO, half+hO),
  303. //back (texture right bottom) correct ground
  304. new Vector2((third*2f)+wO, 0f+hO),
  305. new Vector2((third*2f)+wO, half-hO),
  306. new Vector2(1f-wO, half-hO),
  307. new Vector2(1f-wO, 0f+hO),
  308. //right (texture left bottom) correct sky
  309. new Vector2(third-wO, 1f-hO),
  310. new Vector2(third-wO, half+hO),
  311. new Vector2(0f+wO, half+hO),
  312. new Vector2(0f+wO, 1f-hO),
  313. };
  314. }
  315. else if (_layout == Layout.FacebookTransform32)
  316. {
  317. uv = new Vector2[]
  318. {
  319. //left
  320. new Vector2(third+wO,1f-hO),
  321. new Vector2((third*2f)-wO, 1f-hO),
  322. new Vector2((third*2f)-wO, half+hO),
  323. new Vector2(third+wO, half+hO),
  324. //front
  325. new Vector2(third+wO, half-hO),
  326. new Vector2((third*2f)-wO, half-hO),
  327. new Vector2((third*2f)-wO, 0f+hO),
  328. new Vector2(third+wO, 0f+hO),
  329. //right
  330. new Vector2(0f+wO, 1f-hO),
  331. new Vector2(third-wO, 1f-hO),
  332. new Vector2(third-wO, half+hO),
  333. new Vector2(0f+wO, half+hO),
  334. //back
  335. new Vector2((third*2f)+wO, half-hO),
  336. new Vector2(1f-wO, half-hO),
  337. new Vector2(1f-wO, 0f+hO),
  338. new Vector2((third*2f)+wO, 0f+hO),
  339. //bottom
  340. new Vector2(0f+wO, 0f+hO),
  341. new Vector2(0f+wO, half-hO),
  342. new Vector2(third-wO, half-hO),
  343. new Vector2(third-wO, 0f+hO),
  344. //top
  345. new Vector2(1f-wO, 1f-hO),
  346. new Vector2(1f-wO, half+hO),
  347. new Vector2((third*2f)+wO, half+hO),
  348. new Vector2((third*2f)+wO, 1f-hO)
  349. };
  350. }
  351. if (flipY)
  352. {
  353. for (int i = 0; i < uv.Length; i++)
  354. {
  355. uv[i].y = 1f - uv[i].y;
  356. }
  357. }
  358. _mesh.uv = uv;
  359. _mesh.UploadMeshData(false);
  360. }
  361. }
  362. }