ApplyToMesh.cs 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411
  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. /// Sets up a mesh to display the video from a MediaPlayer
  19. /// </summary>
  20. [AddComponentMenu("AVPro Video/Apply To Mesh", 300)]
  21. #if UNITY_HELPATTRIB
  22. [HelpURL("http://renderheads.com/products/avpro-video/")]
  23. #endif
  24. public class ApplyToMesh : MonoBehaviour
  25. {
  26. // TODO: add specific material / material index to target in the mesh if there are multiple materials
  27. [Header("Media Source")]
  28. [SerializeField] public MediaPlayer _media = null;
  29. public MediaPlayer Player
  30. {
  31. get { return _media; }
  32. set { ChangeMediaPlayer(value); }
  33. }
  34. [Tooltip("Default texture to display when the video texture is preparing")]
  35. [SerializeField] public Texture2D _defaultTexture = null;
  36. public Texture2D DefaultTexture
  37. {
  38. get { return _defaultTexture; }
  39. set { if (_defaultTexture != value) { _defaultTexture = value; _isDirty = true; } }
  40. }
  41. [Space(8f)]
  42. [Header("Renderer Target")]
  43. [SerializeField] public Renderer _mesh = null;
  44. public Renderer MeshRenderer
  45. {
  46. get { return _mesh; }
  47. set { if (_mesh != value) { _mesh = value; _isDirty = true; } }
  48. }
  49. [SerializeField] string _texturePropertyName = "_MainTex";
  50. public string TexturePropertyName
  51. {
  52. get { return _texturePropertyName; }
  53. set
  54. {
  55. if (_texturePropertyName != value)
  56. {
  57. _texturePropertyName = value;
  58. #if UNITY_5_6_OR_NEWER
  59. _propTexture = Shader.PropertyToID(_texturePropertyName);
  60. #endif
  61. _isDirty = true;
  62. }
  63. }
  64. }
  65. [SerializeField] Vector2 _offset = Vector2.zero;
  66. public Vector2 Offset
  67. {
  68. get { return _offset; }
  69. set { if (_offset != value) { _offset = value; _isDirty = true; } }
  70. }
  71. [SerializeField] Vector2 _scale = Vector2.one;
  72. public Vector2 Scale
  73. {
  74. get { return _scale; }
  75. set { if (_scale != value) { _scale = value; _isDirty = true; } }
  76. }
  77. private bool _isDirty = false;
  78. private Texture _lastTextureApplied;
  79. #if UNITY_5_6_OR_NEWER
  80. private int _propTexture;
  81. #endif
  82. private static int _propStereo;
  83. private static int _propAlphaPack;
  84. private static int _propApplyGamma;
  85. private static int _propLayout;
  86. private const string PropChromaTexName = "_ChromaTex";
  87. private static int _propChromaTex;
  88. private const string PropYpCbCrTransformName = "_YpCbCrTransform";
  89. private static int _propYpCbCrTransform;
  90. private const string PropUseYpCbCrName = "_UseYpCbCr";
  91. private static int _propUseYpCbCr;
  92. private static int _propCroppingScalars;
  93. private void Awake()
  94. {
  95. if (_propStereo == 0)
  96. {
  97. _propStereo = Shader.PropertyToID("Stereo");
  98. }
  99. if (_propAlphaPack == 0)
  100. {
  101. _propAlphaPack = Shader.PropertyToID("AlphaPack");
  102. }
  103. if (_propApplyGamma == 0)
  104. {
  105. _propApplyGamma = Shader.PropertyToID("_ApplyGamma");
  106. }
  107. if (_propLayout == 0)
  108. {
  109. _propLayout = Shader.PropertyToID("Layout");
  110. }
  111. if (_propChromaTex == 0)
  112. {
  113. _propChromaTex = Shader.PropertyToID(PropChromaTexName);
  114. }
  115. if (_propYpCbCrTransform == 0)
  116. {
  117. _propYpCbCrTransform = Shader.PropertyToID(PropYpCbCrTransformName);
  118. }
  119. if (_propUseYpCbCr == 0)
  120. {
  121. _propUseYpCbCr = Shader.PropertyToID(PropUseYpCbCrName);
  122. }
  123. if (_propCroppingScalars == 0)
  124. {
  125. _propCroppingScalars = Shader.PropertyToID("_CroppingScalars");
  126. }
  127. if (_media != null)
  128. {
  129. _media.Events.AddListener(OnMediaPlayerEvent);
  130. }
  131. }
  132. public void ForceUpdate()
  133. {
  134. _isDirty = true;
  135. LateUpdate();
  136. }
  137. // Callback function to handle events
  138. private void OnMediaPlayerEvent(MediaPlayer mp, MediaPlayerEvent.EventType et, ErrorCode errorCode)
  139. {
  140. switch (et)
  141. {
  142. case MediaPlayerEvent.EventType.FirstFrameReady:
  143. case MediaPlayerEvent.EventType.PropertiesChanged:
  144. ForceUpdate();
  145. break;
  146. }
  147. }
  148. private void ChangeMediaPlayer(MediaPlayer player)
  149. {
  150. if (_media != player)
  151. {
  152. if (_media != null)
  153. {
  154. _media.Events.RemoveListener(OnMediaPlayerEvent);
  155. }
  156. _media = player;
  157. if (_media != null)
  158. {
  159. _media.Events.AddListener(OnMediaPlayerEvent);
  160. }
  161. _isDirty = true;
  162. }
  163. }
  164. // We do a LateUpdate() to allow for any changes in the texture that may have happened in Update()
  165. private void LateUpdate()
  166. {
  167. bool applied = false;
  168. // Try to apply texture from media
  169. if (_media != null && _media.TextureProducer != null)
  170. {
  171. Texture resamplerTex = _media.FrameResampler == null || _media.FrameResampler.OutputTexture == null ? null : _media.FrameResampler.OutputTexture[0];
  172. Texture texture = _media.m_Resample ? resamplerTex : _media.TextureProducer.GetTexture(0);
  173. if (texture != null)
  174. {
  175. // Check for changing texture
  176. if (texture != _lastTextureApplied)
  177. {
  178. _isDirty = true;
  179. }
  180. if (_isDirty)
  181. {
  182. int planeCount = _media.m_Resample ? 1 : _media.TextureProducer.GetTextureCount();
  183. for (int plane = 0; plane < planeCount; plane++)
  184. {
  185. Texture resamplerTexPlane = _media.FrameResampler == null || _media.FrameResampler.OutputTexture == null ? null : _media.FrameResampler.OutputTexture[plane];
  186. texture = _media.m_Resample ? resamplerTexPlane : _media.TextureProducer.GetTexture(plane);
  187. if (texture != null)
  188. {
  189. ApplyMapping(texture, _media.TextureProducer.RequiresVerticalFlip(), plane);
  190. }
  191. }
  192. }
  193. applied = true;
  194. }
  195. }
  196. // If the media didn't apply a texture, then try to apply the default texture
  197. if (!applied)
  198. {
  199. if (_defaultTexture != _lastTextureApplied)
  200. {
  201. _isDirty = true;
  202. }
  203. if (_isDirty)
  204. {
  205. ApplyMapping(_defaultTexture, false);
  206. }
  207. }
  208. }
  209. private void ApplyMapping(Texture texture, bool requiresYFlip, int plane = 0)
  210. {
  211. if (_mesh != null)
  212. {
  213. _isDirty = false;
  214. Material[] meshMaterials = _mesh.materials;
  215. if (meshMaterials != null)
  216. {
  217. for (int i = 0; i < meshMaterials.Length; i++)
  218. {
  219. Material mat = meshMaterials[i];
  220. if (mat != null)
  221. {
  222. if (plane == 0)
  223. {
  224. #if UNITY_5_6_OR_NEWER
  225. mat.SetTexture(_propTexture, texture);
  226. #else
  227. mat.SetTexture(_texturePropertyName, texture);
  228. #endif
  229. _lastTextureApplied = texture;
  230. if (texture != null)
  231. {
  232. #if UNITY_5_6_OR_NEWER
  233. if (requiresYFlip)
  234. {
  235. mat.SetTextureScale(_propTexture, new Vector2(_scale.x, -_scale.y));
  236. mat.SetTextureOffset(_propTexture, Vector2.up + _offset);
  237. }
  238. else
  239. {
  240. mat.SetTextureScale(_propTexture, _scale);
  241. mat.SetTextureOffset(_propTexture, _offset);
  242. }
  243. #else
  244. if (requiresYFlip)
  245. {
  246. mat.SetTextureScale(_texturePropertyName, new Vector2(_scale.x, -_scale.y));
  247. mat.SetTextureOffset(_texturePropertyName, Vector2.up + _offset);
  248. }
  249. else
  250. {
  251. mat.SetTextureScale(_texturePropertyName, _scale);
  252. mat.SetTextureOffset(_texturePropertyName, _offset);
  253. }
  254. #endif
  255. }
  256. }
  257. else if (plane == 1)
  258. {
  259. if (mat.HasProperty(_propUseYpCbCr) && mat.HasProperty(_propChromaTex))
  260. {
  261. mat.EnableKeyword("USE_YPCBCR");
  262. mat.SetTexture(_propChromaTex, texture);
  263. mat.SetMatrix(_propYpCbCrTransform, _media.TextureProducer.GetYpCbCrTransform());
  264. #if UNITY_5_6_OR_NEWER
  265. if (requiresYFlip)
  266. {
  267. mat.SetTextureScale(_propChromaTex, new Vector2(_scale.x, -_scale.y));
  268. mat.SetTextureOffset(_propChromaTex, Vector2.up + _offset);
  269. }
  270. else
  271. {
  272. mat.SetTextureScale(_propChromaTex, _scale);
  273. mat.SetTextureOffset(_propChromaTex, _offset);
  274. }
  275. #else
  276. if (requiresYFlip)
  277. {
  278. mat.SetTextureScale(PropChromaTexName, new Vector2(_scale.x, -_scale.y));
  279. mat.SetTextureOffset(PropChromaTexName, Vector2.up + _offset);
  280. }
  281. else
  282. {
  283. mat.SetTextureScale(PropChromaTexName, _scale);
  284. mat.SetTextureOffset(PropChromaTexName, _offset);
  285. }
  286. #endif
  287. }
  288. }
  289. if (_media != null)
  290. {
  291. // Apply changes for layout
  292. if (mat.HasProperty(_propLayout))
  293. {
  294. Helper.SetupLayoutMaterial(mat, _media.VideoLayoutMapping);
  295. }
  296. // Apply changes for stereo videos
  297. if (mat.HasProperty(_propStereo))
  298. {
  299. Helper.SetupStereoMaterial(mat, _media.m_StereoPacking, _media.m_DisplayDebugStereoColorTint);
  300. }
  301. // Apply changes for alpha videos
  302. if (mat.HasProperty(_propAlphaPack))
  303. {
  304. Helper.SetupAlphaPackedMaterial(mat, _media.m_AlphaPacking);
  305. }
  306. #if UNITY_PLATFORM_SUPPORTS_LINEAR
  307. // Apply gamma
  308. if (mat.HasProperty(_propApplyGamma))
  309. {
  310. if (texture == _defaultTexture || _media.Info == null)
  311. {
  312. Helper.SetupGammaMaterial(mat, true);
  313. }
  314. else
  315. {
  316. Helper.SetupGammaMaterial(mat, _media.Info.PlayerSupportsLinearColorSpace());
  317. }
  318. }
  319. #else
  320. _propApplyGamma |= 0; // Prevent compiler warning about unused variable
  321. #endif
  322. #if (!UNITY_EDITOR && UNITY_ANDROID)
  323. // Adjust for cropping (when the decoder decodes in blocks that overrun the video frame size, it pads), OES only as we apply this lower down for none-OES
  324. if (_media.PlatformOptionsAndroid.useFastOesPath &&
  325. _media.Info != null &&
  326. mat.HasProperty(_propCroppingScalars) )
  327. {
  328. float[] transform = _media.Info.GetTextureTransform();
  329. if (transform != null)
  330. {
  331. mat.SetVector(_propCroppingScalars, new Vector4( transform[0], transform[3], 1.0f, 1.0f));
  332. }
  333. }
  334. #else
  335. _propCroppingScalars |= 0; // Prevent compiler warning about unused variable
  336. #endif
  337. }
  338. }
  339. }
  340. }
  341. }
  342. }
  343. private void OnEnable()
  344. {
  345. if (_mesh == null)
  346. {
  347. _mesh = this.GetComponent<MeshRenderer>();
  348. if (_mesh == null)
  349. {
  350. Debug.LogWarning("[AVProVideo] No mesh renderer set or found in gameobject");
  351. }
  352. }
  353. #if UNITY_5_6_OR_NEWER
  354. _propTexture = Shader.PropertyToID(_texturePropertyName);
  355. #endif
  356. _isDirty = true;
  357. if (_mesh != null)
  358. {
  359. LateUpdate();
  360. }
  361. }
  362. private void OnDisable()
  363. {
  364. ApplyMapping(_defaultTexture, false);
  365. }
  366. private void OnDestroy()
  367. {
  368. ChangeMediaPlayer(null);
  369. }
  370. }
  371. }