@reactvision/react-viro 2.55.0 → 2.57.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (94) hide show
  1. package/README.md +27 -0
  2. package/android/react_viro/react_viro-release.aar +0 -0
  3. package/android/viro_renderer/viro_renderer-release.aar +0 -0
  4. package/components/AR/ViroARScene.tsx +17 -0
  5. package/components/AR/ViroARSceneNavigator.tsx +33 -0
  6. package/components/Utilities/StreamingAudioManager.ts +73 -0
  7. package/components/Utilities/ViroVersion.ts +1 -1
  8. package/components/ViroCameraTexture.tsx +230 -0
  9. package/components/ViroGameLoop.tsx +74 -0
  10. package/components/ViroGameLoopUtils.ts +52 -0
  11. package/components/ViroObjectDetector.tsx +222 -0
  12. package/components/ViroVirtualButton.tsx +101 -0
  13. package/components/ViroVirtualJoystick.tsx +126 -0
  14. package/components/hooks/useGameLoop.ts +78 -0
  15. package/dist/components/AR/ViroARScene.d.ts +12 -0
  16. package/dist/components/AR/ViroARScene.js +8 -1
  17. package/dist/components/AR/ViroARSceneNavigator.d.ts +30 -0
  18. package/dist/components/Utilities/StreamingAudioManager.d.ts +22 -0
  19. package/dist/components/Utilities/StreamingAudioManager.js +45 -0
  20. package/dist/components/Utilities/ViroVersion.d.ts +1 -1
  21. package/dist/components/Utilities/ViroVersion.js +1 -1
  22. package/dist/components/ViroCameraTexture.d.ts +137 -0
  23. package/dist/components/ViroCameraTexture.js +170 -0
  24. package/dist/components/ViroGameLoop.d.ts +31 -0
  25. package/dist/components/ViroGameLoop.js +31 -0
  26. package/dist/components/ViroGameLoopUtils.d.ts +26 -0
  27. package/dist/components/ViroGameLoopUtils.js +44 -0
  28. package/dist/components/ViroObjectDetector.d.ts +138 -0
  29. package/dist/components/ViroObjectDetector.js +85 -0
  30. package/dist/components/ViroVirtualButton.d.ts +76 -0
  31. package/dist/components/ViroVirtualButton.js +62 -0
  32. package/dist/components/ViroVirtualJoystick.d.ts +85 -0
  33. package/dist/components/ViroVirtualJoystick.js +72 -0
  34. package/dist/components/hooks/useGameLoop.d.ts +34 -0
  35. package/dist/components/hooks/useGameLoop.js +63 -0
  36. package/dist/index.d.ts +11 -1
  37. package/dist/index.js +20 -2
  38. package/dist/plugins/withViro.js +2 -15
  39. package/dist/plugins/withViroAndroid.js +52 -15
  40. package/dist/plugins/withViroIos.js +0 -6
  41. package/index.ts +21 -0
  42. package/ios/ViroReact.podspec +25 -6
  43. package/ios/dist/ViroRenderer/ViroKit.framework/ARCoreCoreMLSemanticsResources.bundle/Info.plist +0 -0
  44. package/ios/dist/ViroRenderer/ViroKit.framework/ARCoreResources.bundle/Info.plist +0 -0
  45. package/ios/dist/ViroRenderer/ViroKit.framework/Headers/VROARDepthMesh.h +9 -1
  46. package/ios/dist/ViroRenderer/ViroKit.framework/Headers/VROARFrame.h +33 -0
  47. package/ios/dist/ViroRenderer/ViroKit.framework/Headers/VROARFrameiOS.h +26 -0
  48. package/ios/dist/ViroRenderer/ViroKit.framework/Headers/VROARScene.h +15 -1
  49. package/ios/dist/ViroRenderer/ViroKit.framework/Headers/VROARSceneDelegateiOS.h +8 -0
  50. package/ios/dist/ViroRenderer/ViroKit.framework/Headers/VROARSession.h +7 -0
  51. package/ios/dist/ViroRenderer/ViroKit.framework/Headers/VROARSessioniOS.h +18 -0
  52. package/ios/dist/ViroRenderer/ViroKit.framework/Headers/VROARWorldMesh.h +111 -8
  53. package/ios/dist/ViroRenderer/ViroKit.framework/Headers/VROAudioPlayer.h +19 -0
  54. package/ios/dist/ViroRenderer/ViroKit.framework/Headers/VROAudioPlayerStreamiOS.h +95 -0
  55. package/ios/dist/ViroRenderer/ViroKit.framework/Headers/VROCameraTextureiOS.h +17 -1
  56. package/ios/dist/ViroRenderer/ViroKit.framework/Headers/VRODriver.h +20 -0
  57. package/ios/dist/ViroRenderer/ViroKit.framework/Headers/VRODynamicGeometry.h +170 -0
  58. package/ios/dist/ViroRenderer/ViroKit.framework/Headers/VRODynamicMeshNode.h +87 -0
  59. package/ios/dist/ViroRenderer/ViroKit.framework/Headers/VROGLTFLoader.h +5 -1
  60. package/ios/dist/ViroRenderer/ViroKit.framework/Headers/VROGameLoopListener.h +125 -0
  61. package/ios/dist/ViroRenderer/ViroKit.framework/Headers/VROInputState.h +133 -0
  62. package/ios/dist/ViroRenderer/ViroKit.framework/Headers/VROMonocularDepthEstimator.h +73 -0
  63. package/ios/dist/ViroRenderer/ViroKit.framework/Headers/VROObjectDetector.h +134 -0
  64. package/ios/dist/ViroRenderer/ViroKit.framework/Headers/VROPCMRingBuffer.h +143 -0
  65. package/ios/dist/ViroRenderer/ViroKit.framework/Headers/VROPencil.h +9 -0
  66. package/ios/dist/ViroRenderer/ViroKit.framework/Headers/VRORenderContext.h +4 -0
  67. package/ios/dist/ViroRenderer/ViroKit.framework/Headers/VRORenderer.h +1 -0
  68. package/ios/dist/ViroRenderer/ViroKit.framework/Headers/VROVertexBuffer.h +102 -0
  69. package/ios/dist/ViroRenderer/ViroKit.framework/Headers/VROViewAR.h +9 -0
  70. package/ios/dist/ViroRenderer/ViroKit.framework/Headers/VROVirtualControllerRegistry.h +106 -0
  71. package/ios/dist/ViroRenderer/ViroKit.framework/Info.plist +0 -0
  72. package/ios/dist/ViroRenderer/ViroKit.framework/Shaders.dat +1 -1
  73. package/ios/dist/ViroRenderer/ViroKit.framework/ViroKit +0 -0
  74. package/ios/dist/ViroRenderer/ViroKit.framework/constant_fsh.glsl +1 -0
  75. package/ios/dist/ViroRenderer/ViroKit.framework/constant_fsh_adreno.glsl +1 -0
  76. package/ios/dist/ViroRenderer/ViroKit.framework/standard_fsh.glsl +1 -0
  77. package/ios/dist/ViroRenderer/ViroKit.framework/standard_vsh.glsl +4 -0
  78. package/ios/dist/ViroRenderer/ViroKit.framework/standard_vsh_adreno.glsl +4 -0
  79. package/ios/dist/ViroRendererVisionOS/ViroKit.podspec +27 -0
  80. package/ios/dist/include/VRTARScene.h +1 -0
  81. package/ios/dist/include/VRTARSceneNavigator.h +3 -0
  82. package/ios/dist/include/VRTCameraTexture.h +62 -0
  83. package/ios/dist/include/VRTCameraTextureManager.h +30 -0
  84. package/ios/dist/include/VRTCameraTextureModule.h +38 -0
  85. package/ios/dist/include/VRTGameLoopView.h +19 -0
  86. package/ios/dist/include/VRTGameLoopViewManager.h +8 -0
  87. package/ios/dist/include/VRTManagedAnimation.h +67 -0
  88. package/ios/dist/include/VRTStreamingAudioModule.h +21 -0
  89. package/ios/dist/include/VRTVirtualButtonView.h +47 -0
  90. package/ios/dist/include/VRTVirtualButtonViewManager.h +21 -0
  91. package/ios/dist/include/VRTVirtualJoystickView.h +59 -0
  92. package/ios/dist/include/VRTVirtualJoystickViewManager.h +26 -0
  93. package/ios/dist/lib/libViroReact.a +0 -0
  94. package/package.json +17 -20
