mujoco-react 12.1.2 → 12.2.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.
@@ -1,4 +1,4 @@
1
- import * as THREE from 'three';
1
+ import * as THREE2 from 'three';
2
2
  import { useThree } from '@react-three/fiber';
3
3
  import { useMemo, useEffect } from 'react';
4
4
  import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
@@ -174,6 +174,64 @@ async function dataUrlToPolicyImageTensor(dataUrl, options) {
174
174
  resolved
175
175
  );
176
176
  }
177
+ function createMetricDepthReader(width, height, texture) {
178
+ const target = new THREE2.WebGLRenderTarget(width, height, { depthBuffer: false });
179
+ const material = new THREE2.ShaderMaterial({
180
+ uniforms: { depthTexture: { value: texture } },
181
+ vertexShader: `varying vec2 vUv;
182
+ void main() { vUv = uv; gl_Position = vec4(position.xy, 0.0, 1.0); }`,
183
+ fragmentShader: `#include <packing>
184
+ uniform sampler2D depthTexture;
185
+ varying vec2 vUv;
186
+ void main() { gl_FragColor = packDepthToRGBA(texture2D(depthTexture, vUv).r); }`,
187
+ depthTest: false,
188
+ depthWrite: false,
189
+ blending: THREE2.NoBlending,
190
+ toneMapped: false
191
+ });
192
+ const geometry = new THREE2.PlaneGeometry(2, 2);
193
+ const scene = new THREE2.Scene();
194
+ scene.add(new THREE2.Mesh(geometry, material));
195
+ const screenCamera = new THREE2.Camera();
196
+ const packed = new Uint8Array(width * height * 4);
197
+ return {
198
+ read(renderer, camera, flipX) {
199
+ renderer.setRenderTarget(target);
200
+ renderer.clear();
201
+ renderer.render(scene, screenCamera);
202
+ renderer.readRenderTargetPixels(target, 0, 0, width, height, packed);
203
+ const result = new Float32Array(width * height);
204
+ const inverse = camera.projectionMatrixInverse.elements;
205
+ for (let y = 0; y < height; y++) {
206
+ for (let x = 0; x < width; x++) {
207
+ const sx = flipX ? width - x - 1 : x;
208
+ const sy = height - y - 1;
209
+ const offset = (sy * width + sx) * 4;
210
+ const r = packed[offset], g = packed[offset + 1], b = packed[offset + 2], a = packed[offset + 3];
211
+ if (r === 255 && g === 255 && b === 255 && a === 255) {
212
+ result[y * width + x] = Infinity;
213
+ continue;
214
+ }
215
+ const d = r / 256 + g / 65536 + b / 16777216 + a / (255 * 16777216);
216
+ const nx = (sx + 0.5) / width * 2 - 1;
217
+ const ny = (sy + 0.5) / height * 2 - 1;
218
+ const nz = d * 2 - 1;
219
+ const z = inverse[2] * nx + inverse[6] * ny + inverse[10] * nz + inverse[14];
220
+ const w = inverse[3] * nx + inverse[7] * ny + inverse[11] * nz + inverse[15];
221
+ result[y * width + x] = -z / w;
222
+ }
223
+ }
224
+ return result;
225
+ },
226
+ dispose() {
227
+ target.dispose();
228
+ material.dispose();
229
+ geometry.dispose();
230
+ }
231
+ };
232
+ }
233
+
234
+ // src/rendering/cameraFrameCapture.ts
177
235
  var CAMERA_FRAME_CAPTURE_RENDER_USER_DATA_KEY = "mujocoReactCameraFrameCaptureRender";
178
236
  var CAMERA_FRAME_CAPTURE_PRE_RENDER_USER_DATA_KEY = "mujocoReactCameraFrameCapturePreRender";
179
237
  var CAPTURE_EXCLUDE_KEY = "mujoco.capture.exclude";
