WebXRRawCameraAccess.js 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. import { WebXRFeatureName, WebXRFeaturesManager } from "../webXRFeaturesManager.js";
  2. import { WebXRAbstractFeature } from "./WebXRAbstractFeature.js";
  3. import { Observable } from "../../Misc/observable.js";
  4. import { WebGLHardwareTexture } from "../../Engines/WebGL/webGLHardwareTexture.js";
  5. import { InternalTexture, InternalTextureSource } from "../../Materials/Textures/internalTexture.js";
  6. import { BaseTexture } from "../../Materials/Textures/baseTexture.js";
  7. /**
  8. * WebXR Feature for WebXR raw camera access
  9. * @since 6.31.0
  10. * @see https://immersive-web.github.io/raw-camera-access/
  11. */
  12. export class WebXRRawCameraAccess extends WebXRAbstractFeature {
  13. /**
  14. * Creates a new instance of the feature
  15. * @param _xrSessionManager the WebXRSessionManager
  16. * @param options options for the Feature
  17. */
  18. constructor(_xrSessionManager, options = {}) {
  19. super(_xrSessionManager);
  20. this.options = options;
  21. this._cachedInternalTextures = [];
  22. /**
  23. * This is an array of camera views
  24. * Note that mostly the array will contain a single view
  25. * If you want to know the order of the views, use the `viewIndex` array
  26. */
  27. this.texturesData = [];
  28. /**
  29. * If needed, this array will contain the eye definition of each texture in `texturesArray`
  30. */
  31. this.viewIndex = [];
  32. /**
  33. * If needed, this array will contain the camera's intrinsics
  34. * You can use this data to convert from camera space to screen space and vice versa
  35. */
  36. this.cameraIntrinsics = [];
  37. /**
  38. * An observable that will notify when the camera's textures are updated
  39. */
  40. this.onTexturesUpdatedObservable = new Observable();
  41. this.xrNativeFeatureName = "camera-access";
  42. }
  43. attach(force) {
  44. if (!super.attach(force)) {
  45. return false;
  46. }
  47. this._glContext = this._xrSessionManager.scene.getEngine()._gl;
  48. this._glBinding = new XRWebGLBinding(this._xrSessionManager.session, this._glContext);
  49. return true;
  50. }
  51. detach() {
  52. if (!super.detach()) {
  53. return false;
  54. }
  55. this._glBinding = undefined;
  56. if (!this.options.doNotDisposeOnDetach) {
  57. this._cachedInternalTextures.forEach((t) => t.dispose());
  58. this.texturesData.forEach((t) => t.dispose());
  59. this._cachedInternalTextures.length = 0;
  60. this.texturesData.length = 0;
  61. this.cameraIntrinsics.length = 0;
  62. }
  63. return true;
  64. }
  65. /**
  66. * Dispose this feature and all of the resources attached
  67. */
  68. dispose() {
  69. super.dispose();
  70. this.onTexturesUpdatedObservable.clear();
  71. }
  72. /**
  73. * @see https://github.com/immersive-web/raw-camera-access/blob/main/explainer.md
  74. * @param view the XRView to update
  75. * @param index the index of the view in the views array
  76. */
  77. _updateCameraIntrinsics(view, index) {
  78. const cameraViewport = {
  79. width: view.camera.width,
  80. height: view.camera.height,
  81. x: 0,
  82. y: 0,
  83. };
  84. const p = view.projectionMatrix;
  85. // Principal point in pixels (typically at or near the center of the viewport)
  86. const u0 = ((1 - p[8]) * cameraViewport.width) / 2 + cameraViewport.x;
  87. const v0 = ((1 - p[9]) * cameraViewport.height) / 2 + cameraViewport.y;
  88. // Focal lengths in pixels (these are equal for square pixels)
  89. const ax = (cameraViewport.width / 2) * p[0];
  90. const ay = (cameraViewport.height / 2) * p[5];
  91. // Skew factor in pixels (nonzero for rhomboid pixels)
  92. const gamma = (cameraViewport.width / 2) * p[4];
  93. this.cameraIntrinsics[index] = {
  94. u0,
  95. v0,
  96. ax,
  97. ay,
  98. gamma,
  99. width: cameraViewport.width,
  100. height: cameraViewport.height,
  101. viewportX: cameraViewport.x,
  102. viewportY: cameraViewport.y,
  103. };
  104. }
  105. _updateInternalTextures(view, index = 0) {
  106. if (!view.camera) {
  107. return false;
  108. }
  109. this.viewIndex[index] = view.eye;
  110. const lp = this._glBinding?.getCameraImage(view.camera);
  111. if (!this._cachedInternalTextures[index]) {
  112. const internalTexture = new InternalTexture(this._xrSessionManager.scene.getEngine(), InternalTextureSource.Unknown, true);
  113. internalTexture.isCube = true;
  114. internalTexture.invertY = false;
  115. // internalTexture._useSRGBBuffer = this.options.reflectionFormat === "srgba8";
  116. internalTexture.format = 5;
  117. internalTexture.generateMipMaps = true;
  118. internalTexture.type = 1;
  119. internalTexture.samplingMode = 3;
  120. internalTexture.width = view.camera.width;
  121. internalTexture.height = view.camera.height;
  122. internalTexture._cachedWrapU = 1;
  123. internalTexture._cachedWrapV = 1;
  124. internalTexture._hardwareTexture = new WebGLHardwareTexture(lp, this._glContext);
  125. this._cachedInternalTextures[index] = internalTexture;
  126. // create the base texture
  127. const texture = new BaseTexture(this._xrSessionManager.scene);
  128. texture.name = `WebXR Raw Camera Access (${index})`;
  129. texture._texture = this._cachedInternalTextures[index];
  130. this.texturesData[index] = texture;
  131. // get the camera intrinsics
  132. this._updateCameraIntrinsics(view, index);
  133. }
  134. else {
  135. // make sure the webgl texture is updated. Should happen automatically
  136. this._cachedInternalTextures[index]._hardwareTexture?.set(lp);
  137. }
  138. this._cachedInternalTextures[index].isReady = true;
  139. return true;
  140. }
  141. _onXRFrame(_xrFrame) {
  142. const referenceSPace = this._xrSessionManager.referenceSpace;
  143. const pose = _xrFrame.getViewerPose(referenceSPace);
  144. if (!pose || !pose.views) {
  145. return;
  146. }
  147. let updated = true;
  148. pose.views.forEach((view, index) => {
  149. updated = updated && this._updateInternalTextures(view, index);
  150. });
  151. if (updated) {
  152. this.onTexturesUpdatedObservable.notifyObservers(this.texturesData);
  153. }
  154. }
  155. }
  156. /**
  157. * The module's name
  158. */
  159. WebXRRawCameraAccess.Name = WebXRFeatureName.RAW_CAMERA_ACCESS;
  160. /**
  161. * The (Babylon) version of this module.
  162. * This is an integer representing the implementation version.
  163. * This number does not correspond to the WebXR specs version
  164. */
  165. WebXRRawCameraAccess.Version = 1;
  166. WebXRFeaturesManager.AddWebXRFeature(WebXRRawCameraAccess.Name, (xrSessionManager, options) => {
  167. return () => new WebXRRawCameraAccess(xrSessionManager, options);
  168. }, WebXRRawCameraAccess.Version, false);
  169. //# sourceMappingURL=WebXRRawCameraAccess.js.map