mujoco-react 10.2.0 → 10.3.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 +21 -0
- package/dist/{chunk-3BMNRSS2.js → chunk-6AZEFI6A.js} +199 -36
- package/dist/chunk-6AZEFI6A.js.map +1 -0
- package/dist/index.d.ts +4 -3
- package/dist/index.js +194 -42
- package/dist/index.js.map +1 -1
- package/dist/spark.d.ts +1 -1
- package/dist/spark.js +4 -10
- package/dist/spark.js.map +1 -1
- package/dist/{types-CLD5K3JD.d.ts → types-BOhNDICK.d.ts} +103 -1
- package/package.json +1 -1
- package/src/components/SceneRenderer.tsx +25 -6
- package/src/core/MujocoCanvas.tsx +8 -4
- package/src/core/MujocoPhysics.tsx +6 -4
- package/src/core/MujocoProvider.tsx +6 -4
- package/src/core/MujocoSimProvider.tsx +189 -9
- package/src/hooks/usePolicy.ts +4 -1
- package/src/hooks/useRemotePolicy.ts +2 -1
- package/src/rendering/GeomBuilder.ts +18 -2
- package/src/rendering/cameraFrameCapture.ts +268 -33
- package/src/spark.tsx +4 -12
- package/src/types.ts +108 -0
- package/dist/chunk-3BMNRSS2.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
import { withContacts, getContact, captureCameraFrame, captureCameraFrameBlob, createCameraFrameCaptureSession, CAMERA_FRAME_CAPTURE_PRE_RENDER_USER_DATA_KEY, CAPTURE_EXCLUDE_KEY } from './chunk-
|
|
2
|
-
export { CAMERA_FRAME_CAPTURE_PRE_RENDER_USER_DATA_KEY, CAMERA_FRAME_CAPTURE_RENDER_USER_DATA_KEY, CAPTURE_EXCLUDE_KEY, ModelActuators, ModelBodies, ModelCameras, ModelGeoms, ModelJoints, ModelKeyframes, ModelResources, ModelSensors, ModelSites, ScenarioLighting, SplatEnvironment, SplatEnvironmentReadinessStatus, VisualScenarioEffects, captureCameraFrame, captureCameraFrameBlob, createCameraFrameCaptureSession, createPairedSplatEnvironment, createSparkSplatViewerUrl, createSplatEnvironmentUserData, createSplatSceneConfig, createVisualScenarioExecutionContext, getContact, getScenarioBackground, getScenarioCameraPosition, getSplatEnvironmentReadiness, registerModelResources, renderCameraFrameToCanvas, useSplatEnvironment, useSplatSceneConfig, useVisualScenarioEffects, useVisualScenarioExecutionContext, withSplatEnvironment } from './chunk-
|
|
1
|
+
import { withContacts, getContact, captureCameraFrame, captureCameraFrameBlob, createCameraFrameCaptureSession, CAMERA_FRAME_CAPTURE_PRE_RENDER_USER_DATA_KEY, CAPTURE_EXCLUDE_KEY } from './chunk-6AZEFI6A.js';
|
|
2
|
+
export { CAMERA_FRAME_CAPTURE_PRE_RENDER_USER_DATA_KEY, CAMERA_FRAME_CAPTURE_RENDER_USER_DATA_KEY, CAPTURE_EXCLUDE_KEY, ModelActuators, ModelBodies, ModelCameras, ModelGeoms, ModelJoints, ModelKeyframes, ModelResources, ModelSensors, ModelSites, ScenarioLighting, SplatEnvironment, SplatEnvironmentReadinessStatus, VisualScenarioEffects, captureCameraFrame, captureCameraFrameBlob, createCameraFrameCaptureSession, createPairedSplatEnvironment, createSparkSplatViewerUrl, createSplatEnvironmentUserData, createSplatSceneConfig, createVisualScenarioExecutionContext, getContact, getScenarioBackground, getScenarioCameraPosition, getSplatEnvironmentReadiness, registerModelResources, renderCameraFrameToCanvas, useSplatEnvironment, useSplatSceneConfig, useVisualScenarioEffects, useVisualScenarioExecutionContext, withSplatEnvironment } from './chunk-6AZEFI6A.js';
|
|
3
3
|
import loadMujoco from '@mujoco/mujoco';
|
|
4
4
|
import defaultMujocoWasmUrl from '@mujoco/mujoco/mujoco.wasm?url';
|
|
5
|
-
import { createContext, forwardRef, useEffect, useContext, useState,
|
|
5
|
+
import { createContext, forwardRef, useRef, useEffect, useContext, useState, useCallback, useMemo, useLayoutEffect } from 'react';
|
|
6
6
|
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
7
7
|
import { Canvas, useThree, useFrame } from '@react-three/fiber';
|
|
8
8
|
import * as THREE11 from 'three';
|
|
9
|
+
import { mergeVertices } from 'three/examples/jsm/utils/BufferGeometryUtils.js';
|
|
9
10
|
import { PivotControls } from '@react-three/drei';
|
|
10
11
|
|
|
11
12
|
var MujocoContext = createContext({
|
|
@@ -43,6 +44,8 @@ function MujocoProvider({
|
|
|
43
44
|
const [error, setError] = useState(null);
|
|
44
45
|
const moduleRef = useRef(null);
|
|
45
46
|
const isMounted = useRef(true);
|
|
47
|
+
const onErrorRef = useRef(onError);
|
|
48
|
+
onErrorRef.current = onError;
|
|
46
49
|
useEffect(() => {
|
|
47
50
|
isMounted.current = true;
|
|
48
51
|
const variant = resolveWasmVariant(wasmVariant, threadedLoader, mtWasmUrl);
|
|
@@ -50,7 +53,7 @@ function MujocoProvider({
|
|
|
50
53
|
const err = new Error('MujocoProvider wasmVariant="threaded" requires a threadedLoader from @mujoco/mujoco/mt');
|
|
51
54
|
setError(err.message);
|
|
52
55
|
setStatus("error");
|
|
53
|
-
|
|
56
|
+
onErrorRef.current?.(err);
|
|
54
57
|
return;
|
|
55
58
|
}
|
|
56
59
|
let selectedWasmUrl = wasmUrl ?? defaultMujocoWasmUrl;
|
|
@@ -59,7 +62,7 @@ function MujocoProvider({
|
|
|
59
62
|
const err = new Error('MujocoProvider wasmVariant="threaded" requires mtWasmUrl from @mujoco/mujoco/mt/mujoco.wasm?url');
|
|
60
63
|
setError(err.message);
|
|
61
64
|
setStatus("error");
|
|
62
|
-
|
|
65
|
+
onErrorRef.current?.(err);
|
|
63
66
|
return;
|
|
64
67
|
}
|
|
65
68
|
selectedWasmUrl = mtWasmUrl;
|
|
@@ -90,13 +93,13 @@ function MujocoProvider({
|
|
|
90
93
|
const msg = err.message || "Failed to init spatial simulation";
|
|
91
94
|
setError(msg);
|
|
92
95
|
setStatus("error");
|
|
93
|
-
|
|
96
|
+
onErrorRef.current?.(new Error(msg));
|
|
94
97
|
}
|
|
95
98
|
});
|
|
96
99
|
return () => {
|
|
97
100
|
isMounted.current = false;
|
|
98
101
|
};
|
|
99
|
-
}, [wasmUrl, mtWasmUrl, threadedLoader, wasmVariant, timeout
|
|
102
|
+
}, [wasmUrl, mtWasmUrl, threadedLoader, wasmVariant, timeout]);
|
|
100
103
|
return /* @__PURE__ */ jsx(
|
|
101
104
|
MujocoContext.Provider,
|
|
102
105
|
{
|
|
@@ -891,11 +894,20 @@ function collectDependencyPaths(xmlString, currentFile, parser) {
|
|
|
891
894
|
}
|
|
892
895
|
|
|
893
896
|
// src/rendering/GeomBuilder.ts
|
|
897
|
+
var DEFAULT_MESH_NORMAL_SMOOTHING_TOLERANCE = 1e-4;
|
|
894
898
|
var GeomBuilder = class {
|
|
895
899
|
mujoco;
|
|
896
900
|
textureCache = /* @__PURE__ */ new Map();
|
|
897
|
-
|
|
901
|
+
renderOptions;
|
|
902
|
+
constructor(mujoco, renderOptions) {
|
|
898
903
|
this.mujoco = mujoco;
|
|
904
|
+
this.renderOptions = renderOptions;
|
|
905
|
+
}
|
|
906
|
+
getMeshNormalSmoothingTolerance() {
|
|
907
|
+
const smoothing = this.renderOptions?.meshNormalSmoothing;
|
|
908
|
+
if (!smoothing) return null;
|
|
909
|
+
if (smoothing === true) return DEFAULT_MESH_NORMAL_SMOOTHING_TOLERANCE;
|
|
910
|
+
return smoothing.tolerance ?? DEFAULT_MESH_NORMAL_SMOOTHING_TOLERANCE;
|
|
899
911
|
}
|
|
900
912
|
getMaterialTexture(mjModel, matId) {
|
|
901
913
|
if (matId < 0 || !mjModel.mat_texid || !mjModel.tex_data) return null;
|
|
@@ -990,6 +1002,10 @@ var GeomBuilder = class {
|
|
|
990
1002
|
geo = new THREE11.BufferGeometry();
|
|
991
1003
|
geo.setAttribute("position", new THREE11.Float32BufferAttribute(mjModel.mesh_vert.subarray(vAdr * 3, (vAdr + vNum) * 3), 3));
|
|
992
1004
|
geo.setIndex(Array.from(mjModel.mesh_face.subarray(fAdr * 3, (fAdr + fNum) * 3)));
|
|
1005
|
+
const smoothingTolerance = this.getMeshNormalSmoothingTolerance();
|
|
1006
|
+
if (smoothingTolerance !== null) {
|
|
1007
|
+
geo = mergeVertices(geo, smoothingTolerance);
|
|
1008
|
+
}
|
|
993
1009
|
geo.computeVertexNormals();
|
|
994
1010
|
}
|
|
995
1011
|
if (geo) {
|
|
@@ -1020,7 +1036,13 @@ var GeomBuilder = class {
|
|
|
1020
1036
|
return null;
|
|
1021
1037
|
}
|
|
1022
1038
|
};
|
|
1023
|
-
function
|
|
1039
|
+
function getRenderOptionsKey(renderOptions) {
|
|
1040
|
+
const smoothing = renderOptions?.meshNormalSmoothing;
|
|
1041
|
+
if (!smoothing) return "default";
|
|
1042
|
+
if (smoothing === true) return "meshNormalSmoothing:true";
|
|
1043
|
+
return `meshNormalSmoothing:${smoothing.tolerance ?? "default"}`;
|
|
1044
|
+
}
|
|
1045
|
+
function SceneRenderer({ renderOptions, ...props }) {
|
|
1024
1046
|
const {
|
|
1025
1047
|
mjModelRef,
|
|
1026
1048
|
mjDataRef,
|
|
@@ -1034,17 +1056,22 @@ function SceneRenderer(props) {
|
|
|
1034
1056
|
const groupRef = useRef(null);
|
|
1035
1057
|
const bodyRefs = useRef([]);
|
|
1036
1058
|
const prevModelRef = useRef(null);
|
|
1059
|
+
const prevRenderOptionsKeyRef = useRef(null);
|
|
1060
|
+
const renderOptionsKey = getRenderOptionsKey(renderOptions);
|
|
1037
1061
|
const geomBuilder = useMemo(() => {
|
|
1038
1062
|
if (status !== "ready") return null;
|
|
1039
|
-
return new GeomBuilder(mujocoRef.current);
|
|
1040
|
-
}, [status, mujocoRef]);
|
|
1063
|
+
return new GeomBuilder(mujocoRef.current, renderOptions);
|
|
1064
|
+
}, [status, mujocoRef, renderOptionsKey]);
|
|
1041
1065
|
useEffect(() => {
|
|
1042
1066
|
if (status !== "ready" || !geomBuilder) return;
|
|
1043
1067
|
const model = mjModelRef.current;
|
|
1044
1068
|
const group = groupRef.current;
|
|
1045
1069
|
if (!model || !group) return;
|
|
1046
|
-
if (prevModelRef.current === model)
|
|
1070
|
+
if (prevModelRef.current === model && prevRenderOptionsKeyRef.current === renderOptionsKey) {
|
|
1071
|
+
return;
|
|
1072
|
+
}
|
|
1047
1073
|
prevModelRef.current = model;
|
|
1074
|
+
prevRenderOptionsKeyRef.current = renderOptionsKey;
|
|
1048
1075
|
while (group.children.length > 0) {
|
|
1049
1076
|
group.remove(group.children[0]);
|
|
1050
1077
|
}
|
|
@@ -1065,7 +1092,7 @@ function SceneRenderer(props) {
|
|
|
1065
1092
|
refs.push(bodyGroup);
|
|
1066
1093
|
}
|
|
1067
1094
|
bodyRefs.current = refs;
|
|
1068
|
-
}, [status, geomBuilder, mjModelRef]);
|
|
1095
|
+
}, [status, geomBuilder, mjModelRef, renderOptionsKey]);
|
|
1069
1096
|
const syncBodiesToData = useCallback(() => {
|
|
1070
1097
|
const data = mjDataRef.current;
|
|
1071
1098
|
if (!data) return;
|
|
@@ -1930,6 +1957,106 @@ function applyMountedCameraPoseOffsets(options, position, quaternion) {
|
|
|
1930
1957
|
]
|
|
1931
1958
|
};
|
|
1932
1959
|
}
|
|
1960
|
+
function resolveMujocoCameraCompatibilityOptions(options) {
|
|
1961
|
+
const compatibility = options.mujocoCameraCompatibility;
|
|
1962
|
+
if (!compatibility) return null;
|
|
1963
|
+
if (compatibility === true) {
|
|
1964
|
+
return {
|
|
1965
|
+
useResolution: true,
|
|
1966
|
+
useIntrinsics: true,
|
|
1967
|
+
useClipping: true,
|
|
1968
|
+
preserveAspect: true,
|
|
1969
|
+
preferResolution: false
|
|
1970
|
+
};
|
|
1971
|
+
}
|
|
1972
|
+
return {
|
|
1973
|
+
useResolution: compatibility.useResolution ?? true,
|
|
1974
|
+
useIntrinsics: compatibility.useIntrinsics ?? true,
|
|
1975
|
+
useClipping: compatibility.useClipping ?? true,
|
|
1976
|
+
preserveAspect: compatibility.preserveAspect ?? true,
|
|
1977
|
+
preferResolution: compatibility.preferResolution ?? false
|
|
1978
|
+
};
|
|
1979
|
+
}
|
|
1980
|
+
function mujocoVisualClip(model) {
|
|
1981
|
+
const map = model.vis?.map;
|
|
1982
|
+
const near = typeof map?.znear === "number" && map.znear > 0 ? map.znear : void 0;
|
|
1983
|
+
const far = typeof map?.zfar === "number" && map.zfar > 0 ? map.zfar : void 0;
|
|
1984
|
+
return { near, far };
|
|
1985
|
+
}
|
|
1986
|
+
function mujocoCameraResolution(model, cameraId) {
|
|
1987
|
+
const resolution = model.cam_resolution;
|
|
1988
|
+
if (!resolution) return {};
|
|
1989
|
+
const width = Number(resolution[cameraId * 2]);
|
|
1990
|
+
const height = Number(resolution[cameraId * 2 + 1]);
|
|
1991
|
+
return {
|
|
1992
|
+
width: Number.isFinite(width) && width > 0 ? width : void 0,
|
|
1993
|
+
height: Number.isFinite(height) && height > 0 ? height : void 0
|
|
1994
|
+
};
|
|
1995
|
+
}
|
|
1996
|
+
function mujocoCameraProjectionMatrix(model, cameraId, width, height, near, far) {
|
|
1997
|
+
const intrinsic = model.cam_intrinsic;
|
|
1998
|
+
const sensorSize = model.cam_sensorsize;
|
|
1999
|
+
if (!intrinsic || !sensorSize || !width || !height) return void 0;
|
|
2000
|
+
const intrinsicOffset = cameraId * 4;
|
|
2001
|
+
const sensorOffset = cameraId * 2;
|
|
2002
|
+
const focalX = Number(intrinsic[intrinsicOffset]);
|
|
2003
|
+
const focalY = Number(intrinsic[intrinsicOffset + 1]);
|
|
2004
|
+
const principalX = Number(intrinsic[intrinsicOffset + 2]);
|
|
2005
|
+
const principalY = Number(intrinsic[intrinsicOffset + 3]);
|
|
2006
|
+
const sensorWidth = Number(sensorSize[sensorOffset]);
|
|
2007
|
+
const sensorHeight = Number(sensorSize[sensorOffset + 1]);
|
|
2008
|
+
if (!Number.isFinite(focalX) || !Number.isFinite(focalY) || !Number.isFinite(principalX) || !Number.isFinite(principalY) || !Number.isFinite(sensorWidth) || !Number.isFinite(sensorHeight) || focalX <= 0 || focalY <= 0 || sensorWidth <= 0 || sensorHeight <= 0) {
|
|
2009
|
+
return void 0;
|
|
2010
|
+
}
|
|
2011
|
+
const fx = focalX / sensorWidth * width;
|
|
2012
|
+
const fy = focalY / sensorHeight * height;
|
|
2013
|
+
const cx = width * (0.5 + principalX / sensorWidth);
|
|
2014
|
+
const cy = height * (0.5 + principalY / sensorHeight);
|
|
2015
|
+
const znear = near ?? 0.01;
|
|
2016
|
+
const zfar = far ?? 100;
|
|
2017
|
+
return new THREE11.Matrix4().set(
|
|
2018
|
+
2 * fx / width,
|
|
2019
|
+
0,
|
|
2020
|
+
1 - 2 * cx / width,
|
|
2021
|
+
0,
|
|
2022
|
+
0,
|
|
2023
|
+
2 * fy / height,
|
|
2024
|
+
2 * cy / height - 1,
|
|
2025
|
+
0,
|
|
2026
|
+
0,
|
|
2027
|
+
0,
|
|
2028
|
+
-(zfar + znear) / (zfar - znear),
|
|
2029
|
+
-2 * zfar * znear / (zfar - znear),
|
|
2030
|
+
0,
|
|
2031
|
+
0,
|
|
2032
|
+
-1,
|
|
2033
|
+
0
|
|
2034
|
+
);
|
|
2035
|
+
}
|
|
2036
|
+
function resolveMujocoCameraCaptureDimensions(requested, cameraResolution, compatibility) {
|
|
2037
|
+
if (!compatibility.useResolution) {
|
|
2038
|
+
return {
|
|
2039
|
+
width: requested.width,
|
|
2040
|
+
height: requested.height
|
|
2041
|
+
};
|
|
2042
|
+
}
|
|
2043
|
+
if (compatibility.preferResolution) {
|
|
2044
|
+
return {
|
|
2045
|
+
width: cameraResolution.width ?? requested.width,
|
|
2046
|
+
height: cameraResolution.height ?? requested.height
|
|
2047
|
+
};
|
|
2048
|
+
}
|
|
2049
|
+
let width = requested.width ?? cameraResolution.width;
|
|
2050
|
+
let height = requested.height ?? cameraResolution.height;
|
|
2051
|
+
if (compatibility.preserveAspect && cameraResolution.width && cameraResolution.height) {
|
|
2052
|
+
if (requested.width !== void 0 && requested.height === void 0) {
|
|
2053
|
+
height = requested.width * cameraResolution.height / cameraResolution.width;
|
|
2054
|
+
} else if (requested.height !== void 0 && requested.width === void 0) {
|
|
2055
|
+
width = requested.height * cameraResolution.width / cameraResolution.height;
|
|
2056
|
+
}
|
|
2057
|
+
}
|
|
2058
|
+
return { width, height };
|
|
2059
|
+
}
|
|
1933
2060
|
function countMountedCameraSelectors(options) {
|
|
1934
2061
|
return Number(Boolean(options.cameraName)) + Number(Boolean(options.siteName)) + Number(Boolean(options.bodyName));
|
|
1935
2062
|
}
|
|
@@ -2033,6 +2160,7 @@ function MujocoSimProvider({
|
|
|
2033
2160
|
paused,
|
|
2034
2161
|
speed,
|
|
2035
2162
|
interpolate,
|
|
2163
|
+
renderOptions,
|
|
2036
2164
|
children
|
|
2037
2165
|
}) {
|
|
2038
2166
|
const { gl, camera, scene } = useThree();
|
|
@@ -2067,24 +2195,12 @@ function MujocoSimProvider({
|
|
|
2067
2195
|
const bodyRegistryRef = useRef(/* @__PURE__ */ new Map());
|
|
2068
2196
|
const hiddenBodiesRef = useRef(/* @__PURE__ */ new Set());
|
|
2069
2197
|
const bodyReloadTimerRef = useRef(null);
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
|
|
2073
|
-
|
|
2074
|
-
|
|
2075
|
-
|
|
2076
|
-
useEffect(() => {
|
|
2077
|
-
pausedRef.current = paused ?? false;
|
|
2078
|
-
}, [paused]);
|
|
2079
|
-
useEffect(() => {
|
|
2080
|
-
speedRef.current = speed ?? 1;
|
|
2081
|
-
}, [speed]);
|
|
2082
|
-
useEffect(() => {
|
|
2083
|
-
substepsRef.current = substeps ?? 1;
|
|
2084
|
-
}, [substeps]);
|
|
2085
|
-
useEffect(() => {
|
|
2086
|
-
interpolateRef.current = interpolate ?? false;
|
|
2087
|
-
}, [interpolate]);
|
|
2198
|
+
configRef.current = config;
|
|
2199
|
+
mujocoRef.current = mujoco;
|
|
2200
|
+
pausedRef.current = paused ?? false;
|
|
2201
|
+
speedRef.current = speed ?? 1;
|
|
2202
|
+
substepsRef.current = substeps ?? 1;
|
|
2203
|
+
interpolateRef.current = interpolate ?? false;
|
|
2088
2204
|
useEffect(() => {
|
|
2089
2205
|
if (!gravity) return;
|
|
2090
2206
|
const model = mjModelRef.current;
|
|
@@ -2590,11 +2706,27 @@ function MujocoSimProvider({
|
|
|
2590
2706
|
for (let i = 0; i < ncam; i += 1) {
|
|
2591
2707
|
const posOffset = i * 3;
|
|
2592
2708
|
const quatOffset = i * 4;
|
|
2709
|
+
const intrinsicOffset = i * 4;
|
|
2710
|
+
const resolutionOffset = i * 2;
|
|
2593
2711
|
result.push({
|
|
2594
2712
|
id: i,
|
|
2595
2713
|
name: getName(model, nameAddresses[i]),
|
|
2596
2714
|
bodyId: model.cam_bodyid?.[i] ?? -1,
|
|
2597
2715
|
fov: model.cam_fovy?.[i] ?? null,
|
|
2716
|
+
resolution: model.cam_resolution ? [
|
|
2717
|
+
model.cam_resolution[resolutionOffset],
|
|
2718
|
+
model.cam_resolution[resolutionOffset + 1]
|
|
2719
|
+
] : null,
|
|
2720
|
+
sensorSize: model.cam_sensorsize ? [
|
|
2721
|
+
model.cam_sensorsize[resolutionOffset],
|
|
2722
|
+
model.cam_sensorsize[resolutionOffset + 1]
|
|
2723
|
+
] : null,
|
|
2724
|
+
intrinsic: model.cam_intrinsic ? [
|
|
2725
|
+
model.cam_intrinsic[intrinsicOffset],
|
|
2726
|
+
model.cam_intrinsic[intrinsicOffset + 1],
|
|
2727
|
+
model.cam_intrinsic[intrinsicOffset + 2],
|
|
2728
|
+
model.cam_intrinsic[intrinsicOffset + 3]
|
|
2729
|
+
] : null,
|
|
2598
2730
|
position: model.cam_pos ? vector3FromArray(model.cam_pos, posOffset) : null,
|
|
2599
2731
|
quaternion: model.cam_quat ? quaternionFromMujocoQuat(model.cam_quat, quatOffset) : null
|
|
2600
2732
|
});
|
|
@@ -2622,10 +2754,22 @@ function MujocoSimProvider({
|
|
|
2622
2754
|
);
|
|
2623
2755
|
}
|
|
2624
2756
|
const pose = applyMountedCameraPoseOffsets(options, position, quaternion);
|
|
2757
|
+
const compatibility = resolveMujocoCameraCompatibilityOptions(options);
|
|
2758
|
+
const cameraResolution = compatibility?.useResolution ? mujocoCameraResolution(model, cameraId) : { width: void 0, height: void 0 };
|
|
2759
|
+
const clip = compatibility?.useClipping ? mujocoVisualClip(model) : { near: void 0, far: void 0 };
|
|
2760
|
+
const { width, height } = compatibility ? resolveMujocoCameraCaptureDimensions(options, cameraResolution, compatibility) : { width: options.width, height: options.height };
|
|
2761
|
+
const near = options.near ?? clip.near;
|
|
2762
|
+
const far = options.far ?? clip.far;
|
|
2763
|
+
const projectionMatrix = compatibility?.useIntrinsics ? mujocoCameraProjectionMatrix(model, cameraId, width, height, near, far) : void 0;
|
|
2625
2764
|
return {
|
|
2626
2765
|
...baseOptions,
|
|
2766
|
+
width,
|
|
2767
|
+
height,
|
|
2627
2768
|
...pose,
|
|
2628
2769
|
fov: options.fov ?? model.cam_fovy?.[cameraId],
|
|
2770
|
+
near,
|
|
2771
|
+
far,
|
|
2772
|
+
projectionMatrix: options.projectionMatrix ?? projectionMatrix,
|
|
2629
2773
|
source: { kind: "mujoco-camera", cameraName: options.cameraName }
|
|
2630
2774
|
};
|
|
2631
2775
|
}
|
|
@@ -3271,7 +3415,7 @@ function MujocoSimProvider({
|
|
|
3271
3415
|
[api, status, requestBodyReload]
|
|
3272
3416
|
);
|
|
3273
3417
|
return /* @__PURE__ */ jsxs(MujocoSimContext.Provider, { value: contextValue, children: [
|
|
3274
|
-
/* @__PURE__ */ jsx(SceneRenderer, {}),
|
|
3418
|
+
/* @__PURE__ */ jsx(SceneRenderer, { renderOptions }),
|
|
3275
3419
|
children
|
|
3276
3420
|
] });
|
|
3277
3421
|
}
|
|
@@ -3289,16 +3433,19 @@ var MujocoCanvas = forwardRef(
|
|
|
3289
3433
|
paused,
|
|
3290
3434
|
speed,
|
|
3291
3435
|
interpolate,
|
|
3436
|
+
renderOptions,
|
|
3292
3437
|
loadingFallback,
|
|
3293
3438
|
children,
|
|
3294
3439
|
...canvasProps
|
|
3295
3440
|
}, ref) {
|
|
3296
3441
|
const { mujoco, status: wasmStatus, error: wasmError } = useMujocoWasm();
|
|
3442
|
+
const onErrorRef = useRef(onError);
|
|
3443
|
+
onErrorRef.current = onError;
|
|
3297
3444
|
useEffect(() => {
|
|
3298
|
-
if (wasmStatus === "error"
|
|
3299
|
-
|
|
3445
|
+
if (wasmStatus === "error") {
|
|
3446
|
+
onErrorRef.current?.(new Error(wasmError ?? "WASM load failed"));
|
|
3300
3447
|
}
|
|
3301
|
-
}, [wasmStatus, wasmError
|
|
3448
|
+
}, [wasmStatus, wasmError]);
|
|
3302
3449
|
if (wasmStatus === "loading" || !mujoco) {
|
|
3303
3450
|
return loadingFallback ? /* @__PURE__ */ jsx(Canvas, { ...canvasProps, children: loadingFallback }) : null;
|
|
3304
3451
|
}
|
|
@@ -3321,6 +3468,7 @@ var MujocoCanvas = forwardRef(
|
|
|
3321
3468
|
paused,
|
|
3322
3469
|
speed,
|
|
3323
3470
|
interpolate,
|
|
3471
|
+
renderOptions,
|
|
3324
3472
|
children
|
|
3325
3473
|
}
|
|
3326
3474
|
) });
|
|
@@ -3329,11 +3477,13 @@ var MujocoCanvas = forwardRef(
|
|
|
3329
3477
|
var MujocoPhysics = forwardRef(
|
|
3330
3478
|
function MujocoPhysics2({ onError, children, ...props }, ref) {
|
|
3331
3479
|
const { mujoco, status: wasmStatus, error: wasmError } = useMujocoWasm();
|
|
3480
|
+
const onErrorRef = useRef(onError);
|
|
3481
|
+
onErrorRef.current = onError;
|
|
3332
3482
|
useEffect(() => {
|
|
3333
|
-
if (wasmStatus === "error"
|
|
3334
|
-
|
|
3483
|
+
if (wasmStatus === "error") {
|
|
3484
|
+
onErrorRef.current?.(new Error(wasmError ?? "WASM load failed"));
|
|
3335
3485
|
}
|
|
3336
|
-
}, [wasmStatus, wasmError
|
|
3486
|
+
}, [wasmStatus, wasmError]);
|
|
3337
3487
|
if (wasmStatus === "error" || wasmStatus === "loading" || !mujoco) {
|
|
3338
3488
|
return null;
|
|
3339
3489
|
}
|
|
@@ -6561,7 +6711,8 @@ function usePolicy(config) {
|
|
|
6561
6711
|
const shouldInfer = !inFlightRef.current && (!queuedAction || actionQueueRef.current.length <= prefetchThreshold);
|
|
6562
6712
|
if (!shouldInfer) return;
|
|
6563
6713
|
const observation = cfg.onObservation({ model, data });
|
|
6564
|
-
const
|
|
6714
|
+
const queuedActions = actionQueueRef.current.length;
|
|
6715
|
+
const result = cfg.infer ? cfg.infer({ observation, model, data, queuedActions }) : observation;
|
|
6565
6716
|
if (isPromiseLike(result)) {
|
|
6566
6717
|
const epoch = epochRef.current;
|
|
6567
6718
|
inFlightRef.current = true;
|
|
@@ -6592,11 +6743,11 @@ function usePolicy(config) {
|
|
|
6592
6743
|
cfg.queueStrategy ?? "append"
|
|
6593
6744
|
);
|
|
6594
6745
|
} else {
|
|
6595
|
-
const [action, ...
|
|
6746
|
+
const [action, ...queuedActions2] = actions;
|
|
6596
6747
|
if (!action) return;
|
|
6597
6748
|
enqueuePolicyActions(
|
|
6598
6749
|
actionQueueRef.current,
|
|
6599
|
-
|
|
6750
|
+
queuedActions2,
|
|
6600
6751
|
observation,
|
|
6601
6752
|
cfg.queueStrategy ?? "append"
|
|
6602
6753
|
);
|
|
@@ -6739,7 +6890,7 @@ function useRemotePolicy(config) {
|
|
|
6739
6890
|
const remoteEpochRef = useRef(0);
|
|
6740
6891
|
const policy = usePolicy({
|
|
6741
6892
|
...config,
|
|
6742
|
-
infer: async ({ observation, model, data }) => {
|
|
6893
|
+
infer: async ({ observation, model, data, queuedActions }) => {
|
|
6743
6894
|
const cfg = configRef.current;
|
|
6744
6895
|
abortController(abortControllerRef.current, createAbortError("Remote policy request was superseded."));
|
|
6745
6896
|
const controller = new AbortController();
|
|
@@ -6751,6 +6902,7 @@ function useRemotePolicy(config) {
|
|
|
6751
6902
|
observation,
|
|
6752
6903
|
model,
|
|
6753
6904
|
data,
|
|
6905
|
+
queuedActions,
|
|
6754
6906
|
reset: requestIndex === 0,
|
|
6755
6907
|
requestIndex,
|
|
6756
6908
|
signal
|