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.
- package/README.md +195 -180
- package/dist/{chunk-CV6LBHC4.js → chunk-SP72GTOD.js} +154 -29
- package/dist/chunk-SP72GTOD.js.map +1 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +24 -2
- package/dist/index.js.map +1 -1
- package/dist/onnx.d.ts +1 -1
- package/dist/spark.d.ts +1 -1
- package/dist/spark.js +1 -1
- package/dist/{types-BvMb-EIC.d.ts → types-CF-BZXtW.d.ts} +27 -1
- package/package.json +1 -1
- package/src/core/MujocoSimProvider.tsx +9 -1
- package/src/hooks/useCameraFrameCapture.ts +17 -0
- package/src/index.ts +2 -0
- package/src/rendering/cameraFrameCapture.ts +96 -2
- package/src/rendering/metricDepth.ts +56 -0
- package/src/types.ts +4 -0
- package/dist/chunk-CV6LBHC4.js.map +0 -1
package/dist/onnx.d.ts
CHANGED
package/dist/spark.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
2
|
import * as _sparkjsdev_spark from '@sparkjsdev/spark';
|
|
3
|
-
import { S as SplatEnvironmentProps, a as PairedSplatEnvironmentConfig, b as SceneConfig, c as SplatEnvironmentReadiness, V as VisualScenarioConfig } from './types-
|
|
3
|
+
import { S as SplatEnvironmentProps, a as PairedSplatEnvironmentConfig, b as SceneConfig, c as SplatEnvironmentReadiness, V as VisualScenarioConfig } from './types-CF-BZXtW.js';
|
|
4
4
|
import 'react';
|
|
5
5
|
import '@react-three/fiber';
|
|
6
6
|
import 'three';
|
package/dist/spark.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useSplatSceneConfig, useSplatEnvironment, SplatEnvironment, CAMERA_FRAME_CAPTURE_RENDER_USER_DATA_KEY } from './chunk-
|
|
1
|
+
import { useSplatSceneConfig, useSplatEnvironment, SplatEnvironment, CAMERA_FRAME_CAPTURE_RENDER_USER_DATA_KEY } from './chunk-SP72GTOD.js';
|
|
2
2
|
import { useThree } from '@react-three/fiber';
|
|
3
3
|
import { useMemo, useState, useEffect, useCallback, useRef } from 'react';
|
|
4
4
|
import * as THREE from 'three';
|
|
@@ -124,6 +124,25 @@ interface CameraFramePixelsResult {
|
|
|
124
124
|
height: number;
|
|
125
125
|
source: CameraFrameCaptureSource;
|
|
126
126
|
}
|
|
127
|
+
/** An owned, aligned RGB-D observation from one render. Scene units must be meters. */
|
|
128
|
+
interface CameraRGBDResult {
|
|
129
|
+
/** Interleaved sRGB bytes (RGB), row-major, top-left origin. */
|
|
130
|
+
rgb: Uint8Array;
|
|
131
|
+
/** Positive camera-axis distance (-view Z) in meters, not Euclidean range.
|
|
132
|
+
* Background / no depth-writing surface is +Infinity. Same pixel order as rgb. */
|
|
133
|
+
depth: Float32Array;
|
|
134
|
+
width: number;
|
|
135
|
+
height: number;
|
|
136
|
+
source: CameraFrameCaptureSource;
|
|
137
|
+
origin: 'top-left';
|
|
138
|
+
depthUnits: 'meters';
|
|
139
|
+
depthConvention: 'camera-z';
|
|
140
|
+
/** Horizontal mirroring applied to both arrays. Undo before unprojecting. */
|
|
141
|
+
flipX: boolean;
|
|
142
|
+
/** Owned column-major matrices. Camera coordinates: +X right, +Y up, -Z forward. */
|
|
143
|
+
projectionMatrix: number[];
|
|
144
|
+
cameraWorldMatrix: number[];
|
|
145
|
+
}
|
|
127
146
|
interface CameraFrameTensorResult extends PolicyImageTensorResult {
|
|
128
147
|
camera: THREE.Camera;
|
|
129
148
|
source: CameraFrameCaptureSource;
|
|
@@ -156,6 +175,8 @@ interface CameraFrameCaptureSession {
|
|
|
156
175
|
capturePixels(options?: CameraFrameCaptureOptions): CameraFramePixelsResult;
|
|
157
176
|
/** Render straight into a normalized policy image tensor (no canvas/PNG encode). */
|
|
158
177
|
captureTensor(options?: CameraFrameCaptureTensorOptions): CameraFrameTensorResult;
|
|
178
|
+
/** Synchronous RGB + metric depth from one render. Returned arrays are owned. */
|
|
179
|
+
captureRGBD(options?: CameraFrameCaptureOptions): CameraRGBDResult;
|
|
159
180
|
dispose(): void;
|
|
160
181
|
}
|
|
161
182
|
declare const CAMERA_FRAME_CAPTURE_RENDER_USER_DATA_KEY = "mujocoReactCameraFrameCaptureRender";
|
|
@@ -178,6 +199,8 @@ declare function captureCameraFrameBlob(renderer: THREE.WebGLRenderer, scene: TH
|
|
|
178
199
|
* `session.captureTensor()` so the render target and buffers are reused.
|
|
179
200
|
*/
|
|
180
201
|
declare function captureCameraFrameTensor(renderer: THREE.WebGLRenderer, scene: THREE.Scene, fallbackCamera: THREE.Camera, options?: CameraFrameCaptureTensorOptions): CameraFrameTensorResult;
|
|
202
|
+
/** One-shot aligned RGB-D observation. Use a session for repeated observations. */
|
|
203
|
+
declare function captureCameraRGBD(renderer: THREE.WebGLRenderer, scene: THREE.Scene, fallbackCamera: THREE.Camera, options?: CameraFrameCaptureOptions): CameraRGBDResult;
|
|
181
204
|
|
|
182
205
|
/**
|
|
183
206
|
* @license
|
|
@@ -1401,6 +1424,8 @@ interface MujocoSimAPI {
|
|
|
1401
1424
|
captureFrameBlob(options?: MujocoFrameCaptureOptions): Promise<FrameCaptureBlobResult>;
|
|
1402
1425
|
captureCameraFrame(options?: CameraFrameCaptureOptions): Promise<CameraFrameCaptureResult>;
|
|
1403
1426
|
captureCameraFrameBlob(options?: CameraFrameCaptureOptions): Promise<CameraFrameCaptureBlobResult>;
|
|
1427
|
+
/** Aligned sRGB + camera-axis depth in meters from one render. */
|
|
1428
|
+
captureCameraRGBD(options?: CameraFrameCaptureOptions): CameraRGBDResult;
|
|
1404
1429
|
/** Capture a camera frame straight into a policy image tensor (no canvas/PNG encode). */
|
|
1405
1430
|
captureCameraFrameTensor(options?: CameraFrameCaptureTensorOptions): CameraFrameTensorResult;
|
|
1406
1431
|
/**
|
|
@@ -1621,6 +1646,7 @@ interface CameraFrameCaptureAPI {
|
|
|
1621
1646
|
isCapturing: boolean;
|
|
1622
1647
|
capture: (options?: CameraFrameCaptureOptions) => Promise<CameraFrameCaptureResult>;
|
|
1623
1648
|
captureBlob: (options?: CameraFrameCaptureOptions) => Promise<CameraFrameCaptureBlobResult>;
|
|
1649
|
+
captureRGBD: (options?: CameraFrameCaptureOptions) => Promise<CameraRGBDResult>;
|
|
1624
1650
|
reset: () => void;
|
|
1625
1651
|
}
|
|
1626
1652
|
interface CameraFrameSequenceCamera extends CameraFrameCaptureOptions {
|
|
@@ -1787,4 +1813,4 @@ interface ArrayJointStateResult {
|
|
|
1787
1813
|
velocity: React__default.RefObject<Float64Array>;
|
|
1788
1814
|
}
|
|
1789
1815
|
|
|
1790
|
-
export { type SensorHandle as $, type ActuatedJointInfo as A, type BodyProps as B, type ControlGroupInfo as C, type DragInteractionProps as D, type SplatSceneConfigState as E, type VisualScenarioExecutionContextInput as F, type VisualScenarioExecutionContext as G, type ScenarioLightingPreset as H, type IkConfig as I, type SplatEnvironmentMetadataInput as J, type SplatEnvironmentMetadata as K, type SplatSceneInput as L, type MujocoContextValue as M, type CameraFrameCaptureOptions as N, type ObservationConfig as O, type PolicyActionChunk as P, type DebugProps as Q, type ReadyCallbackInput as R, type SplatEnvironmentProps as S, type GeomInfo as T, type ContactListenerProps as U, type VisualScenarioConfig as V, type TrajectoryPlayerProps as W, type ActuatorInfo as X, type Sites as Y, type SitePositionResult as Z, type Sensors as _, type PairedSplatEnvironmentConfig as a, type
|
|
1816
|
+
export { type SensorHandle as $, type ActuatedJointInfo as A, type BodyProps as B, type ControlGroupInfo as C, type DragInteractionProps as D, type SplatSceneConfigState as E, type VisualScenarioExecutionContextInput as F, type VisualScenarioExecutionContext as G, type ScenarioLightingPreset as H, type IkConfig as I, type SplatEnvironmentMetadataInput as J, type SplatEnvironmentMetadata as K, type SplatSceneInput as L, type MujocoContextValue as M, type CameraFrameCaptureOptions as N, type ObservationConfig as O, type PolicyActionChunk as P, type DebugProps as Q, type ReadyCallbackInput as R, type SplatEnvironmentProps as S, type GeomInfo as T, type ContactListenerProps as U, type VisualScenarioConfig as V, type TrajectoryPlayerProps as W, type ActuatorInfo as X, type Sites as Y, type SitePositionResult as Z, type Sensors as _, type PairedSplatEnvironmentConfig as a, type CameraRGBDResult as a$, type SensorInfo as a0, type Joints as a1, type ScalarJointStateResult as a2, type ArrayJointStateResult as a3, type JointStateOptions as a4, type JointStateResult as a5, type Bodies as a6, type BodyStateResult as a7, type Geoms as a8, type Actuators as a9, type PolicyCameraFrameCaptureResult as aA, type FrameCaptureStatus as aB, type PolicyCameraFrameCaptureAPI as aC, type CameraFrameCaptureTensorOptions as aD, type CameraFrameTensorResult as aE, type CameraFrameSequenceRecorderAPI as aF, type ImagePointCoordinateSpace as aG, type ImagePointProjectionOptions as aH, type ImagePointProjectionResult as aI, type PolicyVector as aJ, type ActuatorControlValue as aK, type AdvanceOptions as aL, type BodyInfo as aM, CAMERA_FRAME_CAPTURE_PRE_RENDER_USER_DATA_KEY as aN, CAMERA_FRAME_CAPTURE_RENDER_USER_DATA_KEY as aO, CAPTURE_EXCLUDE_KEY as aP, type CameraFrameCaptureBlobResult as aQ, type CameraFrameCaptureQuaternion as aR, type CameraFrameCaptureResult as aS, type CameraFrameCaptureSession as aT, type CameraFrameCaptureVector3 as aU, type CameraFramePixelsResult as aV, type CameraFrameSequenceCameraSummary as aW, type CameraFrameSequenceFrame as aX, type CameraFrameSequenceSampleInput as aY, type CameraFrameSequenceStepInput as aZ, type CameraInfo as a_, type CtrlHandle as aa, type ContactInfo as ab, type KeyboardTeleopConfig as ac, type KeyboardIkTargetConfig as ad, type PolicyConfig as ae, type PolicyAPI as af, type RemotePolicyConfig as ag, type RemotePolicyAPI as ah, type ObservationHandle as ai, type ObservationOutput as aj, type TrajectoryInput as ak, type TrajectoryStateChangeInput as al, type PlaybackState as am, type TrajectoryFrame as an, type FrameCaptureOptions as ao, type FrameCaptureResult as ap, type FrameCaptureBlobResult as aq, type FrameCaptureAPI as ar, type CameraFrameCaptureAPI as as, type Cameras as at, type CameraFrameSequenceCamera as au, type CameraFrameCaptureSource as av, type CameraFrameSequenceOptions as aw, type CameraFrameSequenceResult as ax, type PolicyCameraFrameStream as ay, type PolicyCameraFrameCaptureOptions as az, type SceneConfig as b, type SimulationRuntime as b$, type ControlJointInfo as b0, type DebugVirtualCamera as b1, type FrameCaptureTarget as b2, type FrameCaptureTargetRef as b3, type IKSolveFn as b4, type IkGizmoDragInput as b5, type IkSolveInput as b6, type JointInfo as b7, type JointStateKind as b8, type KeyBinding as b9, type PolicyImageTensorRange as bA, type PolicyImageTensorResult as bB, type PolicyImageTensorSourceOrigin as bC, type PolicyInferenceInput as bD, type PolicyInferenceOutput as bE, type PolicyInferenceResult as bF, type PolicyObservationInput as bG, type RayHit as bH, type Register as bI, type RegisteredModelMap as bJ, type RemotePolicyRequestInfo as bK, type RemotePolicyRequestInput as bL, type RemotePolicyResponseInfo as bM, type RemotePolicyStatus as bN, type ResetCallbackInput as bO, type ResolvedScenarioCameraConfig as bP, type ResolvedScenarioMaterialConfig as bQ, type ResourceSelector as bR, type RuntimeMetrics as bS, type RuntimeOptions as bT, type RuntimeSnapshot as bU, type RuntimeState as bV, type ScenarioCameraConfig as bW, type ScenarioMaterialConfig as bX, type SceneMarker as bY, type SceneObject as bZ, type SensorResult as b_, type KeyboardIkTargetAction as ba, type KeyboardIkTargetBinding as bb, type Keyframes as bc, ModelActuators as bd, ModelBodies as be, ModelCameras as bf, ModelGeoms as bg, ModelJoints as bh, ModelKeyframes as bi, type ModelOptions as bj, type ModelResource as bk, ModelResources as bl, ModelSensors as bm, ModelSites as bn, type Models as bo, type MujocoContact as bp, type MujocoContactArray as bq, type MujocoFrameCaptureOptions as br, type ObservationLayoutItem as bs, type PhysicsConfig as bt, type PhysicsPerformance as bu, type PhysicsStepInput as bv, type PolicyActionInput as bw, type PolicyImageTensorLayout as bx, type PolicyImageTensorOptions as by, type PolicyImageTensorPixelOptions as bz, type SplatEnvironmentReadiness as c, type SiteInfo as c0, type SplatAssetConfig as c1, type SplatScenarioConfig as c2, type StateSnapshot as c3, type TrajectoryData as c4, type TrajectoryFrameCallbackInput as c5, type VisualScenarioMaterialFilterInput as c6, type WorkerPort as c7, type XmlPatch as c8, captureCameraFrame as c9, captureCameraFrameBlob as ca, captureCameraFrameTensor as cb, captureCameraRGBD as cc, createCameraFrameCaptureSession as cd, dataUrlToPolicyImageTensor as ce, getContact as cf, imageDataToPolicyImageTensor as cg, pixelsToPolicyImageTensor as ch, registerModelResources as ci, renderCameraFrameToCanvas as cj, type MujocoCanvasProps as d, type MujocoSimAPI as e, type StepCallbackInput as f, type SelectionCallbackInput as g, type MujocoIntegrator as h, type MujocoModule as i, type MujocoRenderOptions as j, type PhysicsStepCallback as k, type MujocoModel as l, type MujocoData as m, type ControlGroupSelector as n, type ObservationResult as o, type IkContextValue as p, type IkGizmoProps as q, type SceneLightsProps as r, type ScenarioLightingProps as s, type VisualScenarioEffectsProps as t, type SplatRendererKind as u, type SplatFormat as v, type SplatCollisionProxyConfig as w, type SplatCollisionPrimitive as x, SplatEnvironmentReadinessStatus as y, type SplatSceneConfigInput as z };
|
package/package.json
CHANGED
|
@@ -67,6 +67,7 @@ import {
|
|
|
67
67
|
import {
|
|
68
68
|
captureCameraFrame,
|
|
69
69
|
captureCameraFrameBlob,
|
|
70
|
+
captureCameraRGBD,
|
|
70
71
|
createCameraFrameCaptureSession,
|
|
71
72
|
type CameraFrameCaptureTensorOptions,
|
|
72
73
|
} from '../rendering/cameraFrameCapture';
|
|
@@ -1583,6 +1584,12 @@ export function MujocoSimProvider({
|
|
|
1583
1584
|
[camera, gl, resolveCameraCaptureOptions, scene]
|
|
1584
1585
|
);
|
|
1585
1586
|
|
|
1587
|
+
const captureCameraRGBDApi = useCallback(
|
|
1588
|
+
(options: CameraFrameCaptureOptions = {}) =>
|
|
1589
|
+
captureCameraRGBD(gl, scene, camera, resolveCameraCaptureOptions(options)),
|
|
1590
|
+
[camera, gl, resolveCameraCaptureOptions, scene]
|
|
1591
|
+
);
|
|
1592
|
+
|
|
1586
1593
|
const createCameraFrameCaptureSessionApi = useCallback(
|
|
1587
1594
|
(options: CameraFrameCaptureOptions = {}) =>
|
|
1588
1595
|
createCameraFrameCaptureSession(
|
|
@@ -1950,6 +1957,7 @@ export function MujocoSimProvider({
|
|
|
1950
1957
|
captureCameraFrame: captureCameraFrameApi,
|
|
1951
1958
|
captureCameraFrameBlob: captureCameraFrameBlobApi,
|
|
1952
1959
|
captureCameraFrameTensor: captureCameraFrameTensorApi,
|
|
1960
|
+
captureCameraRGBD: captureCameraRGBDApi,
|
|
1953
1961
|
createCameraFrameCaptureSession: createCameraFrameCaptureSessionApi,
|
|
1954
1962
|
resolveCameraCaptureOptions,
|
|
1955
1963
|
recordCameraSequence: recordCameraSequenceApi,
|
|
@@ -1973,7 +1981,7 @@ export function MujocoSimProvider({
|
|
|
1973
1981
|
loadFromFilesApi, addBodyApi, removeBodyApi, recompileApi,
|
|
1974
1982
|
getCanvas, getCanvasSnapshot, captureFrameApi, captureFrameBlobApi,
|
|
1975
1983
|
captureCameraFrameApi, captureCameraFrameBlobApi,
|
|
1976
|
-
captureCameraFrameTensorApi, createCameraFrameCaptureSessionApi,
|
|
1984
|
+
captureCameraFrameTensorApi, captureCameraRGBDApi, createCameraFrameCaptureSessionApi,
|
|
1977
1985
|
resolveCameraCaptureOptions,
|
|
1978
1986
|
recordCameraSequenceApi,
|
|
1979
1987
|
project2DTo3D,
|
|
@@ -83,12 +83,29 @@ export function useCameraFrameCapture(
|
|
|
83
83
|
[defaultOptions, mujoco.api]
|
|
84
84
|
);
|
|
85
85
|
|
|
86
|
+
async function captureRGBD(options: CameraFrameCaptureOptions = {}) {
|
|
87
|
+
setStatus('capturing');
|
|
88
|
+
setError(null);
|
|
89
|
+
try {
|
|
90
|
+
if (!mujoco.api) throw new Error('MuJoCo scene is not ready for camera frame capture.');
|
|
91
|
+
const result = mujoco.api.captureCameraRGBD({ ...defaultOptions, ...options });
|
|
92
|
+
setStatus('captured');
|
|
93
|
+
return result;
|
|
94
|
+
} catch (nextError) {
|
|
95
|
+
const error = nextError instanceof Error ? nextError : new Error('Unable to capture RGB-D.');
|
|
96
|
+
setError(error);
|
|
97
|
+
setStatus('error');
|
|
98
|
+
throw error;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
86
102
|
return {
|
|
87
103
|
status,
|
|
88
104
|
error,
|
|
89
105
|
isCapturing: status === 'capturing',
|
|
90
106
|
capture,
|
|
91
107
|
captureBlob,
|
|
108
|
+
captureRGBD,
|
|
92
109
|
reset,
|
|
93
110
|
};
|
|
94
111
|
}
|
package/src/index.ts
CHANGED
|
@@ -172,6 +172,7 @@ export {
|
|
|
172
172
|
captureCameraFrame,
|
|
173
173
|
captureCameraFrameBlob,
|
|
174
174
|
captureCameraFrameTensor,
|
|
175
|
+
captureCameraRGBD,
|
|
175
176
|
createCameraFrameCaptureSession,
|
|
176
177
|
renderCameraFrameToCanvas,
|
|
177
178
|
} from './rendering/cameraFrameCapture';
|
|
@@ -179,6 +180,7 @@ export type {
|
|
|
179
180
|
CameraFrameCaptureSession,
|
|
180
181
|
CameraFrameCaptureTensorOptions,
|
|
181
182
|
CameraFramePixelsResult,
|
|
183
|
+
CameraRGBDResult,
|
|
182
184
|
CameraFrameTensorResult,
|
|
183
185
|
} from './rendering/cameraFrameCapture';
|
|
184
186
|
export {
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import * as THREE from 'three';
|
|
9
|
+
import { createMetricDepthReader } from './metricDepth';
|
|
9
10
|
import type {
|
|
10
11
|
CameraFrameCaptureBlobResult,
|
|
11
12
|
CameraFrameCaptureOptions,
|
|
@@ -32,6 +33,26 @@ export interface CameraFramePixelsResult {
|
|
|
32
33
|
source: CameraFrameCaptureSource;
|
|
33
34
|
}
|
|
34
35
|
|
|
36
|
+
/** An owned, aligned RGB-D observation from one render. Scene units must be meters. */
|
|
37
|
+
export interface CameraRGBDResult {
|
|
38
|
+
/** Interleaved sRGB bytes (RGB), row-major, top-left origin. */
|
|
39
|
+
rgb: Uint8Array;
|
|
40
|
+
/** Positive camera-axis distance (-view Z) in meters, not Euclidean range.
|
|
41
|
+
* Background / no depth-writing surface is +Infinity. Same pixel order as rgb. */
|
|
42
|
+
depth: Float32Array;
|
|
43
|
+
width: number;
|
|
44
|
+
height: number;
|
|
45
|
+
source: CameraFrameCaptureSource;
|
|
46
|
+
origin: 'top-left';
|
|
47
|
+
depthUnits: 'meters';
|
|
48
|
+
depthConvention: 'camera-z';
|
|
49
|
+
/** Horizontal mirroring applied to both arrays. Undo before unprojecting. */
|
|
50
|
+
flipX: boolean;
|
|
51
|
+
/** Owned column-major matrices. Camera coordinates: +X right, +Y up, -Z forward. */
|
|
52
|
+
projectionMatrix: number[];
|
|
53
|
+
cameraWorldMatrix: number[];
|
|
54
|
+
}
|
|
55
|
+
|
|
35
56
|
export interface CameraFrameTensorResult extends PolicyImageTensorResult {
|
|
36
57
|
camera: THREE.Camera;
|
|
37
58
|
source: CameraFrameCaptureSource;
|
|
@@ -67,6 +88,8 @@ export interface CameraFrameCaptureSession {
|
|
|
67
88
|
capturePixels(options?: CameraFrameCaptureOptions): CameraFramePixelsResult;
|
|
68
89
|
/** Render straight into a normalized policy image tensor (no canvas/PNG encode). */
|
|
69
90
|
captureTensor(options?: CameraFrameCaptureTensorOptions): CameraFrameTensorResult;
|
|
91
|
+
/** Synchronous RGB + metric depth from one render. Returned arrays are owned. */
|
|
92
|
+
captureRGBD(options?: CameraFrameCaptureOptions): CameraRGBDResult;
|
|
70
93
|
dispose(): void;
|
|
71
94
|
}
|
|
72
95
|
|
|
@@ -306,6 +329,11 @@ export function createCaptureCamera(
|
|
|
306
329
|
camera.far = options.far ?? camera.far;
|
|
307
330
|
camera.updateProjectionMatrix();
|
|
308
331
|
}
|
|
332
|
+
if (camera instanceof THREE.OrthographicCamera) {
|
|
333
|
+
camera.near = options.near ?? camera.near;
|
|
334
|
+
camera.far = options.far ?? camera.far;
|
|
335
|
+
camera.updateProjectionMatrix();
|
|
336
|
+
}
|
|
309
337
|
applyProjectionMatrix(camera, options.projectionMatrix);
|
|
310
338
|
|
|
311
339
|
applyCameraPose(camera, options, fallbackCamera);
|
|
@@ -345,6 +373,11 @@ export function prepareCaptureCamera(
|
|
|
345
373
|
camera.far = options.far ?? camera.far;
|
|
346
374
|
camera.updateProjectionMatrix();
|
|
347
375
|
}
|
|
376
|
+
if (camera instanceof THREE.OrthographicCamera) {
|
|
377
|
+
camera.near = options.near ?? camera.near;
|
|
378
|
+
camera.far = options.far ?? camera.far;
|
|
379
|
+
camera.updateProjectionMatrix();
|
|
380
|
+
}
|
|
348
381
|
applyProjectionMatrix(camera, options.projectionMatrix);
|
|
349
382
|
|
|
350
383
|
applyCameraPose(camera, options, fallbackCamera);
|
|
@@ -653,12 +686,14 @@ export function createCameraFrameCaptureSession(
|
|
|
653
686
|
|
|
654
687
|
const pixels = new Uint8Array(width * height * 4);
|
|
655
688
|
const imageData = drawContext.createImageData(width, height);
|
|
689
|
+
let depthReader: ReturnType<typeof createMetricDepthReader> | undefined;
|
|
656
690
|
let inFlight = false, disposed = false;
|
|
657
691
|
function assertAvailable() {
|
|
658
692
|
if (disposed) throw new Error('Camera capture session is disposed');
|
|
659
693
|
if (inFlight) throw new Error('Camera capture session is busy; await the current capture');
|
|
660
694
|
}
|
|
661
695
|
function releaseResources() {
|
|
696
|
+
depthReader?.dispose();
|
|
662
697
|
target.dispose();
|
|
663
698
|
if (isolatedRenderer && !isolatedRenderer.cached) isolatedRenderer.renderer.dispose();
|
|
664
699
|
}
|
|
@@ -727,8 +762,7 @@ export function createCameraFrameCaptureSession(
|
|
|
727
762
|
) {
|
|
728
763
|
withCaptureState(captureOptions, () => {
|
|
729
764
|
sessionRenderer.setRenderTarget(target);
|
|
730
|
-
|
|
731
|
-
sessionRenderer.setScissor(0, 0, width, height);
|
|
765
|
+
// The render target installs its pixel viewport; setters would apply DPR twice.
|
|
732
766
|
sessionRenderer.setScissorTest(false);
|
|
733
767
|
sessionRenderer.clear();
|
|
734
768
|
sessionRenderer.render(scene, camera);
|
|
@@ -780,6 +814,51 @@ export function createCameraFrameCaptureSession(
|
|
|
780
814
|
};
|
|
781
815
|
}
|
|
782
816
|
|
|
817
|
+
function captureRGBD(nextOptions: CameraFrameCaptureOptions = {}): CameraRGBDResult {
|
|
818
|
+
assertAvailable();
|
|
819
|
+
const captureOptions = resolveCaptureOptions(nextOptions);
|
|
820
|
+
if (getCaptureRenderer(scene)) {
|
|
821
|
+
throw new Error('Metric RGB-D capture requires the standard Three renderer; custom capture renderers do not provide aligned depth.');
|
|
822
|
+
}
|
|
823
|
+
if (sessionRenderer.capabilities.logarithmicDepthBuffer || sessionRenderer.capabilities.reversedDepthBuffer) {
|
|
824
|
+
throw new Error('Metric RGB-D capture does not support logarithmic or reversed depth buffers.');
|
|
825
|
+
}
|
|
826
|
+
if (!camera.projectionMatrix.elements.every(Number.isFinite) ||
|
|
827
|
+
!Number.isFinite(camera.projectionMatrix.determinant()) || camera.projectionMatrix.determinant() === 0) {
|
|
828
|
+
throw new Error('Metric RGB-D capture requires a finite, invertible projection matrix.');
|
|
829
|
+
}
|
|
830
|
+
if (!depthReader) {
|
|
831
|
+
// Recreate the framebuffer if this session has already rendered RGB-only frames.
|
|
832
|
+
target.dispose();
|
|
833
|
+
target.depthTexture = new THREE.DepthTexture(width, height, THREE.UnsignedIntType);
|
|
834
|
+
depthReader = createMetricDepthReader(width, height, target.depthTexture);
|
|
835
|
+
}
|
|
836
|
+
const rgb = new Uint8Array(width * height * 3);
|
|
837
|
+
let depth!: Float32Array;
|
|
838
|
+
renderCaptureToTarget(captureOptions, () => {
|
|
839
|
+
sessionRenderer.readRenderTargetPixels(target, 0, 0, width, height, pixels);
|
|
840
|
+
for (let y = 0; y < height; y++) {
|
|
841
|
+
for (let x = 0; x < width; x++) {
|
|
842
|
+
const sx = captureOptions.flipX ? width - x - 1 : x;
|
|
843
|
+
const src = ((height - y - 1) * width + sx) * 4;
|
|
844
|
+
const dst = (y * width + x) * 3;
|
|
845
|
+
for (let c = 0; c < 3; c++) {
|
|
846
|
+
rgb[dst + c] = linearByteToSrgbByte(pixels[src + c]);
|
|
847
|
+
}
|
|
848
|
+
}
|
|
849
|
+
}
|
|
850
|
+
depth = depthReader!.read(sessionRenderer, camera, captureOptions.flipX ?? false);
|
|
851
|
+
});
|
|
852
|
+
return {
|
|
853
|
+
rgb, depth, width, height,
|
|
854
|
+
source: getCameraFrameCaptureSource(captureOptions),
|
|
855
|
+
origin: 'top-left', depthUnits: 'meters', depthConvention: 'camera-z',
|
|
856
|
+
flipX: captureOptions.flipX ?? false,
|
|
857
|
+
projectionMatrix: camera.projectionMatrix.toArray(),
|
|
858
|
+
cameraWorldMatrix: camera.matrixWorld.toArray(),
|
|
859
|
+
};
|
|
860
|
+
}
|
|
861
|
+
|
|
783
862
|
function captureTensor(
|
|
784
863
|
nextOptions: CameraFrameCaptureTensorOptions = {}
|
|
785
864
|
): CameraFrameTensorResult {
|
|
@@ -857,6 +936,7 @@ export function createCameraFrameCaptureSession(
|
|
|
857
936
|
captureAsync,
|
|
858
937
|
capturePixels,
|
|
859
938
|
captureTensor,
|
|
939
|
+
captureRGBD,
|
|
860
940
|
captureDataUrl(nextOptions = {}) {
|
|
861
941
|
const type = nextOptions.type ?? options.type ?? 'image/png';
|
|
862
942
|
const result = capture(nextOptions);
|
|
@@ -991,3 +1071,17 @@ export function captureCameraFrameTensor(
|
|
|
991
1071
|
session.dispose();
|
|
992
1072
|
}
|
|
993
1073
|
}
|
|
1074
|
+
/** One-shot aligned RGB-D observation. Use a session for repeated observations. */
|
|
1075
|
+
export function captureCameraRGBD(
|
|
1076
|
+
renderer: THREE.WebGLRenderer,
|
|
1077
|
+
scene: THREE.Scene,
|
|
1078
|
+
fallbackCamera: THREE.Camera,
|
|
1079
|
+
options: CameraFrameCaptureOptions = {}
|
|
1080
|
+
): CameraRGBDResult {
|
|
1081
|
+
const session = createCameraFrameCaptureSession(renderer, scene, fallbackCamera, options);
|
|
1082
|
+
try {
|
|
1083
|
+
return session.captureRGBD();
|
|
1084
|
+
} finally {
|
|
1085
|
+
session.dispose();
|
|
1086
|
+
}
|
|
1087
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/** @license SPDX-License-Identifier: Apache-2.0 */
|
|
2
|
+
import * as THREE from 'three';
|
|
3
|
+
|
|
4
|
+
/** Internal GPU readback adapter. Read the real depth attachment, preserving
|
|
5
|
+
* alpha tests, displacement, skinning, and depthWrite from the RGB render. */
|
|
6
|
+
export function createMetricDepthReader(width: number, height: number, texture: THREE.DepthTexture) {
|
|
7
|
+
const target = new THREE.WebGLRenderTarget(width, height, { depthBuffer: false });
|
|
8
|
+
const material = new THREE.ShaderMaterial({
|
|
9
|
+
uniforms: { depthTexture: { value: texture } },
|
|
10
|
+
vertexShader: `varying vec2 vUv;
|
|
11
|
+
void main() { vUv = uv; gl_Position = vec4(position.xy, 0.0, 1.0); }`,
|
|
12
|
+
fragmentShader: `#include <packing>
|
|
13
|
+
uniform sampler2D depthTexture;
|
|
14
|
+
varying vec2 vUv;
|
|
15
|
+
void main() { gl_FragColor = packDepthToRGBA(texture2D(depthTexture, vUv).r); }`,
|
|
16
|
+
depthTest: false, depthWrite: false, blending: THREE.NoBlending,
|
|
17
|
+
toneMapped: false,
|
|
18
|
+
});
|
|
19
|
+
const geometry = new THREE.PlaneGeometry(2, 2);
|
|
20
|
+
const scene = new THREE.Scene();
|
|
21
|
+
scene.add(new THREE.Mesh(geometry, material));
|
|
22
|
+
const screenCamera = new THREE.Camera();
|
|
23
|
+
const packed = new Uint8Array(width * height * 4);
|
|
24
|
+
return {
|
|
25
|
+
read(renderer: THREE.WebGLRenderer, camera: THREE.Camera, flipX: boolean) {
|
|
26
|
+
renderer.setRenderTarget(target);
|
|
27
|
+
renderer.clear();
|
|
28
|
+
renderer.render(scene, screenCamera);
|
|
29
|
+
renderer.readRenderTargetPixels(target, 0, 0, width, height, packed);
|
|
30
|
+
const result = new Float32Array(width * height);
|
|
31
|
+
const inverse = camera.projectionMatrixInverse.elements;
|
|
32
|
+
for (let y = 0; y < height; y++) {
|
|
33
|
+
for (let x = 0; x < width; x++) {
|
|
34
|
+
const sx = flipX ? width - x - 1 : x;
|
|
35
|
+
const sy = height - y - 1;
|
|
36
|
+
const offset = (sy * width + sx) * 4;
|
|
37
|
+
const r = packed[offset], g = packed[offset + 1], b = packed[offset + 2], a = packed[offset + 3];
|
|
38
|
+
if (r === 255 && g === 255 && b === 255 && a === 255) {
|
|
39
|
+
result[y * width + x] = Infinity;
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
// Mirrors Three's unpackRGBAToDepth (packing.glsl.js).
|
|
43
|
+
const d = r / 256 + g / 65536 + b / 16777216 + a / (255 * 16777216);
|
|
44
|
+
const nx = (sx + 0.5) / width * 2 - 1;
|
|
45
|
+
const ny = (sy + 0.5) / height * 2 - 1;
|
|
46
|
+
const nz = d * 2 - 1;
|
|
47
|
+
const z = inverse[2] * nx + inverse[6] * ny + inverse[10] * nz + inverse[14];
|
|
48
|
+
const w = inverse[3] * nx + inverse[7] * ny + inverse[11] * nz + inverse[15];
|
|
49
|
+
result[y * width + x] = -z / w;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return result;
|
|
53
|
+
},
|
|
54
|
+
dispose() { target.dispose(); material.dispose(); geometry.dispose(); },
|
|
55
|
+
};
|
|
56
|
+
}
|
package/src/types.ts
CHANGED
|
@@ -13,6 +13,7 @@ import type {
|
|
|
13
13
|
CameraFrameCaptureSession,
|
|
14
14
|
CameraFrameCaptureTensorOptions,
|
|
15
15
|
CameraFrameTensorResult,
|
|
16
|
+
CameraRGBDResult,
|
|
16
17
|
} from './rendering/cameraFrameCapture';
|
|
17
18
|
|
|
18
19
|
// ---- Register (type-safe named resources) ----
|
|
@@ -1548,6 +1549,8 @@ export interface MujocoSimAPI {
|
|
|
1548
1549
|
captureFrameBlob(options?: MujocoFrameCaptureOptions): Promise<FrameCaptureBlobResult>;
|
|
1549
1550
|
captureCameraFrame(options?: CameraFrameCaptureOptions): Promise<CameraFrameCaptureResult>;
|
|
1550
1551
|
captureCameraFrameBlob(options?: CameraFrameCaptureOptions): Promise<CameraFrameCaptureBlobResult>;
|
|
1552
|
+
/** Aligned sRGB + camera-axis depth in meters from one render. */
|
|
1553
|
+
captureCameraRGBD(options?: CameraFrameCaptureOptions): CameraRGBDResult;
|
|
1551
1554
|
/** Capture a camera frame straight into a policy image tensor (no canvas/PNG encode). */
|
|
1552
1555
|
captureCameraFrameTensor(options?: CameraFrameCaptureTensorOptions): CameraFrameTensorResult;
|
|
1553
1556
|
/**
|
|
@@ -1796,6 +1799,7 @@ export interface CameraFrameCaptureAPI {
|
|
|
1796
1799
|
captureBlob: (
|
|
1797
1800
|
options?: CameraFrameCaptureOptions
|
|
1798
1801
|
) => Promise<CameraFrameCaptureBlobResult>;
|
|
1802
|
+
captureRGBD: (options?: CameraFrameCaptureOptions) => Promise<CameraRGBDResult>;
|
|
1799
1803
|
reset: () => void;
|
|
1800
1804
|
}
|
|
1801
1805
|
|