@@ -101,11 +101,6 @@ const withBranchAndroid = (config) => {
101
101
  ]);
102
102
  };
103
103
  const withViroProjectBuildGradle = (config) => (0, config_plugins_1.withProjectBuildGradle)(config, async (newConfig) => {
104
- // Enforce New Architecture requirement
105
- if (!newConfig.modResults.contents.includes("newArchEnabled=true")) {
106
- config_plugins_1.WarningAggregator.addWarningAndroid("withViroAndroid", "ViroReact requires New Architecture to be enabled. " +
107
- 'Please add "newArchEnabled=true" to your android/gradle.properties file.');
108
- }
109
104
  newConfig.modResults.contents = newConfig.modResults.contents.replace(/minSdkVersion.*/, `minSdkVersion = 24`);
110
105
  // Ensure New Architecture is enabled
111
106
  //if (!newConfig.modResults.contents.includes("newArchEnabled=true")) {
@@ -221,23 +216,37 @@ const withViroManifest = (config) => (0, config_plugins_1.withAndroidManifest)(c
221
216
  }
222
217
  }
223
218
  }
224
- if (viroPluginConfig.includes("GVR") ||
225
- viroPluginConfig.includes("OVR_MOBILE")) {
226
- // <!-- Add the following line for cardboard -->
227
- // <category android:name="com.google.intent.category.CARDBOARD" />
219
+ // Derive active XR modes from the config at apply-time.
220
+ // `viroPluginConfig` (module-level) is updated by withBranchAndroid's
221
+ // withDangerousMod callback, which runs *after* withAndroidManifest
222
+ // callbacks — so it is still ["AR","GVR"] here. Read from config.plugins
223
+ // directly instead.
224
+ const activeXrModes = (() => {
225
+ const p = (newConfig.plugins ?? []).find((plugin) => Array.isArray(plugin) && plugin[0] === "@reactvision/react-viro");
226
+ if (Array.isArray(p) && p[1]?.android?.xRMode) {
227
+ const xrMode = p[1].android.xRMode;
228
+ return Array.isArray(xrMode) ? xrMode : [xrMode];
229
+ }
230
+ return viroPluginConfig;
231
+ })();
232
+ if (activeXrModes.includes("GVR") ||
233
+ activeXrModes.includes("OVR_MOBILE")) {
228
234
  contents?.manifest?.application?.[0]?.activity[0]["intent-filter"][0].category.push({
229
235
  $: {
230
236
  "android:name": "com.google.intent.category.CARDBOARD",
231
237
  },
232
238
  });
233
- // <!-- Add the following line for daydream -->
234
- // <category android:name="com.google.intent.category.DAYDREAM" />
235
239
  contents?.manifest?.application?.[0]?.activity[0]["intent-filter"][0].category.push({
236
240
  $: {
237
241
  "android:name": "com.google.intent.category.DAYDREAM",
238
242
  },
239
243
  });
240
244
  }
245
+ // android.permission.SYSTEM_ALERT_WINDOW is merged in from React Native's
246
+ // debug manifest and is rejected by the Meta Quest Store.
247
+ if (contents.manifest["uses-permission"]) {
248
+ contents.manifest["uses-permission"] = contents.manifest["uses-permission"].filter((p) => p.$?.["android:name"] !== "android.permission.SYSTEM_ALERT_WINDOW");
249
+ }
241
250
  contents.manifest.queries = [
242
251
  {
243
252
  package: [
@@ -267,11 +276,13 @@ const withViroManifest = (config) => (0, config_plugins_1.withAndroidManifest)(c
267
276
  "tools:replace": "required",
268
277
  },
269
278
  });
279
+ // Keep GLES 3.0 declared (required=false) so the Quest Store validator
280
+ // sees a graphics API. Previously tools:node="remove" silently stripped
281
+ // this entry from the merged manifest entirely.
270
282
  contents.manifest["uses-feature"].push({
271
283
  $: {
272
284
  "android:glEsVersion": "0x00030000",
273
285
  "android:required": "false",
274
- "tools:node": "remove",
275
286
  "tools:replace": "required",
276
287
  },
277
288
  });
@@ -290,7 +301,7 @@ const withViroManifest = (config) => (0, config_plugins_1.withAndroidManifest)(c
290
301
  },
291
302
  });
