Add CloudXR VR streaming support for PICO 4 Ultra (Early Access)
Replaces manual H264/TCP stereo streaming with NVIDIA CloudXR for
higher-quality stereoscopic rendering and lower latency.
Changes:
- teleop_xr_agent.py: add --cloudxr flag (enables Isaac Sim XR mode,
disables manual StreamingManager)
- deps/cloudxr/: NVIDIA CloudXR.js SDK (Early Access) with Isaac Lab
teleop React web client
- deps/cloudxr/Dockerfile.wss.proxy: HAProxy WSS proxy for PICO 4 Ultra
HTTPS mode (routes wss://48322 → ws://49100)
- deps/cloudxr/isaac/webpack.dev.js: disable file watching to avoid
EMFILE errors with large node_modules
- deps/cloudxr/INSTALL.md: full setup guide
Usage:
# Start CloudXR Runtime + Isaac Lab
cd ~/IsaacLab && ./docker/container.py start \
--files docker-compose.cloudxr-runtime.patch.yaml \
--env-file .env.cloudxr-runtime
# Run teleop with CloudXR
~/IsaacLab/isaaclab.sh -p teleop_xr_agent.py \
--task Isaac-MindRobot-2i-DualArm-IK-Abs-v0 --cloudxr
# Serve web client
cd deps/cloudxr/isaac && npm run dev-server:https
This commit is contained in:
168
deps/cloudxr/react/webpack.common.js
vendored
Normal file
168
deps/cloudxr/react/webpack.common.js
vendored
Normal file
@@ -0,0 +1,168 @@
|
||||
const path = require('path');
|
||||
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
||||
const CopyWebpackPlugin = require('copy-webpack-plugin');
|
||||
const webpack = require('webpack');
|
||||
const DownloadAssetsPlugin = require('./webpack-plugins/DownloadAssetsPlugin');
|
||||
|
||||
const WEBXR_ASSETS_VERSION = '1.0.19';
|
||||
|
||||
module.exports = {
|
||||
entry: './src/index.tsx',
|
||||
|
||||
// Module rules define how different file types are processed
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.tsx?$/,
|
||||
use: {
|
||||
loader: 'ts-loader',
|
||||
options: {
|
||||
// Only transpile, don't type-check (faster builds)
|
||||
transpileOnly: true,
|
||||
},
|
||||
},
|
||||
exclude: /node_modules/,
|
||||
},
|
||||
{
|
||||
test: /\.css$/,
|
||||
use: ['style-loader', 'css-loader'],
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
// Resolve configuration for module resolution
|
||||
resolve: {
|
||||
extensions: ['.tsx', '.ts', '.js'],
|
||||
alias: {
|
||||
// @helpers can be used instead of relative paths to the helpers directory
|
||||
'@helpers': path.resolve(__dirname, '../helpers')
|
||||
}
|
||||
},
|
||||
|
||||
// Output configuration for bundled files
|
||||
output: {
|
||||
filename: 'bundle.js',
|
||||
path: path.resolve(__dirname, './build'),
|
||||
},
|
||||
|
||||
// Webpack plugins that extend webpack's functionality
|
||||
plugins: [
|
||||
// Generates HTML file and automatically injects bundled JavaScript
|
||||
new HtmlWebpackPlugin({
|
||||
template: './src/index.html',
|
||||
favicon: './favicon.ico'
|
||||
}),
|
||||
|
||||
// Inject environment variables
|
||||
new webpack.DefinePlugin({
|
||||
'process.env.WEBXR_ASSETS_VERSION': JSON.stringify(WEBXR_ASSETS_VERSION),
|
||||
}),
|
||||
|
||||
// Download external assets during build
|
||||
new DownloadAssetsPlugin([
|
||||
// HDRI environment map
|
||||
{
|
||||
url: 'https://dl.polyhaven.org/file/ph-assets/HDRIs/hdr/1k/potsdamer_platz_1k.hdr',
|
||||
output: path.resolve(__dirname, 'public/assets/hdri')
|
||||
},
|
||||
// WebXR controller profiles
|
||||
{
|
||||
url: `https://cdn.jsdelivr.net/npm/@webxr-input-profiles/assets@${WEBXR_ASSETS_VERSION}/dist/profiles/profilesList.json`,
|
||||
output: path.resolve(__dirname, `public/npm/@webxr-input-profiles/assets@${WEBXR_ASSETS_VERSION}/dist/profiles`)
|
||||
},
|
||||
// Generic hand profile
|
||||
{
|
||||
url: `https://cdn.jsdelivr.net/npm/@webxr-input-profiles/assets@${WEBXR_ASSETS_VERSION}/dist/profiles/generic-hand/profile.json`,
|
||||
output: path.resolve(__dirname, `public/npm/@webxr-input-profiles/assets@${WEBXR_ASSETS_VERSION}/dist/profiles/generic-hand`)
|
||||
},
|
||||
{
|
||||
url: `https://cdn.jsdelivr.net/npm/@webxr-input-profiles/assets@${WEBXR_ASSETS_VERSION}/dist/profiles/generic-hand/left.glb`,
|
||||
output: path.resolve(__dirname, `public/npm/@webxr-input-profiles/assets@${WEBXR_ASSETS_VERSION}/dist/profiles/generic-hand`)
|
||||
},
|
||||
{
|
||||
url: `https://cdn.jsdelivr.net/npm/@webxr-input-profiles/assets@${WEBXR_ASSETS_VERSION}/dist/profiles/generic-hand/right.glb`,
|
||||
output: path.resolve(__dirname, `public/npm/@webxr-input-profiles/assets@${WEBXR_ASSETS_VERSION}/dist/profiles/generic-hand`)
|
||||
},
|
||||
// Generic trigger profile
|
||||
{
|
||||
url: `https://cdn.jsdelivr.net/npm/@webxr-input-profiles/assets@${WEBXR_ASSETS_VERSION}/dist/profiles/generic-trigger/profile.json`,
|
||||
output: path.resolve(__dirname, `public/npm/@webxr-input-profiles/assets@${WEBXR_ASSETS_VERSION}/dist/profiles/generic-trigger`)
|
||||
},
|
||||
{
|
||||
url: `https://cdn.jsdelivr.net/npm/@webxr-input-profiles/assets@${WEBXR_ASSETS_VERSION}/dist/profiles/generic-trigger/left.glb`,
|
||||
output: path.resolve(__dirname, `public/npm/@webxr-input-profiles/assets@${WEBXR_ASSETS_VERSION}/dist/profiles/generic-trigger`)
|
||||
},
|
||||
{
|
||||
url: `https://cdn.jsdelivr.net/npm/@webxr-input-profiles/assets@${WEBXR_ASSETS_VERSION}/dist/profiles/generic-trigger/right.glb`,
|
||||
output: path.resolve(__dirname, `public/npm/@webxr-input-profiles/assets@${WEBXR_ASSETS_VERSION}/dist/profiles/generic-trigger`)
|
||||
},
|
||||
// Oculus Touch v2
|
||||
{
|
||||
url: `https://cdn.jsdelivr.net/npm/@webxr-input-profiles/assets@${WEBXR_ASSETS_VERSION}/dist/profiles/oculus-touch-v2/profile.json`,
|
||||
output: path.resolve(__dirname, `public/npm/@webxr-input-profiles/assets@${WEBXR_ASSETS_VERSION}/dist/profiles/oculus-touch-v2`)
|
||||
},
|
||||
{
|
||||
url: `https://cdn.jsdelivr.net/npm/@webxr-input-profiles/assets@${WEBXR_ASSETS_VERSION}/dist/profiles/oculus-touch-v2/left.glb`,
|
||||
output: path.resolve(__dirname, `public/npm/@webxr-input-profiles/assets@${WEBXR_ASSETS_VERSION}/dist/profiles/oculus-touch-v2`)
|
||||
},
|
||||
{
|
||||
url: `https://cdn.jsdelivr.net/npm/@webxr-input-profiles/assets@${WEBXR_ASSETS_VERSION}/dist/profiles/oculus-touch-v2/right.glb`,
|
||||
output: path.resolve(__dirname, `public/npm/@webxr-input-profiles/assets@${WEBXR_ASSETS_VERSION}/dist/profiles/oculus-touch-v2`)
|
||||
},
|
||||
// Oculus Touch v3
|
||||
{
|
||||
url: `https://cdn.jsdelivr.net/npm/@webxr-input-profiles/assets@${WEBXR_ASSETS_VERSION}/dist/profiles/oculus-touch-v3/profile.json`,
|
||||
output: path.resolve(__dirname, `public/npm/@webxr-input-profiles/assets@${WEBXR_ASSETS_VERSION}/dist/profiles/oculus-touch-v3`)
|
||||
},
|
||||
{
|
||||
url: `https://cdn.jsdelivr.net/npm/@webxr-input-profiles/assets@${WEBXR_ASSETS_VERSION}/dist/profiles/oculus-touch-v3/left.glb`,
|
||||
output: path.resolve(__dirname, `public/npm/@webxr-input-profiles/assets@${WEBXR_ASSETS_VERSION}/dist/profiles/oculus-touch-v3`)
|
||||
},
|
||||
{
|
||||
url: `https://cdn.jsdelivr.net/npm/@webxr-input-profiles/assets@${WEBXR_ASSETS_VERSION}/dist/profiles/oculus-touch-v3/right.glb`,
|
||||
output: path.resolve(__dirname, `public/npm/@webxr-input-profiles/assets@${WEBXR_ASSETS_VERSION}/dist/profiles/oculus-touch-v3`)
|
||||
},
|
||||
// Meta Quest Touch Plus
|
||||
{
|
||||
url: `https://cdn.jsdelivr.net/npm/@webxr-input-profiles/assets@${WEBXR_ASSETS_VERSION}/dist/profiles/meta-quest-touch-plus/profile.json`,
|
||||
output: path.resolve(__dirname, `public/npm/@webxr-input-profiles/assets@${WEBXR_ASSETS_VERSION}/dist/profiles/meta-quest-touch-plus`)
|
||||
},
|
||||
{
|
||||
url: `https://cdn.jsdelivr.net/npm/@webxr-input-profiles/assets@${WEBXR_ASSETS_VERSION}/dist/profiles/meta-quest-touch-plus/left.glb`,
|
||||
output: path.resolve(__dirname, `public/npm/@webxr-input-profiles/assets@${WEBXR_ASSETS_VERSION}/dist/profiles/meta-quest-touch-plus`)
|
||||
},
|
||||
{
|
||||
url: `https://cdn.jsdelivr.net/npm/@webxr-input-profiles/assets@${WEBXR_ASSETS_VERSION}/dist/profiles/meta-quest-touch-plus/right.glb`,
|
||||
output: path.resolve(__dirname, `public/npm/@webxr-input-profiles/assets@${WEBXR_ASSETS_VERSION}/dist/profiles/meta-quest-touch-plus`)
|
||||
},
|
||||
// Pico 4 Ultra
|
||||
{
|
||||
url: `https://cdn.jsdelivr.net/npm/@webxr-input-profiles/assets@${WEBXR_ASSETS_VERSION}/dist/profiles/pico-4u/profile.json`,
|
||||
output: path.resolve(__dirname, `public/npm/@webxr-input-profiles/assets@${WEBXR_ASSETS_VERSION}/dist/profiles/pico-4u`)
|
||||
},
|
||||
{
|
||||
url: `https://cdn.jsdelivr.net/npm/@webxr-input-profiles/assets@${WEBXR_ASSETS_VERSION}/dist/profiles/pico-4u/left.glb`,
|
||||
output: path.resolve(__dirname, `public/npm/@webxr-input-profiles/assets@${WEBXR_ASSETS_VERSION}/dist/profiles/pico-4u`)
|
||||
},
|
||||
{
|
||||
url: `https://cdn.jsdelivr.net/npm/@webxr-input-profiles/assets@${WEBXR_ASSETS_VERSION}/dist/profiles/pico-4u/right.glb`,
|
||||
output: path.resolve(__dirname, `public/npm/@webxr-input-profiles/assets@${WEBXR_ASSETS_VERSION}/dist/profiles/pico-4u`)
|
||||
},
|
||||
]),
|
||||
|
||||
// Copies static assets from public directory to build output
|
||||
new CopyWebpackPlugin({
|
||||
patterns: [
|
||||
{
|
||||
from: 'public',
|
||||
to: '.',
|
||||
globOptions: {
|
||||
// Don't copy index.html since HtmlWebpackPlugin handles it
|
||||
ignore: ['**/index.html'],
|
||||
},
|
||||
},
|
||||
{ from: './favicon.ico', to: 'favicon.ico' },
|
||||
],
|
||||
}),
|
||||
],
|
||||
};
|
||||
Reference in New Issue
Block a user