OVROverlay.cs 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657
  1. /************************************************************************************
  2. Copyright : Copyright 2017 Oculus VR, LLC. All Rights reserved.
  3. Licensed under the Oculus VR Rift SDK License Version 3.4.1 (the "License");
  4. you may not use the Oculus VR Rift SDK except in compliance with the License,
  5. which is provided at the time of installation or download, or which
  6. otherwise accompanies this software in either electronic or hard copy form.
  7. You may obtain a copy of the License at
  8. https://developer.oculus.com/licenses/sdk-3.4.1
  9. Unless required by applicable law or agreed to in writing, the Oculus VR SDK
  10. distributed under the License is distributed on an "AS IS" BASIS,
  11. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. See the License for the specific language governing permissions and
  13. limitations under the License.
  14. ************************************************************************************/
  15. using UnityEngine;
  16. using System;
  17. using System.Collections;
  18. using System.Runtime.InteropServices;
  19. /// <summary>
  20. /// Add OVROverlay script to an object with an optional mesh primitive
  21. /// rendered as a TimeWarp overlay instead by drawing it into the eye buffer.
  22. /// This will take full advantage of the display resolution and avoid double
  23. /// resampling of the texture.
  24. ///
  25. /// We support 3 types of Overlay shapes right now
  26. /// 1. Quad : This is most common overlay type , you render a quad in Timewarp space.
  27. /// 2. Cylinder: [Mobile Only][Experimental], Display overlay as partial surface of a cylinder
  28. /// * The cylinder's center will be your game object's center
  29. /// * We encoded the cylinder's parameters in transform.scale,
  30. /// **[scale.z] is the radius of the cylinder
  31. /// **[scale.y] is the height of the cylinder
  32. /// **[scale.x] is the length of the arc of cylinder
  33. /// * Limitations
  34. /// **Only the half of the cylinder can be displayed, which means the arc angle has to be smaller than 180 degree, [scale.x] / [scale.z] <= PI
  35. /// **Your camera has to be inside of the inscribed sphere of the cylinder, the overlay will be faded out automatically when the camera is close to the inscribed sphere's surface.
  36. /// **Translation only works correctly with vrDriver 1.04 or above
  37. /// 3. Cubemap: Display overlay as a cube map
  38. /// 4. OffcenterCubemap: [Mobile Only] Display overlay as a cube map with a texture coordinate offset
  39. /// * The actually sampling will looks like [color = texture(cubeLayerSampler, normalize(direction) + offset)] instead of [color = texture( cubeLayerSampler, direction )]
  40. /// * The extra center offset can be feed from transform.position
  41. /// * Note: if transform.position's magnitude is greater than 1, which will cause some cube map pixel always invisible
  42. /// Which is usually not what people wanted, we don't kill the ability for developer to do so here, but will warn out.
  43. /// 5. Equirect: Display overlay as a 360-degree equirectangular skybox.
  44. /// </summary>
  45. public class OVROverlay : MonoBehaviour
  46. {
  47. #region Interface
  48. /// <summary>
  49. /// Determines the on-screen appearance of a layer.
  50. /// </summary>
  51. public enum OverlayShape
  52. {
  53. Quad = OVRPlugin.OverlayShape.Quad,
  54. Cylinder = OVRPlugin.OverlayShape.Cylinder,
  55. Cubemap = OVRPlugin.OverlayShape.Cubemap,
  56. OffcenterCubemap = OVRPlugin.OverlayShape.OffcenterCubemap,
  57. Equirect = OVRPlugin.OverlayShape.Equirect,
  58. }
  59. /// <summary>
  60. /// Whether the layer appears behind or infront of other content in the scene.
  61. /// </summary>
  62. public enum OverlayType
  63. {
  64. None,
  65. Underlay,
  66. Overlay,
  67. };
  68. /// <summary>
  69. /// Specify overlay's type
  70. /// </summary>
  71. public OverlayType currentOverlayType = OverlayType.Overlay;
  72. /// <summary>
  73. /// If true, the texture's content is copied to the compositor each frame.
  74. /// </summary>
  75. public bool isDynamic = false;
  76. /// <summary>
  77. /// If true, the layer would be used to present protected content (e.g. HDCP). The flag is effective only on PC.
  78. /// </summary>
  79. public bool isProtectedContent = false;
  80. /// <summary>
  81. /// Specify overlay's shape
  82. /// </summary>
  83. public OverlayShape currentOverlayShape = OverlayShape.Quad;
  84. private OverlayShape prevOverlayShape = OverlayShape.Quad;
  85. /// <summary>
  86. /// The left- and right-eye Textures to show in the layer.
  87. /// \note If you need to change the texture on a per-frame basis, please use OverrideOverlayTextureInfo(..) to avoid caching issues.
  88. /// </summary>
  89. public Texture[] textures = new Texture[] { null, null };
  90. protected IntPtr[] texturePtrs = new IntPtr[] { IntPtr.Zero, IntPtr.Zero };
  91. /// <summary>
  92. /// Use this function to set texture and texNativePtr when app is running
  93. /// GetNativeTexturePtr is a slow behavior, the value should be pre-cached
  94. /// </summary>
  95. #if UNITY_2017_2_OR_NEWER
  96. public void OverrideOverlayTextureInfo(Texture srcTexture, IntPtr nativePtr, UnityEngine.XR.XRNode node)
  97. #else
  98. public void OverrideOverlayTextureInfo(Texture srcTexture, IntPtr nativePtr, UnityEngine.VR.VRNode node)
  99. #endif
  100. {
  101. #if UNITY_2017_2_OR_NEWER
  102. int index = (node == UnityEngine.XR.XRNode.RightEye) ? 1 : 0;
  103. #else
  104. int index = (node == UnityEngine.VR.VRNode.RightEye) ? 1 : 0;
  105. #endif
  106. if (textures.Length <= index)
  107. return;
  108. textures[index] = srcTexture;
  109. texturePtrs[index] = nativePtr;
  110. isOverridePending = true;
  111. }
  112. protected bool isOverridePending;
  113. internal const int maxInstances = 15;
  114. internal static OVROverlay[] instances = new OVROverlay[maxInstances];
  115. #endregion
  116. private static Material tex2DMaterial;
  117. private static Material cubeMaterial;
  118. private OVRPlugin.LayerLayout layout {
  119. get {
  120. #if UNITY_ANDROID && !UNITY_EDITOR
  121. if (textures.Length == 2 && textures[1] != null)
  122. return OVRPlugin.LayerLayout.Stereo;
  123. #endif
  124. return OVRPlugin.LayerLayout.Mono;
  125. }
  126. }
  127. private struct LayerTexture {
  128. public Texture appTexture;
  129. public IntPtr appTexturePtr;
  130. public Texture[] swapChain;
  131. public IntPtr[] swapChainPtr;
  132. };
  133. private LayerTexture[] layerTextures;
  134. private OVRPlugin.LayerDesc layerDesc;
  135. private int stageCount = -1;
  136. private int layerIndex = -1; // Controls the composition order based on wake-up time.
  137. private int layerId = 0; // The layer's internal handle in the compositor.
  138. private GCHandle layerIdHandle;
  139. private IntPtr layerIdPtr = IntPtr.Zero;
  140. private int frameIndex = 0;
  141. private int prevFrameIndex = -1;
  142. private Renderer rend;
  143. private int texturesPerStage { get { return (layout == OVRPlugin.LayerLayout.Stereo) ? 2 : 1; } }
  144. private bool CreateLayer(int mipLevels, int sampleCount, OVRPlugin.EyeTextureFormat etFormat, int flags, OVRPlugin.Sizei size, OVRPlugin.OverlayShape shape)
  145. {
  146. if (!layerIdHandle.IsAllocated || layerIdPtr == IntPtr.Zero)
  147. {
  148. layerIdHandle = GCHandle.Alloc(layerId, GCHandleType.Pinned);
  149. layerIdPtr = layerIdHandle.AddrOfPinnedObject();
  150. }
  151. if (layerIndex == -1)
  152. {
  153. for (int i = 0; i < maxInstances; ++i)
  154. {
  155. if (instances[i] == null || instances[i] == this)
  156. {
  157. layerIndex = i;
  158. instances[i] = this;
  159. break;
  160. }
  161. }
  162. }
  163. bool needsSetup = (
  164. isOverridePending ||
  165. layerDesc.MipLevels != mipLevels ||
  166. layerDesc.SampleCount != sampleCount ||
  167. layerDesc.Format != etFormat ||
  168. layerDesc.Layout != layout ||
  169. layerDesc.LayerFlags != flags ||
  170. !layerDesc.TextureSize.Equals(size) ||
  171. layerDesc.Shape != shape);
  172. if (!needsSetup)
  173. return false;
  174. OVRPlugin.LayerDesc desc = OVRPlugin.CalculateLayerDesc(shape, layout, size, mipLevels, sampleCount, etFormat, flags);
  175. OVRPlugin.EnqueueSetupLayer(desc, layerIdPtr);
  176. layerId = (int)layerIdHandle.Target;
  177. if (layerId > 0)
  178. {
  179. layerDesc = desc;
  180. stageCount = OVRPlugin.GetLayerTextureStageCount(layerId);
  181. }
  182. isOverridePending = false;
  183. return true;
  184. }
  185. private bool CreateLayerTextures(bool useMipmaps, OVRPlugin.Sizei size, bool isHdr)
  186. {
  187. bool needsCopy = false;
  188. if (stageCount <= 0)
  189. return false;
  190. // For newer SDKs, blit directly to the surface that will be used in compositing.
  191. if (layerTextures == null)
  192. layerTextures = new LayerTexture[texturesPerStage];
  193. for (int eyeId = 0; eyeId < texturesPerStage; ++eyeId)
  194. {
  195. if (layerTextures[eyeId].swapChain == null)
  196. layerTextures[eyeId].swapChain = new Texture[stageCount];
  197. if (layerTextures[eyeId].swapChainPtr == null)
  198. layerTextures[eyeId].swapChainPtr = new IntPtr[stageCount];
  199. for (int stage = 0; stage < stageCount; ++stage)
  200. {
  201. Texture sc = layerTextures[eyeId].swapChain[stage];
  202. IntPtr scPtr = layerTextures[eyeId].swapChainPtr[stage];
  203. if (sc != null && scPtr != IntPtr.Zero)
  204. continue;
  205. if (scPtr == IntPtr.Zero)
  206. scPtr = OVRPlugin.GetLayerTexture(layerId, stage, (OVRPlugin.Eye)eyeId);
  207. if (scPtr == IntPtr.Zero)
  208. continue;
  209. var txFormat = (isHdr) ? TextureFormat.RGBAHalf : TextureFormat.RGBA32;
  210. if (currentOverlayShape != OverlayShape.Cubemap && currentOverlayShape != OverlayShape.OffcenterCubemap)
  211. sc = Texture2D.CreateExternalTexture(size.w, size.h, txFormat, useMipmaps, true, scPtr);
  212. #if UNITY_2017_1_OR_NEWER
  213. else
  214. sc = Cubemap.CreateExternalTexture(size.w, txFormat, useMipmaps, scPtr);
  215. #endif
  216. layerTextures[eyeId].swapChain[stage] = sc;
  217. layerTextures[eyeId].swapChainPtr[stage] = scPtr;
  218. needsCopy = true;
  219. }
  220. }
  221. return needsCopy;
  222. }
  223. private void DestroyLayerTextures()
  224. {
  225. for (int eyeId = 0; layerTextures != null && eyeId < texturesPerStage; ++eyeId)
  226. {
  227. if (layerTextures[eyeId].swapChain != null)
  228. {
  229. for (int stage = 0; stage < stageCount; ++stage)
  230. DestroyImmediate(layerTextures[eyeId].swapChain[stage]);
  231. }
  232. }
  233. layerTextures = null;
  234. }
  235. private void DestroyLayer()
  236. {
  237. if (layerIndex != -1)
  238. {
  239. // Turn off the overlay if it was on.
  240. OVRPlugin.EnqueueSubmitLayer(true, false, IntPtr.Zero, IntPtr.Zero, -1, 0, OVRPose.identity.ToPosef(), Vector3.one.ToVector3f(), layerIndex, (OVRPlugin.OverlayShape)prevOverlayShape);
  241. instances[layerIndex] = null;
  242. layerIndex = -1;
  243. }
  244. if (layerIdPtr != IntPtr.Zero)
  245. {
  246. OVRPlugin.EnqueueDestroyLayer(layerIdPtr);
  247. layerIdPtr = IntPtr.Zero;
  248. layerIdHandle.Free();
  249. layerId = 0;
  250. }
  251. layerDesc = new OVRPlugin.LayerDesc();
  252. frameIndex = 0;
  253. prevFrameIndex = -1;
  254. }
  255. private bool LatchLayerTextures()
  256. {
  257. for (int i = 0; i < texturesPerStage; ++i)
  258. {
  259. if (textures[i] != layerTextures[i].appTexture || layerTextures[i].appTexturePtr == IntPtr.Zero)
  260. {
  261. if (textures[i] != null)
  262. {
  263. #if UNITY_EDITOR
  264. var assetPath = UnityEditor.AssetDatabase.GetAssetPath(textures[i]);
  265. var importer = (UnityEditor.TextureImporter)UnityEditor.TextureImporter.GetAtPath(assetPath);
  266. if (importer && importer.textureType != UnityEditor.TextureImporterType.Default)
  267. {
  268. Debug.LogError("Need Default Texture Type for overlay");
  269. return false;
  270. }
  271. #endif
  272. var rt = textures[i] as RenderTexture;
  273. if (rt && !rt.IsCreated())
  274. rt.Create();
  275. layerTextures[i].appTexturePtr = (texturePtrs[i] != IntPtr.Zero) ? texturePtrs[i] : textures[i].GetNativeTexturePtr();
  276. if (layerTextures[i].appTexturePtr != IntPtr.Zero)
  277. layerTextures[i].appTexture = textures[i];
  278. }
  279. }
  280. if (currentOverlayShape == OverlayShape.Cubemap)
  281. {
  282. if (textures[i] as Cubemap == null)
  283. {
  284. Debug.LogError("Need Cubemap texture for cube map overlay");
  285. return false;
  286. }
  287. }
  288. }
  289. #if !UNITY_ANDROID || UNITY_EDITOR
  290. if (currentOverlayShape == OverlayShape.OffcenterCubemap)
  291. {
  292. Debug.LogWarning("Overlay shape " + currentOverlayShape + " is not supported on current platform");
  293. return false;
  294. }
  295. #endif
  296. if (layerTextures[0].appTexture == null || layerTextures[0].appTexturePtr == IntPtr.Zero)
  297. return false;
  298. return true;
  299. }
  300. private OVRPlugin.LayerDesc GetCurrentLayerDesc()
  301. {
  302. OVRPlugin.LayerDesc newDesc = new OVRPlugin.LayerDesc() {
  303. Format = OVRPlugin.EyeTextureFormat.R8G8B8A8_sRGB,
  304. LayerFlags = (int)OVRPlugin.LayerFlags.TextureOriginAtBottomLeft,
  305. Layout = layout,
  306. MipLevels = 1,
  307. SampleCount = 1,
  308. Shape = (OVRPlugin.OverlayShape)currentOverlayShape,
  309. TextureSize = new OVRPlugin.Sizei() { w = textures[0].width, h = textures[0].height }
  310. };
  311. var tex2D = textures[0] as Texture2D;
  312. if (tex2D != null)
  313. {
  314. if (tex2D.format == TextureFormat.RGBAHalf || tex2D.format == TextureFormat.RGBAFloat)
  315. newDesc.Format = OVRPlugin.EyeTextureFormat.R16G16B16A16_FP;
  316. newDesc.MipLevels = tex2D.mipmapCount;
  317. }
  318. var texCube = textures[0] as Cubemap;
  319. if (texCube != null)
  320. {
  321. if (texCube.format == TextureFormat.RGBAHalf || texCube.format == TextureFormat.RGBAFloat)
  322. newDesc.Format = OVRPlugin.EyeTextureFormat.R16G16B16A16_FP;
  323. newDesc.MipLevels = texCube.mipmapCount;
  324. }
  325. var rt = textures[0] as RenderTexture;
  326. if (rt != null)
  327. {
  328. newDesc.SampleCount = rt.antiAliasing;
  329. if (rt.format == RenderTextureFormat.ARGBHalf || rt.format == RenderTextureFormat.ARGBFloat || rt.format == RenderTextureFormat.RGB111110Float)
  330. newDesc.Format = OVRPlugin.EyeTextureFormat.R16G16B16A16_FP;
  331. }
  332. if (isProtectedContent)
  333. {
  334. newDesc.LayerFlags |= (int)OVRPlugin.LayerFlags.ProtectedContent;
  335. }
  336. return newDesc;
  337. }
  338. private bool PopulateLayer(int mipLevels, bool isHdr, OVRPlugin.Sizei size, int sampleCount, int stage)
  339. {
  340. bool ret = false;
  341. RenderTextureFormat rtFormat = (isHdr) ? RenderTextureFormat.ARGBHalf : RenderTextureFormat.ARGB32;
  342. for (int eyeId = 0; eyeId < texturesPerStage; ++eyeId)
  343. {
  344. Texture et = layerTextures[eyeId].swapChain[stage];
  345. if (et == null)
  346. continue;
  347. for (int mip = 0; mip < mipLevels; ++mip)
  348. {
  349. int width = size.w >> mip;
  350. if (width < 1) width = 1;
  351. int height = size.h >> mip;
  352. if (height < 1) height = 1;
  353. #if UNITY_2017_1_1 || UNITY_2017_2_OR_NEWER
  354. RenderTextureDescriptor descriptor = new RenderTextureDescriptor(width, height, rtFormat, 0);
  355. descriptor.msaaSamples = sampleCount;
  356. descriptor.useMipMap = true;
  357. descriptor.autoGenerateMips = false;
  358. descriptor.sRGB = false;
  359. var tempRTDst = RenderTexture.GetTemporary(descriptor);
  360. #else
  361. var tempRTDst = RenderTexture.GetTemporary(width, height, 0, rtFormat, RenderTextureReadWrite.Linear, sampleCount);
  362. #endif
  363. if (!tempRTDst.IsCreated())
  364. tempRTDst.Create();
  365. tempRTDst.DiscardContents();
  366. bool dataIsLinear = isHdr || (QualitySettings.activeColorSpace == ColorSpace.Linear);
  367. #if !UNITY_2017_1_OR_NEWER
  368. var rt = textures[eyeId] as RenderTexture;
  369. dataIsLinear |= rt != null && rt.sRGB; //HACK: Unity 5.6 and earlier convert to linear on read from sRGB RenderTexture.
  370. #endif
  371. #if UNITY_ANDROID && !UNITY_EDITOR
  372. dataIsLinear = true; //HACK: Graphics.CopyTexture causes linear->srgb conversion on target write with D3D but not GLES.
  373. #endif
  374. if (currentOverlayShape != OverlayShape.Cubemap && currentOverlayShape != OverlayShape.OffcenterCubemap)
  375. {
  376. tex2DMaterial.SetInt("_linearToSrgb", (!isHdr && dataIsLinear) ? 1 : 0);
  377. //Resolve, decompress, swizzle, etc not handled by simple CopyTexture.
  378. #if !UNITY_ANDROID || UNITY_EDITOR
  379. // The PC compositor uses premultiplied alpha, so multiply it here.
  380. tex2DMaterial.SetInt("_premultiply", 1);
  381. #endif
  382. Graphics.Blit(textures[eyeId], tempRTDst, tex2DMaterial);
  383. Graphics.CopyTexture(tempRTDst, 0, 0, et, 0, mip);
  384. }
  385. #if UNITY_2017_1_OR_NEWER
  386. else // Cubemap
  387. {
  388. for (int face = 0; face < 6; ++face)
  389. {
  390. cubeMaterial.SetInt("_linearToSrgb", (!isHdr && dataIsLinear) ? 1 : 0);
  391. #if !UNITY_ANDROID || UNITY_EDITOR
  392. // The PC compositor uses premultiplied alpha, so multiply it here.
  393. cubeMaterial.SetInt("_premultiply", 1);
  394. #endif
  395. cubeMaterial.SetInt("_face", face);
  396. //Resolve, decompress, swizzle, etc not handled by simple CopyTexture.
  397. Graphics.Blit(textures[eyeId], tempRTDst, cubeMaterial);
  398. Graphics.CopyTexture(tempRTDst, 0, 0, et, face, mip);
  399. }
  400. }
  401. #endif
  402. RenderTexture.ReleaseTemporary(tempRTDst);
  403. ret = true;
  404. }
  405. }
  406. return ret;
  407. }
  408. private bool SubmitLayer(bool overlay, bool headLocked, OVRPose pose, Vector3 scale, int frameIndex)
  409. {
  410. int rightEyeIndex = (texturesPerStage >= 2) ? 1 : 0;
  411. bool isOverlayVisible = OVRPlugin.EnqueueSubmitLayer(overlay, headLocked, layerTextures[0].appTexturePtr, layerTextures[rightEyeIndex].appTexturePtr, layerId, frameIndex, pose.flipZ().ToPosef(), scale.ToVector3f(), layerIndex, (OVRPlugin.OverlayShape)currentOverlayShape);
  412. prevOverlayShape = currentOverlayShape;
  413. return isOverlayVisible;
  414. }
  415. #region Unity Messages
  416. void Awake()
  417. {
  418. Debug.Log("Overlay Awake");
  419. if (tex2DMaterial == null)
  420. tex2DMaterial = new Material(Shader.Find("Oculus/Texture2D Blit"));
  421. if (cubeMaterial == null)
  422. cubeMaterial = new Material(Shader.Find("Oculus/Cubemap Blit"));
  423. rend = GetComponent<Renderer>();
  424. if (textures.Length == 0)
  425. textures = new Texture[] { null };
  426. // Backward compatibility
  427. if (rend != null && textures[0] == null)
  428. textures[0] = rend.material.mainTexture;
  429. }
  430. void OnEnable()
  431. {
  432. if (!OVRManager.isHmdPresent)
  433. {
  434. enabled = false;
  435. return;
  436. }
  437. }
  438. void OnDisable()
  439. {
  440. if ((gameObject.hideFlags & HideFlags.DontSaveInBuild) != 0)
  441. return;
  442. DestroyLayerTextures();
  443. DestroyLayer();
  444. }
  445. void OnDestroy()
  446. {
  447. DestroyLayerTextures();
  448. DestroyLayer();
  449. }
  450. bool ComputeSubmit(ref OVRPose pose, ref Vector3 scale, ref bool overlay, ref bool headLocked)
  451. {
  452. Camera headCamera = Camera.main;
  453. overlay = (currentOverlayType == OverlayType.Overlay);
  454. headLocked = false;
  455. for (var t = transform; t != null && !headLocked; t = t.parent)
  456. headLocked |= (t == headCamera.transform);
  457. pose = (headLocked) ? transform.ToHeadSpacePose(headCamera) : transform.ToTrackingSpacePose(headCamera);
  458. scale = transform.lossyScale;
  459. for (int i = 0; i < 3; ++i)
  460. scale[i] /= headCamera.transform.lossyScale[i];
  461. if (currentOverlayShape == OverlayShape.Cubemap)
  462. {
  463. #if UNITY_ANDROID && !UNITY_EDITOR
  464. //HACK: VRAPI cubemaps assume are yawed 180 degrees relative to LibOVR.
  465. pose.orientation = pose.orientation * Quaternion.AngleAxis(180, Vector3.up);
  466. #endif
  467. pose.position = headCamera.transform.position;
  468. }
  469. // Pack the offsetCenter directly into pose.position for offcenterCubemap
  470. if (currentOverlayShape == OverlayShape.OffcenterCubemap)
  471. {
  472. pose.position = transform.position;
  473. if (pose.position.magnitude > 1.0f)
  474. {
  475. Debug.LogWarning("Your cube map center offset's magnitude is greater than 1, which will cause some cube map pixel always invisible .");
  476. return false;
  477. }
  478. }
  479. // Cylinder overlay sanity checking
  480. if (currentOverlayShape == OverlayShape.Cylinder)
  481. {
  482. float arcAngle = scale.x / scale.z / (float)Math.PI * 180.0f;
  483. if (arcAngle > 180.0f)
  484. {
  485. Debug.LogWarning("Cylinder overlay's arc angle has to be below 180 degree, current arc angle is " + arcAngle + " degree." );
  486. return false;
  487. }
  488. }
  489. return true;
  490. }
  491. void LateUpdate()
  492. {
  493. // The overlay must be specified every eye frame, because it is positioned relative to the
  494. // current head location. If frames are dropped, it will be time warped appropriately,
  495. // just like the eye buffers.
  496. if (currentOverlayType == OverlayType.None || textures.Length < texturesPerStage || textures[0] == null)
  497. return;
  498. OVRPose pose = OVRPose.identity;
  499. Vector3 scale = Vector3.one;
  500. bool overlay = false;
  501. bool headLocked = false;
  502. if (!ComputeSubmit(ref pose, ref scale, ref overlay, ref headLocked))
  503. return;
  504. OVRPlugin.LayerDesc newDesc = GetCurrentLayerDesc();
  505. bool isHdr = (newDesc.Format == OVRPlugin.EyeTextureFormat.R16G16B16A16_FP);
  506. bool createdLayer = CreateLayer(newDesc.MipLevels, newDesc.SampleCount, newDesc.Format, newDesc.LayerFlags, newDesc.TextureSize, newDesc.Shape);
  507. if (layerIndex == -1 || layerId <= 0)
  508. return;
  509. bool useMipmaps = (newDesc.MipLevels > 1);
  510. createdLayer |= CreateLayerTextures(useMipmaps, newDesc.TextureSize, isHdr);
  511. if (layerTextures[0].appTexture as RenderTexture != null)
  512. isDynamic = true;
  513. if (!LatchLayerTextures())
  514. return;
  515. // Don't populate the same frame image twice.
  516. if (frameIndex > prevFrameIndex)
  517. {
  518. int stage = frameIndex % stageCount;
  519. if (!PopulateLayer (newDesc.MipLevels, isHdr, newDesc.TextureSize, newDesc.SampleCount, stage))
  520. return;
  521. }
  522. bool isOverlayVisible = SubmitLayer(overlay, headLocked, pose, scale, frameIndex);
  523. prevFrameIndex = frameIndex;
  524. if (isDynamic)
  525. ++frameIndex;
  526. // Backward compatibility: show regular renderer if overlay isn't visible.
  527. if (rend)
  528. rend.enabled = !isOverlayVisible;
  529. }
  530. #endregion
  531. }