292
303
  // Quest-specific features and permissions — after uses-feature is initialized
293
- if (viroPluginConfig.includes("QUEST")) {
304
+ if (activeXrModes.includes("QUEST")) {
294
305
  contents.manifest["uses-feature"].push({
295
306
  $: {
296
307
  "android:name": "android.hardware.vr.headtracking",
@@ -313,6 +324,13 @@ const withViroManifest = (config) => (0, config_plugins_1.withAndroidManifest)(c
313
324
  "android:required": "false",
314
325
  },
315
326
  });
327
+ // Required when com.oculus.permission.EYE_TRACKING is declared.
328
+ contents.manifest["uses-feature"].push({
329
+ $: {
330
+ "android:name": "oculus.software.eye_tracking",
331
+ "android:required": "false",
332
+ },
333
+ });
316
334
  const existingPermissions = (contents.manifest["uses-permission"] || [])
317
335
  .map((p) => p.$?.["android:name"]);
318
336
  if (!existingPermissions.includes("com.oculus.permission.HAND_TRACKING")) {
@@ -541,7 +559,12 @@ class VRActivity : ReactActivity() {
541
559
  return config;
542
560
  },
543
561
  ]);
544
- // 2. Add VRActivity to AndroidManifest
562
+ // 2. Cap targetSdkVersion to 34 — Meta Quest Store rejects targetSdk > 34.
563
+ config = (0, config_plugins_1.withAppBuildGradle)(config, (config) => {
564
+ config.modResults.contents = config.modResults.contents.replace(/targetSdk(?:Version)?\s*[=\s]\s*(\d+)/g, (match, ver) => parseInt(ver, 10) > 34 ? match.replace(ver, "34") : match);
565
+ return config;
566
+ });
567
+ // 3. Add VRActivity to AndroidManifest
545
568
  config = (0, config_plugins_1.withAndroidManifest)(config, async (config) => {
546
569
  const app = config.modResults.manifest.application?.[0];
547
570
  if (!app)
@@ -566,10 +589,24 @@ class VRActivity : ReactActivity() {
566
589
  ],
567
590
  },
568
591
  ],
592
+ "meta-data": [
593
+ {
594
+ $: {
595
+ "android:name": "com.oculus.vr.focusaware",
596
+ "android:value": "true",
597
+ },
598
+ },
599
+ ],
569
600
  });