@@ -229,7 +287,7 @@ function createIsolatedRenderer(sourceRenderer, width, height, options) {
229
287
  function createUncachedIsolatedRenderer(sourceRenderer, width, height, options) {
230
288
  const isolation = getRenderIsolationOptions(options);
231
289
  const canvas = document.createElement("canvas");
232
- const renderer = new THREE.WebGLRenderer({
290
+ const renderer = new THREE2.WebGLRenderer({
233
291
  canvas,
234
292
  antialias: isolation.antialias ?? false,
235
293
  alpha: isolation.alpha ?? false,
@@ -245,13 +303,13 @@ function createUncachedIsolatedRenderer(sourceRenderer, width, height, options)
245
303
  }
246
304
  function toVector3(value, fallback) {
247
305
  if (!value) return fallback.clone();
248
- return value instanceof THREE.Vector3 ? value.clone() : new THREE.Vector3(value[0], value[1], value[2]);
306
+ return value instanceof THREE2.Vector3 ? value.clone() : new THREE2.Vector3(value[0], value[1], value[2]);
249
307
  }
250
308
  function applyCameraPose(camera, options, fallbackCamera) {
251
309
  camera.position.copy(toVector3(options.position, fallbackCamera.position));
252
310
  camera.up.copy(toVector3(options.up, fallbackCamera.up));
253
311
  if (options.quaternion) {
254
- if (options.quaternion instanceof THREE.Quaternion) {
312
+ if (options.quaternion instanceof THREE2.Quaternion) {
255
313
  camera.quaternion.copy(options.quaternion);
256
314
  } else {
257
315
  camera.quaternion.set(
@@ -262,7 +320,7 @@ function applyCameraPose(camera, options, fallbackCamera) {
262
320
  );
263
321
  }
264
322
  } else if (options.lookAt) {
265
- camera.lookAt(toVector3(options.lookAt, new THREE.Vector3()));
323
+ camera.lookAt(toVector3(options.lookAt, new THREE2.Vector3()));
266
324
  } else {
267
325
  camera.quaternion.copy(fallbackCamera.quaternion);
268
326
  }
@@ -270,7 +328,7 @@ function applyCameraPose(camera, options, fallbackCamera) {
270
328
  }
271
329
  function applyProjectionMatrix(camera, projectionMatrix) {
272
330
  if (!projectionMatrix) return;
273
- if (projectionMatrix instanceof THREE.Matrix4) {
331
+ if (projectionMatrix instanceof THREE2.Matrix4) {
274
332
  camera.projectionMatrix.copy(projectionMatrix);
275
333
  } else {
276
334
  camera.projectionMatrix.fromArray(projectionMatrix);
@@ -278,14 +336,19 @@ function applyProjectionMatrix(camera, projectionMatrix) {
278
336
  camera.projectionMatrixInverse.copy(camera.projectionMatrix).invert();
279
337
  }
280
338
  function createCaptureCamera(options, fallbackCamera, width, height) {
281
- const camera = options.camera ? options.camera.clone() : fallbackCamera instanceof THREE.PerspectiveCamera ? fallbackCamera.clone() : new THREE.PerspectiveCamera(45, width / height, 0.01, 100);
282
- if (camera instanceof THREE.PerspectiveCamera) {
339
+ const camera = options.camera ? options.camera.clone() : fallbackCamera instanceof THREE2.PerspectiveCamera ? fallbackCamera.clone() : new THREE2.PerspectiveCamera(45, width / height, 0.01, 100);
340
+ if (camera instanceof THREE2.PerspectiveCamera) {
283
341
  camera.aspect = width / height;
284
342
  camera.fov = options.fov ?? camera.fov;
285
343
  camera.near = options.near ?? camera.near;
286
344
  camera.far = options.far ?? camera.far;
287
345
  camera.updateProjectionMatrix();
288
346
  }
347
+ if (camera instanceof THREE2.OrthographicCamera) {
348
+ camera.near = options.near ?? camera.near;
349
+ camera.far = options.far ?? camera.far;
350
+ camera.updateProjectionMatrix();
351
+ }
289
352
  applyProjectionMatrix(camera, options.projectionMatrix);
290
353
  applyCameraPose(camera, options, fallbackCamera);
291
354
  return camera;
@@ -305,20 +368,25 @@ function prepareCaptureCamera(camera, options, fallbackCamera, width, height) {
305
368
  if (options.camera) {
306
369
  camera.copy(options.camera);
307
370
  }
308
- if (camera instanceof THREE.PerspectiveCamera) {
371
+ if (camera instanceof THREE2.PerspectiveCamera) {
309
372
  camera.aspect = width / height;
310
373
  camera.fov = options.fov ?? camera.fov;
311
374
  camera.near = options.near ?? camera.near;
312
375
  camera.far = options.far ?? camera.far;
313
376
  camera.updateProjectionMatrix();
314
377
  }
378
+ if (camera instanceof THREE2.OrthographicCamera) {
379
+ camera.near = options.near ?? camera.near;
380
+ camera.far = options.far ?? camera.far;
381
+ camera.updateProjectionMatrix();
382
+ }
315
383
  applyProjectionMatrix(camera, options.projectionMatrix);
316
384
  applyCameraPose(camera, options, fallbackCamera);
317
385
  }
318
386
  function readRenderTargetToCanvas(renderer, target, canvas, context, pixels, imageData, width, height, outputColorSpace, flipX = false, readback = true) {
319
387
  if (readback) renderer.readRenderTargetPixels(target, 0, 0, width, height, pixels);
320
388
  const rowBytes = width * 4;
321
- const encodeSrgb = outputColorSpace === THREE.SRGBColorSpace;
389
+ const encodeSrgb = outputColorSpace === THREE2.SRGBColorSpace;
322
390
  for (let y = 0; y < height; y += 1) {
323
391
  const sourceStart = (height - y - 1) * rowBytes;
324
392
  const targetStart = y * rowBytes;
@@ -421,9 +489,9 @@ function getCameraFrameCaptureSource(options) {
421
489
  return { kind: "fallback-camera" };
422
490
  }
423
491
  function saveRendererState(renderer) {
424
- const viewport = new THREE.Vector4();
425
- const scissor = new THREE.Vector4();
426
- const clearColor = new THREE.Color();
492
+ const viewport = new THREE2.Vector4();
493
+ const scissor = new THREE2.Vector4();
494
+ const clearColor = new THREE2.Color();
427
495
  renderer.getViewport(viewport);
428
496
  renderer.getScissor(scissor);
429
497
  renderer.getClearColor(clearColor);
@@ -474,7 +542,7 @@ function applyCaptureVisualOverrides(renderer, scene, options) {
474
542
  const previousSceneState = saveSceneVisualState(scene);
475
543
  if (hasOwn(overrides, "sceneBackground")) {
476
544
  const background = overrides.sceneBackground;
477
- scene.background = background === false ? null : typeof background === "string" || typeof background === "number" ? new THREE.Color(background) : background ?? null;
545
+ scene.background = background === false ? null : typeof background === "string" || typeof background === "number" ? new THREE2.Color(background) : background ?? null;
478
546
  }
479
547
  if (hasOwn(overrides, "sceneEnvironment")) {
480
548
  const environment = overrides.sceneEnvironment;
@@ -517,9 +585,9 @@ function createCameraFrameCaptureSession(renderer, scene, fallbackCamera, option
517
585
  const isolatedRenderer = createIsolatedRenderer(renderer, width, height, options);
518
586
  const sessionRenderer = isolatedRenderer?.renderer ?? renderer;
519
587
  const camera = createCaptureCamera(options, fallbackCamera, width, height);
520
- const target = new THREE.WebGLRenderTarget(width, height, {
521
- format: THREE.RGBAFormat,
522
- type: THREE.UnsignedByteType
588
+ const target = new THREE2.WebGLRenderTarget(width, height, {
589
+ format: THREE2.RGBAFormat,
590
+ type: THREE2.UnsignedByteType
523
591
  });
524
592
  const canvas = document.createElement("canvas");
525
593
  canvas.width = width;
@@ -532,12 +600,14 @@ function createCameraFrameCaptureSession(renderer, scene, fallbackCamera, option
532
600
  const drawContext = context;
533
601
  const pixels = new Uint8Array(width * height * 4);
534
602
  const imageData = drawContext.createImageData(width, height);
603
+ let depthReader;
535
604
  let inFlight = false, disposed = false;
536
605
  function assertAvailable() {
537
606
  if (disposed) throw new Error("Camera capture session is disposed");
538
607
  if (inFlight) throw new Error("Camera capture session is busy; await the current capture");
539
608
  }
540
609
  function releaseResources() {
610
+ depthReader?.dispose();
541
611
  target.dispose();
542
612
  if (isolatedRenderer && !isolatedRenderer.cached) isolatedRenderer.renderer.dispose();
543
613
  }
@@ -576,7 +646,7 @@ function createCameraFrameCaptureSession(renderer, scene, fallbackCamera, option
576
646
  sessionRenderer.xr.enabled = false;
577
647
  if (captureOptions.background !== void 0) {
578
648
  sessionRenderer.setClearColor(
579
- new THREE.Color(captureOptions.background),
649
+ new THREE2.Color(captureOptions.background),
580
650
  captureOptions.backgroundAlpha ?? previousState.clearAlpha
581
651
  );
582
652
  } else if (captureOptions.backgroundAlpha !== void 0) {
@@ -592,8 +662,6 @@ function createCameraFrameCaptureSession(renderer, scene, fallbackCamera, option
592
662
  function renderCaptureToTarget(captureOptions, readback) {
593
663
  withCaptureState(captureOptions, () => {
594
664
  sessionRenderer.setRenderTarget(target);
595
- sessionRenderer.setViewport(0, 0, width, height);
596
- sessionRenderer.setScissor(0, 0, width, height);
597
665
  sessionRenderer.setScissorTest(false);
598
666
  sessionRenderer.clear();
599
667
  sessionRenderer.render(scene, camera);
@@ -641,6 +709,53 @@ function createCameraFrameCaptureSession(renderer, scene, fallbackCamera, option
641
709
  source: getCameraFrameCaptureSource(captureOptions)
642
710
  };
643
711
  }
712
+ function captureRGBD(nextOptions = {}) {
713
+ assertAvailable();
714
+ const captureOptions = resolveCaptureOptions(nextOptions);
715
+ if (getCaptureRenderer(scene)) {
716
+ throw new Error("Metric RGB-D capture requires the standard Three renderer; custom capture renderers do not provide aligned depth.");
717
+ }
718
+ if (sessionRenderer.capabilities.logarithmicDepthBuffer || sessionRenderer.capabilities.reversedDepthBuffer) {
719
+ throw new Error("Metric RGB-D capture does not support logarithmic or reversed depth buffers.");
720
+ }
721
+ if (!camera.projectionMatrix.elements.every(Number.isFinite) || !Number.isFinite(camera.projectionMatrix.determinant()) || camera.projectionMatrix.determinant() === 0) {
722
+ throw new Error("Metric RGB-D capture requires a finite, invertible projection matrix.");
723
+ }
724
+ if (!depthReader) {
725
+ target.dispose();
726
+ target.depthTexture = new THREE2.DepthTexture(width, height, THREE2.UnsignedIntType);
727
+ depthReader = createMetricDepthReader(width, height, target.depthTexture);
728
+ }
729
+ const rgb = new Uint8Array(width * height * 3);
730
+ let depth;
731
+ renderCaptureToTarget(captureOptions, () => {
732
+ sessionRenderer.readRenderTargetPixels(target, 0, 0, width, height, pixels);
733
+ for (let y = 0; y < height; y++) {
734
+ for (let x = 0; x < width; x++) {
735
+ const sx = captureOptions.flipX ? width - x - 1 : x;
736
+ const src = ((height - y - 1) * width + sx) * 4;
737
+ const dst = (y * width + x) * 3;
738
+ for (let c = 0; c < 3; c++) {
739
+ rgb[dst + c] = linearByteToSrgbByte(pixels[src + c]);
740
+ }
741
+ }
742
+ }
743
+ depth = depthReader.read(sessionRenderer, camera, captureOptions.flipX ?? false);
744
+ });
745
+ return {
746
+ rgb,
747
+ depth,
748
+ width,
749
+ height,
750
+ source: getCameraFrameCaptureSource(captureOptions),
751
+ origin: "top-left",
752
+ depthUnits: "meters",
753
+ depthConvention: "camera-z",
754
+ flipX: captureOptions.flipX ?? false,
755
+ projectionMatrix: camera.projectionMatrix.toArray(),
756
+ cameraWorldMatrix: camera.matrixWorld.toArray()
757
+ };
758
+ }
644
759
  function captureTensor(nextOptions = {}) {
645
760
  const result = capturePixels(nextOptions);
646
761
  const tensor = pixelsToPolicyImageTensor(pixels, {
@@ -730,6 +845,7 @@ function createCameraFrameCaptureSession(renderer, scene, fallbackCamera, option
730
845
  captureAsync,
731
846
  capturePixels,
732
847
  captureTensor,
848
+ captureRGBD,
733
849
  captureDataUrl(nextOptions = {}) {
734
850
  const type = nextOptions.type ?? options.type ?? "image/png";
735
851
  const result = capture(nextOptions);
@@ -834,6 +950,14 @@ function captureCameraFrameTensor(renderer, scene, fallbackCamera, options = {})
834
950
  session.dispose();
835
951
  }
836
952
  }
953
+ function captureCameraRGBD(renderer, scene, fallbackCamera, options = {}) {
954
+ const session = createCameraFrameCaptureSession(renderer, scene, fallbackCamera, options);
955
+ try {
956
+ return session.captureRGBD();
957
+ } finally {
958
+ session.dispose();
959
+ }
960
+ }
837
961
  var DEFAULT_BACKGROUND = "#181a1f";
838
962
  function ScenarioLighting({
839
963
  preset = "studio",
@@ -1007,7 +1131,7 @@ function useVisualScenarioEffects({
1007
1131
  gl.toneMappingExposure = scenario.camera?.exposure ?? 1;
1008
1132
  }
1009
1133
  if (applyBackground) {
1010
- scene.background = new THREE.Color(
1134
+ scene.background = new THREE2.Color(
1011
1135
  background ?? getScenarioBackground(scenario.lighting)
1012
1136
  );
1013
1137
  }
@@ -1347,21 +1471,21 @@ function SplatPlaceholder() {
1347
1471
  transparent: true,
1348
1472
  opacity: 0.06,
1349
1473
  wireframe: true,
1350
- side: THREE.DoubleSide
1474
+ side: THREE2.DoubleSide
1351
1475
  }
1352
1476
  )
1353
1477
  ] }) });
1354
1478
  }
1355
1479
  function createScenarioFog(scenario, background, fogNear, fogFar) {
1356
1480
  if (scenario.lighting === "low-light") {
1357
- return new THREE.Fog(
1481
+ return new THREE2.Fog(
1358
1482
  background ?? getScenarioBackground(scenario.lighting),
1359
1483
  fogNear ?? 2.5,
1360
1484
  fogFar ?? 9
1361
1485
  );
1362
1486
  }
1363
1487
  if (scenario.lighting === "warehouse") {
1364
- return new THREE.Fog(
1488
+ return new THREE2.Fog(
1365
1489
  background ?? getScenarioBackground(scenario.lighting),
1366
1490
  fogNear ?? 5,
1367
1491
  fogFar ?? 16
@@ -1373,7 +1497,7 @@ function applyScenarioMaterials(scene, scenario, snapshots, materialFilter) {
1373
1497
  const materials = scenario.materials;
1374
1498
  if (!materials) return;
1375
1499
  scene.traverse((object) => {
1376
- if (!(object instanceof THREE.Mesh)) {
1500
+ if (!(object instanceof THREE2.Mesh)) {
1377
1501
  return;
1378
1502
  }
1379
1503
  for (const material of normalizeMaterials(object.material)) {
@@ -1412,7 +1536,7 @@ function normalizeMaterials(material) {
1412
1536
  return Array.isArray(material) ? material : [material];
1413
1537
  }
1414
1538
  function getMutableScenarioMaterial(material) {
1415
- if (material instanceof THREE.MeshStandardMaterial || material instanceof THREE.MeshPhysicalMaterial) {
1539
+ if (material instanceof THREE2.MeshStandardMaterial || material instanceof THREE2.MeshPhysicalMaterial) {
1416
1540
  return material;
1417
1541
  }
1418
1542
  return null;
@@ -1438,6 +1562,7 @@ function clamp01(value) {
1438
1562
  *
1439
1563
  * Helpers for turning browser camera captures into policy image tensors.
1440
1564
  */
1565
+ /** @license SPDX-License-Identifier: Apache-2.0 */
1441
1566
  /**
1442
1567
  * @license
1443
1568
  * SPDX-License-Identifier: Apache-2.0
@@ -1445,6 +1570,6 @@ function clamp01(value) {
1445
1570
  * Offscreen camera-frame capture for R3F/MuJoCo scenes.
1446
1571
  */
1447
1572
 
1448
- 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, createCaptureCamera, createPairedSplatEnvironment, createSparkSplatViewerUrl, createSplatEnvironmentUserData, createSplatSceneConfig, createVisualScenarioExecutionContext, dataUrlToPolicyImageTensor, getContact, getScenarioBackground, getScenarioCameraPosition, getSplatEnvironmentReadiness, imageDataToPolicyImageTensor, pixelsToPolicyImageTensor, prepareCaptureCamera, registerModelResources, renderCameraFrameToCanvas, useSplatEnvironment, useSplatSceneConfig, useVisualScenarioEffects, useVisualScenarioExecutionContext, withContacts, withSplatEnvironment };
1449
- //# sourceMappingURL=chunk-CV6LBHC4.js.map
1450
- //# sourceMappingURL=chunk-CV6LBHC4.js.map
1573
+ 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, captureCameraRGBD, createCameraFrameCaptureSession, createCaptureCamera, createPairedSplatEnvironment, createSparkSplatViewerUrl, createSplatEnvironmentUserData, createSplatSceneConfig, createVisualScenarioExecutionContext, dataUrlToPolicyImageTensor, getContact, getScenarioBackground, getScenarioCameraPosition, getSplatEnvironmentReadiness, imageDataToPolicyImageTensor, pixelsToPolicyImageTensor, prepareCaptureCamera, registerModelResources, renderCameraFrameToCanvas, useSplatEnvironment, useSplatSceneConfig, useVisualScenarioEffects, useVisualScenarioExecutionContext, withContacts, withSplatEnvironment };
1574
+ //# sourceMappingURL=chunk-SP72GTOD.js.map
1575
+ //# sourceMappingURL=chunk-SP72GTOD.js.map