mujoco-react 10.7.0 → 10.9.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/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
- import { withContacts, getContact, captureCameraFrame, captureCameraFrameBlob, createCameraFrameCaptureSession, CAMERA_FRAME_CAPTURE_PRE_RENDER_USER_DATA_KEY, CAPTURE_EXCLUDE_KEY, createCaptureCamera, prepareCaptureCamera } from './chunk-EN55TTGH.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, captureCameraFrameTensor, createCameraFrameCaptureSession, createPairedSplatEnvironment, createSparkSplatViewerUrl, createSplatEnvironmentUserData, createSplatSceneConfig, createVisualScenarioExecutionContext, dataUrlToPolicyImageTensor, getContact, getScenarioBackground, getScenarioCameraPosition, getSplatEnvironmentReadiness, imageDataToPolicyImageTensor, pixelsToPolicyImageTensor, registerModelResources, renderCameraFrameToCanvas, useSplatEnvironment, useSplatSceneConfig, useVisualScenarioEffects, useVisualScenarioExecutionContext, withSplatEnvironment } from './chunk-EN55TTGH.js';
1
+ import { withContacts, getContact, captureCameraFrame, captureCameraFrameBlob, createCameraFrameCaptureSession, CAMERA_FRAME_CAPTURE_PRE_RENDER_USER_DATA_KEY, CAPTURE_EXCLUDE_KEY, createCaptureCamera, prepareCaptureCamera } from './chunk-5WFYM73E.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, captureCameraFrameTensor, createCameraFrameCaptureSession, createPairedSplatEnvironment, createSparkSplatViewerUrl, createSplatEnvironmentUserData, createSplatSceneConfig, createVisualScenarioExecutionContext, dataUrlToPolicyImageTensor, getContact, getScenarioBackground, getScenarioCameraPosition, getSplatEnvironmentReadiness, imageDataToPolicyImageTensor, pixelsToPolicyImageTensor, registerModelResources, renderCameraFrameToCanvas, useSplatEnvironment, useSplatSceneConfig, useVisualScenarioEffects, useVisualScenarioExecutionContext, withSplatEnvironment } from './chunk-5WFYM73E.js';
3
3
  import loadMujoco from '@mujoco/mujoco';
4
4
  import defaultMujocoWasmUrl from '@mujoco/mujoco/mujoco.wasm?url';
5
5
  import { createContext, forwardRef, useRef, useEffect, useContext, useState, useCallback, useMemo, useLayoutEffect, useId } from 'react';