570
601
  }
571
- // Inject com.oculus.app_id into <application> for Meta Quest App Name
602
+ // Quest store validator requires all activities to be landscape.
603
+ // Only apply when targeting Quest (questAppId present); AR/phone apps use portrait.
572
604
  const questAppId = props?.android?.questAppId;
605
+ const mainActivity = app.activity?.[0];
606
+ if (questAppId && mainActivity?.$ && mainActivity.$["android:name"] !== ".VRActivity") {
607
+ mainActivity.$["android:screenOrientation"] = "landscape";
608
+ }
609
+ // Inject com.oculus.app_id into <application> for Meta Quest App Name
573
610
  if (questAppId) {
574
611
  if (!app["meta-data"])
575
612
  app["meta-data"] = [];
@@ -35,12 +35,6 @@ const withViroPods = (config) => {
35
35
  }
36
36
  }
37
37
  fs_1.default.readFile(`${root}/Podfile`, "utf-8", (err, data) => {
38
- // Check for New Architecture environment variable
39
- if (!data.includes('ENV["RCT_NEW_ARCH_ENABLED"]') &&
40
- !data.includes("RCT_NEW_ARCH_ENABLED=1")) {
41
- config_plugins_1.WarningAggregator.addWarningIOS("withViroIos", "ViroReact requires New Architecture to be enabled. " +
42
- "Please set RCT_NEW_ARCH_ENABLED=1 in your ios/.xcode.env file.");
43
- }
44
38
  // ViroReact with integrated Fabric support
45
39
  let viroPods = ` # ViroReact with integrated New Architecture (Fabric) support\n` +
46
40
  ` # Automatically includes Fabric components when RCT_NEW_ARCH_ENABLED=1\n` +
package/index.ts CHANGED
@@ -28,6 +28,11 @@ import {
28
28
  ViroTrackingStateConstants,
29
29
  } from "./components/ViroConstants";
30
30
  import { ViroController } from "./components/ViroController";
31
+ import { ViroVirtualJoystick } from "./components/ViroVirtualJoystick";
32
+ import { ViroVirtualButton } from "./components/ViroVirtualButton";
33
+ import { ViroGameLoop } from "./components/ViroGameLoop";
34
+ import { ViroGameLoopUtils } from "./components/ViroGameLoopUtils";
35
+ import { useGameLoop, useLateUpdate, useFixedUpdate } from "./components/hooks/useGameLoop";
31
36
  import { ViroDirectionalLight } from "./components/ViroDirectionalLight";
32
37
  import { ViroFlexView } from "./components/ViroFlexView";
33
38
  import { ViroGeometry } from "./components/ViroGeometry";
@@ -41,6 +46,10 @@ import {
41
46
  ViroShaderModifier,
42
47
  } from "./components/Material/ViroMaterials";
43
48
  import { ViroMaterialVideo } from "./components/ViroMaterialVideo";
49
+ import { ViroCameraTexture } from "./components/ViroCameraTexture";
50
+ export type { ViroCameraPosition, ViroCameraReadyEvent } from "./components/ViroCameraTexture";
51
+ import { ViroObjectDetector } from "./components/ViroObjectDetector";
52
+ export type { ViroDetectorMode, ViroDetectedObject, ViroDetectionBoundingBox, ViroDetectionEvent, ViroDetectorReadyEvent, ViroDetectorErrorEvent } from "./components/ViroObjectDetector";
44
53
  import { ViroNode } from "./components/ViroNode";
45
54
  import { ViroOmniLight } from "./components/ViroOmniLight";
46
55
  import { ViroOrbitCamera } from "./components/ViroOrbitCamera";
@@ -180,6 +189,7 @@ import { ViroQuestEntryPoint } from "./components/ViroQuestEntryPoint";
180
189
  import { VRQuestNavigatorBridge } from "./components/Utilities/VRQuestNavigatorBridge";
181
190
  import { VRModuleOpenXR, useVRViewTag, exitVRScene } from "./components/Utilities/VRModuleOpenXR";
182
191
  import type { VRModuleOpenXRType } from "./components/Utilities/VRModuleOpenXR";
192
+ import { StreamingAudioManager } from "./components/Utilities/StreamingAudioManager";
183
193
  import { AppRegistry } from "react-native";
184
194
 
185
195
  // Auto-register the Quest VR entry point. VRActivity launches this component
@@ -199,6 +209,13 @@ export {
199
209
  ViroButton,
200
210
  ViroCamera,
201
211
  ViroController,
212
+ ViroVirtualJoystick,
213
+ ViroVirtualButton,
214
+ ViroGameLoop,
215
+ ViroGameLoopUtils,
216
+ useGameLoop,
217
+ useLateUpdate,
218
+ useFixedUpdate,
202
219
  ViroDirectionalLight,
203
220
  ViroFlexView,
204
221
  ViroGeometry,
@@ -207,6 +224,8 @@ export {
207
224
  ViroMaterials,
208
225
  ViroARCamera,
209
226
  ViroMaterialVideo,
227
+ ViroCameraTexture,
228
+ ViroObjectDetector,
210
229
  ViroNode,
211
230
  ViroOmniLight,
212
231
  ViroOrbitCamera,
@@ -244,6 +263,8 @@ export {
244
263
  useVRViewTag,
245
264
  exitVRScene,
246
265
  Viro3DSceneNavigator,
266
+ // Streaming audio
267
+ StreamingAudioManager,
247
268
  // Utilities
248
269
  hasOpenXRSupport,
249
270
  isQuest,
@@ -18,16 +18,20 @@ Pod::Spec.new do |s|
18
18
  # visionOS: CompositorServices drives the immersive render loop.
19
19
  s.visionos.frameworks = ['Metal', 'MetalKit', 'CompositorServices', 'ARKit']
20
20
 
21
+ # iOS: frameworks required by source files compiled from the pod
22
+ # (VRTObjectDetectorView uses AVFoundation + Accelerate; CoreVideo for CVPixelBuffer)
23
+ s.ios.frameworks = ['AVFoundation', 'Accelerate', 'CoreVideo']
24
+
21
25
  # Base source files (always included)
22
26
  source_files_array = ['ViroReact/**/*.{h,m,mm,swift}']
23
27
  header_files_array = ['ViroReact/**/*.h']
24
-
28
+
25
29
  # Include dist files if they exist (for release builds)
26
30
  if File.exist?(File.join(__dir__, 'dist/include'))
27
31
  source_files_array << 'dist/include/**/*.{h,m,mm}'
28
32
  header_files_array << 'dist/include/*.h'
29
33
  end
30
-
34
+
31
35
  s.source_files = source_files_array
32
36
  s.public_header_files = header_files_array
33
37
 
@@ -39,15 +43,30 @@ Pod::Spec.new do |s|
39
43
  if File.exist?(File.join(__dir__, 'dist/lib/libViroReact.a'))
40
44
  s.vendored_libraries = 'dist/lib/libViroReact.a'
41
45
  end
42
-
46
+
43
47
  # React Native dependencies
44
48
  s.dependency 'React-Core'
45
-
49
+
50
+ # ONNX Runtime is distributed as a vendored dynamic xcframework (onnxruntime.xcframework).
51
+ # When the xcframework is present in ios/dist/Frameworks/, enable inference by setting:
52
+ # GCC_PREPROCESSOR_DEFINITIONS = $(inherited) VIRO_ONNXRUNTIME_AVAILABLE=1
53
+ # Until then, VRTObjectDetectorView compiles with the camera pipeline active
54
+ # and inference returning empty results.
55
+ if File.exist?(File.join(__dir__, 'dist/Frameworks/onnxruntime.xcframework'))
56
+ s.vendored_frameworks = [
57
+ 'dist/ViroRenderer/ViroKit.framework',
58
+ 'dist/Frameworks/onnxruntime.xcframework'
59
+ ]
60
+ s.pod_target_xcconfig = {
61
+ 'GCC_PREPROCESSOR_DEFINITIONS' => '$(inherited) RCT_NEW_ARCH_ENABLED=1 VIRO_ONNXRUNTIME_AVAILABLE=1'
62
+ }
63
+ end
64
+
46
65
  # Fabric dependencies
47
66
  s.dependency 'React-RCTFabric'
48
67
  s.dependency 'React-Fabric'
49
68
  s.dependency 'React-FabricComponents'
50
-
69
+
51
70
  # Fabric-specific build configuration
52
71
  s.pod_target_xcconfig = {
53
72
  'SWIFT_VERSION' => '5.0',
@@ -63,5 +82,5 @@ Pod::Spec.new do |s|
63
82
  'GCC_PREPROCESSOR_DEFINITIONS' => '$(inherited) RCT_NEW_ARCH_ENABLED=1',
64
83
  'OTHER_CPLUSPLUSFLAGS' => '$(inherited) -std=c++17'
65
84
  }
66
-
85
+
67
86
  end
@@ -28,6 +28,7 @@
28
28
 
29
29
  #include <vector>
30
30
  #include <memory>
31
+ #include <string>
31
32
  #include "VROVector3f.h"
32
33
 
33
34
  /**
@@ -52,7 +53,8 @@ public:
52
53
  */
53
54
  VROARDepthMesh(std::vector<VROVector3f> vertices,
54
55
  std::vector<int> indices,
55
- std::vector<float> confidences);
56
+ std::vector<float> confidences,
57
+ std::string source = "lidar");
56
58
 
57
59
  ~VROARDepthMesh();
58
60
 
@@ -91,10 +93,16 @@ public:
91
93
  */
92
94
  bool isValid() const;
93
95
 
96
+ /**
97
+ * Get the depth source identifier. "lidar" or "monocular".
98
+ */
99
+ const std::string& getSource() const { return _source; }
100
+
94
101
  private:
95
102
  std::vector<VROVector3f> _vertices;
96
103
  std::vector<int> _indices;
97
104
  std::vector<float> _confidences;
105
+ std::string _source;
98
106
  };
99
107
 
100
108
  #endif /* VROARDepthMesh_h */
@@ -176,6 +176,29 @@ public:
176
176
  return nullptr;
177
177
  }
178
178
 
179
+ /**
180
+ * Generate a persistent mesh from all active ARMeshAnchor objects (iOS LiDAR, iOS 13.4+).
181
+ * ARKit accumulates the mesh as the user scans the environment — geometry seen in
182
+ * previous frames remains present even when no longer in the camera frustum.
183
+ * Returns nullptr on non-LiDAR devices, Android, or unsupported OS versions.
184
+ * Source tag: "lidar"
185
+ */
186
+ virtual std::shared_ptr<VROARDepthMesh> generateMeshAnchorMesh() {
187
+ return nullptr;
188
+ }
189
+
190
+ /**
191
+ * Generate a mesh by triangulating all detected AR plane anchors.
192
+ * Fallback path for non-LiDAR iOS and non-Depth-API Android devices.
193
+ * Plane anchors are persistent within the AR session, so the mesh degrades
194
+ * gracefully rather than disappearing on unsupported hardware.
195
+ * Returns nullptr if no planes have been detected yet.
196
+ * Source tag: "plane"
197
+ */
198
+ virtual std::shared_ptr<VROARDepthMesh> generatePlaneMesh() {
199
+ return nullptr;
200
+ }
201
+
179
202
  /*
180
203
  Returns the transform matrix to convert from camera texture coordinates
181
204
  to depth texture coordinates. The depth map may have a different
@@ -188,6 +211,16 @@ public:
188
211
  return VROMatrix4f::identity();
189
212
  }
190
213
 
214
+ /*
215
+ Debug-only variant: orientation-corrected transform WITHOUT the ScaleFill
216
+ crop correction. Maps the full screen [0,1]×[0,1] to the full depth texture
217
+ [0,1]×[0,1] so the debug overlay fills the screen without magenta bands.
218
+ The occlusion path still uses getDepthTextureTransform() for correctness.
219
+ */
220
+ virtual VROMatrix4f getDepthDebugTextureTransform() const {
221
+ return VROMatrix4f::identity();
222
+ }
223
+
191
224
  // ========================================================================
192
225
  // Scene Semantics API
193
226
  // ========================================================================
@@ -94,6 +94,17 @@ public:
94
94
  */
95
95
  VROMatrix4f getDepthTextureTransform() const;
96
96
 
97
+ /*
98
+ Returns a simplified depth transform for DEBUG visualization only.
99
+ Unlike getDepthTextureTransform(), this does NOT apply the ScaleFill
100
+ crop correction — it maps the full screen [0,1]×[0,1] to the full
101
+ depth texture [0,1]×[0,1]. This gives a single full-screen depth
102
+ overlay (no magenta bands at the edges of the coverage region).
103
+ The occlusion path still uses getDepthTextureTransform() for
104
+ correctness (only occlude where real depth data exists).
105
+ */
106
+ VROMatrix4f getDepthDebugTextureTransform() const;
107
+
97
108
  // Scene Semantics support (requires ARCore SDK with Semantics extension)
98
109
  float getSemanticLabelFraction(VROSemanticLabel label) override;
99
110
 
@@ -103,6 +114,12 @@ public:
103
114
  float minConfidence = 0.3f,
104
115
  float maxDepth = 5.0f) override;
105
116
 
117
+ // Persistent mesh from ARMeshAnchor (LiDAR, iOS 13.4+)
118
+ std::shared_ptr<VROARDepthMesh> generateMeshAnchorMesh() override;
119
+
120
+ // Plane-based fallback mesh (non-LiDAR / non-Depth-API)
121
+ std::shared_ptr<VROARDepthMesh> generatePlaneMesh() override;
122
+
106
123
  private:
107
124
 
108
125
  ARFrame *_frame;
@@ -127,6 +144,15 @@ private:
127
144
  */
128
145
  float sampleDepthTextureAtUV(std::shared_ptr<VROTexture> texture, float u, float v) const;
129
146
 
147
+ /*
148
+ Unproject a camera-image-space point (normalized [0,1] in ARKit's landscape image
149
+ space, the same space used for [ARFrame hitTest:]) at a given metric depth (meters
150
+ along the optical axis) to a world-space position. Returns false if camera
151
+ intrinsics are unavailable. Used to build a depth-derived DepthPoint hit result.
152
+ */
153
+ bool unprojectToWorld(VROVector3f cameraImagePoint, float depthMeters,
154
+ VROVector3f &outWorld) const;
155
+
130
156
  };
