@reactvision/react-viro 2.53.1 → 2.55.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.
- package/README.md +85 -46
- package/android/react_viro/react_viro-release.aar +0 -0
- package/android/viro_renderer/viro_renderer-release.aar +0 -0
- package/components/AR/ViroARCamera.tsx +5 -0
- package/components/AR/ViroARImageMarker.tsx +5 -0
- package/components/AR/ViroARObjectMarker.tsx +5 -0
- package/components/AR/ViroARPlane.tsx +5 -0
- package/components/AR/ViroARPlaneSelector.tsx +5 -0
- package/components/AR/ViroARScene.tsx +5 -0
- package/components/AR/ViroARSceneNavigator.tsx +84 -0
- package/components/AR/ViroCommonProps.ts +11 -0
- package/components/Material/ViroMaterials.ts +51 -0
- package/components/Studio/StudioARScene.tsx +368 -0
- package/components/Studio/StudioSceneNavigator.tsx +191 -0
- package/components/Studio/VRTStudioModule.ts +40 -0
- package/components/Studio/domain/animationRegistry.ts +86 -0
- package/components/Studio/domain/collisionBindingsRuntime.ts +93 -0
- package/components/Studio/domain/collisionPairKey.ts +15 -0
- package/components/Studio/domain/dragConfiguration.ts +48 -0
- package/components/Studio/domain/materialConfig.ts +276 -0
- package/components/Studio/domain/physicsConfig.ts +204 -0
- package/components/Studio/domain/sceneNavigationHandler.ts +150 -0
- package/components/Studio/domain/studioMaterials.ts +33 -0
- package/components/Studio/domain/triggerImageRegistry.ts +64 -0
- package/components/Studio/domain/useStudioShaderTimeUniforms.ts +51 -0
- package/components/Studio/domain/useStudioShaderViewportUniforms.ts +52 -0
- package/components/Studio/domain/viroNodeFactory.tsx +323 -0
- package/components/Studio/index.ts +18 -0
- package/components/Studio/types.ts +164 -0
- package/components/Types/ViroEvents.ts +53 -0
- package/components/Utilities/VRModuleOpenXR.ts +50 -0
- package/components/Utilities/VRQuestNavigatorBridge.ts +168 -0
- package/components/Utilities/ViroPlatform.ts +52 -0
- package/components/Utilities/ViroUtils.tsx +48 -0
- package/components/Utilities/ViroVersion.ts +1 -1
- package/components/Utilities/useAnySourceHover.ts +55 -0
- package/components/Utilities/useAnySourcePressed.ts +70 -0
- package/components/Viro360Image.tsx +7 -0
- package/components/ViroQuestEntryPoint.tsx +79 -0
- package/components/ViroVRSceneNavigator.tsx +44 -19
- package/components/ViroXRSceneNavigator.tsx +217 -0
- package/components/VisionOS/ViroVisionOSModule.ts +93 -0
- package/dist/components/AR/ViroARCamera.d.ts +1 -1
- package/dist/components/AR/ViroARCamera.js +5 -0
- package/dist/components/AR/ViroARImageMarker.d.ts +1 -1
- package/dist/components/AR/ViroARImageMarker.js +5 -0
- package/dist/components/AR/ViroARObjectMarker.d.ts +1 -1
- package/dist/components/AR/ViroARObjectMarker.js +5 -0
- package/dist/components/AR/ViroARPlane.d.ts +1 -1
- package/dist/components/AR/ViroARPlane.js +5 -0
- package/dist/components/AR/ViroARPlaneSelector.d.ts +1 -1
- package/dist/components/AR/ViroARPlaneSelector.js +5 -0
- package/dist/components/AR/ViroARScene.d.ts +1 -1
- package/dist/components/AR/ViroARScene.js +5 -0
- package/dist/components/AR/ViroARSceneNavigator.d.ts +36 -0
- package/dist/components/AR/ViroARSceneNavigator.js +41 -0
- package/dist/components/AR/ViroCommonProps.d.ts +11 -0
- package/dist/components/Material/ViroMaterials.d.ts +12 -0
- package/dist/components/Material/ViroMaterials.js +25 -0
- package/dist/components/ReactVisionClient.d.ts +25 -0
- package/dist/components/ReactVisionClient.js +11 -0
- package/dist/components/Studio/StudioARScene.d.ts +15 -0
- package/dist/components/Studio/StudioARScene.js +299 -0
- package/dist/components/Studio/StudioSceneNavigator.d.ts +31 -0
- package/dist/components/Studio/StudioSceneNavigator.js +174 -0
- package/dist/components/Studio/VRTStudioModule.d.ts +15 -0
- package/dist/components/Studio/VRTStudioModule.js +31 -0
- package/dist/components/Studio/domain/animationRegistry.d.ts +11 -0
- package/dist/components/Studio/domain/animationRegistry.js +67 -0
- package/dist/components/Studio/domain/collisionBindingsRuntime.d.ts +21 -0
- package/dist/components/Studio/domain/collisionBindingsRuntime.js +54 -0
- package/dist/components/Studio/domain/collisionPairKey.d.ts +8 -0
- package/dist/components/Studio/domain/collisionPairKey.js +15 -0
- package/dist/components/Studio/domain/dragConfiguration.d.ts +20 -0
- package/dist/components/Studio/domain/dragConfiguration.js +37 -0
- package/dist/components/Studio/domain/materialConfig.d.ts +56 -0
- package/dist/components/Studio/domain/materialConfig.js +239 -0
- package/dist/components/Studio/domain/physicsConfig.d.ts +69 -0
- package/dist/components/Studio/domain/physicsConfig.js +165 -0
- package/dist/components/Studio/domain/sceneNavigationHandler.d.ts +12 -0
- package/dist/components/Studio/domain/sceneNavigationHandler.js +112 -0
- package/dist/components/Studio/domain/studioMaterials.d.ts +6 -0
- package/dist/components/Studio/domain/studioMaterials.js +30 -0
- package/dist/components/Studio/domain/triggerImageRegistry.d.ts +13 -0
- package/dist/components/Studio/domain/triggerImageRegistry.js +47 -0
- package/dist/components/Studio/domain/useStudioShaderTimeUniforms.d.ts +6 -0
- package/dist/components/Studio/domain/useStudioShaderTimeUniforms.js +48 -0
- package/dist/components/Studio/domain/useStudioShaderViewportUniforms.d.ts +6 -0
- package/dist/components/Studio/domain/useStudioShaderViewportUniforms.js +48 -0
- package/dist/components/Studio/domain/viroNodeFactory.d.ts +28 -0
- package/dist/components/Studio/domain/viroNodeFactory.js +193 -0
- package/dist/components/Studio/index.d.ts +3 -0
- package/dist/components/Studio/index.js +7 -0
- package/dist/components/Studio/types.d.ts +149 -0
- package/dist/components/Studio/types.js +4 -0
- package/dist/components/Types/ViroEvents.d.ts +49 -1
- package/dist/components/Types/ViroEvents.js +1 -0
- package/dist/components/Utilities/VRModuleOpenXR.d.ts +32 -0
- package/dist/components/Utilities/VRModuleOpenXR.js +44 -0
- package/dist/components/Utilities/VRQuestNavigatorBridge.d.ts +85 -0
- package/dist/components/Utilities/VRQuestNavigatorBridge.js +124 -0
- package/dist/components/Utilities/ViroPlatform.d.ts +10 -0
- package/dist/components/Utilities/ViroPlatform.js +43 -0
- package/dist/components/Utilities/ViroUtils.d.ts +19 -0
- package/dist/components/Utilities/ViroUtils.js +34 -0
- package/dist/components/Utilities/ViroVersion.d.ts +1 -1
- package/dist/components/Utilities/ViroVersion.js +1 -1
- package/dist/components/Utilities/useAnySourceHover.d.ts +36 -0
- package/dist/components/Utilities/useAnySourceHover.js +48 -0
- package/dist/components/Utilities/useAnySourcePressed.d.ts +37 -0
- package/dist/components/Utilities/useAnySourcePressed.js +61 -0
- package/dist/components/Viro360Image.d.ts +7 -0
- package/dist/components/ViroQuestEntryPoint.d.ts +13 -0
- package/dist/components/ViroQuestEntryPoint.js +104 -0
- package/dist/components/ViroVRSceneNavigator.d.ts +24 -10
- package/dist/components/ViroVRSceneNavigator.js +21 -18
- package/dist/components/ViroXRSceneNavigator.d.ts +54 -0
- package/dist/components/ViroXRSceneNavigator.js +173 -0
- package/dist/components/VisionOS/ViroVisionOSModule.d.ts +65 -0
- package/dist/components/VisionOS/ViroVisionOSModule.js +91 -0
- package/dist/index.d.ts +16 -3
- package/dist/index.js +34 -2
- package/dist/plugins/withViro.d.ts +28 -1
- package/dist/plugins/withViroAndroid.js +312 -7
- package/dist/plugins/withViroIos.js +17 -8
- package/dist/plugins/withViroVisionOS.d.ts +24 -0
- package/dist/plugins/withViroVisionOS.js +265 -0
- package/index.ts +66 -0
- package/ios/ViroReact.podspec +15 -5
- package/ios/dist/ViroRenderer/ViroKit.framework/ARCoreCoreMLSemanticsResources.bundle/Info.plist +0 -0
- package/ios/dist/ViroRenderer/ViroKit.framework/ARCoreResources.bundle/Info.plist +0 -0
- package/ios/dist/ViroRenderer/ViroKit.framework/Headers/VROARSession.h +30 -1
- package/ios/dist/ViroRenderer/ViroKit.framework/Headers/VROARSessioniOS.h +16 -0
- package/ios/dist/ViroRenderer/ViroKit.framework/Headers/VROGLTFLoader.h +34 -0
- package/ios/dist/ViroRenderer/ViroKit.framework/Headers/VROInputControllerBase.h +74 -0
- package/ios/dist/ViroRenderer/ViroKit.framework/Headers/VROInputType.h +11 -3
- package/ios/dist/ViroRenderer/ViroKit.framework/Headers/VROMaterial.h +29 -0
- package/ios/dist/ViroRenderer/ViroKit.framework/Headers/VROMorpher.h +4 -0
- package/ios/dist/ViroRenderer/ViroKit.framework/Headers/VROPlatformUtil.h +13 -0
- package/ios/dist/ViroRenderer/ViroKit.framework/Headers/VROPortal.h +17 -0
- package/ios/dist/ViroRenderer/ViroKit.framework/Headers/VRORenderContext.h +41 -0
- package/ios/dist/ViroRenderer/ViroKit.framework/Headers/VRORenderer.h +23 -0
- package/ios/dist/ViroRenderer/ViroKit.framework/Headers/VROSemantics.h +14 -0
- package/ios/dist/ViroRenderer/ViroKit.framework/Headers/VROViewAR.h +11 -0
- package/ios/dist/ViroRenderer/ViroKit.framework/Info.plist +0 -0
- package/ios/dist/ViroRenderer/ViroKit.framework/Shaders.dat +1 -1
- package/ios/dist/ViroRenderer/ViroKit.framework/ViroKit +0 -0
- package/ios/dist/ViroRenderer/ViroKit.podspec +5 -0
- package/ios/dist/include/VRT360Image.h +1 -0
- package/ios/dist/include/VRTARSceneNavigator.h +7 -0
- package/ios/dist/include/VRTStudioModule.h +6 -0
- package/ios/dist/lib/libViroReact.a +0 -0
- package/package.json +8 -8
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* withViroVisionOS.ts
|
|
4
|
+
*
|
|
5
|
+
* Expo config plugin that adds a visionOS target to your app's Xcode project.
|
|
6
|
+
*
|
|
7
|
+
* What it does:
|
|
8
|
+
* 1. Writes the SwiftUI App entry point (ViroVisionApp.swift) into the target folder
|
|
9
|
+
* 2. Adds a visionOS pod target to the Podfile
|
|
10
|
+
* 3. Creates a visionOS Xcode target in the .pbxproj with correct SDK + build settings
|
|
11
|
+
*
|
|
12
|
+
* Usage in app.json:
|
|
13
|
+
* {
|
|
14
|
+
* "plugins": [
|
|
15
|
+
* ["@reactvision/react-viro", { ... }],
|
|
16
|
+
* "@reactvision/react-viro/plugins/withViroVisionOS"
|
|
17
|
+
* ]
|
|
18
|
+
* }
|
|
19
|
+
*
|
|
20
|
+
* After running `expo prebuild`, run `pod install` in ios/ then build the
|
|
21
|
+
* <AppName>Vision target in Xcode targeting the visionOS simulator.
|
|
22
|
+
*/
|
|
23
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
24
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
25
|
+
};
|
|
26
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
27
|
+
exports.withViroVisionOS = void 0;
|
|
28
|
+
const config_plugins_1 = require("@expo/config-plugins");
|
|
29
|
+
const fs_1 = __importDefault(require("fs"));
|
|
30
|
+
const path_1 = __importDefault(require("path"));
|
|
31
|
+
// ─── Constants ────────────────────────────────────────────────────────────────
|
|
32
|
+
const TARGET_SUFFIX = "Vision";
|
|
33
|
+
const VISIONOS_DEPLOYMENT_TARGET = "1.0";
|
|
34
|
+
const PODFILE_MARKER = "# viro-visionos-target";
|
|
35
|
+
// ─── Swift App entry point template ──────────────────────────────────────────
|
|
36
|
+
function viroVisionAppSwift(targetName, bundleId) {
|
|
37
|
+
return `// ViroVisionApp.swift
|
|
38
|
+
// Auto-generated by @reactvision/react-viro — DO NOT EDIT MANUALLY.
|
|
39
|
+
// Re-generated on every expo prebuild run.
|
|
40
|
+
|
|
41
|
+
import SwiftUI
|
|
42
|
+
import ViroReact
|
|
43
|
+
|
|
44
|
+
@main
|
|
45
|
+
struct ${targetName}App: App {
|
|
46
|
+
/// Current immersion style — driven by ViroVisionOSModule.enterImmersiveSpace(style).
|
|
47
|
+
@State private var immersionStyle: ImmersionStyle = .mixed
|
|
48
|
+
|
|
49
|
+
var body: some Scene {
|
|
50
|
+
// Main 2D window (hosts React Native UI if needed, or acts as launch host).
|
|
51
|
+
WindowGroup {
|
|
52
|
+
ViroVisionLaunchView()
|
|
53
|
+
.viroImmersiveSpaceController()
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// The Viro immersive rendering space.
|
|
57
|
+
// Opened via ViroVisionOSModule.enterImmersiveSpace() from JavaScript.
|
|
58
|
+
ImmersiveSpace(id: ViroImmersiveSpace.id) {
|
|
59
|
+
ViroImmersiveSpaceView()
|
|
60
|
+
}
|
|
61
|
+
.immersionStyle(selection: $immersionStyle, in: .mixed, .full, .progressive)
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/// Minimal launch view displayed in the 2D window.
|
|
66
|
+
/// Replace with your own SwiftUI content or a React Native root view.
|
|
67
|
+
struct ViroVisionLaunchView: View {
|
|
68
|
+
@State private var isImmersed = false
|
|
69
|
+
|
|
70
|
+
var body: some View {
|
|
71
|
+
VStack(spacing: 20) {
|
|
72
|
+
Text("ReactVision AR")
|
|
73
|
+
.font(.largeTitle)
|
|
74
|
+
.fontWeight(.bold)
|
|
75
|
+
|
|
76
|
+
Button(isImmersed ? "Exit Immersive Space" : "Enter Immersive Space") {
|
|
77
|
+
Task {
|
|
78
|
+
if isImmersed {
|
|
79
|
+
await ViroImmersiveCoordinator.shared.exit()
|
|
80
|
+
} else {
|
|
81
|
+
await ViroImmersiveCoordinator.shared.enter(styleString: "mixed")
|
|
82
|
+
}
|
|
83
|
+
isImmersed.toggle()
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
.buttonStyle(.borderedProminent)
|
|
87
|
+
}
|
|
88
|
+
.padding(40)
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
`;
|
|
92
|
+
}
|
|
93
|
+
// ─── 1. Write Swift files ─────────────────────────────────────────────────────
|
|
94
|
+
const withVisionOSSwiftFiles = (config) => {
|
|
95
|
+
return (0, config_plugins_1.withDangerousMod)(config, [
|
|
96
|
+
"ios",
|
|
97
|
+
async (newConfig) => {
|
|
98
|
+
const root = newConfig.modRequest.platformProjectRoot;
|
|
99
|
+
const projectName = newConfig.modRequest.projectName;
|
|
100
|
+
const targetName = `${projectName}${TARGET_SUFFIX}`;
|
|
101
|
+
const bundleId = `${newConfig.ios?.bundleIdentifier ?? "com.example"}.vision`;
|
|
102
|
+
const targetDir = path_1.default.join(root, targetName);
|
|
103
|
+
if (!fs_1.default.existsSync(targetDir)) {
|
|
104
|
+
fs_1.default.mkdirSync(targetDir, { recursive: true });
|
|
105
|
+
}
|
|
106
|
+
// Always overwrite — it's auto-generated.
|
|
107
|
+
fs_1.default.writeFileSync(path_1.default.join(targetDir, "ViroVisionApp.swift"), viroVisionAppSwift(targetName, bundleId), "utf-8");
|
|
108
|
+
return newConfig;
|
|
109
|
+
},
|
|
110
|
+
]);
|
|
111
|
+
};
|
|
112
|
+
// ─── 2. Podfile target block ──────────────────────────────────────────────────
|
|
113
|
+
const withVisionOSPodfile = (config) => {
|
|
114
|
+
return (0, config_plugins_1.withDangerousMod)(config, [
|
|
115
|
+
"ios",
|
|
116
|
+
async (newConfig) => {
|
|
117
|
+
const root = newConfig.modRequest.platformProjectRoot;
|
|
118
|
+
const projectName = newConfig.modRequest.projectName;
|
|
119
|
+
const targetName = `${projectName}${TARGET_SUFFIX}`;
|
|
120
|
+
const podfilePath = path_1.default.join(root, "Podfile");
|
|
121
|
+
let podfile = fs_1.default.readFileSync(podfilePath, "utf-8");
|
|
122
|
+
// Idempotent — skip if already present.
|
|
123
|
+
if (podfile.includes(PODFILE_MARKER))
|
|
124
|
+
return newConfig;
|
|
125
|
+
const podBlock = [
|
|
126
|
+
"",
|
|
127
|
+
PODFILE_MARKER,
|
|
128
|
+
`# ViroKit (iOS-only) and ViroReact (ObjC) are excluded until ViroKit`,
|
|
129
|
+
`# is compiled for xros SDK (Week 2). The POC uses Metal + CompositorServices directly.`,
|
|
130
|
+
`target '${targetName}' do`,
|
|
131
|
+
`end`,
|
|
132
|
+
"",
|
|
133
|
+
].join("\n");
|
|
134
|
+
fs_1.default.writeFileSync(podfilePath, podfile + podBlock, "utf-8");
|
|
135
|
+
return newConfig;
|
|
136
|
+
},
|
|
137
|
+
]);
|
|
138
|
+
};
|
|
139
|
+
// ─── 3. Xcode target ─────────────────────────────────────────────────────────
|
|
140
|
+
const withVisionOSXcodeTarget = (config) => {
|
|
141
|
+
return (0, config_plugins_1.withXcodeProject)(config, (newConfig) => {
|
|
142
|
+
const pbxProject = newConfig.modResults;
|
|
143
|
+
const projectName = newConfig.modRequest.projectName;
|
|
144
|
+
const targetName = `${projectName}${TARGET_SUFFIX}`;
|
|
145
|
+
const bundleId = `${newConfig.ios?.bundleIdentifier ?? "com.example"}.vision`;
|
|
146
|
+
const targetDir = targetName; // relative path inside ios/
|
|
147
|
+
// ── Check for existing target ────────────────────────────────────────────
|
|
148
|
+
const nativeTargets = pbxProject.pbxNativeTargetSection();
|
|
149
|
+
const alreadyExists = Object.values(nativeTargets).some((t) => t &&
|
|
150
|
+
typeof t === "object" &&
|
|
151
|
+
(t.name === targetName || t.name === `"${targetName}"`));
|
|
152
|
+
if (alreadyExists)
|
|
153
|
+
return newConfig;
|
|
154
|
+
// ── Add the target (creates PBX phases + config list) ────────────────────
|
|
155
|
+
const target = pbxProject.addTarget(targetName, "application", targetDir, bundleId);
|
|
156
|
+
if (!target) {
|
|
157
|
+
config_plugins_1.WarningAggregator.addWarningIOS("withViroVisionOS", `Failed to add visionOS target "${targetName}" to Xcode project. ` +
|
|
158
|
+
"Add it manually in Xcode: File → New → Target → visionOS → App.");
|
|
159
|
+
return newConfig;
|
|
160
|
+
}
|
|
161
|
+
// ── Set visionOS build settings on every config for this target ──────────
|
|
162
|
+
const configList = pbxProject.pbxXCBuildConfigurationSection();
|
|
163
|
+
for (const conf of Object.values(configList)) {
|
|
164
|
+
if (!conf || typeof conf !== "object" || !conf.buildSettings)
|
|
165
|
+
continue;
|
|
166
|
+
const name = conf.buildSettings.PRODUCT_NAME;
|
|
167
|
+
if (!name)
|
|
168
|
+
continue;
|
|
169
|
+
const normalized = name.replace(/^"(.*)"$/, "$1");
|
|
170
|
+
if (normalized !== targetName)
|
|
171
|
+
continue;
|
|
172
|
+
const bs = conf.buildSettings;
|
|
173
|
+
// visionOS SDK
|
|
174
|
+
bs.SDKROOT = "xros";
|
|
175
|
+
bs.SUPPORTED_PLATFORMS = '"xros xrsimulator"';
|
|
176
|
+
bs[`"DEPLOYMENT_TARGET[sdk=xros*]"`] = `"${VISIONOS_DEPLOYMENT_TARGET}"`;
|
|
177
|
+
bs.TARGETED_DEVICE_FAMILY = '"7"';
|
|
178
|
+
// Swift
|
|
179
|
+
bs.SWIFT_VERSION = '"5.0"';
|
|
180
|
+
bs.CLANG_ENABLE_MODULES = "YES";
|
|
181
|
+
// Runpath for dynamic frameworks (CocoaPods)
|
|
182
|
+
bs.LD_RUNPATH_SEARCH_PATHS = '"$(inherited) @executable_path/Frameworks"';
|
|
183
|
+
// Embed Swift standard libraries
|
|
184
|
+
bs.ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = "YES";
|
|
185
|
+
// App-specific
|
|
186
|
+
bs.PRODUCT_BUNDLE_IDENTIFIER = `"${bundleId}"`;
|
|
187
|
+
bs.INFOPLIST_FILE = `"${targetDir}/Info.plist"`;
|
|
188
|
+
bs.GENERATE_INFOPLIST_FILE = "NO";
|
|
189
|
+
bs.ASSETCATALOG_COMPILER_APPICON_NAME = "AppIcon";
|
|
190
|
+
// Don't strip Swift symbols in debug
|
|
191
|
+
if (conf.name === "Debug") {
|
|
192
|
+
bs.SWIFT_OPTIMIZATION_LEVEL = '"-Onone"';
|
|
193
|
+
bs.SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG";
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
// ── Write Info.plist for the visionOS target ──────────────────────────────
|
|
197
|
+
// (written during the dangerous mod pass — cannot write files here)
|
|
198
|
+
// Logged as a reminder.
|
|
199
|
+
config_plugins_1.WarningAggregator.addWarningIOS("withViroVisionOS", `visionOS target "${targetName}" added. ` +
|
|
200
|
+
`Run "pod install" in ios/ then build the target in Xcode. ` +
|
|
201
|
+
`An Info.plist will be auto-generated by Xcode for the new target.`);
|
|
202
|
+
return newConfig;
|
|
203
|
+
});
|
|
204
|
+
};
|
|
205
|
+
// ─── 4. Info.plist for visionOS target ───────────────────────────────────────
|
|
206
|
+
const INFOPLIST_CONTENT = `<?xml version="1.0" encoding="UTF-8"?>
|
|
207
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
208
|
+
<plist version="1.0">
|
|
209
|
+
<dict>
|
|
210
|
+
<key>CFBundleDevelopmentRegion</key>
|
|
211
|
+
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
|
212
|
+
<key>CFBundleExecutable</key>
|
|
213
|
+
<string>$(EXECUTABLE_NAME)</string>
|
|
214
|
+
<key>CFBundleIdentifier</key>
|
|
215
|
+
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
|
216
|
+
<key>CFBundleInfoDictionaryVersion</key>
|
|
217
|
+
<string>6.0</string>
|
|
218
|
+
<key>CFBundleName</key>
|
|
219
|
+
<string>$(PRODUCT_NAME)</string>
|
|
220
|
+
<key>CFBundlePackageType</key>
|
|
221
|
+
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
|
|
222
|
+
<key>CFBundleShortVersionString</key>
|
|
223
|
+
<string>1.0</string>
|
|
224
|
+
<key>CFBundleVersion</key>
|
|
225
|
+
<string>1</string>
|
|
226
|
+
<key>UIApplicationSceneManifest</key>
|
|
227
|
+
<dict>
|
|
228
|
+
<key>UIApplicationSupportsMultipleScenes</key>
|
|
229
|
+
<true/>
|
|
230
|
+
</dict>
|
|
231
|
+
<key>NSHandsTrackingUsageDescription</key>
|
|
232
|
+
<string>Hand tracking is used for interaction in AR experiences.</string>
|
|
233
|
+
</dict>
|
|
234
|
+
</plist>
|
|
235
|
+
`;
|
|
236
|
+
const withVisionOSInfoPlist = (config) => {
|
|
237
|
+
return (0, config_plugins_1.withDangerousMod)(config, [
|
|
238
|
+
"ios",
|
|
239
|
+
async (newConfig) => {
|
|
240
|
+
const root = newConfig.modRequest.platformProjectRoot;
|
|
241
|
+
const projectName = newConfig.modRequest.projectName;
|
|
242
|
+
const targetName = `${projectName}${TARGET_SUFFIX}`;
|
|
243
|
+
const targetDir = path_1.default.join(root, targetName);
|
|
244
|
+
if (!fs_1.default.existsSync(targetDir)) {
|
|
245
|
+
fs_1.default.mkdirSync(targetDir, { recursive: true });
|
|
246
|
+
}
|
|
247
|
+
const plistPath = path_1.default.join(targetDir, "Info.plist");
|
|
248
|
+
if (!fs_1.default.existsSync(plistPath)) {
|
|
249
|
+
fs_1.default.writeFileSync(plistPath, INFOPLIST_CONTENT, "utf-8");
|
|
250
|
+
}
|
|
251
|
+
return newConfig;
|
|
252
|
+
},
|
|
253
|
+
]);
|
|
254
|
+
};
|
|
255
|
+
// ─── Main export ──────────────────────────────────────────────────────────────
|
|
256
|
+
const withViroVisionOS = (config) => {
|
|
257
|
+
return (0, config_plugins_1.withPlugins)(config, [
|
|
258
|
+
withVisionOSSwiftFiles,
|
|
259
|
+
withVisionOSInfoPlist,
|
|
260
|
+
withVisionOSPodfile,
|
|
261
|
+
withVisionOSXcodeTarget,
|
|
262
|
+
]);
|
|
263
|
+
};
|
|
264
|
+
exports.withViroVisionOS = withViroVisionOS;
|
|
265
|
+
exports.default = exports.withViroVisionOS;
|
package/index.ts
CHANGED
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
*
|
|
5
5
|
*/
|
|
6
6
|
import { ViroAnimations } from "./components/Animation/ViroAnimations";
|
|
7
|
+
import { StudioSceneNavigator, StudioARScene } from "./components/Studio";
|
|
8
|
+
import { ViroVisionOSModule, isVisionOS, enterImmersiveSpace, exitImmersiveSpace } from "./components/VisionOS/ViroVisionOSModule";
|
|
7
9
|
import { Viro3DObject } from "./components/Viro3DObject";
|
|
8
10
|
import { Viro360Image } from "./components/Viro360Image";
|
|
9
11
|
import { Viro360Video } from "./components/Viro360Video";
|
|
@@ -59,14 +61,22 @@ import { ViroSpotLight } from "./components/ViroSpotLight";
|
|
|
59
61
|
import { ViroText } from "./components/ViroText";
|
|
60
62
|
import { ViroVideo } from "./components/ViroVideo";
|
|
61
63
|
import { ViroVRSceneNavigator } from "./components/ViroVRSceneNavigator";
|
|
64
|
+
import { ViroXRSceneNavigator } from "./components/ViroXRSceneNavigator";
|
|
62
65
|
import { Viro3DSceneNavigator } from "./components/Viro3DSceneNavigator";
|
|
66
|
+
import { hasOpenXRSupport, isQuest } from "./components/Utilities/ViroPlatform";
|
|
67
|
+
import { useAnySourceHover } from "./components/Utilities/useAnySourceHover";
|
|
68
|
+
import { useAnySourcePressed } from "./components/Utilities/useAnySourcePressed";
|
|
63
69
|
import { ViroTextStyle } from "./components/Styles/ViroTextStyle";
|
|
64
70
|
import { ViroStyle } from "./components/Styles/ViroStyle";
|
|
65
71
|
import {
|
|
66
72
|
polarToCartesian,
|
|
67
73
|
polarToCartesianActual,
|
|
68
74
|
isARSupportedOnDevice,
|
|
75
|
+
requestRequiredPermissions,
|
|
76
|
+
checkPermissions,
|
|
69
77
|
ViroARSupportResponse,
|
|
78
|
+
ViroPermissionsResult,
|
|
79
|
+
ViroPermission,
|
|
70
80
|
latLngToMercator,
|
|
71
81
|
gpsToArWorld,
|
|
72
82
|
} from "./components/Utilities/ViroUtils";
|
|
@@ -157,10 +167,25 @@ import {
|
|
|
157
167
|
ViroMonocularDepthSupportResult,
|
|
158
168
|
ViroMonocularDepthModelAvailableResult,
|
|
159
169
|
ViroMonocularDepthPreferenceResult,
|
|
170
|
+
// Quest / OpenXR Hand Tracking Types
|
|
171
|
+
ViroJoint,
|
|
172
|
+
ViroHandJoints,
|
|
173
|
+
ViroHandPinchEvent,
|
|
174
|
+
ViroHandUpdateEvent,
|
|
160
175
|
} from "./components/Types/ViroEvents";
|
|
161
176
|
import { ViroSurface } from "./components/ViroSurface";
|
|
162
177
|
import { ViroSceneNavigator } from "./components/ViroSceneNavigator";
|
|
163
178
|
import { VIRO_VERSION } from "./components/Utilities/ViroVersion";
|
|
179
|
+
import { ViroQuestEntryPoint } from "./components/ViroQuestEntryPoint";
|
|
180
|
+
import { VRQuestNavigatorBridge } from "./components/Utilities/VRQuestNavigatorBridge";
|
|
181
|
+
import { VRModuleOpenXR, useVRViewTag, exitVRScene } from "./components/Utilities/VRModuleOpenXR";
|
|
182
|
+
import type { VRModuleOpenXRType } from "./components/Utilities/VRModuleOpenXR";
|
|
183
|
+
import { AppRegistry } from "react-native";
|
|
184
|
+
|
|
185
|
+
// Auto-register the Quest VR entry point. VRActivity launches this component
|
|
186
|
+
// as 'VRQuestScene'. Registering here means apps need no manual setup.
|
|
187
|
+
// Apps that need a custom VR root can re-register after importing this package.
|
|
188
|
+
AppRegistry.registerComponent("VRQuestScene", () => ViroQuestEntryPoint);
|
|
164
189
|
|
|
165
190
|
export {
|
|
166
191
|
ViroARImageMarker,
|
|
@@ -211,18 +236,33 @@ export {
|
|
|
211
236
|
ViroText,
|
|
212
237
|
ViroVideo,
|
|
213
238
|
ViroVRSceneNavigator,
|
|
239
|
+
ViroXRSceneNavigator,
|
|
240
|
+
ViroQuestEntryPoint,
|
|
241
|
+
// Quest bridge — for custom VR roots and VRModuleOpenXR viewTag access
|
|
242
|
+
VRQuestNavigatorBridge,
|
|
243
|
+
VRModuleOpenXR,
|
|
244
|
+
useVRViewTag,
|
|
245
|
+
exitVRScene,
|
|
214
246
|
Viro3DSceneNavigator,
|
|
215
247
|
// Utilities
|
|
248
|
+
hasOpenXRSupport,
|
|
249
|
+
isQuest,
|
|
250
|
+
useAnySourceHover,
|
|
251
|
+
useAnySourcePressed,
|
|
216
252
|
ViroARTrackingReasonConstants,
|
|
217
253
|
ViroRecordingErrorConstants,
|
|
218
254
|
ViroTrackingStateConstants,
|
|
219
255
|
polarToCartesian,
|
|
220
256
|
polarToCartesianActual,
|
|
221
257
|
isARSupportedOnDevice,
|
|
258
|
+
requestRequiredPermissions,
|
|
259
|
+
checkPermissions,
|
|
222
260
|
latLngToMercator,
|
|
223
261
|
gpsToArWorld,
|
|
224
262
|
// Types
|
|
225
263
|
ViroARSupportResponse,
|
|
264
|
+
ViroPermissionsResult,
|
|
265
|
+
ViroPermission,
|
|
226
266
|
ViroHoverEvent,
|
|
227
267
|
ViroClickEvent,
|
|
228
268
|
ViroClickStateEvent,
|
|
@@ -315,4 +355,30 @@ export {
|
|
|
315
355
|
ViroMonocularDepthSupportResult,
|
|
316
356
|
ViroMonocularDepthModelAvailableResult,
|
|
317
357
|
ViroMonocularDepthPreferenceResult,
|
|
358
|
+
// Quest / OpenXR Hand Tracking Types
|
|
359
|
+
ViroJoint,
|
|
360
|
+
ViroHandJoints,
|
|
361
|
+
ViroHandPinchEvent,
|
|
362
|
+
ViroHandUpdateEvent,
|
|
363
|
+
// Studio Integration
|
|
364
|
+
StudioSceneNavigator,
|
|
365
|
+
StudioARScene,
|
|
366
|
+
// VisionOS
|
|
367
|
+
ViroVisionOSModule,
|
|
368
|
+
isVisionOS,
|
|
369
|
+
enterImmersiveSpace,
|
|
370
|
+
exitImmersiveSpace,
|
|
318
371
|
};
|
|
372
|
+
|
|
373
|
+
export type { VRModuleOpenXRType };
|
|
374
|
+
export type { ImmersiveSpaceStyle } from "./components/VisionOS/ViroVisionOSModule";
|
|
375
|
+
|
|
376
|
+
export type {
|
|
377
|
+
StudioSceneResponse,
|
|
378
|
+
StudioAsset,
|
|
379
|
+
StudioAnimation,
|
|
380
|
+
StudioCollisionBinding,
|
|
381
|
+
StudioSceneFunction,
|
|
382
|
+
StudioSceneMeta,
|
|
383
|
+
StudioProjectMeta,
|
|
384
|
+
} from "./components/Studio";
|
package/ios/ViroReact.podspec
CHANGED
|
@@ -12,10 +12,14 @@ Pod::Spec.new do |s|
|
|
|
12
12
|
s.author = 'ReactVision'
|
|
13
13
|
s.requires_arc = true
|
|
14
14
|
s.platform = :ios, '12.0'
|
|
15
|
-
s.ios.deployment_target
|
|
16
|
-
|
|
15
|
+
s.ios.deployment_target = '12.0'
|
|
16
|
+
s.visionos.deployment_target = '1.0'
|
|
17
|
+
|
|
18
|
+
# visionOS: CompositorServices drives the immersive render loop.
|
|
19
|
+
s.visionos.frameworks = ['Metal', 'MetalKit', 'CompositorServices', 'ARKit']
|
|
20
|
+
|
|
17
21
|
# Base source files (always included)
|
|
18
|
-
source_files_array = ['ViroReact/**/*.{h,m,mm}']
|
|
22
|
+
source_files_array = ['ViroReact/**/*.{h,m,mm,swift}']
|
|
19
23
|
header_files_array = ['ViroReact/**/*.h']
|
|
20
24
|
|
|
21
25
|
# Include dist files if they exist (for release builds)
|
|
@@ -26,7 +30,12 @@ Pod::Spec.new do |s|
|
|
|
26
30
|
|
|
27
31
|
s.source_files = source_files_array
|
|
28
32
|
s.public_header_files = header_files_array
|
|
29
|
-
|
|
33
|
+
|
|
34
|
+
# visionOS-only sources: keep them out of the iOS build so consumers running
|
|
35
|
+
# `pod install` for iOS don't pull CompositorServices / VRODriverVisionOS.h
|
|
36
|
+
# into a target where those symbols don't exist.
|
|
37
|
+
s.ios.exclude_files = ['ViroReact/VisionOS/**/*']
|
|
38
|
+
|
|
30
39
|
if File.exist?(File.join(__dir__, 'dist/lib/libViroReact.a'))
|
|
31
40
|
s.vendored_libraries = 'dist/lib/libViroReact.a'
|
|
32
41
|
end
|
|
@@ -40,7 +49,8 @@ Pod::Spec.new do |s|
|
|
|
40
49
|
s.dependency 'React-FabricComponents'
|
|
41
50
|
|
|
42
51
|
# Fabric-specific build configuration
|
|
43
|
-
s.pod_target_xcconfig = {
|
|
52
|
+
s.pod_target_xcconfig = {
|
|
53
|
+
'SWIFT_VERSION' => '5.0',
|
|
44
54
|
'CLANG_CXX_LANGUAGE_STANDARD' => 'c++17',
|
|
45
55
|
'HEADER_SEARCH_PATHS' => [
|
|
46
56
|
'"$(PODS_TARGET_SRCROOT)/ViroReact"',
|
package/ios/dist/ViroRenderer/ViroKit.framework/ARCoreCoreMLSemanticsResources.bundle/Info.plist
CHANGED
|
Binary file
|
|
Binary file
|
|
@@ -319,7 +319,21 @@ public:
|
|
|
319
319
|
texture are updated after each call to updateFrame().
|
|
320
320
|
*/
|
|
321
321
|
virtual std::shared_ptr<VROTexture> getCameraBackgroundTexture() = 0;
|
|
322
|
-
|
|
322
|
+
|
|
323
|
+
/*
|
|
324
|
+
Get the semantic texture for the current frame. Each pixel is a VROSemanticLabel
|
|
325
|
+
value (0-11, R8 format). Returns nullptr if semantic mode is not enabled or
|
|
326
|
+
the platform does not support it.
|
|
327
|
+
*/
|
|
328
|
+
virtual std::shared_ptr<VROTexture> getSemanticTexture() { return nullptr; }
|
|
329
|
+
|
|
330
|
+
/*
|
|
331
|
+
Get the confidence texture for the current frame. Each pixel is a confidence value
|
|
332
|
+
(R8, 0=uncertain, 255=certain) corresponding to the label in getSemanticTexture().
|
|
333
|
+
Returns nullptr if not supported; callers should substitute a 1×1 white texture.
|
|
334
|
+
*/
|
|
335
|
+
virtual std::shared_ptr<VROTexture> getSemanticConfidenceTexture() { return nullptr; }
|
|
336
|
+
|
|
323
337
|
/*
|
|
324
338
|
Invoke when the viewport changes. The AR engine may adjust its camera
|
|
325
339
|
background and projection matrices in response to a viewport change.
|
|
@@ -557,6 +571,21 @@ public:
|
|
|
557
571
|
std::function<void(bool success, std::string error)> callback) {
|
|
558
572
|
if (callback) callback(false, "Not supported");
|
|
559
573
|
}
|
|
574
|
+
virtual void rvGetScene(
|
|
575
|
+
const std::string& sceneId,
|
|
576
|
+
std::function<void(bool success, std::string jsonData, std::string error)> callback) {
|
|
577
|
+
if (callback) callback(false, "", "Not supported");
|
|
578
|
+
}
|
|
579
|
+
virtual void rvGetSceneAssets(
|
|
580
|
+
const std::string& sceneId,
|
|
581
|
+
std::function<void(bool success, std::string jsonData, std::string error)> callback) {
|
|
582
|
+
if (callback) callback(false, "", "Not supported");
|
|
583
|
+
}
|
|
584
|
+
virtual void rvGetProject(
|
|
585
|
+
const std::string& projectId,
|
|
586
|
+
std::function<void(bool success, std::string jsonData, std::string error)> callback) {
|
|
587
|
+
if (callback) callback(false, "", "Not supported");
|
|
588
|
+
}
|
|
560
589
|
|
|
561
590
|
// ========================================================================
|
|
562
591
|
// ReactVision Geospatial CRUD API
|
|
@@ -90,6 +90,8 @@ public:
|
|
|
90
90
|
std::unique_ptr<VROARFrame> &updateFrame();
|
|
91
91
|
std::unique_ptr<VROARFrame> &getLastFrame();
|
|
92
92
|
std::shared_ptr<VROTexture> getCameraBackgroundTexture();
|
|
93
|
+
std::shared_ptr<VROTexture> getSemanticTexture() override;
|
|
94
|
+
std::shared_ptr<VROTexture> getSemanticConfidenceTexture() override;
|
|
93
95
|
|
|
94
96
|
void setViewport(VROViewport viewport);
|
|
95
97
|
void setOrientation(VROCameraOrientation orientation);
|
|
@@ -195,6 +197,12 @@ public:
|
|
|
195
197
|
double confidence, int matchCount, int inlierCount, int processingTimeMs,
|
|
196
198
|
const std::string& platform, const std::string& externalUserId,
|
|
197
199
|
std::function<void(bool, std::string)> callback) override;
|
|
200
|
+
void rvGetProject(const std::string& projectId,
|
|
201
|
+
std::function<void(bool, std::string, std::string)> callback) override;
|
|
202
|
+
void rvGetScene(const std::string& sceneId,
|
|
203
|
+
std::function<void(bool, std::string, std::string)> callback) override;
|
|
204
|
+
void rvGetSceneAssets(const std::string& sceneId,
|
|
205
|
+
std::function<void(bool, std::string, std::string)> callback) override;
|
|
198
206
|
|
|
199
207
|
// Scene Semantics API
|
|
200
208
|
bool isSemanticModeSupported() const override;
|
|
@@ -326,6 +334,14 @@ private:
|
|
|
326
334
|
Video texture cache used for transferring camera content to OpenGL.
|
|
327
335
|
*/
|
|
328
336
|
std::shared_ptr<VROVideoTextureCacheOpenGL> _videoTextureCache;
|
|
337
|
+
|
|
338
|
+
/*
|
|
339
|
+
Fallback 1×1 all-white confidence texture (conf=1.0 everywhere).
|
|
340
|
+
Returned by getSemanticConfidenceTexture() because the ARCore iOS SDK does not
|
|
341
|
+
expose a per-pixel confidence image. The result is hard alpha edges (no soft blend)
|
|
342
|
+
on iOS, identical to the previous discard behaviour.
|
|
343
|
+
*/
|
|
344
|
+
std::shared_ptr<VROTexture> _defaultConfidenceTexture;
|
|
329
345
|
|
|
330
346
|
/*
|
|
331
347
|
Update the VROARAnchor with the transforms in the given ARAnchor.
|
|
@@ -37,6 +37,8 @@
|
|
|
37
37
|
#include "VROMaterial.h"
|
|
38
38
|
#include "VROModelIOUtil.h"
|
|
39
39
|
#include "VROByteBuffer.h"
|
|
40
|
+
#include "VROVector3f.h"
|
|
41
|
+
#include "VROQuaternion.h"
|
|
40
42
|
|
|
41
43
|
class VROMorpher;
|
|
42
44
|
class VRONode;
|
|
@@ -143,6 +145,7 @@ private:
|
|
|
143
145
|
std::map<int, std::shared_ptr<VROMorpher>> &morphers,
|
|
144
146
|
std::shared_ptr<VRODriver> driver);
|
|
145
147
|
static std::string getMorphTargetName(const tinygltf::Model &gModel,
|
|
148
|
+
const tinygltf::Mesh &gMesh,
|
|
146
149
|
const tinygltf::Primitive &gPrimtive, int targetIndex);
|
|
147
150
|
|
|
148
151
|
static void injectGLTF(std::shared_ptr<VRONode> gltfNode, std::shared_ptr<VRONode> rootNode,
|
|
@@ -213,6 +216,7 @@ private:
|
|
|
213
216
|
const tinygltf::Skin &skin,
|
|
214
217
|
std::vector<VROMatrix4f> &invBindTransformsOut);
|
|
215
218
|
static void clearCachedData();
|
|
219
|
+
static void injectBindPoseAnimations();
|
|
216
220
|
|
|
217
221
|
/*
|
|
218
222
|
As multiple mesh attributes may point to the same texture or data arrays when loading a
|
|
@@ -240,6 +244,24 @@ private:
|
|
|
240
244
|
static std::map<int, std::shared_ptr<VROGeometrySource>> _meshBoneIndices;
|
|
241
245
|
static std::map<int, std::shared_ptr<VROGeometrySource>> _meshBoneWeights;
|
|
242
246
|
|
|
247
|
+
/*
|
|
248
|
+
Maps each glTF node index to its parent node index. Needed to walk up the scene graph
|
|
249
|
+
for multi-skin models where a skin's root joint has non-joint ancestors (e.g. a visor
|
|
250
|
+
skin whose root is the Neck joint, whose ancestors Hips/Spine are only in the body skin).
|
|
251
|
+
Populated in processSkinner(), cleared in clearCachedData().
|
|
252
|
+
*/
|
|
253
|
+
static std::map<int, int> _nodeParentMap;
|
|
254
|
+
|
|
255
|
+
/*
|
|
256
|
+
Maps each skin index to the set of node indices that are ancestors of that skin's mesh
|
|
257
|
+
node (the glTF node that has gNode.skin == skinIndex). These ancestors are already applied
|
|
258
|
+
by Viro's renderer as the mesh node's modelMatrix, so the ancestor walk in
|
|
259
|
+
processSkeletalTransformsForFrame must stop before including them to avoid double-applying
|
|
260
|
+
transforms (e.g. Character's scale=0.01 being applied twice → model becomes invisible).
|
|
261
|
+
Populated in processSkinner(), cleared in clearCachedData().
|
|
262
|
+
*/
|
|
263
|
+
static std::map<int, std::set<int>> _skinMeshAncestors;
|
|
264
|
+
|
|
243
265
|
/*
|
|
244
266
|
Cached maps of nodeIndexes to it's corresponding animations. These caches are cleared
|
|
245
267
|
out after the parsing of a single gLTF model. Note that _nodeKeyFrameAnims is of the form:
|
|
@@ -248,6 +270,18 @@ private:
|
|
|
248
270
|
static std::map<int, std::map<int, std::vector<std::shared_ptr<VROKeyframeAnimation>>>> _nodeKeyFrameAnims;
|
|
249
271
|
static std::map<int, std::vector<std::shared_ptr<VROSkeletalAnimation>>> _skinSkeletalAnims;
|
|
250
272
|
|
|
273
|
+
/*
|
|
274
|
+
Per-node VRONode references and bind-pose TRS, populated during processNode for any node
|
|
275
|
+
that has keyframe animations. Used by injectBindPoseAnimations() to create single-frame
|
|
276
|
+
bind-pose reset animations for animation names a node doesn't participate in.
|
|
277
|
+
Without these, switching animations leaves non-driven nodes at the previous animation's
|
|
278
|
+
final pose, causing visible mesh disassembly.
|
|
279
|
+
*/
|
|
280
|
+
static std::map<int, std::shared_ptr<VRONode>> _nodeGLTFMap;
|
|
281
|
+
static std::map<int, VROVector3f> _nodeBindPos;
|
|
282
|
+
static std::map<int, VROVector3f> _nodeBindScale;
|
|
283
|
+
static std::map<int, VROQuaternion> _nodeBindRot;
|
|
284
|
+
|
|
251
285
|
/*
|
|
252
286
|
Returns the local transform of the node index retried from the gltf model.
|
|
253
287
|
*/
|