webXRManagedOutputCanvas.ts 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. import { Nullable } from "../types";
  2. import { ThinEngine } from '../Engines/thinEngine';
  3. import { WebXRRenderTarget } from "./webXRTypes";
  4. import { WebXRSessionManager } from './webXRSessionManager';
  5. import { Observable } from '../Misc/observable';
  6. /**
  7. * COnfiguration object for WebXR output canvas
  8. */
  9. export class WebXRManagedOutputCanvasOptions {
  10. /**
  11. * An optional canvas in case you wish to create it yourself and provide it here.
  12. * If not provided, a new canvas will be created
  13. */
  14. public canvasElement?: HTMLCanvasElement;
  15. /**
  16. * Options for this XR Layer output
  17. */
  18. public canvasOptions?: XRWebGLLayerOptions;
  19. /**
  20. * CSS styling for a newly created canvas (if not provided)
  21. */
  22. public newCanvasCssStyle?: string;
  23. /**
  24. * Get the default values of the configuration object
  25. * @returns default values of this configuration object
  26. */
  27. public static GetDefaults(): WebXRManagedOutputCanvasOptions {
  28. const defaults = new WebXRManagedOutputCanvasOptions();
  29. defaults.canvasOptions = {
  30. antialias: true,
  31. depth: true,
  32. stencil: false,
  33. alpha: true,
  34. multiview: false,
  35. framebufferScaleFactor: 1
  36. };
  37. defaults.newCanvasCssStyle = "position:absolute; bottom:0px;right:0px;z-index:10;width:90%;height:100%;background-color: #000000;";
  38. return defaults;
  39. }
  40. }
  41. /**
  42. * Creates a canvas that is added/removed from the webpage when entering/exiting XR
  43. */
  44. export class WebXRManagedOutputCanvas implements WebXRRenderTarget {
  45. private _canvas: Nullable<HTMLCanvasElement> = null;
  46. private _engine: ThinEngine;
  47. private _originalCanvasSize: {
  48. width: number,
  49. height: number
  50. };
  51. /**
  52. * Rendering context of the canvas which can be used to display/mirror xr content
  53. */
  54. public canvasContext: WebGLRenderingContext;
  55. /**
  56. * xr layer for the canvas
  57. */
  58. public xrLayer: Nullable<XRWebGLLayer> = null;
  59. public onXRLayerInitObservable: Observable<XRWebGLLayer> = new Observable();
  60. /**
  61. * Initializes the canvas to be added/removed upon entering/exiting xr
  62. * @param _xrSessionManager The XR Session manager
  63. * @param _options optional configuration for this canvas output. defaults will be used if not provided
  64. */
  65. constructor(_xrSessionManager: WebXRSessionManager, private _options: WebXRManagedOutputCanvasOptions = WebXRManagedOutputCanvasOptions.GetDefaults()) {
  66. this._engine = _xrSessionManager.scene.getEngine();
  67. if (!_options.canvasElement) {
  68. const canvas = document.createElement('canvas');
  69. canvas.style.cssText = this._options.newCanvasCssStyle || "position:absolute; bottom:0px;right:0px;";
  70. this._setManagedOutputCanvas(canvas);
  71. } else {
  72. this._setManagedOutputCanvas(_options.canvasElement);
  73. }
  74. _xrSessionManager.onXRSessionInit.add(() => {
  75. this._addCanvas();
  76. });
  77. _xrSessionManager.onXRSessionEnded.add(() => {
  78. this._removeCanvas();
  79. });
  80. }
  81. /**
  82. * Disposes of the object
  83. */
  84. public dispose() {
  85. this._removeCanvas();
  86. this._setManagedOutputCanvas(null);
  87. }
  88. /**
  89. * Initializes the xr layer for the session
  90. * @param xrSession xr session
  91. * @returns a promise that will resolve once the XR Layer has been created
  92. */
  93. public initializeXRLayerAsync(xrSession: XRSession): Promise<XRWebGLLayer> {
  94. const createLayer = () => {
  95. const layer = new XRWebGLLayer(xrSession, this.canvasContext, this._options.canvasOptions);
  96. this.onXRLayerInitObservable.notifyObservers(layer);
  97. return layer;
  98. };
  99. // support canvases without makeXRCompatible
  100. if (!(this.canvasContext as any).makeXRCompatible) {
  101. this.xrLayer = createLayer();
  102. return Promise.resolve(this.xrLayer);
  103. }
  104. return (this.canvasContext as any).makeXRCompatible().then(() => {
  105. this.xrLayer = createLayer();
  106. return this.xrLayer;
  107. });
  108. }
  109. private _addCanvas() {
  110. if (this._canvas && this._canvas !== this._engine.getRenderingCanvas()) {
  111. document.body.appendChild(this._canvas);
  112. }
  113. if (this.xrLayer) {
  114. this._setCanvasSize(true);
  115. } else {
  116. this.onXRLayerInitObservable.addOnce((layer) => {
  117. this._setCanvasSize(true, layer);
  118. });
  119. }
  120. }
  121. private _removeCanvas() {
  122. if (this._canvas && document.body.contains(this._canvas) && this._canvas !== this._engine.getRenderingCanvas()) {
  123. document.body.removeChild(this._canvas);
  124. }
  125. this._setCanvasSize(false);
  126. }
  127. private _setCanvasSize(init: boolean = true, xrLayer = this.xrLayer) {
  128. if (!this._canvas) {
  129. return;
  130. }
  131. if (init) {
  132. if (xrLayer) {
  133. this._canvas.style.width = xrLayer.framebufferWidth + 'px';
  134. this._canvas.style.height = xrLayer.framebufferHeight + 'px';
  135. }
  136. } else {
  137. if (this._originalCanvasSize) {
  138. this._canvas.style.width = this._originalCanvasSize.width + 'px';
  139. this._canvas.style.height = this._originalCanvasSize.height + 'px';
  140. }
  141. }
  142. }
  143. private _setManagedOutputCanvas(canvas: Nullable<HTMLCanvasElement>) {
  144. this._removeCanvas();
  145. if (!canvas) {
  146. this._canvas = null;
  147. (this.canvasContext as any) = null;
  148. } else {
  149. this._originalCanvasSize = {
  150. width: canvas.offsetWidth,
  151. height: canvas.offsetHeight
  152. };
  153. this._canvas = canvas;
  154. this.canvasContext = <any>this._canvas.getContext('webgl2');
  155. if (!this.canvasContext) {
  156. this.canvasContext = <any>this._canvas.getContext('webgl');
  157. }
  158. }
  159. }
  160. }