131
157
 
132
158
  #endif
@@ -44,6 +44,12 @@ public:
44
44
  virtual void onTrackingUpdated(VROARTrackingState state, VROARTrackingStateReason reason) = 0;
45
45
  virtual void onAmbientLightUpdate(float ambientLightIntensity, VROVector3f ambientLightColor) = 0;
46
46
  virtual void onWorldMeshUpdated(const VROWorldMeshStats& stats) {}
47
+
48
+ /*
49
+ Called once when depth data (LiDAR or monocular) first becomes available for the
50
+ session, i.e. hit tests can now return DepthPoints. Optional.
51
+ */
52
+ virtual void onDepthReady() {}
47
53
  };
48
54
 
49
55
  class VROARScene : public VROScene {
@@ -113,6 +119,12 @@ public:
113
119
  void setDelegate(std::shared_ptr<VROARSceneDelegate> delegate);
114
120
  void setTrackingState(VROARTrackingState state, VROARTrackingStateReason reason, bool force);
115
121
 
122
+ /*
123
+ Notify the delegate that depth data is now available. Fires the delegate's
124
+ onDepthReady() exactly once per scene; subsequent calls are no-ops.
125
+ */
126
+ void notifyDepthReady();
127
+
116
128
  /*
117
129
  Get the ambient light estimate of the scene.
118
130
  */
@@ -151,6 +163,7 @@ public:
151
163
  bool isWorldMeshEnabled() const;
152
164
  void setWorldMeshConfig(const VROWorldMeshConfig& config);
153
165
  VROWorldMeshStats getWorldMeshStats() const;
166
+ std::shared_ptr<VROARWorldMesh> getWorldMesh() const { return _worldMesh; }
154
167
 
155
168
  /*
156
169
  Override computePhysics to add world mesh debug drawing.
@@ -179,7 +192,8 @@ private:
179
192
  std::shared_ptr<VRONode> _pointCloudNode;
180
193
  std::shared_ptr<VROFixedParticleEmitter> _pointCloudEmitter;
181
194
  std::weak_ptr<VROARSceneDelegate> _delegate;
182
-
195
+ bool _depthReadyNotified = false;
196
+
183
197
  /*
184
198
  Ambient light estimation. The intensity is in lumens and the color is in linear space.
185
199
  */
@@ -38,6 +38,8 @@
38
38
  - (void)onAnchorFound:(std::shared_ptr<VROARAnchor>)anchor;
39
39
  - (void)onAnchorUpdated:(std::shared_ptr<VROARAnchor>)anchor;
40
40
  - (void)onAnchorRemoved:(std::shared_ptr<VROARAnchor>)anchor;
41
+ @optional
42
+ - (void)onDepthReady;
41
43
  @end
42
44
 
43
45
  class VROARSceneDelegateiOS : public VROARSceneDelegate, public VROARDeclarativeSessionDelegate {
@@ -71,6 +73,12 @@ public:
71
73
  [_delegate onAmbientLightUpdate:intensity color:color];
72
74
  }
73
75
 
76
+ virtual void onDepthReady() {
77
+ if ([_delegate respondsToSelector:@selector(onDepthReady)]) {
78
+ [_delegate onDepthReady];
79
+ }
80
+ }
81
+
74
82
  private:
75
83
  __weak id<VROARSceneDelegateProtocol> _delegate;
76
84
  };