@@ -1001,14 +1001,34 @@ var GeomBuilder = class {
1001
1001
  const vNum = mjModel.mesh_vertnum[mId];
1002
1002
  const fAdr = mjModel.mesh_faceadr[mId];
1003
1003
  const fNum = mjModel.mesh_facenum[mId];
1004
- geo = new THREE11.BufferGeometry();
1005
- geo.setAttribute("position", new THREE11.Float32BufferAttribute(mjModel.mesh_vert.subarray(vAdr * 3, (vAdr + vNum) * 3), 3));
1006
- geo.setIndex(Array.from(mjModel.mesh_face.subarray(fAdr * 3, (fAdr + fNum) * 3)));
1007
- const smoothingTolerance = this.getMeshNormalSmoothingTolerance();
1008
- if (smoothingTolerance !== null) {
1009
- geo = mergeVertices(geo, smoothingTolerance);
1004
+ const tAdr = mjModel.mesh_texcoordadr?.[mId] ?? -1;
1005
+ if (map && tAdr >= 0 && mjModel.mesh_texcoord && mjModel.mesh_facetexcoord) {
1006
+ const corners = fNum * 3;
1007
+ const positions = new Float32Array(corners * 3);
1008
+ const uvs = new Float32Array(corners * 2);
1009
+ for (let c = 0; c < corners; c++) {
1010
+ const v = vAdr + mjModel.mesh_face[fAdr * 3 + c];
1011
+ positions[c * 3] = mjModel.mesh_vert[v * 3];
1012
+ positions[c * 3 + 1] = mjModel.mesh_vert[v * 3 + 1];
1013
+ positions[c * 3 + 2] = mjModel.mesh_vert[v * 3 + 2];
1014
+ const t = tAdr + mjModel.mesh_facetexcoord[fAdr * 3 + c];
1015
+ uvs[c * 2] = mjModel.mesh_texcoord[t * 2];
1016
+ uvs[c * 2 + 1] = 1 - mjModel.mesh_texcoord[t * 2 + 1];
1017
+ }
1018
+ geo = new THREE11.BufferGeometry();
1019
+ geo.setAttribute("position", new THREE11.Float32BufferAttribute(positions, 3));
1020
+ geo.setAttribute("uv", new THREE11.Float32BufferAttribute(uvs, 2));
1021
+ geo.computeVertexNormals();
1022
+ } else {
1023
+ geo = new THREE11.BufferGeometry();
1024
+ geo.setAttribute("position", new THREE11.Float32BufferAttribute(mjModel.mesh_vert.subarray(vAdr * 3, (vAdr + vNum) * 3), 3));
1025
+ geo.setIndex(Array.from(mjModel.mesh_face.subarray(fAdr * 3, (fAdr + fNum) * 3)));
1026
+ const smoothingTolerance = this.getMeshNormalSmoothingTolerance();
1027
+ if (smoothingTolerance !== null) {
1028
+ geo = mergeVertices(geo, smoothingTolerance);
1029
+ }
1030
+ geo.computeVertexNormals();
1010
1031
  }
1011
- geo.computeVertexNormals();
1012
1032
  }
1013
1033
  if (geo) {
1014
1034
  const isPlane = type === getVal(MG.mjGEOM_PLANE);
@@ -1051,6 +1071,7 @@ function SceneRenderer({ renderOptions, ...props }) {
1051
1071
  mujocoRef,
1052
1072
  onSelectionRef,
1053
1073
  hiddenBodiesRef,
1074
+ hiddenBodiesVersion,
1054
1075
  interpolateRef,
1055
1076
  interpolationStateRef,
1056
1077
  status
@@ -1059,6 +1080,7 @@ function SceneRenderer({ renderOptions, ...props }) {
1059
1080
  const bodyRefs = useRef([]);
1060
1081
  const prevModelRef = useRef(null);
1061
1082
  const prevRenderOptionsKeyRef = useRef(null);
1083
+ const prevHiddenVersionRef = useRef(null);
1062
1084
  const renderOptionsKey = getRenderOptionsKey(renderOptions);
1063
1085
  const geomBuilder = useMemo(() => {
1064
1086
  if (status !== "ready") return null;
@@ -1069,11 +1091,12 @@ function SceneRenderer({ renderOptions, ...props }) {
1069
1091
  const model = mjModelRef.current;
1070
1092
  const group = groupRef.current;
1071
1093
  if (!model || !group) return;
1072
- if (prevModelRef.current === model && prevRenderOptionsKeyRef.current === renderOptionsKey) {
1094
+ if (prevModelRef.current === model && prevRenderOptionsKeyRef.current === renderOptionsKey && prevHiddenVersionRef.current === hiddenBodiesVersion) {
1073
1095
  return;
1074
1096
  }
1075
1097
  prevModelRef.current = model;
1076
1098
  prevRenderOptionsKeyRef.current = renderOptionsKey;
1099
+ prevHiddenVersionRef.current = hiddenBodiesVersion;
1077
1100
  while (group.children.length > 0) {
1078
1101
  group.remove(group.children[0]);
1079
1102
  }
@@ -1094,7 +1117,7 @@ function SceneRenderer({ renderOptions, ...props }) {
1094
1117
  refs.push(bodyGroup);
1095
1118
  }
1096
1119
  bodyRefs.current = refs;
1097
- }, [status, geomBuilder, mjModelRef, renderOptionsKey]);
1120
+ }, [status, geomBuilder, mjModelRef, renderOptionsKey, hiddenBodiesRef, hiddenBodiesVersion]);
1098
1121
  const syncBodiesToData = useCallback(() => {
1099
1122
  const data = mjDataRef.current;
1100
1123
  if (!data) return;
@@ -2275,6 +2298,7 @@ function MujocoSimProvider({
2275
2298
  speed,
2276
2299
  interpolate,
2277
2300
  renderOptions,
2301
+ hiddenBodies,
2278
2302
  children
2279
2303
  }) {
2280
2304
  const { gl, camera, scene } = useThree();
@@ -2308,6 +2332,8 @@ function MujocoSimProvider({
2308
2332
  const errorRef = useRef(null);
2309
2333
  const bodyRegistryRef = useRef(/* @__PURE__ */ new Map());
2310
2334
  const hiddenBodiesRef = useRef(/* @__PURE__ */ new Set());
2335
+ const providedHiddenBodiesRef = useRef(new Set(hiddenBodies ?? []));
2336
+ const [hiddenBodiesVersion, setHiddenBodiesVersion] = useState(0);
2311
2337
  const bodyReloadTimerRef = useRef(null);
2312
2338
  configRef.current = config;
2313
2339
  mujocoRef.current = mujoco;
@@ -2329,15 +2355,37 @@ function MujocoSimProvider({
2329
2355
  if (!model?.opt) return;
2330
2356
  model.opt.timestep = timestep;
2331
2357
  }, [timestep]);
2358
+ const hiddenBodiesKey = (hiddenBodies ?? []).join("\0");
2359
+ useEffect(() => {
2360
+ const next = new Set(hiddenBodies ?? []);
2361
+ const prev = providedHiddenBodiesRef.current;
2362
+ let unchanged = next.size === prev.size;
2363
+ if (unchanged) {
2364
+ for (const name of next) {
2365
+ if (!prev.has(name)) {
2366
+ unchanged = false;
2367
+ break;
2368
+ }
2369
+ }
2370
+ }
2371
+ if (unchanged) return;
2372
+ providedHiddenBodiesRef.current = next;
2373
+ recomputeHiddenBodies();
2374
+ setHiddenBodiesVersion((v) => v + 1);
2375
+ }, [hiddenBodiesKey]);
2376
+ function recomputeHiddenBodies() {
2377
+ hiddenBodiesRef.current.clear();
2378
+ for (const [name, entry] of bodyRegistryRef.current) {
2379
+ if (entry.hasCustomChildren) hiddenBodiesRef.current.add(name);
2380
+ }
2381
+ for (const name of providedHiddenBodiesRef.current) hiddenBodiesRef.current.add(name);
2382
+ }
2332
2383
  function buildMergedConfig(baseConfig) {
2384
+ recomputeHiddenBodies();
2333
2385
  if (bodyRegistryRef.current.size === 0) return baseConfig;
2334
2386
  const registeredNames = new Set(bodyRegistryRef.current.keys());
2335
2387
  const baseObjects = (baseConfig.sceneObjects ?? []).filter((o) => !registeredNames.has(o.name));
2336
2388
  const registeredBodies = Array.from(bodyRegistryRef.current.values()).map((e) => e.definition);
2337
- hiddenBodiesRef.current.clear();
2338
- for (const [name, entry] of bodyRegistryRef.current) {
2339
- if (entry.hasCustomChildren) hiddenBodiesRef.current.add(name);
2340
- }
2341
2389
  return { ...baseConfig, sceneObjects: [...baseObjects, ...registeredBodies] };
2342
2390
  }
2343
2391
  useEffect(() => {
@@ -3555,10 +3603,11 @@ function MujocoSimProvider({
3555
3603
  errorRef,
3556
3604
  bodyRegistryRef,
3557
3605
  hiddenBodiesRef,
3606
+ hiddenBodiesVersion,
3558
3607
  requestBodyReload,
3559
3608
  status
3560
3609
  }),
3561
- [api, status, requestBodyReload]
3610
+ [api, status, requestBodyReload, hiddenBodiesVersion]
3562
3611
  );
3563
3612
  return /* @__PURE__ */ jsxs(MujocoSimContext.Provider, { value: contextValue, children: [
3564
3613
  /* @__PURE__ */ jsx(SceneRenderer, { renderOptions }),
@@ -3580,6 +3629,7 @@ var MujocoCanvas = forwardRef(
3580
3629
  speed,
3581
3630
  interpolate,
3582
3631
  renderOptions,
3632
+ hiddenBodies,
3583
3633
  loadingFallback,
3584
3634
  children,
3585
3635
  ...canvasProps
@@ -3615,6 +3665,7 @@ var MujocoCanvas = forwardRef(
3615
3665
  speed,
3616
3666
  interpolate,
3617
3667
  renderOptions,
3668
+ hiddenBodies,
3618
3669
  children
3619
3670
  }
3620
3671
  ) });
@@ -3778,7 +3829,8 @@ var DEFAULTS = {
3778
3829
  tolerance: 1e-3,
3779
3830
  epsilon: 1e-6,
3780
3831
  posWeight: 1,
3781
- rotWeight: 0.3
3832
+ rotWeight: 0.3,
3833
+ maxStepRad: 0.5
3782
3834
  };
3783
3835
  function resolveOptions(opts) {
3784
3836
  return {
@@ -3788,6 +3840,7 @@ function resolveOptions(opts) {
3788
3840
  epsilon: opts?.epsilon ?? DEFAULTS.epsilon,
3789
3841
  posWeight: opts?.posWeight ?? DEFAULTS.posWeight,
3790
3842
  rotWeight: opts?.rotWeight ?? DEFAULTS.rotWeight,
3843
+ maxStepRad: opts?.maxStepRad ?? DEFAULTS.maxStepRad,
3791
3844
  jointLimits: opts?.jointLimits
3792
3845
  };
3793
3846
  }
@@ -3898,7 +3951,20 @@ var GenericIK = class {
3898
3951
  }
3899
3952
  dq[j] = sum;
3900
3953
  }
3901
- for (let i = 0; i < n; i++) q[i] += dq[i];
3954
+ for (let i = 0; i < n; i++) {
3955
+ let step = dq[i];
3956
+ if (step > o.maxStepRad) step = o.maxStepRad;
3957
+ else if (step < -o.maxStepRad) step = -o.maxStepRad;
3958
+ let next = q[i] + step;
3959
+ const limits = o.jointLimits?.[i];
3960
+ if (limits) {
3961
+ const low = Math.min(limits[0], limits[1]);
3962
+ const high = Math.max(limits[0], limits[1]);
3963
+ if (next < low) next = low;
3964
+ else if (next > high) next = high;
3965
+ }
3966
+ q[i] = next;
3967
+ }
3902
3968
  }
3903
3969
  data.qpos.set(savedQpos);
3904
3970
  this.mujoco.mj_forward(model, data);
@@ -4058,7 +4124,16 @@ var useIkController = createControllerHook(
4058
4124
  const ikTargetRef = useRef(new THREE11.Group());
4059
4125
  const siteIdRef = useRef(-1);
4060
4126
  const controlGroupRef = useRef(null);
4061
- const genericIkRef = useRef(new GenericIK(mujocoRef.current));
4127
+ const genericIkRef = useRef(null);
4128
+ const genericIkModuleRef = useRef(null);
4129
+ const getGenericIk = useCallback(() => {
4130
+ const module = mujocoRef.current;
4131
+ if (!genericIkRef.current || genericIkModuleRef.current !== module) {
4132
+ genericIkRef.current = new GenericIK(module);
4133
+ genericIkModuleRef.current = module;
4134
+ }
4135
+ return genericIkRef.current;
4136
+ }, [mujocoRef]);
4062
4137
  const firstIkEnableRef = useRef(true);
4063
4138
  const needsInitialSync = useRef(true);
4064
4139
  const gizmoAnimRef = useRef({
@@ -4109,7 +4184,7 @@ var useIkController = createControllerHook(
4109
4184
  const data = mjDataRef.current;
4110
4185
  const controlGroup2 = controlGroupRef.current;
4111
4186
  if (!model || !data || !controlGroup2 || siteIdRef.current === -1) return null;
4112
- return genericIkRef.current.solve(
4187
+ return getGenericIk().solve(
4113
4188
  model,
4114
4189
  data,
4115
4190
  siteIdRef.current,
@@ -4128,7 +4203,7 @@ var useIkController = createControllerHook(
4128
4203
  }
4129
4204
  );
4130
4205
  },
4131
- [config, mjModelRef, mjDataRef]
4206
+ [config, mjModelRef, mjDataRef, getGenericIk]
4132
4207
  );
4133
4208
  const ikSolveFnRef = useRef(ikSolveFn);
4134
4209
  ikSolveFnRef.current = ikSolveFn;