@@ -370,6 +370,13 @@ public:
370
370
  _occlusionMode = mode;
371
371
  }
372
372
 
373
+ /*
374
+ Notify the session that world mesh was enabled or disabled.
375
+ Platform implementations use this to activate depth sensing when the
376
+ world mesh needs it (e.g. ARCore must set DepthMode::Automatic).
377
+ */
378
+ virtual void onWorldMeshEnabled(bool enabled) {}
379
+
373
380
  /*
374
381
  Get the current occlusion mode.
375
382
  */
@@ -126,6 +126,19 @@ public:
126
126
  void setPreferMonocularDepth(bool prefer);
127
127
  bool isPreferMonocularDepth() const;
128
128
 
129
+ // Use the front (TrueDepth) camera via ARFaceTrackingConfiguration.
130
+ // When true, world tracking, planes, and LiDAR are unavailable.
131
+ void setFrontCameraEnabled(bool enabled);
132
+ bool isFrontCameraEnabled() const { return _frontCameraEnabled; }
133
+
134
+ // Multiply all monocular depth values by this factor before use.
135
+ // 1.0 = no change (default). Use < 1.0 if model overestimates distance.
136
+ void setMonocularDepthScale(float scale);
137
+
138
+ // Set the target inference rate (default 5). Thermal state overrides this
139
+ // downward automatically (Fair→3fps, Serious→2fps, Critical→stop).
140
+ void setMonocularDepthTargetFPS(int fps);
141
+
129
142
  /*
130
143
  Set the base URL from which to download the depth model.
131
144
  The full URL will be: baseURL/DepthPro.mlmodelc.zip
@@ -224,6 +237,8 @@ public:
224
237
  Get the native ARSession object for anchor creation.
225
238
  */
226
239
  ARSession *getARSession() const { return _session; }
240
+ ARConfiguration *getSessionConfiguration() const { return _sessionConfiguration; }
241
+ bool isPaused() const { return _sessionPaused; }
227
242
 
228
243
  private:
229
244
 
@@ -356,7 +371,10 @@ private:
356
371
  std::shared_ptr<VROMonocularDepthEstimator> _monocularDepthEstimator;
357
372
  bool _monocularDepthEnabled;
358
373
  bool _preferMonocularDepth; // When true, use monocular even on LiDAR devices
374
+ bool _frontCameraEnabled; // When true, use ARFaceTrackingConfiguration (front camera)
359
375
  bool _monocularDepthLoading;
376
+ float _monocularDepthScale; // Multiplied into depth values (1.0 = no change)
377
+ int _monocularDepthTargetFPS; // 0 = use estimator default
360
378
  std::shared_ptr<VRODriver> _driver;
361
379
 
362
380
  void updateTrackingType(VROTrackingType trackingType);