mujoco-react 10.0.1 → 10.1.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/{chunk-QTCAVQS6.js → chunk-FEKBKHEN.js} +56 -5
- package/dist/chunk-FEKBKHEN.js.map +1 -0
- package/dist/index.d.ts +271 -19
- package/dist/index.js +1451 -409
- package/dist/index.js.map +1 -1
- package/dist/spark.d.ts +1 -1
- package/dist/spark.js +1 -1
- package/dist/{types-BaSMqJHT.d.ts → types-BHBNJubg.d.ts} +133 -2
- package/package.json +1 -1
- package/src/components/SceneRenderer.tsx +11 -4
- package/src/core/MujocoSimProvider.tsx +67 -6
- package/src/core/SceneLoader.ts +8 -2
- package/src/hooks/useContactHistory.ts +155 -0
- package/src/hooks/useControlWriter.ts +176 -0
- package/src/hooks/useNamedObservation.ts +42 -0
- package/src/hooks/usePolicy.ts +133 -10
- package/src/hooks/usePolicyCameraFrames.ts +162 -0
- package/src/hooks/usePose.ts +119 -0
- package/src/hooks/useRemotePolicy.ts +329 -0
- package/src/index.ts +81 -0
- package/src/policyCameraFrames.ts +213 -0
- package/src/policyControls.ts +87 -0
- package/src/policyObservation.ts +172 -0
- package/src/rendering/GeomBuilder.ts +73 -24
- package/src/rendering/cameraFrameCapture.ts +74 -2
- package/src/types.ts +151 -1
- package/dist/chunk-QTCAVQS6.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { withContacts, getContact, captureCameraFrame, captureCameraFrameBlob, createCameraFrameCaptureSession, CAPTURE_EXCLUDE_KEY } from './chunk-
|
|
2
|
-
export { 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-FEKBKHEN.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-FEKBKHEN.js';
|
|
3
3
|
import loadMujoco from '@mujoco/mujoco';
|
|
4
4
|
import defaultMujocoWasmUrl from '@mujoco/mujoco/mujoco.wasm?url';
|
|
5
5
|
import { createContext, forwardRef, useEffect, useContext, useState, useRef, 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
|
-
import * as
|
|
8
|
+
import * as THREE10 from 'three';
|
|
9
9
|
import { PivotControls } from '@react-three/drei';
|
|
10
10
|
|
|
11
11
|
var MujocoContext = createContext({
|
|
@@ -105,16 +105,16 @@ function MujocoProvider({
|
|
|
105
105
|
}
|
|
106
106
|
);
|
|
107
107
|
}
|
|
108
|
-
var CapsuleGeometry = class extends
|
|
108
|
+
var CapsuleGeometry = class extends THREE10.BufferGeometry {
|
|
109
109
|
parameters;
|
|
110
110
|
constructor(radius = 1, length = 1, capSegments = 4, radialSegments = 8) {
|
|
111
111
|
super();
|
|
112
112
|
this.type = "CapsuleGeometry";
|
|
113
113
|
this.parameters = { radius, length, capSegments, radialSegments };
|
|
114
|
-
const path = new
|
|
114
|
+
const path = new THREE10.Path();
|
|
115
115
|
path.absarc(0, -length / 2, radius, Math.PI * 1.5, 0, false);
|
|
116
116
|
path.absarc(0, length / 2, radius, 0, Math.PI * 0.5, false);
|
|
117
|
-
const latheGeometry = new
|
|
117
|
+
const latheGeometry = new THREE10.LatheGeometry(path.getPoints(capSegments), radialSegments);
|
|
118
118
|
const self = this;
|
|
119
119
|
self.setIndex(latheGeometry.getIndex());
|
|
120
120
|
self.setAttribute("position", latheGeometry.getAttribute("position"));
|
|
@@ -122,231 +122,6 @@ var CapsuleGeometry = class extends THREE11.BufferGeometry {
|
|
|
122
122
|
self.setAttribute("uv", latheGeometry.getAttribute("uv"));
|
|
123
123
|
}
|
|
124
124
|
};
|
|
125
|
-
var Reflector = class extends THREE11.Mesh {
|
|
126
|
-
isReflector = true;
|
|
127
|
-
camera;
|
|
128
|
-
reflectorPlane = new THREE11.Plane();
|
|
129
|
-
normal = new THREE11.Vector3();
|
|
130
|
-
reflectorWorldPosition = new THREE11.Vector3();
|
|
131
|
-
cameraWorldPosition = new THREE11.Vector3();
|
|
132
|
-
rotationMatrix = new THREE11.Matrix4();
|
|
133
|
-
lookAtPosition = new THREE11.Vector3(0, 0, -1);
|
|
134
|
-
clipPlane = new THREE11.Vector4();
|
|
135
|
-
view = new THREE11.Vector3();
|
|
136
|
-
target = new THREE11.Vector3();
|
|
137
|
-
q = new THREE11.Vector4();
|
|
138
|
-
textureMatrix = new THREE11.Matrix4();
|
|
139
|
-
virtualCamera;
|
|
140
|
-
renderTarget;
|
|
141
|
-
constructor(geometry, options = {}) {
|
|
142
|
-
super(geometry);
|
|
143
|
-
this.type = "Reflector";
|
|
144
|
-
this.camera = new THREE11.PerspectiveCamera();
|
|
145
|
-
const color = options.color !== void 0 ? new THREE11.Color(options.color) : new THREE11.Color(8355711);
|
|
146
|
-
const textureWidth = options.textureWidth || 512;
|
|
147
|
-
const textureHeight = options.textureHeight || 512;
|
|
148
|
-
const clipBias = options.clipBias || 0;
|
|
149
|
-
const multisample = options.multisample !== void 0 ? options.multisample : 4;
|
|
150
|
-
const blendTexture = options.texture || void 0;
|
|
151
|
-
const mixStrength = options.mixStrength !== void 0 ? options.mixStrength : 0.25;
|
|
152
|
-
this.virtualCamera = this.camera;
|
|
153
|
-
this.renderTarget = new THREE11.WebGLRenderTarget(textureWidth, textureHeight, {
|
|
154
|
-
samples: multisample,
|
|
155
|
-
type: THREE11.HalfFloatType
|
|
156
|
-
});
|
|
157
|
-
this.material = new THREE11.MeshPhysicalMaterial({
|
|
158
|
-
map: blendTexture,
|
|
159
|
-
color,
|
|
160
|
-
roughness: 0.5,
|
|
161
|
-
metalness: 0.1
|
|
162
|
-
});
|
|
163
|
-
this.material.onBeforeCompile = (shader) => {
|
|
164
|
-
shader.uniforms.tDiffuse = { value: this.renderTarget.texture };
|
|
165
|
-
shader.uniforms.textureMatrix = { value: this.textureMatrix };
|
|
166
|
-
shader.uniforms.mixStrength = { value: mixStrength };
|
|
167
|
-
const bodyStart = shader.vertexShader.indexOf("void main() {");
|
|
168
|
-
shader.vertexShader = "uniform mat4 textureMatrix;\nvarying vec4 vUvReflection;\n" + shader.vertexShader.slice(0, bodyStart) + shader.vertexShader.slice(bodyStart, -1) + " vUvReflection = textureMatrix * vec4( position, 1.0 );\n}";
|
|
169
|
-
const fragmentBodyStart = shader.fragmentShader.indexOf("void main() {");
|
|
170
|
-
shader.fragmentShader = "uniform sampler2D tDiffuse;\nuniform float mixStrength;\nvarying vec4 vUvReflection;\n" + shader.fragmentShader.slice(0, fragmentBodyStart) + shader.fragmentShader.slice(fragmentBodyStart, -1) + " vec4 reflectionColor = texture2DProj( tDiffuse, vUvReflection );\n gl_FragColor = vec4( mix( gl_FragColor.rgb, reflectionColor.rgb, mixStrength ), gl_FragColor.a );\n}";
|
|
171
|
-
};
|
|
172
|
-
this.receiveShadow = true;
|
|
173
|
-
this.onBeforeRender = (renderer, scene, camera) => {
|
|
174
|
-
this.reflectorWorldPosition.setFromMatrixPosition(this.matrixWorld);
|
|
175
|
-
this.cameraWorldPosition.setFromMatrixPosition(camera.matrixWorld);
|
|
176
|
-
this.rotationMatrix.extractRotation(this.matrixWorld);
|
|
177
|
-
this.normal.set(0, 0, 1);
|
|
178
|
-
this.normal.applyMatrix4(this.rotationMatrix);
|
|
179
|
-
this.view.subVectors(this.reflectorWorldPosition, this.cameraWorldPosition);
|
|
180
|
-
if (this.view.dot(this.normal) > 0) return;
|
|
181
|
-
this.view.reflect(this.normal).negate();
|
|
182
|
-
this.view.add(this.reflectorWorldPosition);
|
|
183
|
-
this.rotationMatrix.extractRotation(camera.matrixWorld);
|
|
184
|
-
this.lookAtPosition.set(0, 0, -1);
|
|
185
|
-
this.lookAtPosition.applyMatrix4(this.rotationMatrix);
|
|
186
|
-
this.lookAtPosition.add(this.cameraWorldPosition);
|
|
187
|
-
this.target.subVectors(this.reflectorWorldPosition, this.lookAtPosition);
|
|
188
|
-
this.target.reflect(this.normal).negate();
|
|
189
|
-
this.target.add(this.reflectorWorldPosition);
|
|
190
|
-
this.virtualCamera.position.copy(this.view);
|
|
191
|
-
this.virtualCamera.up.set(0, 1, 0);
|
|
192
|
-
this.virtualCamera.up.applyMatrix4(this.rotationMatrix);
|
|
193
|
-
this.virtualCamera.up.reflect(this.normal);
|
|
194
|
-
this.virtualCamera.lookAt(this.target);
|
|
195
|
-
this.virtualCamera.far = camera.far;
|
|
196
|
-
this.virtualCamera.updateMatrixWorld();
|
|
197
|
-
this.virtualCamera.projectionMatrix.copy(camera.projectionMatrix);
|
|
198
|
-
this.textureMatrix.set(
|
|
199
|
-
0.5,
|
|
200
|
-
0,
|
|
201
|
-
0,
|
|
202
|
-
0.5,
|
|
203
|
-
0,
|
|
204
|
-
0.5,
|
|
205
|
-
0,
|
|
206
|
-
0.5,
|
|
207
|
-
0,
|
|
208
|
-
0,
|
|
209
|
-
0.5,
|
|
210
|
-
0.5,
|
|
211
|
-
0,
|
|
212
|
-
0,
|
|
213
|
-
0,
|
|
214
|
-
1
|
|
215
|
-
);
|
|
216
|
-
this.textureMatrix.multiply(this.virtualCamera.projectionMatrix);
|
|
217
|
-
this.textureMatrix.multiply(this.virtualCamera.matrixWorldInverse);
|
|
218
|
-
this.textureMatrix.multiply(this.matrixWorld);
|
|
219
|
-
this.reflectorPlane.setFromNormalAndCoplanarPoint(this.normal, this.reflectorWorldPosition);
|
|
220
|
-
this.reflectorPlane.applyMatrix4(this.virtualCamera.matrixWorldInverse);
|
|
221
|
-
this.clipPlane.set(this.reflectorPlane.normal.x, this.reflectorPlane.normal.y, this.reflectorPlane.normal.z, this.reflectorPlane.constant);
|
|
222
|
-
const projectionMatrix = this.virtualCamera.projectionMatrix;
|
|
223
|
-
this.q.x = (Math.sign(this.clipPlane.x) + projectionMatrix.elements[8]) / projectionMatrix.elements[0];
|
|
224
|
-
this.q.y = (Math.sign(this.clipPlane.y) + projectionMatrix.elements[9]) / projectionMatrix.elements[5];
|
|
225
|
-
this.q.z = -1;
|
|
226
|
-
this.q.w = (1 + projectionMatrix.elements[10]) / projectionMatrix.elements[14];
|
|
227
|
-
this.clipPlane.multiplyScalar(2 / this.clipPlane.dot(this.q));
|
|
228
|
-
projectionMatrix.elements[2] = this.clipPlane.x;
|
|
229
|
-
projectionMatrix.elements[6] = this.clipPlane.y;
|
|
230
|
-
projectionMatrix.elements[10] = this.clipPlane.z + 1 - clipBias;
|
|
231
|
-
projectionMatrix.elements[14] = this.clipPlane.w;
|
|
232
|
-
this.visible = false;
|
|
233
|
-
const currentRenderTarget = renderer.getRenderTarget();
|
|
234
|
-
const currentXrEnabled = renderer.xr.enabled;
|
|
235
|
-
const currentShadowAutoUpdate = renderer.shadowMap.autoUpdate;
|
|
236
|
-
renderer.xr.enabled = false;
|
|
237
|
-
renderer.shadowMap.autoUpdate = false;
|
|
238
|
-
renderer.setRenderTarget(this.renderTarget);
|
|
239
|
-
renderer.state.buffers.depth.setMask(true);
|
|
240
|
-
if (renderer.autoClear === false) renderer.clear();
|
|
241
|
-
renderer.render(scene, this.virtualCamera);
|
|
242
|
-
renderer.xr.enabled = currentXrEnabled;
|
|
243
|
-
renderer.shadowMap.autoUpdate = currentShadowAutoUpdate;
|
|
244
|
-
renderer.setRenderTarget(currentRenderTarget);
|
|
245
|
-
const viewport = camera.viewport;
|
|
246
|
-
if (viewport !== void 0) {
|
|
247
|
-
renderer.state.viewport(viewport);
|
|
248
|
-
}
|
|
249
|
-
this.visible = true;
|
|
250
|
-
};
|
|
251
|
-
}
|
|
252
|
-
getRenderTarget() {
|
|
253
|
-
return this.renderTarget;
|
|
254
|
-
}
|
|
255
|
-
dispose() {
|
|
256
|
-
this.renderTarget.dispose();
|
|
257
|
-
const mesh = this;
|
|
258
|
-
if (Array.isArray(mesh.material)) {
|
|
259
|
-
mesh.material.forEach((m) => m.dispose());
|
|
260
|
-
} else {
|
|
261
|
-
mesh.material.dispose();
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
|
-
};
|
|
265
|
-
|
|
266
|
-
// src/rendering/GeomBuilder.ts
|
|
267
|
-
var GeomBuilder = class {
|
|
268
|
-
mujoco;
|
|
269
|
-
constructor(mujoco) {
|
|
270
|
-
this.mujoco = mujoco;
|
|
271
|
-
}
|
|
272
|
-
/**
|
|
273
|
-
* Creates a Three.js Object3D (usually a Mesh) for a specific geometry in the MuJoCo model.
|
|
274
|
-
* Returns null if the geometry shouldn't be rendered (e.g., invisible collision triggers).
|
|
275
|
-
*/
|
|
276
|
-
create(mjModel, g) {
|
|
277
|
-
if (mjModel.geom_group[g] === 3) return null;
|
|
278
|
-
const type = mjModel.geom_type[g];
|
|
279
|
-
const size = mjModel.geom_size.subarray(g * 3, g * 3 + 3);
|
|
280
|
-
const pos = mjModel.geom_pos.subarray(g * 3, g * 3 + 3);
|
|
281
|
-
const quat = mjModel.geom_quat.subarray(g * 4, g * 4 + 4);
|
|
282
|
-
const matId = mjModel.geom_matid[g];
|
|
283
|
-
const color = new THREE11.Color(16777215);
|
|
284
|
-
let opacity = 1;
|
|
285
|
-
if (matId >= 0) {
|
|
286
|
-
const rgba = mjModel.mat_rgba.subarray(matId * 4, matId * 4 + 4);
|
|
287
|
-
color.setRGB(rgba[0], rgba[1], rgba[2]);
|
|
288
|
-
opacity = rgba[3];
|
|
289
|
-
} else {
|
|
290
|
-
const rgba = mjModel.geom_rgba.subarray(g * 4, g * 4 + 4);
|
|
291
|
-
color.setRGB(rgba[0], rgba[1], rgba[2]);
|
|
292
|
-
opacity = rgba[3];
|
|
293
|
-
}
|
|
294
|
-
const MG = this.mujoco.mjtGeom;
|
|
295
|
-
let geo = null;
|
|
296
|
-
const getVal = (v) => v?.value ?? v;
|
|
297
|
-
if (type === getVal(MG.mjGEOM_PLANE)) {
|
|
298
|
-
geo = new THREE11.PlaneGeometry(size[0] * 2 || 5, size[1] * 2 || 5);
|
|
299
|
-
} else if (type === getVal(MG.mjGEOM_SPHERE)) {
|
|
300
|
-
geo = new THREE11.SphereGeometry(size[0], 24, 24);
|
|
301
|
-
} else if (type === getVal(MG.mjGEOM_CAPSULE)) {
|
|
302
|
-
geo = new CapsuleGeometry(size[0], size[1] * 2, 24, 12);
|
|
303
|
-
geo.rotateX(Math.PI / 2);
|
|
304
|
-
} else if (type === getVal(MG.mjGEOM_BOX)) {
|
|
305
|
-
geo = new THREE11.BoxGeometry(size[0] * 2, size[1] * 2, size[2] * 2);
|
|
306
|
-
} else if (type === getVal(MG.mjGEOM_CYLINDER)) {
|
|
307
|
-
geo = new THREE11.CylinderGeometry(size[0], size[0], size[1] * 2, 24);
|
|
308
|
-
geo.rotateX(Math.PI / 2);
|
|
309
|
-
} else if (type === getVal(MG.mjGEOM_MESH)) {
|
|
310
|
-
const mId = mjModel.geom_dataid[g];
|
|
311
|
-
const vAdr = mjModel.mesh_vertadr[mId];
|
|
312
|
-
const vNum = mjModel.mesh_vertnum[mId];
|
|
313
|
-
const fAdr = mjModel.mesh_faceadr[mId];
|
|
314
|
-
const fNum = mjModel.mesh_facenum[mId];
|
|
315
|
-
geo = new THREE11.BufferGeometry();
|
|
316
|
-
geo.setAttribute("position", new THREE11.Float32BufferAttribute(mjModel.mesh_vert.subarray(vAdr * 3, (vAdr + vNum) * 3), 3));
|
|
317
|
-
geo.setIndex(Array.from(mjModel.mesh_face.subarray(fAdr * 3, (fAdr + fNum) * 3)));
|
|
318
|
-
geo.computeVertexNormals();
|
|
319
|
-
}
|
|
320
|
-
if (geo) {
|
|
321
|
-
let mesh;
|
|
322
|
-
if (type === getVal(MG.mjGEOM_PLANE)) {
|
|
323
|
-
mesh = new Reflector(geo, {
|
|
324
|
-
clipBias: 3e-3,
|
|
325
|
-
textureWidth: 1024,
|
|
326
|
-
textureHeight: 1024,
|
|
327
|
-
color,
|
|
328
|
-
mixStrength: 0.25
|
|
329
|
-
});
|
|
330
|
-
} else {
|
|
331
|
-
mesh = new THREE11.Mesh(geo, new THREE11.MeshStandardMaterial({
|
|
332
|
-
color,
|
|
333
|
-
transparent: opacity < 1,
|
|
334
|
-
opacity,
|
|
335
|
-
roughness: 0.6,
|
|
336
|
-
metalness: 0.2
|
|
337
|
-
}));
|
|
338
|
-
mesh.castShadow = true;
|
|
339
|
-
mesh.receiveShadow = true;
|
|
340
|
-
}
|
|
341
|
-
mesh.position.set(pos[0], pos[1], pos[2]);
|
|
342
|
-
mesh.quaternion.set(quat[1], quat[2], quat[3], quat[0]);
|
|
343
|
-
mesh.userData.bodyID = mjModel.geom_bodyid[g];
|
|
344
|
-
mesh.userData.geomID = g;
|
|
345
|
-
return mesh;
|
|
346
|
-
}
|
|
347
|
-
return null;
|
|
348
|
-
}
|
|
349
|
-
};
|
|
350
125
|
|
|
351
126
|
// src/core/SceneLoader.ts
|
|
352
127
|
var JOINT_TYPE_NAMES = {
|
|
@@ -704,8 +479,10 @@ function createContiguousControlGroup(mjModel, count) {
|
|
|
704
479
|
}
|
|
705
480
|
function sceneObjectToXml(obj) {
|
|
706
481
|
const joint = obj.freejoint ? "<freejoint/>" : "";
|
|
482
|
+
const geomName = obj.geomName ?? `${obj.name}_geom`;
|
|
707
483
|
const pos = obj.position.map((v) => v.toFixed(3)).join(" ");
|
|
708
|
-
const
|
|
484
|
+
const sizeValues = obj.type === "sphere" ? obj.size.slice(0, 1) : obj.type === "cylinder" ? obj.size.slice(0, 2) : obj.size;
|
|
485
|
+
const size = sizeValues.map((v) => v.toFixed(3)).join(" ");
|
|
709
486
|
const rgba = obj.rgba.join(" ");
|
|
710
487
|
const mass = obj.mass ? ` mass="${obj.mass}"` : "";
|
|
711
488
|
const friction = obj.friction ? ` friction="${obj.friction}"` : "";
|
|
@@ -713,7 +490,7 @@ function sceneObjectToXml(obj) {
|
|
|
713
490
|
const solimp = obj.solimp ? ` solimp="${obj.solimp}"` : "";
|
|
714
491
|
const condim = obj.condim ? ` condim="${obj.condim}"` : "";
|
|
715
492
|
const group = obj.group !== void 0 ? ` group="${obj.group}"` : "";
|
|
716
|
-
return `<body name="${obj.name}" pos="${pos}">${joint}<geom type="${obj.type}" size="${size}" rgba="${rgba}" contype="1" conaffinity="1"${mass}${friction}${solref}${solimp}${condim}${group}/></body>`;
|
|
493
|
+
return `<body name="${obj.name}" pos="${pos}">${joint}<geom name="${geomName}" type="${obj.type}" size="${size}" rgba="${rgba}" contype="1" conaffinity="1"${mass}${friction}${solref}${solimp}${condim}${group}/></body>`;
|
|
717
494
|
}
|
|
718
495
|
function ensureDir(mujoco, fname) {
|
|
719
496
|
const dirParts = fname.split("/");
|
|
@@ -1112,6 +889,137 @@ function collectDependencyPaths(xmlString, currentFile, parser) {
|
|
|
1112
889
|
});
|
|
1113
890
|
return paths;
|
|
1114
891
|
}
|
|
892
|
+
|
|
893
|
+
// src/rendering/GeomBuilder.ts
|
|
894
|
+
var GeomBuilder = class {
|
|
895
|
+
mujoco;
|
|
896
|
+
textureCache = /* @__PURE__ */ new Map();
|
|
897
|
+
constructor(mujoco) {
|
|
898
|
+
this.mujoco = mujoco;
|
|
899
|
+
}
|
|
900
|
+
getMaterialTexture(mjModel, matId) {
|
|
901
|
+
if (matId < 0 || !mjModel.mat_texid || !mjModel.tex_data) return null;
|
|
902
|
+
const materialCount = Math.max(1, Math.floor(mjModel.mat_rgba.length / 4));
|
|
903
|
+
const textureRoles = Math.max(1, Math.floor(mjModel.mat_texid.length / materialCount));
|
|
904
|
+
let texId = -1;
|
|
905
|
+
for (let role = 0; role < textureRoles; role += 1) {
|
|
906
|
+
const candidate = mjModel.mat_texid[matId * textureRoles + role];
|
|
907
|
+
if (candidate >= 0) {
|
|
908
|
+
texId = candidate;
|
|
909
|
+
break;
|
|
910
|
+
}
|
|
911
|
+
}
|
|
912
|
+
if (texId < 0) return null;
|
|
913
|
+
const cached = this.textureCache.get(texId);
|
|
914
|
+
if (cached) return cached;
|
|
915
|
+
const width = Number(mjModel.tex_width[texId]);
|
|
916
|
+
const height = Number(mjModel.tex_height[texId]);
|
|
917
|
+
const channels = Number(mjModel.tex_nchannel[texId]);
|
|
918
|
+
const offset = Number(mjModel.tex_adr[texId]);
|
|
919
|
+
if (width <= 0 || height <= 0 || channels <= 0 || offset < 0) return null;
|
|
920
|
+
const source = mjModel.tex_data.subarray(offset, offset + width * height * channels);
|
|
921
|
+
const rgba = new Uint8Array(width * height * 4);
|
|
922
|
+
for (let i = 0, j = 0; i < width * height; i += 1, j += channels) {
|
|
923
|
+
const r = source[j] ?? 255;
|
|
924
|
+
const g = channels > 1 ? source[j + 1] : r;
|
|
925
|
+
const b = channels > 2 ? source[j + 2] : r;
|
|
926
|
+
const a = channels > 3 ? source[j + 3] : 255;
|
|
927
|
+
const out = i * 4;
|
|
928
|
+
rgba[out] = r;
|
|
929
|
+
rgba[out + 1] = g;
|
|
930
|
+
rgba[out + 2] = b;
|
|
931
|
+
rgba[out + 3] = a;
|
|
932
|
+
}
|
|
933
|
+
const texture = new THREE10.DataTexture(rgba, width, height, THREE10.RGBAFormat);
|
|
934
|
+
texture.colorSpace = THREE10.LinearSRGBColorSpace;
|
|
935
|
+
texture.wrapS = THREE10.RepeatWrapping;
|
|
936
|
+
texture.wrapT = THREE10.RepeatWrapping;
|
|
937
|
+
texture.flipY = true;
|
|
938
|
+
const repeatOffset = matId * 2;
|
|
939
|
+
const repeatS = mjModel.mat_texrepeat?.[repeatOffset] ?? 1;
|
|
940
|
+
const repeatT = mjModel.mat_texrepeat?.[repeatOffset + 1] ?? 1;
|
|
941
|
+
texture.repeat.set(repeatS || 1, repeatT || 1);
|
|
942
|
+
texture.needsUpdate = true;
|
|
943
|
+
this.textureCache.set(texId, texture);
|
|
944
|
+
return texture;
|
|
945
|
+
}
|
|
946
|
+
/**
|
|
947
|
+
* Creates a Three.js Object3D (usually a Mesh) for a specific geometry in the MuJoCo model.
|
|
948
|
+
* Returns null if the geometry shouldn't be rendered (e.g., invisible collision triggers).
|
|
949
|
+
*/
|
|
950
|
+
create(mjModel, g) {
|
|
951
|
+
if (mjModel.geom_group[g] === 3) return null;
|
|
952
|
+
const type = mjModel.geom_type[g];
|
|
953
|
+
const size = mjModel.geom_size.subarray(g * 3, g * 3 + 3);
|
|
954
|
+
const pos = mjModel.geom_pos.subarray(g * 3, g * 3 + 3);
|
|
955
|
+
const quat = mjModel.geom_quat.subarray(g * 4, g * 4 + 4);
|
|
956
|
+
const matId = mjModel.geom_matid[g];
|
|
957
|
+
const color = new THREE10.Color(16777215);
|
|
958
|
+
const map = this.getMaterialTexture(mjModel, matId);
|
|
959
|
+
let opacity = 1;
|
|
960
|
+
if (matId >= 0) {
|
|
961
|
+
const rgba = mjModel.mat_rgba.subarray(matId * 4, matId * 4 + 4);
|
|
962
|
+
color.setRGB(rgba[0], rgba[1], rgba[2]);
|
|
963
|
+
opacity = rgba[3];
|
|
964
|
+
} else {
|
|
965
|
+
const rgba = mjModel.geom_rgba.subarray(g * 4, g * 4 + 4);
|
|
966
|
+
color.setRGB(rgba[0], rgba[1], rgba[2]);
|
|
967
|
+
opacity = rgba[3];
|
|
968
|
+
}
|
|
969
|
+
const MG = this.mujoco.mjtGeom;
|
|
970
|
+
let geo = null;
|
|
971
|
+
const getVal = (v) => v?.value ?? v;
|
|
972
|
+
if (type === getVal(MG.mjGEOM_PLANE)) {
|
|
973
|
+
geo = new THREE10.PlaneGeometry(size[0] * 2 || 5, size[1] * 2 || 5);
|
|
974
|
+
} else if (type === getVal(MG.mjGEOM_SPHERE)) {
|
|
975
|
+
geo = new THREE10.SphereGeometry(size[0], 24, 24);
|
|
976
|
+
} else if (type === getVal(MG.mjGEOM_CAPSULE)) {
|
|
977
|
+
geo = new CapsuleGeometry(size[0], size[1] * 2, 24, 12);
|
|
978
|
+
geo.rotateX(Math.PI / 2);
|
|
979
|
+
} else if (type === getVal(MG.mjGEOM_BOX)) {
|
|
980
|
+
geo = new THREE10.BoxGeometry(size[0] * 2, size[1] * 2, size[2] * 2);
|
|
981
|
+
} else if (type === getVal(MG.mjGEOM_CYLINDER)) {
|
|
982
|
+
geo = new THREE10.CylinderGeometry(size[0], size[0], size[1] * 2, 24);
|
|
983
|
+
geo.rotateX(Math.PI / 2);
|
|
984
|
+
} else if (type === getVal(MG.mjGEOM_MESH)) {
|
|
985
|
+
const mId = mjModel.geom_dataid[g];
|
|
986
|
+
const vAdr = mjModel.mesh_vertadr[mId];
|
|
987
|
+
const vNum = mjModel.mesh_vertnum[mId];
|
|
988
|
+
const fAdr = mjModel.mesh_faceadr[mId];
|
|
989
|
+
const fNum = mjModel.mesh_facenum[mId];
|
|
990
|
+
geo = new THREE10.BufferGeometry();
|
|
991
|
+
geo.setAttribute("position", new THREE10.Float32BufferAttribute(mjModel.mesh_vert.subarray(vAdr * 3, (vAdr + vNum) * 3), 3));
|
|
992
|
+
geo.setIndex(Array.from(mjModel.mesh_face.subarray(fAdr * 3, (fAdr + fNum) * 3)));
|
|
993
|
+
geo.computeVertexNormals();
|
|
994
|
+
}
|
|
995
|
+
if (geo) {
|
|
996
|
+
const isPlane = type === getVal(MG.mjGEOM_PLANE);
|
|
997
|
+
const materialMap = isPlane && map ? map.clone() : map;
|
|
998
|
+
if (isPlane && materialMap) {
|
|
999
|
+
materialMap.repeat.multiplyScalar(2.5);
|
|
1000
|
+
materialMap.needsUpdate = true;
|
|
1001
|
+
}
|
|
1002
|
+
const mesh = new THREE10.Mesh(geo, new THREE10.MeshStandardMaterial({
|
|
1003
|
+
color,
|
|
1004
|
+
map: materialMap,
|
|
1005
|
+
transparent: opacity < 1,
|
|
1006
|
+
opacity,
|
|
1007
|
+
roughness: 0.6,
|
|
1008
|
+
metalness: 0
|
|
1009
|
+
}));
|
|
1010
|
+
mesh.castShadow = type !== getVal(MG.mjGEOM_PLANE);
|
|
1011
|
+
mesh.receiveShadow = true;
|
|
1012
|
+
mesh.position.set(pos[0], pos[1], pos[2]);
|
|
1013
|
+
mesh.quaternion.set(quat[1], quat[2], quat[3], quat[0]);
|
|
1014
|
+
mesh.userData.bodyID = mjModel.geom_bodyid[g];
|
|
1015
|
+
mesh.userData.geomID = g;
|
|
1016
|
+
mesh.userData.geomGroup = mjModel.geom_group[g];
|
|
1017
|
+
mesh.userData.geomName = getName(mjModel, mjModel.name_geomadr[g]);
|
|
1018
|
+
return mesh;
|
|
1019
|
+
}
|
|
1020
|
+
return null;
|
|
1021
|
+
}
|
|
1022
|
+
};
|
|
1115
1023
|
function SceneRenderer(props) {
|
|
1116
1024
|
const {
|
|
1117
1025
|
mjModelRef,
|
|
@@ -1142,7 +1050,7 @@ function SceneRenderer(props) {
|
|
|
1142
1050
|
}
|
|
1143
1051
|
const refs = [];
|
|
1144
1052
|
for (let i = 0; i < model.nbody; i++) {
|
|
1145
|
-
const bodyGroup = new
|
|
1053
|
+
const bodyGroup = new THREE10.Group();
|
|
1146
1054
|
bodyGroup.userData.bodyID = i;
|
|
1147
1055
|
const bodyName = getName(model, model.name_bodyadr[i]);
|
|
1148
1056
|
if (!hiddenBodiesRef.current.has(bodyName)) {
|
|
@@ -1158,7 +1066,7 @@ function SceneRenderer(props) {
|
|
|
1158
1066
|
}
|
|
1159
1067
|
bodyRefs.current = refs;
|
|
1160
1068
|
}, [status, geomBuilder, mjModelRef]);
|
|
1161
|
-
|
|
1069
|
+
const syncBodiesToData = useCallback(() => {
|
|
1162
1070
|
const data = mjDataRef.current;
|
|
1163
1071
|
if (!data) return;
|
|
1164
1072
|
const bodies = bodyRefs.current;
|
|
@@ -1171,9 +1079,9 @@ function SceneRenderer(props) {
|
|
|
1171
1079
|
const alpha = interpolation.alpha;
|
|
1172
1080
|
const i3 = i * 3;
|
|
1173
1081
|
ref.position.set(
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1082
|
+
THREE10.MathUtils.lerp(interpolation.previousXpos[i3], interpolation.currentXpos[i3], alpha),
|
|
1083
|
+
THREE10.MathUtils.lerp(interpolation.previousXpos[i3 + 1], interpolation.currentXpos[i3 + 1], alpha),
|
|
1084
|
+
THREE10.MathUtils.lerp(interpolation.previousXpos[i3 + 2], interpolation.currentXpos[i3 + 2], alpha)
|
|
1177
1085
|
);
|
|
1178
1086
|
const i4 = i * 4;
|
|
1179
1087
|
_previousQuat.set(
|
|
@@ -1203,12 +1111,17 @@ function SceneRenderer(props) {
|
|
|
1203
1111
|
);
|
|
1204
1112
|
}
|
|
1205
1113
|
}
|
|
1206
|
-
});
|
|
1114
|
+
}, [interpolateRef, interpolationStateRef, mjDataRef]);
|
|
1115
|
+
useFrame(syncBodiesToData);
|
|
1207
1116
|
return /* @__PURE__ */ jsx(
|
|
1208
1117
|
"group",
|
|
1209
1118
|
{
|
|
1210
1119
|
...props,
|
|
1211
1120
|
ref: groupRef,
|
|
1121
|
+
userData: {
|
|
1122
|
+
...props.userData,
|
|
1123
|
+
[CAMERA_FRAME_CAPTURE_PRE_RENDER_USER_DATA_KEY]: syncBodiesToData
|
|
1124
|
+
},
|
|
1212
1125
|
onDoubleClick: (e) => {
|
|
1213
1126
|
if (typeof props.onDoubleClick === "function") props.onDoubleClick(e);
|
|
1214
1127
|
e.stopPropagation();
|
|
@@ -1228,8 +1141,8 @@ function SceneRenderer(props) {
|
|
|
1228
1141
|
}
|
|
1229
1142
|
);
|
|
1230
1143
|
}
|
|
1231
|
-
var _previousQuat = new
|
|
1232
|
-
var _currentQuat = new
|
|
1144
|
+
var _previousQuat = new THREE10.Quaternion();
|
|
1145
|
+
var _currentQuat = new THREE10.Quaternion();
|
|
1233
1146
|
function isTargetRef(target) {
|
|
1234
1147
|
return Boolean(target && typeof target === "object" && "current" in target);
|
|
1235
1148
|
}
|
|
@@ -1810,8 +1723,8 @@ var _applyPoint = new Float64Array(3);
|
|
|
1810
1723
|
var _rayPnt = new Float64Array(3);
|
|
1811
1724
|
var _rayVec = new Float64Array(3);
|
|
1812
1725
|
var _rayGeomId = new Int32Array(1);
|
|
1813
|
-
var _projRaycaster = new
|
|
1814
|
-
var _projNdc = new
|
|
1726
|
+
var _projRaycaster = new THREE10.Raycaster();
|
|
1727
|
+
var _projNdc = new THREE10.Vector2();
|
|
1815
1728
|
function waitForNextAnimationFrame2() {
|
|
1816
1729
|
return new Promise((resolve) => {
|
|
1817
1730
|
requestAnimationFrame(() => resolve());
|
|
@@ -1836,7 +1749,7 @@ function quaternionFromMujocoQuat(values, offset) {
|
|
|
1836
1749
|
];
|
|
1837
1750
|
}
|
|
1838
1751
|
function quaternionFromXmat(values, offset) {
|
|
1839
|
-
const matrix = new
|
|
1752
|
+
const matrix = new THREE10.Matrix4();
|
|
1840
1753
|
matrix.set(
|
|
1841
1754
|
values[offset],
|
|
1842
1755
|
values[offset + 1],
|
|
@@ -1855,13 +1768,49 @@ function quaternionFromXmat(values, offset) {
|
|
|
1855
1768
|
0,
|
|
1856
1769
|
1
|
|
1857
1770
|
);
|
|
1858
|
-
const quaternion = new
|
|
1771
|
+
const quaternion = new THREE10.Quaternion().setFromRotationMatrix(matrix);
|
|
1859
1772
|
return [quaternion.x, quaternion.y, quaternion.z, quaternion.w];
|
|
1860
1773
|
}
|
|
1861
1774
|
function omitResolvedCameraSelectors(options) {
|
|
1862
1775
|
const { cameraName, siteName, bodyName, ...rest } = options;
|
|
1863
1776
|
return rest;
|
|
1864
1777
|
}
|
|
1778
|
+
function vector3FromCaptureValue(value) {
|
|
1779
|
+
return value instanceof THREE10.Vector3 ? value.clone() : new THREE10.Vector3(value[0], value[1], value[2]);
|
|
1780
|
+
}
|
|
1781
|
+
function quaternionFromCaptureValue(value) {
|
|
1782
|
+
return value instanceof THREE10.Quaternion ? value.clone() : new THREE10.Quaternion(value[0], value[1], value[2], value[3]);
|
|
1783
|
+
}
|
|
1784
|
+
function applyMountedCameraPoseOffsets(options, position, quaternion) {
|
|
1785
|
+
const resolvedPosition = new THREE10.Vector3(position[0], position[1], position[2]);
|
|
1786
|
+
const resolvedQuaternion = new THREE10.Quaternion(
|
|
1787
|
+
quaternion[0],
|
|
1788
|
+
quaternion[1],
|
|
1789
|
+
quaternion[2],
|
|
1790
|
+
quaternion[3]
|
|
1791
|
+
);
|
|
1792
|
+
if (options.positionOffset) {
|
|
1793
|
+
resolvedPosition.add(
|
|
1794
|
+
vector3FromCaptureValue(options.positionOffset).applyQuaternion(resolvedQuaternion)
|
|
1795
|
+
);
|
|
1796
|
+
}
|
|
1797
|
+
if (options.quaternionOffset) {
|
|
1798
|
+
resolvedQuaternion.multiply(quaternionFromCaptureValue(options.quaternionOffset)).normalize();
|
|
1799
|
+
}
|
|
1800
|
+
return {
|
|
1801
|
+
position: [
|
|
1802
|
+
resolvedPosition.x,
|
|
1803
|
+
resolvedPosition.y,
|
|
1804
|
+
resolvedPosition.z
|
|
1805
|
+
],
|
|
1806
|
+
quaternion: [
|
|
1807
|
+
resolvedQuaternion.x,
|
|
1808
|
+
resolvedQuaternion.y,
|
|
1809
|
+
resolvedQuaternion.z,
|
|
1810
|
+
resolvedQuaternion.w
|
|
1811
|
+
]
|
|
1812
|
+
};
|
|
1813
|
+
}
|
|
1865
1814
|
function countMountedCameraSelectors(options) {
|
|
1866
1815
|
return Number(Boolean(options.cameraName)) + Number(Boolean(options.siteName)) + Number(Boolean(options.bodyName));
|
|
1867
1816
|
}
|
|
@@ -2553,10 +2502,10 @@ function MujocoSimProvider({
|
|
|
2553
2502
|
`MuJoCo camera "${options.cameraName}" does not expose a capture pose.`
|
|
2554
2503
|
);
|
|
2555
2504
|
}
|
|
2505
|
+
const pose = applyMountedCameraPoseOffsets(options, position, quaternion);
|
|
2556
2506
|
return {
|
|
2557
2507
|
...baseOptions,
|
|
2558
|
-
|
|
2559
|
-
quaternion,
|
|
2508
|
+
...pose,
|
|
2560
2509
|
fov: options.fov ?? model.cam_fovy?.[cameraId],
|
|
2561
2510
|
source: { kind: "mujoco-camera", cameraName: options.cameraName }
|
|
2562
2511
|
};
|
|
@@ -2566,10 +2515,14 @@ function MujocoSimProvider({
|
|
|
2566
2515
|
if (siteId < 0) {
|
|
2567
2516
|
throw new Error(`MuJoCo site "${options.siteName}" was not found.`);
|
|
2568
2517
|
}
|
|
2518
|
+
const pose = applyMountedCameraPoseOffsets(
|
|
2519
|
+
options,
|
|
2520
|
+
vector3FromArray(data.site_xpos, siteId * 3),
|
|
2521
|
+
quaternionFromXmat(data.site_xmat, siteId * 9)
|
|
2522
|
+
);
|
|
2569
2523
|
return {
|
|
2570
2524
|
...baseOptions,
|
|
2571
|
-
|
|
2572
|
-
quaternion: quaternionFromXmat(data.site_xmat, siteId * 9),
|
|
2525
|
+
...pose,
|
|
2573
2526
|
source: { kind: "mujoco-site", siteName: options.siteName }
|
|
2574
2527
|
};
|
|
2575
2528
|
}
|
|
@@ -2583,10 +2536,14 @@ function MujocoSimProvider({
|
|
|
2583
2536
|
`MuJoCo body "${options.bodyName}" does not expose world orientation data.`
|
|
2584
2537
|
);
|
|
2585
2538
|
}
|
|
2539
|
+
const pose = applyMountedCameraPoseOffsets(
|
|
2540
|
+
options,
|
|
2541
|
+
vector3FromArray(data.xpos, bodyId * 3),
|
|
2542
|
+
quaternionFromXmat(data.xmat, bodyId * 9)
|
|
2543
|
+
);
|
|
2586
2544
|
return {
|
|
2587
2545
|
...baseOptions,
|
|
2588
|
-
|
|
2589
|
-
quaternion: quaternionFromXmat(data.xmat, bodyId * 9),
|
|
2546
|
+
...pose,
|
|
2590
2547
|
source: { kind: "mujoco-body", bodyName: options.bodyName }
|
|
2591
2548
|
};
|
|
2592
2549
|
}
|
|
@@ -2633,7 +2590,7 @@ function MujocoSimProvider({
|
|
|
2633
2590
|
const geomId = _rayGeomId[0];
|
|
2634
2591
|
const bodyId = geomId >= 0 ? model.geom_bodyid[geomId] : -1;
|
|
2635
2592
|
return {
|
|
2636
|
-
point: new
|
|
2593
|
+
point: new THREE10.Vector3(
|
|
2637
2594
|
origin.x + dir.x * dist,
|
|
2638
2595
|
origin.y + dir.y * dist,
|
|
2639
2596
|
origin.z + dir.z * dist
|
|
@@ -3612,7 +3569,7 @@ function solve6x6(A, b, x) {
|
|
|
3612
3569
|
}
|
|
3613
3570
|
|
|
3614
3571
|
// src/hooks/useIkController.ts
|
|
3615
|
-
var _syncMat4 = new
|
|
3572
|
+
var _syncMat4 = new THREE10.Matrix4();
|
|
3616
3573
|
function syncGizmoToSite(data, siteId, target) {
|
|
3617
3574
|
if (siteId === -1) return;
|
|
3618
3575
|
const sitePos = data.site_xpos.subarray(siteId * 3, siteId * 3 + 3);
|
|
@@ -3644,7 +3601,7 @@ var useIkController = createControllerHook(
|
|
|
3644
3601
|
const { mjModelRef, mjDataRef, mujocoRef, resetCallbacks, status } = useMujocoContext();
|
|
3645
3602
|
const ikEnabledRef = useRef(false);
|
|
3646
3603
|
const ikCalculatingRef = useRef(false);
|
|
3647
|
-
const ikTargetRef = useRef(new
|
|
3604
|
+
const ikTargetRef = useRef(new THREE10.Group());
|
|
3648
3605
|
const siteIdRef = useRef(-1);
|
|
3649
3606
|
const controlGroupRef = useRef(null);
|
|
3650
3607
|
const genericIkRef = useRef(new GenericIK(mujocoRef.current));
|
|
@@ -3652,10 +3609,10 @@ var useIkController = createControllerHook(
|
|
|
3652
3609
|
const needsInitialSync = useRef(true);
|
|
3653
3610
|
const gizmoAnimRef = useRef({
|
|
3654
3611
|
active: false,
|
|
3655
|
-
startPos: new
|
|
3656
|
-
endPos: new
|
|
3657
|
-
startRot: new
|
|
3658
|
-
endRot: new
|
|
3612
|
+
startPos: new THREE10.Vector3(),
|
|
3613
|
+
endPos: new THREE10.Vector3(),
|
|
3614
|
+
startRot: new THREE10.Quaternion(),
|
|
3615
|
+
endRot: new THREE10.Quaternion(),
|
|
3659
3616
|
startTime: 0,
|
|
3660
3617
|
duration: 1e3
|
|
3661
3618
|
});
|
|
@@ -3724,8 +3681,8 @@ var useIkController = createControllerHook(
|
|
|
3724
3681
|
const ga = gizmoAnimRef.current;
|
|
3725
3682
|
const target = ikTargetRef.current;
|
|
3726
3683
|
if (!ga.active || !target) return;
|
|
3727
|
-
const
|
|
3728
|
-
const elapsed =
|
|
3684
|
+
const now2 = performance.now();
|
|
3685
|
+
const elapsed = now2 - ga.startTime;
|
|
3729
3686
|
const t = Math.min(elapsed / ga.duration, 1);
|
|
3730
3687
|
const ease = 1 - Math.pow(1 - t, 3);
|
|
3731
3688
|
target.position.lerpVectors(ga.startPos, ga.endPos, ease);
|
|
@@ -3807,8 +3764,8 @@ var useIkController = createControllerHook(
|
|
|
3807
3764
|
const target = ikTargetRef.current;
|
|
3808
3765
|
if (!target) return;
|
|
3809
3766
|
const targetPos = pos.clone();
|
|
3810
|
-
const targetRot = new
|
|
3811
|
-
new
|
|
3767
|
+
const targetRot = new THREE10.Quaternion().setFromEuler(
|
|
3768
|
+
new THREE10.Euler(Math.PI, 0, 0)
|
|
3812
3769
|
);
|
|
3813
3770
|
if (duration > 0) {
|
|
3814
3771
|
const ga = gizmoAnimRef.current;
|
|
@@ -3833,7 +3790,7 @@ var useIkController = createControllerHook(
|
|
|
3833
3790
|
if (!ikCalculatingRef.current || !target) return null;
|
|
3834
3791
|
return {
|
|
3835
3792
|
pos: target.position.clone(),
|
|
3836
|
-
rot: new
|
|
3793
|
+
rot: new THREE10.Euler().setFromQuaternion(target.quaternion)
|
|
3837
3794
|
};
|
|
3838
3795
|
},
|
|
3839
3796
|
[]
|
|
@@ -3929,10 +3886,10 @@ function Body({
|
|
|
3929
3886
|
if (!hasChildren) return null;
|
|
3930
3887
|
return /* @__PURE__ */ jsx("group", { ref: groupRef, children });
|
|
3931
3888
|
}
|
|
3932
|
-
var _mat4 = new
|
|
3933
|
-
var _pos = new
|
|
3934
|
-
var _quat = new
|
|
3935
|
-
var _scale = new
|
|
3889
|
+
var _mat4 = new THREE10.Matrix4();
|
|
3890
|
+
var _pos = new THREE10.Vector3();
|
|
3891
|
+
var _quat = new THREE10.Quaternion();
|
|
3892
|
+
var _scale = new THREE10.Vector3(1, 1, 1);
|
|
3936
3893
|
function IkGizmo({ controller, siteName, scale = 0.18, onDrag }) {
|
|
3937
3894
|
const { mjModelRef, mjDataRef, status } = useMujocoContext();
|
|
3938
3895
|
const { ikTargetRef, siteIdRef, ikEnabledRef, setIkEnabled } = controller;
|
|
@@ -4031,7 +3988,7 @@ function IkGizmo({ controller, siteName, scale = 0.18, onDrag }) {
|
|
|
4031
3988
|
}
|
|
4032
3989
|
);
|
|
4033
3990
|
}
|
|
4034
|
-
var _dummy = new
|
|
3991
|
+
var _dummy = new THREE10.Object3D();
|
|
4035
3992
|
function ContactMarkers({
|
|
4036
3993
|
maxContacts = 100,
|
|
4037
3994
|
radius = 8e-3,
|
|
@@ -4085,11 +4042,11 @@ function ContactMarkers({
|
|
|
4085
4042
|
var _force = new Float64Array(3);
|
|
4086
4043
|
var _torque = new Float64Array(3);
|
|
4087
4044
|
var _point = new Float64Array(3);
|
|
4088
|
-
var _bodyPos = new
|
|
4089
|
-
var _bodyQuat = new
|
|
4090
|
-
var _worldHit = new
|
|
4091
|
-
var _raycaster = new
|
|
4092
|
-
var _mouse = new
|
|
4045
|
+
var _bodyPos = new THREE10.Vector3();
|
|
4046
|
+
var _bodyQuat = new THREE10.Quaternion();
|
|
4047
|
+
var _worldHit = new THREE10.Vector3();
|
|
4048
|
+
var _raycaster = new THREE10.Raycaster();
|
|
4049
|
+
var _mouse = new THREE10.Vector2();
|
|
4093
4050
|
function DragInteraction({
|
|
4094
4051
|
stiffness = 250,
|
|
4095
4052
|
showArrow = true,
|
|
@@ -4100,16 +4057,16 @@ function DragInteraction({
|
|
|
4100
4057
|
const draggingRef = useRef(false);
|
|
4101
4058
|
const bodyIdRef = useRef(-1);
|
|
4102
4059
|
const grabDistanceRef = useRef(0);
|
|
4103
|
-
const localHitRef = useRef(new
|
|
4104
|
-
const grabWorldRef = useRef(new
|
|
4105
|
-
const mouseWorldRef = useRef(new
|
|
4060
|
+
const localHitRef = useRef(new THREE10.Vector3());
|
|
4061
|
+
const grabWorldRef = useRef(new THREE10.Vector3());
|
|
4062
|
+
const mouseWorldRef = useRef(new THREE10.Vector3());
|
|
4106
4063
|
const arrowRef = useRef(null);
|
|
4107
4064
|
const groupRef = useRef(null);
|
|
4108
4065
|
useEffect(() => {
|
|
4109
4066
|
if (!showArrow || !groupRef.current) return;
|
|
4110
|
-
const arrow = new
|
|
4111
|
-
new
|
|
4112
|
-
new
|
|
4067
|
+
const arrow = new THREE10.ArrowHelper(
|
|
4068
|
+
new THREE10.Vector3(0, 1, 0),
|
|
4069
|
+
new THREE10.Vector3(),
|
|
4113
4070
|
0.1,
|
|
4114
4071
|
16729156
|
|
4115
4072
|
);
|
|
@@ -4292,7 +4249,7 @@ function useSceneLights(intensity = 1) {
|
|
|
4292
4249
|
const dr = lightDiffuse ? lightDiffuse[3 * i] : 1;
|
|
4293
4250
|
const dg = lightDiffuse ? lightDiffuse[3 * i + 1] : 1;
|
|
4294
4251
|
const db = lightDiffuse ? lightDiffuse[3 * i + 2] : 1;
|
|
4295
|
-
const color = new
|
|
4252
|
+
const color = new THREE10.Color(dr, dg, db);
|
|
4296
4253
|
const px = lightPos[3 * i];
|
|
4297
4254
|
const py = lightPos[3 * i + 1];
|
|
4298
4255
|
const pz = lightPos[3 * i + 2];
|
|
@@ -4300,7 +4257,7 @@ function useSceneLights(intensity = 1) {
|
|
|
4300
4257
|
const dy = lightDir[3 * i + 1];
|
|
4301
4258
|
const dz = lightDir[3 * i + 2];
|
|
4302
4259
|
if (isDirectional) {
|
|
4303
|
-
const light = new
|
|
4260
|
+
const light = new THREE10.DirectionalLight(color, finalIntensity);
|
|
4304
4261
|
light.position.set(px, py, pz);
|
|
4305
4262
|
light.target.position.set(px + dx, py + dy, pz + dz);
|
|
4306
4263
|
light.castShadow = castShadow;
|
|
@@ -4323,7 +4280,7 @@ function useSceneLights(intensity = 1) {
|
|
|
4323
4280
|
const cutoff = lightCutoff ? lightCutoff[i] : 45;
|
|
4324
4281
|
const exponent = lightExponent ? lightExponent[i] : 10;
|
|
4325
4282
|
const angle = cutoff * Math.PI / 180;
|
|
4326
|
-
const light = new
|
|
4283
|
+
const light = new THREE10.SpotLight(color, finalIntensity, 0, angle, exponent / 128);
|
|
4327
4284
|
light.position.set(px, py, pz);
|
|
4328
4285
|
light.target.position.set(px + dx, py + dy, pz + dz);
|
|
4329
4286
|
light.castShadow = castShadow;
|
|
@@ -4606,12 +4563,12 @@ var JOINT_COLORS = {
|
|
|
4606
4563
|
3: 16776960
|
|
4607
4564
|
// hinge - yellow
|
|
4608
4565
|
};
|
|
4609
|
-
var _v3a = new
|
|
4610
|
-
new
|
|
4611
|
-
var _quat2 = new
|
|
4612
|
-
var _cameraMatrix = new
|
|
4613
|
-
var _contactPos = new
|
|
4614
|
-
var _contactNormal = new
|
|
4566
|
+
var _v3a = new THREE10.Vector3();
|
|
4567
|
+
new THREE10.Vector3();
|
|
4568
|
+
var _quat2 = new THREE10.Quaternion();
|
|
4569
|
+
var _cameraMatrix = new THREE10.Matrix4();
|
|
4570
|
+
var _contactPos = new THREE10.Vector3();
|
|
4571
|
+
var _contactNormal = new THREE10.Vector3();
|
|
4615
4572
|
var MAX_CONTACT_ARROWS = 50;
|
|
4616
4573
|
var CAMERA_DEBUG_LENGTH = 0.12;
|
|
4617
4574
|
var CAMERA_DEBUG_FRUSTUM_DEPTH = 0.08;
|
|
@@ -4644,21 +4601,21 @@ function Debug({
|
|
|
4644
4601
|
let geometry = null;
|
|
4645
4602
|
switch (type) {
|
|
4646
4603
|
case 2:
|
|
4647
|
-
geometry = new
|
|
4604
|
+
geometry = new THREE10.SphereGeometry(s[3 * i], 12, 8);
|
|
4648
4605
|
break;
|
|
4649
4606
|
case 3:
|
|
4650
|
-
geometry = new
|
|
4607
|
+
geometry = new THREE10.CapsuleGeometry(s[3 * i], s[3 * i + 1] * 2, 6, 8);
|
|
4651
4608
|
break;
|
|
4652
4609
|
case 5:
|
|
4653
|
-
geometry = new
|
|
4610
|
+
geometry = new THREE10.CylinderGeometry(s[3 * i], s[3 * i], s[3 * i + 1] * 2, 12);
|
|
4654
4611
|
break;
|
|
4655
4612
|
case 6:
|
|
4656
|
-
geometry = new
|
|
4613
|
+
geometry = new THREE10.BoxGeometry(s[3 * i] * 2, s[3 * i + 1] * 2, s[3 * i + 2] * 2);
|
|
4657
4614
|
break;
|
|
4658
4615
|
}
|
|
4659
4616
|
if (geometry) {
|
|
4660
|
-
const mat = new
|
|
4661
|
-
const mesh = new
|
|
4617
|
+
const mat = new THREE10.MeshBasicMaterial({ color: 65280, wireframe: true, transparent: true, opacity: 0.3 });
|
|
4618
|
+
const mesh = new THREE10.Mesh(geometry, mat);
|
|
4662
4619
|
mesh.userData.geomId = i;
|
|
4663
4620
|
mesh.userData.bodyId = model.geom_bodyid[i];
|
|
4664
4621
|
geoms.push(mesh);
|
|
@@ -4681,9 +4638,9 @@ function Debug({
|
|
|
4681
4638
|
}
|
|
4682
4639
|
if (maxGeomSize > 0) radius = maxGeomSize * 0.15;
|
|
4683
4640
|
}
|
|
4684
|
-
const geometry = new
|
|
4685
|
-
const mat = new
|
|
4686
|
-
const mesh = new
|
|
4641
|
+
const geometry = new THREE10.OctahedronGeometry(radius);
|
|
4642
|
+
const mat = new THREE10.MeshBasicMaterial({ color: 16711935, depthTest: false });
|
|
4643
|
+
const mesh = new THREE10.Mesh(geometry, mat);
|
|
4687
4644
|
mesh.renderOrder = 999;
|
|
4688
4645
|
mesh.frustumCulled = false;
|
|
4689
4646
|
mesh.userData.siteId = i;
|
|
@@ -4695,9 +4652,9 @@ function Debug({
|
|
|
4695
4652
|
ctx.font = "bold 36px monospace";
|
|
4696
4653
|
ctx.textAlign = "center";
|
|
4697
4654
|
ctx.fillText(getName(model, model.name_siteadr[i]), 128, 42);
|
|
4698
|
-
const tex = new
|
|
4699
|
-
const spriteMat = new
|
|
4700
|
-
const sprite = new
|
|
4655
|
+
const tex = new THREE10.CanvasTexture(canvas);
|
|
4656
|
+
const spriteMat = new THREE10.SpriteMaterial({ map: tex, depthTest: false, transparent: true });
|
|
4657
|
+
const sprite = new THREE10.Sprite(spriteMat);
|
|
4701
4658
|
const labelScale = radius * 15;
|
|
4702
4659
|
sprite.scale.set(labelScale, labelScale * 0.25, 1);
|
|
4703
4660
|
sprite.position.y = radius * 2;
|
|
@@ -4720,9 +4677,9 @@ function Debug({
|
|
|
4720
4677
|
}
|
|
4721
4678
|
}
|
|
4722
4679
|
const arrowLen = Math.max(maxGeomSize * 0.8, 0.05);
|
|
4723
|
-
const arrow = new
|
|
4724
|
-
new
|
|
4725
|
-
new
|
|
4680
|
+
const arrow = new THREE10.ArrowHelper(
|
|
4681
|
+
new THREE10.Vector3(0, 0, 1),
|
|
4682
|
+
new THREE10.Vector3(),
|
|
4726
4683
|
arrowLen,
|
|
4727
4684
|
color,
|
|
4728
4685
|
arrowLen * 0.25,
|
|
@@ -4730,7 +4687,7 @@ function Debug({
|
|
|
4730
4687
|
);
|
|
4731
4688
|
arrow.renderOrder = 999;
|
|
4732
4689
|
arrow.frustumCulled = false;
|
|
4733
|
-
arrow.line.material = new
|
|
4690
|
+
arrow.line.material = new THREE10.LineBasicMaterial({ color, depthTest: false });
|
|
4734
4691
|
arrow.cone.material.depthTest = false;
|
|
4735
4692
|
arrow.line.renderOrder = 999;
|
|
4736
4693
|
arrow.line.frustumCulled = false;
|
|
@@ -4745,20 +4702,20 @@ function Debug({
|
|
|
4745
4702
|
}
|
|
4746
4703
|
if (showCameras && model.ncam && model.name_camadr) {
|
|
4747
4704
|
for (let i = 0; i < model.ncam; i++) {
|
|
4748
|
-
const group = new
|
|
4705
|
+
const group = new THREE10.Group();
|
|
4749
4706
|
group.userData.cameraId = i;
|
|
4750
4707
|
group.renderOrder = 999;
|
|
4751
4708
|
group.frustumCulled = false;
|
|
4752
|
-
const marker = new
|
|
4753
|
-
new
|
|
4754
|
-
new
|
|
4709
|
+
const marker = new THREE10.Mesh(
|
|
4710
|
+
new THREE10.BoxGeometry(0.014, 9e-3, 6e-3),
|
|
4711
|
+
new THREE10.MeshBasicMaterial({ color: 3718648, depthTest: false })
|
|
4755
4712
|
);
|
|
4756
4713
|
marker.renderOrder = 999;
|
|
4757
4714
|
marker.frustumCulled = false;
|
|
4758
4715
|
group.add(marker);
|
|
4759
|
-
const forward = new
|
|
4760
|
-
new
|
|
4761
|
-
new
|
|
4716
|
+
const forward = new THREE10.ArrowHelper(
|
|
4717
|
+
new THREE10.Vector3(0, 0, -1),
|
|
4718
|
+
new THREE10.Vector3(),
|
|
4762
4719
|
CAMERA_DEBUG_LENGTH,
|
|
4763
4720
|
3718648,
|
|
4764
4721
|
CAMERA_DEBUG_LENGTH * 0.24,
|
|
@@ -4766,20 +4723,20 @@ function Debug({
|
|
|
4766
4723
|
);
|
|
4767
4724
|
forward.renderOrder = 999;
|
|
4768
4725
|
forward.frustumCulled = false;
|
|
4769
|
-
forward.line.material = new
|
|
4726
|
+
forward.line.material = new THREE10.LineBasicMaterial({
|
|
4770
4727
|
color: 3718648,
|
|
4771
4728
|
depthTest: false
|
|
4772
4729
|
});
|
|
4773
4730
|
forward.cone.material.depthTest = false;
|
|
4774
4731
|
group.add(forward);
|
|
4775
|
-
const frustumGeometry = new
|
|
4732
|
+
const frustumGeometry = new THREE10.BufferGeometry();
|
|
4776
4733
|
frustumGeometry.setAttribute(
|
|
4777
4734
|
"position",
|
|
4778
|
-
new
|
|
4735
|
+
new THREE10.Float32BufferAttribute(new Float32Array(8 * 2 * 3), 3)
|
|
4779
4736
|
);
|
|
4780
|
-
const frustum = new
|
|
4737
|
+
const frustum = new THREE10.LineSegments(
|
|
4781
4738
|
frustumGeometry,
|
|
4782
|
-
new
|
|
4739
|
+
new THREE10.LineBasicMaterial({
|
|
4783
4740
|
color: 3718648,
|
|
4784
4741
|
transparent: true,
|
|
4785
4742
|
opacity: 0.8,
|
|
@@ -4798,9 +4755,9 @@ function Debug({
|
|
|
4798
4755
|
ctx.font = "bold 32px monospace";
|
|
4799
4756
|
ctx.textAlign = "center";
|
|
4800
4757
|
ctx.fillText(getName(model, model.name_camadr[i]), 128, 42);
|
|
4801
|
-
const texture = new
|
|
4802
|
-
const sprite = new
|
|
4803
|
-
new
|
|
4758
|
+
const texture = new THREE10.CanvasTexture(canvas);
|
|
4759
|
+
const sprite = new THREE10.Sprite(
|
|
4760
|
+
new THREE10.SpriteMaterial({
|
|
4804
4761
|
map: texture,
|
|
4805
4762
|
depthTest: false,
|
|
4806
4763
|
transparent: true
|
|
@@ -4816,9 +4773,9 @@ function Debug({
|
|
|
4816
4773
|
}
|
|
4817
4774
|
if (showCOM) {
|
|
4818
4775
|
for (let i = 1; i < model.nbody; i++) {
|
|
4819
|
-
const geometry = new
|
|
4820
|
-
const mat = new
|
|
4821
|
-
const mesh = new
|
|
4776
|
+
const geometry = new THREE10.SphereGeometry(5e-3, 6, 6);
|
|
4777
|
+
const mat = new THREE10.MeshBasicMaterial({ color: 16711680 });
|
|
4778
|
+
const mesh = new THREE10.Mesh(geometry, mat);
|
|
4822
4779
|
mesh.userData.bodyId = i;
|
|
4823
4780
|
comMarkers.push(mesh);
|
|
4824
4781
|
}
|
|
@@ -4927,7 +4884,7 @@ function Debug({
|
|
|
4927
4884
|
);
|
|
4928
4885
|
group.quaternion.setFromRotationMatrix(_cameraMatrix);
|
|
4929
4886
|
const fovy = model.cam_fovy?.[cameraId] ?? 45;
|
|
4930
|
-
const halfHeight = Math.tan(
|
|
4887
|
+
const halfHeight = Math.tan(THREE10.MathUtils.degToRad(fovy) / 2) * CAMERA_DEBUG_FRUSTUM_DEPTH;
|
|
4931
4888
|
const halfWidth = halfHeight * 4 / 3;
|
|
4932
4889
|
const positions = group.userData.frustum.geometry.attributes.position;
|
|
4933
4890
|
const array = positions.array;
|
|
@@ -4972,9 +4929,9 @@ function Debug({
|
|
|
4972
4929
|
contactPoolInitRef.current = true;
|
|
4973
4930
|
const pool = [];
|
|
4974
4931
|
for (let i = 0; i < MAX_CONTACT_ARROWS; i++) {
|
|
4975
|
-
const arrow = new
|
|
4976
|
-
new
|
|
4977
|
-
new
|
|
4932
|
+
const arrow = new THREE10.ArrowHelper(
|
|
4933
|
+
new THREE10.Vector3(0, 1, 0),
|
|
4934
|
+
new THREE10.Vector3(),
|
|
4978
4935
|
0.1,
|
|
4979
4936
|
16729156,
|
|
4980
4937
|
0.03,
|
|
@@ -5039,9 +4996,9 @@ function Debug({
|
|
|
5039
4996
|
}
|
|
5040
4997
|
);
|
|
5041
4998
|
}
|
|
5042
|
-
var DEFAULT_TENDON_COLOR = new
|
|
4999
|
+
var DEFAULT_TENDON_COLOR = new THREE10.Color(0.3, 0.3, 0.8);
|
|
5043
5000
|
var DEFAULT_TENDON_WIDTH = 2e-3;
|
|
5044
|
-
new
|
|
5001
|
+
new THREE10.Vector3();
|
|
5045
5002
|
function TendonRenderer(props) {
|
|
5046
5003
|
const { mjModelRef, mjDataRef, status } = useMujocoContext();
|
|
5047
5004
|
const groupRef = useRef(null);
|
|
@@ -5055,7 +5012,7 @@ function TendonRenderer(props) {
|
|
|
5055
5012
|
if (!model || !data || !group) return;
|
|
5056
5013
|
const ntendon = model.ntendon ?? 0;
|
|
5057
5014
|
if (ntendon === 0) return;
|
|
5058
|
-
const material = new
|
|
5015
|
+
const material = new THREE10.MeshStandardMaterial({
|
|
5059
5016
|
color: DEFAULT_TENDON_COLOR,
|
|
5060
5017
|
roughness: 0.6,
|
|
5061
5018
|
metalness: 0.1
|
|
@@ -5070,11 +5027,11 @@ function TendonRenderer(props) {
|
|
|
5070
5027
|
curves.push(null);
|
|
5071
5028
|
continue;
|
|
5072
5029
|
}
|
|
5073
|
-
const points = Array.from({ length: wrapNum }, () => new
|
|
5074
|
-
const curve = new
|
|
5030
|
+
const points = Array.from({ length: wrapNum }, () => new THREE10.Vector3());
|
|
5031
|
+
const curve = new THREE10.CatmullRomCurve3(points, false);
|
|
5075
5032
|
const segments = Math.max(wrapNum * 2, 4);
|
|
5076
|
-
const geometry = new
|
|
5077
|
-
const mesh = new
|
|
5033
|
+
const geometry = new THREE10.TubeGeometry(curve, segments, DEFAULT_TENDON_WIDTH, 6, false);
|
|
5034
|
+
const mesh = new THREE10.Mesh(geometry, material);
|
|
5078
5035
|
mesh.frustumCulled = false;
|
|
5079
5036
|
group.add(mesh);
|
|
5080
5037
|
meshes.push(mesh);
|
|
@@ -5129,11 +5086,11 @@ function TendonRenderer(props) {
|
|
|
5129
5086
|
if (curve.points.length !== validCount) {
|
|
5130
5087
|
curve.points.length = validCount;
|
|
5131
5088
|
while (curve.points.length < validCount) {
|
|
5132
|
-
curve.points.push(new
|
|
5089
|
+
curve.points.push(new THREE10.Vector3());
|
|
5133
5090
|
}
|
|
5134
5091
|
}
|
|
5135
5092
|
mesh.geometry.dispose();
|
|
5136
|
-
mesh.geometry = new
|
|
5093
|
+
mesh.geometry = new THREE10.TubeGeometry(
|
|
5137
5094
|
curve,
|
|
5138
5095
|
Math.max(validCount * 2, 4),
|
|
5139
5096
|
DEFAULT_TENDON_WIDTH,
|
|
@@ -5160,24 +5117,24 @@ function FlexRenderer(props) {
|
|
|
5160
5117
|
const vertAdr = model.flex_vertadr[f];
|
|
5161
5118
|
const vertNum = model.flex_vertnum[f];
|
|
5162
5119
|
if (vertNum === 0) continue;
|
|
5163
|
-
const geometry = new
|
|
5120
|
+
const geometry = new THREE10.BufferGeometry();
|
|
5164
5121
|
const positions = new Float32Array(vertNum * 3);
|
|
5165
|
-
geometry.setAttribute("position", new
|
|
5122
|
+
geometry.setAttribute("position", new THREE10.BufferAttribute(positions, 3));
|
|
5166
5123
|
geometry.computeVertexNormals();
|
|
5167
|
-
let color = new
|
|
5124
|
+
let color = new THREE10.Color(0.5, 0.5, 0.5);
|
|
5168
5125
|
if (model.flex_rgba) {
|
|
5169
|
-
color = new
|
|
5126
|
+
color = new THREE10.Color(
|
|
5170
5127
|
model.flex_rgba[4 * f],
|
|
5171
5128
|
model.flex_rgba[4 * f + 1],
|
|
5172
5129
|
model.flex_rgba[4 * f + 2]
|
|
5173
5130
|
);
|
|
5174
5131
|
}
|
|
5175
|
-
const material = new
|
|
5132
|
+
const material = new THREE10.MeshStandardMaterial({
|
|
5176
5133
|
color,
|
|
5177
5134
|
roughness: 0.7,
|
|
5178
|
-
side:
|
|
5135
|
+
side: THREE10.DoubleSide
|
|
5179
5136
|
});
|
|
5180
|
-
const mesh = new
|
|
5137
|
+
const mesh = new THREE10.Mesh(geometry, material);
|
|
5181
5138
|
mesh.userData.flexId = f;
|
|
5182
5139
|
mesh.userData.vertAdr = vertAdr;
|
|
5183
5140
|
mesh.userData.vertNum = vertNum;
|
|
@@ -5213,7 +5170,7 @@ function FlexRenderer(props) {
|
|
|
5213
5170
|
return /* @__PURE__ */ jsx("group", { ...props, ref: groupRef });
|
|
5214
5171
|
}
|
|
5215
5172
|
var GEOM_TYPE_NAMES2 = ["plane", "hfield", "sphere", "capsule", "ellipsoid", "cylinder", "box", "mesh"];
|
|
5216
|
-
var _matrix = new
|
|
5173
|
+
var _matrix = new THREE10.Matrix4();
|
|
5217
5174
|
function getGeomInfo(model, geomId) {
|
|
5218
5175
|
const size = model.geom_size.subarray(geomId * 3, geomId * 3 + 3);
|
|
5219
5176
|
const type = model.geom_type[geomId];
|
|
@@ -5235,10 +5192,10 @@ function geomSignature(model, geomId) {
|
|
|
5235
5192
|
return [type, size, mat, data, rgba].join("|");
|
|
5236
5193
|
}
|
|
5237
5194
|
function firstMesh(object) {
|
|
5238
|
-
if (object instanceof
|
|
5195
|
+
if (object instanceof THREE10.Mesh) return object;
|
|
5239
5196
|
let mesh = null;
|
|
5240
5197
|
object.traverse((child) => {
|
|
5241
|
-
if (!mesh && child instanceof
|
|
5198
|
+
if (!mesh && child instanceof THREE10.Mesh) mesh = child;
|
|
5242
5199
|
});
|
|
5243
5200
|
return mesh;
|
|
5244
5201
|
}
|
|
@@ -5532,12 +5489,12 @@ function useTrajectoryPlayer(trajectory, options = {}) {
|
|
|
5532
5489
|
if ((optionsRef.current.mode ?? "kinematic") !== "kinematic") return;
|
|
5533
5490
|
const traj = trajectoryRef.current;
|
|
5534
5491
|
if (traj.length === 0) return;
|
|
5535
|
-
const
|
|
5492
|
+
const now2 = performance.now();
|
|
5536
5493
|
const fps = optionsRef.current.fps ?? 30;
|
|
5537
5494
|
const frameInterval = 1e3 / (fps * speedRef.current);
|
|
5538
|
-
const elapsed =
|
|
5495
|
+
const elapsed = now2 - lastFrameTimeRef.current;
|
|
5539
5496
|
if (elapsed < frameInterval) return;
|
|
5540
|
-
lastFrameTimeRef.current =
|
|
5497
|
+
lastFrameTimeRef.current = now2;
|
|
5541
5498
|
const model = mjModelRef.current;
|
|
5542
5499
|
const data = mjDataRef.current;
|
|
5543
5500
|
if (!model || !data) return;
|
|
@@ -5667,12 +5624,12 @@ function useActuators() {
|
|
|
5667
5624
|
return actuators;
|
|
5668
5625
|
}, [status, mjModelRef]);
|
|
5669
5626
|
}
|
|
5670
|
-
var _mat42 = new
|
|
5627
|
+
var _mat42 = new THREE10.Matrix4();
|
|
5671
5628
|
function useSitePosition(siteName) {
|
|
5672
5629
|
const { mjModelRef, mjDataRef, status } = useMujocoContext();
|
|
5673
5630
|
const siteIdRef = useRef(-1);
|
|
5674
|
-
const positionRef = useRef(new
|
|
5675
|
-
const quaternionRef = useRef(new
|
|
5631
|
+
const positionRef = useRef(new THREE10.Vector3());
|
|
5632
|
+
const quaternionRef = useRef(new THREE10.Quaternion());
|
|
5676
5633
|
useEffect(() => {
|
|
5677
5634
|
const model = mjModelRef.current;
|
|
5678
5635
|
if (!model || status !== "ready") {
|
|
@@ -5865,10 +5822,10 @@ function useJointState(name, options = {}) {
|
|
|
5865
5822
|
function useBodyState(name) {
|
|
5866
5823
|
const { mjModelRef, status } = useMujocoContext();
|
|
5867
5824
|
const bodyIdRef = useRef(-1);
|
|
5868
|
-
const position = useRef(new
|
|
5869
|
-
const quaternion = useRef(new
|
|
5870
|
-
const linearVelocity = useRef(new
|
|
5871
|
-
const angularVelocity = useRef(new
|
|
5825
|
+
const position = useRef(new THREE10.Vector3());
|
|
5826
|
+
const quaternion = useRef(new THREE10.Quaternion());
|
|
5827
|
+
const linearVelocity = useRef(new THREE10.Vector3());
|
|
5828
|
+
const angularVelocity = useRef(new THREE10.Vector3());
|
|
5872
5829
|
useEffect(() => {
|
|
5873
5830
|
const model = mjModelRef.current;
|
|
5874
5831
|
if (!model || status !== "ready") return;
|
|
@@ -5894,6 +5851,93 @@ function useBodyState(name) {
|
|
|
5894
5851
|
});
|
|
5895
5852
|
return { position, quaternion, linearVelocity, angularVelocity };
|
|
5896
5853
|
}
|
|
5854
|
+
var _matrix2 = new THREE10.Matrix4();
|
|
5855
|
+
function quaternionFromMatrixArray(target, values, offset) {
|
|
5856
|
+
_matrix2.set(
|
|
5857
|
+
values[offset],
|
|
5858
|
+
values[offset + 1],
|
|
5859
|
+
values[offset + 2],
|
|
5860
|
+
0,
|
|
5861
|
+
values[offset + 3],
|
|
5862
|
+
values[offset + 4],
|
|
5863
|
+
values[offset + 5],
|
|
5864
|
+
0,
|
|
5865
|
+
values[offset + 6],
|
|
5866
|
+
values[offset + 7],
|
|
5867
|
+
values[offset + 8],
|
|
5868
|
+
0,
|
|
5869
|
+
0,
|
|
5870
|
+
0,
|
|
5871
|
+
0,
|
|
5872
|
+
1
|
|
5873
|
+
);
|
|
5874
|
+
target.setFromRotationMatrix(_matrix2);
|
|
5875
|
+
}
|
|
5876
|
+
function quaternionFromMujocoQuat2(target, values, offset) {
|
|
5877
|
+
target.set(
|
|
5878
|
+
values[offset + 1] ?? 0,
|
|
5879
|
+
values[offset + 2] ?? 0,
|
|
5880
|
+
values[offset + 3] ?? 0,
|
|
5881
|
+
values[offset] ?? 1
|
|
5882
|
+
);
|
|
5883
|
+
}
|
|
5884
|
+
function useNamedPose(kind, name) {
|
|
5885
|
+
const { mjModelRef, status } = useMujocoContext();
|
|
5886
|
+
const idRef = useRef(-1);
|
|
5887
|
+
const foundRef = useRef(false);
|
|
5888
|
+
const positionRef = useRef(new THREE10.Vector3());
|
|
5889
|
+
const quaternionRef = useRef(new THREE10.Quaternion());
|
|
5890
|
+
useEffect(() => {
|
|
5891
|
+
const model = mjModelRef.current;
|
|
5892
|
+
if (!model || status !== "ready") {
|
|
5893
|
+
idRef.current = -1;
|
|
5894
|
+
foundRef.current = false;
|
|
5895
|
+
return;
|
|
5896
|
+
}
|
|
5897
|
+
if (kind === "body") idRef.current = findBodyByName(model, name);
|
|
5898
|
+
else if (kind === "geom") idRef.current = findGeomByName(model, name);
|
|
5899
|
+
else idRef.current = findSiteByName(model, name);
|
|
5900
|
+
foundRef.current = idRef.current >= 0;
|
|
5901
|
+
}, [kind, name, status, mjModelRef]);
|
|
5902
|
+
useAfterPhysicsStep(({ data }) => {
|
|
5903
|
+
const id = idRef.current;
|
|
5904
|
+
if (id < 0) return;
|
|
5905
|
+
if (kind === "body") {
|
|
5906
|
+
const p2 = id * 3;
|
|
5907
|
+
positionRef.current.set(data.xpos[p2], data.xpos[p2 + 1], data.xpos[p2 + 2]);
|
|
5908
|
+
if (data.xmat) {
|
|
5909
|
+
quaternionFromMatrixArray(quaternionRef.current, data.xmat, id * 9);
|
|
5910
|
+
} else {
|
|
5911
|
+
quaternionFromMujocoQuat2(quaternionRef.current, data.xquat, id * 4);
|
|
5912
|
+
}
|
|
5913
|
+
return;
|
|
5914
|
+
}
|
|
5915
|
+
if (kind === "geom") {
|
|
5916
|
+
const p2 = id * 3;
|
|
5917
|
+
positionRef.current.set(data.geom_xpos[p2], data.geom_xpos[p2 + 1], data.geom_xpos[p2 + 2]);
|
|
5918
|
+
quaternionFromMatrixArray(quaternionRef.current, data.geom_xmat, id * 9);
|
|
5919
|
+
return;
|
|
5920
|
+
}
|
|
5921
|
+
const p = id * 3;
|
|
5922
|
+
positionRef.current.set(data.site_xpos[p], data.site_xpos[p + 1], data.site_xpos[p + 2]);
|
|
5923
|
+
quaternionFromMatrixArray(quaternionRef.current, data.site_xmat, id * 9);
|
|
5924
|
+
});
|
|
5925
|
+
return {
|
|
5926
|
+
id: idRef,
|
|
5927
|
+
found: foundRef,
|
|
5928
|
+
position: positionRef,
|
|
5929
|
+
quaternion: quaternionRef
|
|
5930
|
+
};
|
|
5931
|
+
}
|
|
5932
|
+
function useBodyPose(name) {
|
|
5933
|
+
return useNamedPose("body", name);
|
|
5934
|
+
}
|
|
5935
|
+
function useGeomPose(name) {
|
|
5936
|
+
return useNamedPose("geom", name);
|
|
5937
|
+
}
|
|
5938
|
+
function useSitePose(name) {
|
|
5939
|
+
return useNamedPose("site", name);
|
|
5940
|
+
}
|
|
5897
5941
|
function useCtrl(name) {
|
|
5898
5942
|
const { mjModelRef, mjDataRef, status } = useMujocoContext();
|
|
5899
5943
|
const actuatorIdRef = useRef(-1);
|
|
@@ -5927,47 +5971,240 @@ function useCtrl(name) {
|
|
|
5927
5971
|
}
|
|
5928
5972
|
}), [name, mjDataRef]);
|
|
5929
5973
|
}
|
|
5930
|
-
|
|
5931
|
-
|
|
5932
|
-
|
|
5933
|
-
|
|
5934
|
-
|
|
5935
|
-
|
|
5936
|
-
|
|
5937
|
-
|
|
5938
|
-
|
|
5974
|
+
var claimsByModel = /* @__PURE__ */ new WeakMap();
|
|
5975
|
+
function getClaims(model) {
|
|
5976
|
+
let claims = claimsByModel.get(model);
|
|
5977
|
+
if (!claims) {
|
|
5978
|
+
claims = /* @__PURE__ */ new Map();
|
|
5979
|
+
claimsByModel.set(model, claims);
|
|
5980
|
+
}
|
|
5981
|
+
return claims;
|
|
5982
|
+
}
|
|
5983
|
+
function releaseClaims(model, token) {
|
|
5984
|
+
if (!model) return;
|
|
5985
|
+
const claims = claimsByModel.get(model);
|
|
5986
|
+
if (!claims) return;
|
|
5987
|
+
for (const [actuatorIndex, claim] of claims) {
|
|
5988
|
+
if (claim.token === token) claims.delete(actuatorIndex);
|
|
5989
|
+
}
|
|
5990
|
+
}
|
|
5991
|
+
function useControlWriter(options) {
|
|
5992
|
+
const {
|
|
5993
|
+
owner,
|
|
5994
|
+
selector,
|
|
5995
|
+
enabled = true,
|
|
5996
|
+
warnOnConflict = true,
|
|
5997
|
+
allowSameOwner = true,
|
|
5998
|
+
onConflict
|
|
5999
|
+
} = options;
|
|
6000
|
+
const { api, mjModelRef, mjDataRef, status } = useMujocoContext();
|
|
6001
|
+
const tokenRef = useRef(Symbol(owner));
|
|
6002
|
+
const claimedModelRef = useRef(null);
|
|
6003
|
+
const groupRef = useRef(null);
|
|
6004
|
+
const conflictsRef = useRef([]);
|
|
6005
|
+
const onConflictRef = useRef(onConflict);
|
|
6006
|
+
onConflictRef.current = onConflict;
|
|
6007
|
+
const release = useCallback(() => {
|
|
6008
|
+
releaseClaims(claimedModelRef.current, tokenRef.current);
|
|
6009
|
+
claimedModelRef.current = null;
|
|
6010
|
+
conflictsRef.current = [];
|
|
6011
|
+
}, []);
|
|
5939
6012
|
useEffect(() => {
|
|
6013
|
+
release();
|
|
6014
|
+
if (!enabled || status !== "ready") {
|
|
6015
|
+
groupRef.current = null;
|
|
6016
|
+
return;
|
|
6017
|
+
}
|
|
5940
6018
|
const model = mjModelRef.current;
|
|
5941
|
-
if (!model
|
|
5942
|
-
|
|
5943
|
-
|
|
5944
|
-
|
|
5945
|
-
|
|
6019
|
+
if (!model) {
|
|
6020
|
+
groupRef.current = null;
|
|
6021
|
+
return;
|
|
6022
|
+
}
|
|
6023
|
+
const group = selector ? api.resolveControlGroup(selector) : api.getControlMap();
|
|
6024
|
+
groupRef.current = group;
|
|
6025
|
+
if (!group) return;
|
|
6026
|
+
const claims = getClaims(model);
|
|
6027
|
+
const conflicts = [];
|
|
6028
|
+
for (const actuatorIndex of group.ctrlAdr) {
|
|
6029
|
+
const existing = claims.get(actuatorIndex);
|
|
6030
|
+
if (existing && existing.token !== tokenRef.current && (!allowSameOwner || existing.owner !== owner)) {
|
|
6031
|
+
conflicts.push({
|
|
6032
|
+
actuatorIndex,
|
|
6033
|
+
owner: existing.owner,
|
|
6034
|
+
requestedBy: owner
|
|
6035
|
+
});
|
|
5946
6036
|
}
|
|
5947
6037
|
}
|
|
5948
|
-
|
|
5949
|
-
|
|
5950
|
-
|
|
5951
|
-
|
|
5952
|
-
|
|
5953
|
-
|
|
5954
|
-
|
|
5955
|
-
pressedRef.current.add(key);
|
|
5956
|
-
const binding = bindingsRef.current[key];
|
|
5957
|
-
if (binding.toggle) {
|
|
5958
|
-
const current = toggleStateRef.current.get(key) ?? false;
|
|
5959
|
-
toggleStateRef.current.set(key, !current);
|
|
5960
|
-
}
|
|
6038
|
+
conflictsRef.current = conflicts;
|
|
6039
|
+
if (conflicts.length > 0) {
|
|
6040
|
+
onConflictRef.current?.(conflicts);
|
|
6041
|
+
if (warnOnConflict) {
|
|
6042
|
+
console.warn(
|
|
6043
|
+
`[mujoco-react] Control writer "${owner}" conflicts with existing writer(s): ${conflicts.map((conflict) => `${conflict.actuatorIndex}:${conflict.owner}`).join(", ")}`
|
|
6044
|
+
);
|
|
5961
6045
|
}
|
|
5962
|
-
|
|
5963
|
-
|
|
5964
|
-
|
|
5965
|
-
|
|
5966
|
-
|
|
5967
|
-
|
|
5968
|
-
return
|
|
5969
|
-
|
|
5970
|
-
|
|
6046
|
+
return;
|
|
6047
|
+
}
|
|
6048
|
+
for (const actuatorIndex of group.ctrlAdr) {
|
|
6049
|
+
claims.set(actuatorIndex, { owner, token: tokenRef.current });
|
|
6050
|
+
}
|
|
6051
|
+
claimedModelRef.current = model;
|
|
6052
|
+
return release;
|
|
6053
|
+
}, [allowSameOwner, api, enabled, mjModelRef, owner, release, selector, status, warnOnConflict]);
|
|
6054
|
+
const canWrite = useCallback(() => enabled && groupRef.current !== null && conflictsRef.current.length === 0, [enabled]);
|
|
6055
|
+
const read = useCallback(() => {
|
|
6056
|
+
const data = mjDataRef.current;
|
|
6057
|
+
const group = groupRef.current;
|
|
6058
|
+
if (!data || !group) return new Float64Array(0);
|
|
6059
|
+
return group.readCtrl(data);
|
|
6060
|
+
}, [mjDataRef]);
|
|
6061
|
+
const write = useCallback((values, writeOptions = {}) => {
|
|
6062
|
+
const data = mjDataRef.current;
|
|
6063
|
+
const group = groupRef.current;
|
|
6064
|
+
if (!data || !group) return false;
|
|
6065
|
+
if (!writeOptions.force && !canWrite()) return false;
|
|
6066
|
+
group.writeCtrl(data, values);
|
|
6067
|
+
return true;
|
|
6068
|
+
}, [canWrite, mjDataRef]);
|
|
6069
|
+
return useMemo(() => ({
|
|
6070
|
+
owner,
|
|
6071
|
+
group: groupRef,
|
|
6072
|
+
conflicts: conflictsRef,
|
|
6073
|
+
canWrite,
|
|
6074
|
+
read,
|
|
6075
|
+
write,
|
|
6076
|
+
release
|
|
6077
|
+
}), [canWrite, owner, read, release, write]);
|
|
6078
|
+
}
|
|
6079
|
+
var geomNameCacheByModel2 = /* @__PURE__ */ new WeakMap();
|
|
6080
|
+
var bodyNameCacheByModel = /* @__PURE__ */ new WeakMap();
|
|
6081
|
+
function getCachedName(cacheByModel, model, id, address) {
|
|
6082
|
+
if (id < 0) return "";
|
|
6083
|
+
let cache = cacheByModel.get(model);
|
|
6084
|
+
if (!cache) {
|
|
6085
|
+
cache = /* @__PURE__ */ new Map();
|
|
6086
|
+
cacheByModel.set(model, cache);
|
|
6087
|
+
}
|
|
6088
|
+
let name = cache.get(id);
|
|
6089
|
+
if (name === void 0) {
|
|
6090
|
+
name = getName(model, address);
|
|
6091
|
+
cache.set(id, name);
|
|
6092
|
+
}
|
|
6093
|
+
return name;
|
|
6094
|
+
}
|
|
6095
|
+
function matchesFilter(entry, bodyNames, geomNames, includeWorldBody) {
|
|
6096
|
+
if (!includeWorldBody && (entry.body1 === 0 || entry.body2 === 0)) return false;
|
|
6097
|
+
if (bodyNames && !bodyNames.includes(entry.body1Name) && !bodyNames.includes(entry.body2Name)) {
|
|
6098
|
+
return false;
|
|
6099
|
+
}
|
|
6100
|
+
if (geomNames && !geomNames.includes(entry.geom1Name) && !geomNames.includes(entry.geom2Name)) {
|
|
6101
|
+
return false;
|
|
6102
|
+
}
|
|
6103
|
+
return true;
|
|
6104
|
+
}
|
|
6105
|
+
function useContactHistory(options = {}) {
|
|
6106
|
+
const entriesRef = useRef([]);
|
|
6107
|
+
const optionsRef = useRef(options);
|
|
6108
|
+
optionsRef.current = options;
|
|
6109
|
+
const clear = useCallback(() => {
|
|
6110
|
+
entriesRef.current = [];
|
|
6111
|
+
}, []);
|
|
6112
|
+
const countPair = useCallback((nameA, nameB) => {
|
|
6113
|
+
let count = 0;
|
|
6114
|
+
for (const entry of entriesRef.current) {
|
|
6115
|
+
const matchesBodies = entry.body1Name === nameA && entry.body2Name === nameB || entry.body1Name === nameB && entry.body2Name === nameA;
|
|
6116
|
+
const matchesGeoms = entry.geom1Name === nameA && entry.geom2Name === nameB || entry.geom1Name === nameB && entry.geom2Name === nameA;
|
|
6117
|
+
if (matchesBodies || matchesGeoms) count += 1;
|
|
6118
|
+
}
|
|
6119
|
+
return count;
|
|
6120
|
+
}, []);
|
|
6121
|
+
useAfterPhysicsStep(({ model, data }) => {
|
|
6122
|
+
if ((data.ncon ?? 0) <= 0) return;
|
|
6123
|
+
const {
|
|
6124
|
+
maxLength = 2e3,
|
|
6125
|
+
bodyNames,
|
|
6126
|
+
geomNames,
|
|
6127
|
+
includeWorldBody = false
|
|
6128
|
+
} = optionsRef.current;
|
|
6129
|
+
if (maxLength <= 0) return;
|
|
6130
|
+
const nextEntries = [];
|
|
6131
|
+
withContacts(data, (contacts) => {
|
|
6132
|
+
for (let index = 0; index < data.ncon; index += 1) {
|
|
6133
|
+
const contact = getContact(contacts, index);
|
|
6134
|
+
if (!contact) break;
|
|
6135
|
+
const body1 = model.geom_bodyid[contact.geom1] ?? -1;
|
|
6136
|
+
const body2 = model.geom_bodyid[contact.geom2] ?? -1;
|
|
6137
|
+
const entry = {
|
|
6138
|
+
geom1: contact.geom1,
|
|
6139
|
+
geom2: contact.geom2,
|
|
6140
|
+
geom1Name: getCachedName(geomNameCacheByModel2, model, contact.geom1, model.name_geomadr[contact.geom1]),
|
|
6141
|
+
geom2Name: getCachedName(geomNameCacheByModel2, model, contact.geom2, model.name_geomadr[contact.geom2]),
|
|
6142
|
+
body1,
|
|
6143
|
+
body2,
|
|
6144
|
+
body1Name: body1 >= 0 ? getCachedName(bodyNameCacheByModel, model, body1, model.name_bodyadr[body1]) : "",
|
|
6145
|
+
body2Name: body2 >= 0 ? getCachedName(bodyNameCacheByModel, model, body2, model.name_bodyadr[body2]) : "",
|
|
6146
|
+
pos: [contact.pos[0], contact.pos[1], contact.pos[2]],
|
|
6147
|
+
depth: contact.dist,
|
|
6148
|
+
time: data.time
|
|
6149
|
+
};
|
|
6150
|
+
if (matchesFilter(entry, bodyNames, geomNames, includeWorldBody)) {
|
|
6151
|
+
nextEntries.push(entry);
|
|
6152
|
+
}
|
|
6153
|
+
}
|
|
6154
|
+
});
|
|
6155
|
+
if (nextEntries.length === 0) return;
|
|
6156
|
+
entriesRef.current.push(...nextEntries);
|
|
6157
|
+
if (entriesRef.current.length > maxLength) {
|
|
6158
|
+
entriesRef.current.splice(0, entriesRef.current.length - maxLength);
|
|
6159
|
+
}
|
|
6160
|
+
});
|
|
6161
|
+
return {
|
|
6162
|
+
entries: entriesRef,
|
|
6163
|
+
clear,
|
|
6164
|
+
countPair
|
|
6165
|
+
};
|
|
6166
|
+
}
|
|
6167
|
+
function useKeyboardTeleop(config) {
|
|
6168
|
+
const { mjModelRef, mjDataRef, status } = useMujocoContext();
|
|
6169
|
+
const pressedRef = useRef(/* @__PURE__ */ new Set());
|
|
6170
|
+
const toggleStateRef = useRef(/* @__PURE__ */ new Map());
|
|
6171
|
+
const enabledRef = useRef(config.enabled ?? true);
|
|
6172
|
+
enabledRef.current = config.enabled ?? true;
|
|
6173
|
+
const bindingsRef = useRef(config.bindings);
|
|
6174
|
+
bindingsRef.current = config.bindings;
|
|
6175
|
+
const actuatorCacheRef = useRef(/* @__PURE__ */ new Map());
|
|
6176
|
+
useEffect(() => {
|
|
6177
|
+
const model = mjModelRef.current;
|
|
6178
|
+
if (!model || status !== "ready") return;
|
|
6179
|
+
const cache = /* @__PURE__ */ new Map();
|
|
6180
|
+
for (const binding of Object.values(config.bindings)) {
|
|
6181
|
+
if (!cache.has(binding.actuator)) {
|
|
6182
|
+
cache.set(binding.actuator, findActuatorByName(model, binding.actuator));
|
|
6183
|
+
}
|
|
6184
|
+
}
|
|
6185
|
+
actuatorCacheRef.current = cache;
|
|
6186
|
+
}, [config.bindings, status, mjModelRef]);
|
|
6187
|
+
useEffect(() => {
|
|
6188
|
+
const onKeyDown = (e) => {
|
|
6189
|
+
if (!enabledRef.current) return;
|
|
6190
|
+
const key = e.key.toLowerCase();
|
|
6191
|
+
if (bindingsRef.current[key]) {
|
|
6192
|
+
pressedRef.current.add(key);
|
|
6193
|
+
const binding = bindingsRef.current[key];
|
|
6194
|
+
if (binding.toggle) {
|
|
6195
|
+
const current = toggleStateRef.current.get(key) ?? false;
|
|
6196
|
+
toggleStateRef.current.set(key, !current);
|
|
6197
|
+
}
|
|
6198
|
+
}
|
|
6199
|
+
};
|
|
6200
|
+
const onKeyUp = (e) => {
|
|
6201
|
+
pressedRef.current.delete(e.key.toLowerCase());
|
|
6202
|
+
};
|
|
6203
|
+
window.addEventListener("keydown", onKeyDown);
|
|
6204
|
+
window.addEventListener("keyup", onKeyUp);
|
|
6205
|
+
return () => {
|
|
6206
|
+
window.removeEventListener("keydown", onKeyDown);
|
|
6207
|
+
window.removeEventListener("keyup", onKeyUp);
|
|
5971
6208
|
};
|
|
5972
6209
|
}, []);
|
|
5973
6210
|
useBeforePhysicsStep(({ data }) => {
|
|
@@ -5992,9 +6229,9 @@ function useKeyboardTeleop(config) {
|
|
|
5992
6229
|
}
|
|
5993
6230
|
var DEFAULT_TRANSLATE_SPEED = 0.25;
|
|
5994
6231
|
var DEFAULT_ROTATE_SPEED = 1;
|
|
5995
|
-
var _translation = new
|
|
5996
|
-
var _axis = new
|
|
5997
|
-
var _quat3 = new
|
|
6232
|
+
var _translation = new THREE10.Vector3();
|
|
6233
|
+
var _axis = new THREE10.Vector3();
|
|
6234
|
+
var _quat3 = new THREE10.Quaternion();
|
|
5998
6235
|
function actionSign(action) {
|
|
5999
6236
|
return action.endsWith("+") ? 1 : -1;
|
|
6000
6237
|
}
|
|
@@ -6119,29 +6356,114 @@ function useKeyboardIkTarget(config) {
|
|
|
6119
6356
|
}
|
|
6120
6357
|
});
|
|
6121
6358
|
}
|
|
6359
|
+
function isPromiseLike(value) {
|
|
6360
|
+
return typeof value === "object" && value !== null && "then" in value && typeof value.then === "function";
|
|
6361
|
+
}
|
|
6362
|
+
function isPolicyActionChunk(value) {
|
|
6363
|
+
return Array.isArray(value) && value.length > 0 && (Array.isArray(value[0]) || ArrayBuffer.isView(value[0]));
|
|
6364
|
+
}
|
|
6365
|
+
function toPolicyActions(output) {
|
|
6366
|
+
return isPolicyActionChunk(output) ? [...output] : [output];
|
|
6367
|
+
}
|
|
6368
|
+
function enqueuePolicyActions(queue, actions, observation, strategy) {
|
|
6369
|
+
if (strategy === "replace") {
|
|
6370
|
+
queue.splice(0, queue.length);
|
|
6371
|
+
}
|
|
6372
|
+
queue.push(...actions.map((action) => ({ action, observation })));
|
|
6373
|
+
}
|
|
6122
6374
|
function usePolicy(config) {
|
|
6123
6375
|
const lastActionTimeRef = useRef(0);
|
|
6124
6376
|
const lastObservationRef = useRef(null);
|
|
6125
6377
|
const lastActionRef = useRef(null);
|
|
6378
|
+
const actionQueueRef = useRef([]);
|
|
6379
|
+
const inFlightRef = useRef(false);
|
|
6380
|
+
const lastErrorRef = useRef(null);
|
|
6381
|
+
const epochRef = useRef(0);
|
|
6126
6382
|
const isRunningRef = useRef(config.enabled ?? true);
|
|
6127
6383
|
const configRef = useRef(config);
|
|
6128
6384
|
configRef.current = config;
|
|
6129
6385
|
isRunningRef.current = config.enabled ?? isRunningRef.current;
|
|
6386
|
+
const clearQueue = useCallback(() => {
|
|
6387
|
+
epochRef.current += 1;
|
|
6388
|
+
actionQueueRef.current.splice(0, actionQueueRef.current.length);
|
|
6389
|
+
inFlightRef.current = false;
|
|
6390
|
+
lastErrorRef.current = null;
|
|
6391
|
+
}, []);
|
|
6392
|
+
const reset = useCallback(() => {
|
|
6393
|
+
clearQueue();
|
|
6394
|
+
lastActionTimeRef.current = 0;
|
|
6395
|
+
lastObservationRef.current = null;
|
|
6396
|
+
lastActionRef.current = null;
|
|
6397
|
+
}, [clearQueue]);
|
|
6130
6398
|
useBeforePhysicsStep(({ model, data }) => {
|
|
6131
6399
|
if (!isRunningRef.current) return;
|
|
6132
6400
|
const cfg = configRef.current;
|
|
6133
6401
|
model.opt?.timestep ?? 2e-3;
|
|
6134
6402
|
const interval = 1 / cfg.frequency;
|
|
6135
6403
|
if (data.time - lastActionTimeRef.current >= interval) {
|
|
6404
|
+
const queuedAction = actionQueueRef.current.shift();
|
|
6405
|
+
if (queuedAction) {
|
|
6406
|
+
cfg.onAction({
|
|
6407
|
+
action: queuedAction.action,
|
|
6408
|
+
observation: queuedAction.observation,
|
|
6409
|
+
model,
|
|
6410
|
+
data
|
|
6411
|
+
});
|
|
6412
|
+
lastActionTimeRef.current = data.time;
|
|
6413
|
+
lastActionRef.current = queuedAction.action;
|
|
6414
|
+
}
|
|
6415
|
+
const prefetchThreshold = cfg.prefetchThreshold ?? 0;
|
|
6416
|
+
const shouldInfer = !inFlightRef.current && (!queuedAction || actionQueueRef.current.length <= prefetchThreshold);
|
|
6417
|
+
if (!shouldInfer) return;
|
|
6136
6418
|
const observation = cfg.onObservation({ model, data });
|
|
6137
|
-
const
|
|
6138
|
-
|
|
6419
|
+
const result = cfg.infer ? cfg.infer({ observation, model, data }) : observation;
|
|
6420
|
+
if (isPromiseLike(result)) {
|
|
6421
|
+
const epoch = epochRef.current;
|
|
6422
|
+
inFlightRef.current = true;
|
|
6423
|
+
result.then((output) => {
|
|
6424
|
+
if (epoch !== epochRef.current) return;
|
|
6425
|
+
enqueuePolicyActions(
|
|
6426
|
+
actionQueueRef.current,
|
|
6427
|
+
toPolicyActions(output),
|
|
6428
|
+
observation,
|
|
6429
|
+
cfg.queueStrategy ?? "append"
|
|
6430
|
+
);
|
|
6431
|
+
lastErrorRef.current = null;
|
|
6432
|
+
}).catch((error) => {
|
|
6433
|
+
if (epoch !== epochRef.current) return;
|
|
6434
|
+
lastErrorRef.current = error;
|
|
6435
|
+
cfg.onError?.(error);
|
|
6436
|
+
}).finally(() => {
|
|
6437
|
+
if (epoch !== epochRef.current) return;
|
|
6438
|
+
inFlightRef.current = false;
|
|
6439
|
+
});
|
|
6440
|
+
} else {
|
|
6441
|
+
const actions = toPolicyActions(result);
|
|
6442
|
+
if (queuedAction) {
|
|
6443
|
+
enqueuePolicyActions(
|
|
6444
|
+
actionQueueRef.current,
|
|
6445
|
+
actions,
|
|
6446
|
+
observation,
|
|
6447
|
+
cfg.queueStrategy ?? "append"
|
|
6448
|
+
);
|
|
6449
|
+
} else {
|
|
6450
|
+
const [action, ...queuedActions] = actions;
|
|
6451
|
+
if (!action) return;
|
|
6452
|
+
enqueuePolicyActions(
|
|
6453
|
+
actionQueueRef.current,
|
|
6454
|
+
queuedActions,
|
|
6455
|
+
observation,
|
|
6456
|
+
cfg.queueStrategy ?? "append"
|
|
6457
|
+
);
|
|
6458
|
+
cfg.onAction({ action, observation, model, data });
|
|
6459
|
+
lastActionRef.current = action;
|
|
6460
|
+
}
|
|
6461
|
+
}
|
|
6139
6462
|
lastActionTimeRef.current = data.time;
|
|
6140
6463
|
lastObservationRef.current = observation;
|
|
6141
|
-
lastActionRef.current = action;
|
|
6142
6464
|
}
|
|
6143
6465
|
});
|
|
6144
|
-
return {
|
|
6466
|
+
return useMemo(() => ({
|
|
6145
6467
|
get isRunning() {
|
|
6146
6468
|
return isRunningRef.current;
|
|
6147
6469
|
},
|
|
@@ -6150,15 +6472,304 @@ function usePolicy(config) {
|
|
|
6150
6472
|
},
|
|
6151
6473
|
stop: () => {
|
|
6152
6474
|
isRunningRef.current = false;
|
|
6475
|
+
if (configRef.current.clearQueueOnStop) reset();
|
|
6476
|
+
},
|
|
6477
|
+
clearQueue,
|
|
6478
|
+
reset,
|
|
6479
|
+
get inFlight() {
|
|
6480
|
+
return inFlightRef.current;
|
|
6481
|
+
},
|
|
6482
|
+
get queuedActions() {
|
|
6483
|
+
return actionQueueRef.current.length;
|
|
6153
6484
|
},
|
|
6154
6485
|
get lastObservation() {
|
|
6155
6486
|
return lastObservationRef.current;
|
|
6156
6487
|
},
|
|
6157
6488
|
get lastAction() {
|
|
6158
6489
|
return lastActionRef.current;
|
|
6490
|
+
},
|
|
6491
|
+
get lastError() {
|
|
6492
|
+
return lastErrorRef.current;
|
|
6159
6493
|
}
|
|
6494
|
+
}), [clearQueue, reset]);
|
|
6495
|
+
}
|
|
6496
|
+
function now() {
|
|
6497
|
+
return typeof performance !== "undefined" ? performance.now() : Date.now();
|
|
6498
|
+
}
|
|
6499
|
+
function isAbortError(error) {
|
|
6500
|
+
return typeof DOMException !== "undefined" && error instanceof DOMException && error.name === "AbortError" || error instanceof Error && error.name === "AbortError";
|
|
6501
|
+
}
|
|
6502
|
+
function createAbortError(message) {
|
|
6503
|
+
if (typeof DOMException !== "undefined") {
|
|
6504
|
+
return new DOMException(message, "AbortError");
|
|
6505
|
+
}
|
|
6506
|
+
const error = new Error(message);
|
|
6507
|
+
error.name = "AbortError";
|
|
6508
|
+
return error;
|
|
6509
|
+
}
|
|
6510
|
+
function abortController(controller, reason) {
|
|
6511
|
+
if (!controller || controller.signal.aborted) return;
|
|
6512
|
+
if (reason !== void 0) {
|
|
6513
|
+
controller.abort(reason);
|
|
6514
|
+
} else {
|
|
6515
|
+
controller.abort();
|
|
6516
|
+
}
|
|
6517
|
+
}
|
|
6518
|
+
function createMergedAbortSignal(localSignal, externalSignal) {
|
|
6519
|
+
if (!externalSignal) return localSignal;
|
|
6520
|
+
if (externalSignal.aborted) {
|
|
6521
|
+
const controller2 = new AbortController();
|
|
6522
|
+
abortController(controller2, externalSignal.reason);
|
|
6523
|
+
return controller2.signal;
|
|
6524
|
+
}
|
|
6525
|
+
if (typeof AbortSignal !== "undefined" && typeof AbortSignal.any === "function") {
|
|
6526
|
+
return AbortSignal.any([localSignal, externalSignal]);
|
|
6527
|
+
}
|
|
6528
|
+
const controller = new AbortController();
|
|
6529
|
+
const abortFromLocal = () => abortController(controller, localSignal.reason);
|
|
6530
|
+
const abortFromExternal = () => abortController(controller, externalSignal.reason);
|
|
6531
|
+
localSignal.addEventListener("abort", abortFromLocal, { once: true });
|
|
6532
|
+
externalSignal.addEventListener("abort", abortFromExternal, { once: true });
|
|
6533
|
+
return controller.signal;
|
|
6534
|
+
}
|
|
6535
|
+
function vectorToArray(vector) {
|
|
6536
|
+
return Array.from(vector, (value) => Number(value));
|
|
6537
|
+
}
|
|
6538
|
+
function isPolicyVectorArray(value) {
|
|
6539
|
+
return Array.isArray(value) && value.every((entry) => Array.isArray(entry) || ArrayBuffer.isView(entry));
|
|
6540
|
+
}
|
|
6541
|
+
function isPolicyVector(value) {
|
|
6542
|
+
return Array.isArray(value) || ArrayBuffer.isView(value);
|
|
6543
|
+
}
|
|
6544
|
+
function defaultBuildRemotePolicyRequest(input) {
|
|
6545
|
+
const observation = vectorToArray(input.observation);
|
|
6546
|
+
return {
|
|
6547
|
+
observation,
|
|
6548
|
+
state: observation,
|
|
6549
|
+
time: input.data.time,
|
|
6550
|
+
reset: input.reset
|
|
6160
6551
|
};
|
|
6161
6552
|
}
|
|
6553
|
+
async function defaultReadRemotePolicyResponse(response) {
|
|
6554
|
+
const text = await response.text();
|
|
6555
|
+
if (text.length === 0) return null;
|
|
6556
|
+
return JSON.parse(text);
|
|
6557
|
+
}
|
|
6558
|
+
function defaultParseRemotePolicyResponse(responseBody) {
|
|
6559
|
+
if (responseBody && typeof responseBody === "object") {
|
|
6560
|
+
const body = responseBody;
|
|
6561
|
+
if (typeof body.error === "string" && body.error.length > 0) {
|
|
6562
|
+
throw new Error(body.error);
|
|
6563
|
+
}
|
|
6564
|
+
if (isPolicyVectorArray(body.actions) && body.actions.length > 0) {
|
|
6565
|
+
return body.actions;
|
|
6566
|
+
}
|
|
6567
|
+
if (isPolicyVector(body.action)) {
|
|
6568
|
+
return body.action;
|
|
6569
|
+
}
|
|
6570
|
+
}
|
|
6571
|
+
if (isPolicyVectorArray(responseBody) && responseBody.length > 0) {
|
|
6572
|
+
return responseBody;
|
|
6573
|
+
}
|
|
6574
|
+
if (isPolicyVector(responseBody)) {
|
|
6575
|
+
return responseBody;
|
|
6576
|
+
}
|
|
6577
|
+
throw new Error("Remote policy response must include `action` or `actions`.");
|
|
6578
|
+
}
|
|
6579
|
+
function createHttpError(response, responseBody) {
|
|
6580
|
+
const suffix = responseBody && typeof responseBody === "object" && "error" in responseBody ? `: ${String(responseBody.error)}` : "";
|
|
6581
|
+
return new Error(`Remote policy request failed with HTTP ${response.status}${suffix}`);
|
|
6582
|
+
}
|
|
6583
|
+
function useRemotePolicy(config) {
|
|
6584
|
+
const configRef = useRef(config);
|
|
6585
|
+
configRef.current = config;
|
|
6586
|
+
const requestCountRef = useRef(0);
|
|
6587
|
+
const responseCountRef = useRef(0);
|
|
6588
|
+
const remoteStatusRef = useRef("idle");
|
|
6589
|
+
const lastRequestBodyRef = useRef(null);
|
|
6590
|
+
const lastResponseBodyRef = useRef(null);
|
|
6591
|
+
const lastHttpStatusRef = useRef(null);
|
|
6592
|
+
const lastRequestMsRef = useRef(null);
|
|
6593
|
+
const abortControllerRef = useRef(null);
|
|
6594
|
+
const remoteEpochRef = useRef(0);
|
|
6595
|
+
const policy = usePolicy({
|
|
6596
|
+
...config,
|
|
6597
|
+
infer: async ({ observation, model, data }) => {
|
|
6598
|
+
const cfg = configRef.current;
|
|
6599
|
+
abortController(abortControllerRef.current, createAbortError("Remote policy request was superseded."));
|
|
6600
|
+
const controller = new AbortController();
|
|
6601
|
+
abortControllerRef.current = controller;
|
|
6602
|
+
const signal = createMergedAbortSignal(controller.signal, cfg.signal);
|
|
6603
|
+
const remoteEpoch = remoteEpochRef.current;
|
|
6604
|
+
const requestIndex = requestCountRef.current;
|
|
6605
|
+
const requestInput = {
|
|
6606
|
+
observation,
|
|
6607
|
+
model,
|
|
6608
|
+
data,
|
|
6609
|
+
reset: requestIndex === 0,
|
|
6610
|
+
requestIndex,
|
|
6611
|
+
signal
|
|
6612
|
+
};
|
|
6613
|
+
requestCountRef.current += 1;
|
|
6614
|
+
const requestStartedAt = now();
|
|
6615
|
+
const body = await (cfg.buildRequest?.(requestInput) ?? defaultBuildRemotePolicyRequest(requestInput));
|
|
6616
|
+
signal.throwIfAborted();
|
|
6617
|
+
if (remoteEpoch !== remoteEpochRef.current) {
|
|
6618
|
+
throw createAbortError("Remote policy request was reset.");
|
|
6619
|
+
}
|
|
6620
|
+
lastRequestBodyRef.current = body;
|
|
6621
|
+
remoteStatusRef.current = "requesting";
|
|
6622
|
+
cfg.onRequest?.({
|
|
6623
|
+
...requestInput,
|
|
6624
|
+
body,
|
|
6625
|
+
requestStartedAt
|
|
6626
|
+
});
|
|
6627
|
+
let response = null;
|
|
6628
|
+
let responseBody = null;
|
|
6629
|
+
try {
|
|
6630
|
+
const headers = new Headers(cfg.headers);
|
|
6631
|
+
if (!headers.has("content-type")) {
|
|
6632
|
+
headers.set("content-type", "application/json");
|
|
6633
|
+
}
|
|
6634
|
+
const fetcher = cfg.fetcher ?? fetch;
|
|
6635
|
+
response = await fetcher(String(cfg.endpoint), {
|
|
6636
|
+
...cfg.requestInit,
|
|
6637
|
+
method: cfg.method ?? "POST",
|
|
6638
|
+
credentials: cfg.credentials,
|
|
6639
|
+
headers,
|
|
6640
|
+
signal,
|
|
6641
|
+
body: typeof body === "string" ? body : JSON.stringify(body)
|
|
6642
|
+
});
|
|
6643
|
+
if (remoteEpoch === remoteEpochRef.current) {
|
|
6644
|
+
lastHttpStatusRef.current = response.status;
|
|
6645
|
+
}
|
|
6646
|
+
responseBody = await (cfg.readResponse?.(response) ?? defaultReadRemotePolicyResponse(response));
|
|
6647
|
+
signal.throwIfAborted();
|
|
6648
|
+
if (remoteEpoch !== remoteEpochRef.current) {
|
|
6649
|
+
throw createAbortError("Remote policy request was reset.");
|
|
6650
|
+
}
|
|
6651
|
+
lastResponseBodyRef.current = responseBody;
|
|
6652
|
+
if (!response.ok) {
|
|
6653
|
+
throw createHttpError(response, responseBody);
|
|
6654
|
+
}
|
|
6655
|
+
const responseFinishedAt = now();
|
|
6656
|
+
const info = {
|
|
6657
|
+
...requestInput,
|
|
6658
|
+
body,
|
|
6659
|
+
requestStartedAt,
|
|
6660
|
+
response,
|
|
6661
|
+
responseBody,
|
|
6662
|
+
responseFinishedAt,
|
|
6663
|
+
requestMs: responseFinishedAt - requestStartedAt
|
|
6664
|
+
};
|
|
6665
|
+
if (remoteEpoch === remoteEpochRef.current) {
|
|
6666
|
+
lastRequestMsRef.current = info.requestMs;
|
|
6667
|
+
responseCountRef.current += 1;
|
|
6668
|
+
}
|
|
6669
|
+
cfg.onResponse?.(info);
|
|
6670
|
+
const output = await (cfg.parseResponse?.(responseBody, info) ?? defaultParseRemotePolicyResponse(responseBody));
|
|
6671
|
+
if (remoteEpoch === remoteEpochRef.current) {
|
|
6672
|
+
remoteStatusRef.current = "ready";
|
|
6673
|
+
}
|
|
6674
|
+
return output;
|
|
6675
|
+
} catch (error) {
|
|
6676
|
+
if (response && remoteEpoch === remoteEpochRef.current) {
|
|
6677
|
+
lastHttpStatusRef.current = response.status;
|
|
6678
|
+
}
|
|
6679
|
+
if (isAbortError(error) || signal.aborted) {
|
|
6680
|
+
if (remoteEpoch === remoteEpochRef.current) {
|
|
6681
|
+
remoteStatusRef.current = "aborted";
|
|
6682
|
+
}
|
|
6683
|
+
throw error;
|
|
6684
|
+
}
|
|
6685
|
+
if (remoteEpoch === remoteEpochRef.current) {
|
|
6686
|
+
remoteStatusRef.current = "error";
|
|
6687
|
+
}
|
|
6688
|
+
throw error;
|
|
6689
|
+
} finally {
|
|
6690
|
+
if (abortControllerRef.current === controller) {
|
|
6691
|
+
abortControllerRef.current = null;
|
|
6692
|
+
}
|
|
6693
|
+
}
|
|
6694
|
+
}
|
|
6695
|
+
});
|
|
6696
|
+
return useMemo(() => {
|
|
6697
|
+
const abort = (reason) => {
|
|
6698
|
+
abortController(abortControllerRef.current, reason);
|
|
6699
|
+
if (abortControllerRef.current) {
|
|
6700
|
+
remoteStatusRef.current = "aborted";
|
|
6701
|
+
}
|
|
6702
|
+
};
|
|
6703
|
+
const resetRemoteState = () => {
|
|
6704
|
+
remoteEpochRef.current += 1;
|
|
6705
|
+
abort(createAbortError("Remote policy request was reset."));
|
|
6706
|
+
requestCountRef.current = 0;
|
|
6707
|
+
responseCountRef.current = 0;
|
|
6708
|
+
remoteStatusRef.current = "idle";
|
|
6709
|
+
lastRequestBodyRef.current = null;
|
|
6710
|
+
lastResponseBodyRef.current = null;
|
|
6711
|
+
lastHttpStatusRef.current = null;
|
|
6712
|
+
lastRequestMsRef.current = null;
|
|
6713
|
+
};
|
|
6714
|
+
return {
|
|
6715
|
+
get isRunning() {
|
|
6716
|
+
return policy.isRunning;
|
|
6717
|
+
},
|
|
6718
|
+
start: policy.start,
|
|
6719
|
+
stop: () => {
|
|
6720
|
+
if (configRef.current.abortOnStop ?? true) {
|
|
6721
|
+
abort(createAbortError("Remote policy request was stopped."));
|
|
6722
|
+
}
|
|
6723
|
+
policy.stop();
|
|
6724
|
+
if (configRef.current.clearQueueOnStop) {
|
|
6725
|
+
resetRemoteState();
|
|
6726
|
+
}
|
|
6727
|
+
},
|
|
6728
|
+
clearQueue: policy.clearQueue,
|
|
6729
|
+
abort,
|
|
6730
|
+
reset: () => {
|
|
6731
|
+
resetRemoteState();
|
|
6732
|
+
policy.reset();
|
|
6733
|
+
},
|
|
6734
|
+
get inFlight() {
|
|
6735
|
+
return policy.inFlight;
|
|
6736
|
+
},
|
|
6737
|
+
get queuedActions() {
|
|
6738
|
+
return policy.queuedActions;
|
|
6739
|
+
},
|
|
6740
|
+
get lastObservation() {
|
|
6741
|
+
return policy.lastObservation;
|
|
6742
|
+
},
|
|
6743
|
+
get lastAction() {
|
|
6744
|
+
return policy.lastAction;
|
|
6745
|
+
},
|
|
6746
|
+
get lastError() {
|
|
6747
|
+
return policy.lastError;
|
|
6748
|
+
},
|
|
6749
|
+
get remoteStatus() {
|
|
6750
|
+
return remoteStatusRef.current;
|
|
6751
|
+
},
|
|
6752
|
+
get requestCount() {
|
|
6753
|
+
return requestCountRef.current;
|
|
6754
|
+
},
|
|
6755
|
+
get responseCount() {
|
|
6756
|
+
return responseCountRef.current;
|
|
6757
|
+
},
|
|
6758
|
+
get lastRequestBody() {
|
|
6759
|
+
return lastRequestBodyRef.current;
|
|
6760
|
+
},
|
|
6761
|
+
get lastResponseBody() {
|
|
6762
|
+
return lastResponseBodyRef.current;
|
|
6763
|
+
},
|
|
6764
|
+
get lastHttpStatus() {
|
|
6765
|
+
return lastHttpStatusRef.current;
|
|
6766
|
+
},
|
|
6767
|
+
get lastRequestMs() {
|
|
6768
|
+
return lastRequestMsRef.current;
|
|
6769
|
+
}
|
|
6770
|
+
};
|
|
6771
|
+
}, [policy]);
|
|
6772
|
+
}
|
|
6162
6773
|
var EMPTY_OBSERVATION = {
|
|
6163
6774
|
values: new Float32Array(0),
|
|
6164
6775
|
layout: []
|
|
@@ -6179,6 +6790,134 @@ function useObservation(config) {
|
|
|
6179
6790
|
}
|
|
6180
6791
|
}), [mjDataRef, mjModelRef]);
|
|
6181
6792
|
}
|
|
6793
|
+
|
|
6794
|
+
// src/policyObservation.ts
|
|
6795
|
+
function pushValues(target, value, size) {
|
|
6796
|
+
if (typeof value === "number") {
|
|
6797
|
+
target.push(value);
|
|
6798
|
+
for (let index = 1; index < size; index += 1) target.push(0);
|
|
6799
|
+
return;
|
|
6800
|
+
}
|
|
6801
|
+
for (let index = 0; index < size; index += 1) {
|
|
6802
|
+
target.push(Number(value[index] ?? 0));
|
|
6803
|
+
}
|
|
6804
|
+
}
|
|
6805
|
+
function readNamedObservation(model, data, options) {
|
|
6806
|
+
const values = [];
|
|
6807
|
+
const layout = [];
|
|
6808
|
+
const missing = options.missing ?? "skip";
|
|
6809
|
+
for (const field of options.fields) {
|
|
6810
|
+
const start = values.length;
|
|
6811
|
+
const value = field.read({ model, data });
|
|
6812
|
+
if (value === null || value === void 0) {
|
|
6813
|
+
if (missing === "skip") continue;
|
|
6814
|
+
if (missing === "throw") {
|
|
6815
|
+
throw new Error(`Unable to read named observation field "${field.name}".`);
|
|
6816
|
+
}
|
|
6817
|
+
for (let index = 0; index < field.size; index += 1) values.push(0);
|
|
6818
|
+
} else {
|
|
6819
|
+
pushValues(values, value, field.size);
|
|
6820
|
+
}
|
|
6821
|
+
layout.push({
|
|
6822
|
+
name: field.name,
|
|
6823
|
+
start,
|
|
6824
|
+
size: field.size,
|
|
6825
|
+
units: field.units
|
|
6826
|
+
});
|
|
6827
|
+
}
|
|
6828
|
+
return {
|
|
6829
|
+
values: options.output === "float64" ? new Float64Array(values) : new Float32Array(values),
|
|
6830
|
+
layout
|
|
6831
|
+
};
|
|
6832
|
+
}
|
|
6833
|
+
function createNamedObservationBuilder(options) {
|
|
6834
|
+
return (model, data) => readNamedObservation(model, data, options);
|
|
6835
|
+
}
|
|
6836
|
+
function qposField(name, index, units = "qpos") {
|
|
6837
|
+
return {
|
|
6838
|
+
name,
|
|
6839
|
+
size: 1,
|
|
6840
|
+
units,
|
|
6841
|
+
read: ({ data }) => data.qpos[index]
|
|
6842
|
+
};
|
|
6843
|
+
}
|
|
6844
|
+
function qvelField(name, index, units = "qvel") {
|
|
6845
|
+
return {
|
|
6846
|
+
name,
|
|
6847
|
+
size: 1,
|
|
6848
|
+
units,
|
|
6849
|
+
read: ({ data }) => data.qvel[index]
|
|
6850
|
+
};
|
|
6851
|
+
}
|
|
6852
|
+
function ctrlField(name, index, units = "ctrl") {
|
|
6853
|
+
return {
|
|
6854
|
+
name,
|
|
6855
|
+
size: 1,
|
|
6856
|
+
units,
|
|
6857
|
+
read: ({ data }) => data.ctrl[index]
|
|
6858
|
+
};
|
|
6859
|
+
}
|
|
6860
|
+
function bodyPositionField(name, units = "world_position") {
|
|
6861
|
+
return {
|
|
6862
|
+
name: `body:${name}:xpos`,
|
|
6863
|
+
size: 3,
|
|
6864
|
+
units,
|
|
6865
|
+
read: ({ model, data }) => {
|
|
6866
|
+
const bodyId = findBodyByName(model, name);
|
|
6867
|
+
if (bodyId < 0) return null;
|
|
6868
|
+
const offset = bodyId * 3;
|
|
6869
|
+
return data.xpos.subarray(offset, offset + 3);
|
|
6870
|
+
}
|
|
6871
|
+
};
|
|
6872
|
+
}
|
|
6873
|
+
function geomPositionField(name, units = "world_position") {
|
|
6874
|
+
return {
|
|
6875
|
+
name: `geom:${name}:xpos`,
|
|
6876
|
+
size: 3,
|
|
6877
|
+
units,
|
|
6878
|
+
read: ({ model, data }) => {
|
|
6879
|
+
const geomId = findGeomByName(model, name);
|
|
6880
|
+
if (geomId < 0) return null;
|
|
6881
|
+
const offset = geomId * 3;
|
|
6882
|
+
return data.geom_xpos.subarray(offset, offset + 3);
|
|
6883
|
+
}
|
|
6884
|
+
};
|
|
6885
|
+
}
|
|
6886
|
+
function sitePositionField(name, units = "world_position") {
|
|
6887
|
+
return {
|
|
6888
|
+
name: `site:${name}:xpos`,
|
|
6889
|
+
size: 3,
|
|
6890
|
+
units,
|
|
6891
|
+
read: ({ model, data }) => {
|
|
6892
|
+
const siteId = findSiteByName(model, name);
|
|
6893
|
+
if (siteId < 0) return null;
|
|
6894
|
+
const offset = siteId * 3;
|
|
6895
|
+
return data.site_xpos.subarray(offset, offset + 3);
|
|
6896
|
+
}
|
|
6897
|
+
};
|
|
6898
|
+
}
|
|
6899
|
+
|
|
6900
|
+
// src/hooks/useNamedObservation.ts
|
|
6901
|
+
var EMPTY_NAMED_OBSERVATION = {
|
|
6902
|
+
values: new Float32Array(0),
|
|
6903
|
+
layout: []
|
|
6904
|
+
};
|
|
6905
|
+
function useNamedObservation(options) {
|
|
6906
|
+
const { mjModelRef, mjDataRef } = useMujocoContext();
|
|
6907
|
+
const optionsRef = useRef(options);
|
|
6908
|
+
optionsRef.current = options;
|
|
6909
|
+
return useMemo(() => ({
|
|
6910
|
+
read() {
|
|
6911
|
+
const model = mjModelRef.current;
|
|
6912
|
+
const data = mjDataRef.current;
|
|
6913
|
+
if (!model || !data) return EMPTY_NAMED_OBSERVATION;
|
|
6914
|
+
return readNamedObservation(model, data, optionsRef.current);
|
|
6915
|
+
},
|
|
6916
|
+
readValues() {
|
|
6917
|
+
return this.read().values;
|
|
6918
|
+
}
|
|
6919
|
+
}), [mjDataRef, mjModelRef]);
|
|
6920
|
+
}
|
|
6182
6921
|
function useTrajectoryRecorder(options = {}) {
|
|
6183
6922
|
const { mjModelRef } = useMujocoContext();
|
|
6184
6923
|
const recordingRef = useRef(false);
|
|
@@ -6414,6 +7153,223 @@ function useCameraFrameCapture(defaultOptions = {}) {
|
|
|
6414
7153
|
reset
|
|
6415
7154
|
};
|
|
6416
7155
|
}
|
|
7156
|
+
|
|
7157
|
+
// src/policyCameraFrames.ts
|
|
7158
|
+
function addPolicyImageAliases(images, stream, frame, includeObservationImageAliases) {
|
|
7159
|
+
const keys = /* @__PURE__ */ new Set();
|
|
7160
|
+
keys.add(stream.key);
|
|
7161
|
+
for (const alias of stream.aliases ?? []) keys.add(alias);
|
|
7162
|
+
if (includeObservationImageAliases) {
|
|
7163
|
+
keys.add(`observation.images.${stream.key}`);
|
|
7164
|
+
for (const alias of stream.aliases ?? []) {
|
|
7165
|
+
keys.add(`observation.images.${alias}`);
|
|
7166
|
+
}
|
|
7167
|
+
}
|
|
7168
|
+
for (const key of keys) {
|
|
7169
|
+
images[key] = frame.dataUrl;
|
|
7170
|
+
}
|
|
7171
|
+
}
|
|
7172
|
+
function describeFrameSource(key, frame) {
|
|
7173
|
+
return `${key}:${frame.source.kind}`;
|
|
7174
|
+
}
|
|
7175
|
+
function hasExplicitPolicyCameraSource(options) {
|
|
7176
|
+
return Boolean(
|
|
7177
|
+
options?.camera || options?.position || options?.quaternion || options?.source
|
|
7178
|
+
);
|
|
7179
|
+
}
|
|
7180
|
+
function createPolicyCameraFrameCapturePlan(options) {
|
|
7181
|
+
const {
|
|
7182
|
+
cameraKeys,
|
|
7183
|
+
defaults,
|
|
7184
|
+
streamOptions,
|
|
7185
|
+
includeObservationImageAliases,
|
|
7186
|
+
requireAll,
|
|
7187
|
+
...sourceOptions
|
|
7188
|
+
} = options;
|
|
7189
|
+
const mountedPlan = createMountedCameraFrameSequencePlan(cameraKeys, {
|
|
7190
|
+
...sourceOptions,
|
|
7191
|
+
defaults,
|
|
7192
|
+
cameraOptions: streamOptions
|
|
7193
|
+
});
|
|
7194
|
+
const streams = [];
|
|
7195
|
+
const missingKeys = new Set(mountedPlan.missingKeys);
|
|
7196
|
+
for (const key of cameraKeys) {
|
|
7197
|
+
const perStreamOptions = streamOptions?.[key];
|
|
7198
|
+
if (hasExplicitPolicyCameraSource(perStreamOptions)) {
|
|
7199
|
+
missingKeys.delete(key);
|
|
7200
|
+
streams.push({
|
|
7201
|
+
...defaults,
|
|
7202
|
+
...perStreamOptions,
|
|
7203
|
+
key,
|
|
7204
|
+
aliases: perStreamOptions?.aliases
|
|
7205
|
+
});
|
|
7206
|
+
continue;
|
|
7207
|
+
}
|
|
7208
|
+
const mountedCamera = mountedPlan.cameras.find((camera) => camera.key === key);
|
|
7209
|
+
if (!mountedCamera) continue;
|
|
7210
|
+
const { key: _mountedKey, ...captureOptions } = mountedCamera;
|
|
7211
|
+
streams.push({
|
|
7212
|
+
...captureOptions,
|
|
7213
|
+
key,
|
|
7214
|
+
aliases: perStreamOptions?.aliases
|
|
7215
|
+
});
|
|
7216
|
+
}
|
|
7217
|
+
const result = {
|
|
7218
|
+
cameraKeys: [...cameraKeys],
|
|
7219
|
+
streams,
|
|
7220
|
+
includeObservationImageAliases,
|
|
7221
|
+
mountedPlan,
|
|
7222
|
+
missingKeys: [...missingKeys]
|
|
7223
|
+
};
|
|
7224
|
+
if (requireAll && result.missingKeys.length > 0) {
|
|
7225
|
+
throw new Error(
|
|
7226
|
+
`Unable to resolve policy camera stream${result.missingKeys.length === 1 ? "" : "s"} for ${result.missingKeys.join(", ")}.`
|
|
7227
|
+
);
|
|
7228
|
+
}
|
|
7229
|
+
return result;
|
|
7230
|
+
}
|
|
7231
|
+
function createPolicyCameraFrameCapturePlanFromApi(api, options) {
|
|
7232
|
+
return createPolicyCameraFrameCapturePlan({
|
|
7233
|
+
...options,
|
|
7234
|
+
cameras: api.getCameras(),
|
|
7235
|
+
sites: api.getSites(),
|
|
7236
|
+
bodies: api.getBodies()
|
|
7237
|
+
});
|
|
7238
|
+
}
|
|
7239
|
+
async function capturePolicyCameraFrames(target, options) {
|
|
7240
|
+
const includeObservationImageAliases = options.includeObservationImageAliases ?? true;
|
|
7241
|
+
const entries = await Promise.all(
|
|
7242
|
+
options.streams.map(async ({ key, aliases, ...captureOptions }) => {
|
|
7243
|
+
const frame = await target.captureCameraFrame(captureOptions);
|
|
7244
|
+
return [key, { frame, aliases }];
|
|
7245
|
+
})
|
|
7246
|
+
);
|
|
7247
|
+
const frames = {};
|
|
7248
|
+
const images = {};
|
|
7249
|
+
const sourceParts = [];
|
|
7250
|
+
for (const [key, { frame, aliases }] of entries) {
|
|
7251
|
+
const stream = { key, aliases };
|
|
7252
|
+
frames[key] = frame;
|
|
7253
|
+
addPolicyImageAliases(
|
|
7254
|
+
images,
|
|
7255
|
+
stream,
|
|
7256
|
+
frame,
|
|
7257
|
+
includeObservationImageAliases
|
|
7258
|
+
);
|
|
7259
|
+
sourceParts.push(describeFrameSource(key, frame));
|
|
7260
|
+
}
|
|
7261
|
+
return {
|
|
7262
|
+
frames,
|
|
7263
|
+
images,
|
|
7264
|
+
sourceSummary: sourceParts.length > 0 ? sourceParts.join(" + ") : "not used by policy",
|
|
7265
|
+
capturedAt: Date.now()
|
|
7266
|
+
};
|
|
7267
|
+
}
|
|
7268
|
+
async function capturePolicyCameraFramesFromMountedStreams(target, options) {
|
|
7269
|
+
const plan = createPolicyCameraFrameCapturePlanFromApi(target, options);
|
|
7270
|
+
const result = await capturePolicyCameraFrames(target, plan);
|
|
7271
|
+
return { ...result, plan };
|
|
7272
|
+
}
|
|
7273
|
+
|
|
7274
|
+
// src/hooks/usePolicyCameraFrames.ts
|
|
7275
|
+
function mergePolicyCameraFrameCaptureOptions(defaultOptions, options) {
|
|
7276
|
+
return {
|
|
7277
|
+
...defaultOptions,
|
|
7278
|
+
...options,
|
|
7279
|
+
cameraKeys: options.cameraKeys ?? defaultOptions.cameraKeys,
|
|
7280
|
+
aliases: {
|
|
7281
|
+
...defaultOptions.aliases,
|
|
7282
|
+
...options.aliases
|
|
7283
|
+
},
|
|
7284
|
+
defaults: {
|
|
7285
|
+
...defaultOptions.defaults,
|
|
7286
|
+
...options.defaults
|
|
7287
|
+
},
|
|
7288
|
+
streamOptions: {
|
|
7289
|
+
...defaultOptions.streamOptions,
|
|
7290
|
+
...options.streamOptions
|
|
7291
|
+
}
|
|
7292
|
+
};
|
|
7293
|
+
}
|
|
7294
|
+
function usePolicyCameraFrames(defaultOptions) {
|
|
7295
|
+
const mujoco = useMujoco();
|
|
7296
|
+
const [status, setStatus] = useState("idle");
|
|
7297
|
+
const [error, setError] = useState(null);
|
|
7298
|
+
const reset = useCallback(() => {
|
|
7299
|
+
setStatus("idle");
|
|
7300
|
+
setError(null);
|
|
7301
|
+
}, []);
|
|
7302
|
+
const capture = useCallback(
|
|
7303
|
+
async (options = {}) => {
|
|
7304
|
+
if (!mujoco.api) {
|
|
7305
|
+
throw new Error("MuJoCo scene is not ready for policy camera capture.");
|
|
7306
|
+
}
|
|
7307
|
+
setStatus("capturing");
|
|
7308
|
+
setError(null);
|
|
7309
|
+
try {
|
|
7310
|
+
const result = await capturePolicyCameraFrames(mujoco.api, {
|
|
7311
|
+
...defaultOptions,
|
|
7312
|
+
...options,
|
|
7313
|
+
streams: options.streams ?? defaultOptions.streams
|
|
7314
|
+
});
|
|
7315
|
+
setStatus("captured");
|
|
7316
|
+
return result;
|
|
7317
|
+
} catch (nextError) {
|
|
7318
|
+
const error2 = nextError instanceof Error ? nextError : new Error("Unable to capture policy camera frames.");
|
|
7319
|
+
setError(error2);
|
|
7320
|
+
setStatus("error");
|
|
7321
|
+
throw error2;
|
|
7322
|
+
}
|
|
7323
|
+
},
|
|
7324
|
+
[defaultOptions, mujoco.api]
|
|
7325
|
+
);
|
|
7326
|
+
return {
|
|
7327
|
+
status,
|
|
7328
|
+
error,
|
|
7329
|
+
isCapturing: status === "capturing",
|
|
7330
|
+
capture,
|
|
7331
|
+
reset
|
|
7332
|
+
};
|
|
7333
|
+
}
|
|
7334
|
+
function usePolicyCameraFramesFromMountedStreams(defaultOptions) {
|
|
7335
|
+
const mujoco = useMujoco();
|
|
7336
|
+
const [status, setStatus] = useState("idle");
|
|
7337
|
+
const [error, setError] = useState(null);
|
|
7338
|
+
const reset = useCallback(() => {
|
|
7339
|
+
setStatus("idle");
|
|
7340
|
+
setError(null);
|
|
7341
|
+
}, []);
|
|
7342
|
+
const capture = useCallback(
|
|
7343
|
+
async (options = {}) => {
|
|
7344
|
+
if (!mujoco.api) {
|
|
7345
|
+
throw new Error("MuJoCo scene is not ready for mounted policy camera capture.");
|
|
7346
|
+
}
|
|
7347
|
+
setStatus("capturing");
|
|
7348
|
+
setError(null);
|
|
7349
|
+
try {
|
|
7350
|
+
const result = await capturePolicyCameraFramesFromMountedStreams(
|
|
7351
|
+
mujoco.api,
|
|
7352
|
+
mergePolicyCameraFrameCaptureOptions(defaultOptions, options)
|
|
7353
|
+
);
|
|
7354
|
+
setStatus("captured");
|
|
7355
|
+
return result;
|
|
7356
|
+
} catch (nextError) {
|
|
7357
|
+
const error2 = nextError instanceof Error ? nextError : new Error("Unable to capture mounted policy camera frames.");
|
|
7358
|
+
setError(error2);
|
|
7359
|
+
setStatus("error");
|
|
7360
|
+
throw error2;
|
|
7361
|
+
}
|
|
7362
|
+
},
|
|
7363
|
+
[defaultOptions, mujoco.api]
|
|
7364
|
+
);
|
|
7365
|
+
return {
|
|
7366
|
+
status,
|
|
7367
|
+
error,
|
|
7368
|
+
isCapturing: status === "capturing",
|
|
7369
|
+
capture,
|
|
7370
|
+
reset
|
|
7371
|
+
};
|
|
7372
|
+
}
|
|
6417
7373
|
function useCameraSequenceRecorder() {
|
|
6418
7374
|
const mujoco = useMujoco();
|
|
6419
7375
|
const [status, setStatus] = useState("idle");
|
|
@@ -6534,6 +7490,38 @@ function useMountedCameraSequenceRecorder(defaultOptions = {}) {
|
|
|
6534
7490
|
reset
|
|
6535
7491
|
};
|
|
6536
7492
|
}
|
|
7493
|
+
|
|
7494
|
+
// src/policyControls.ts
|
|
7495
|
+
function clampPolicyActionValue(model, actuatorIndex, value) {
|
|
7496
|
+
const ranges = model.actuator_ctrlrange;
|
|
7497
|
+
const min = ranges?.[actuatorIndex * 2] ?? -Infinity;
|
|
7498
|
+
const max = ranges?.[actuatorIndex * 2 + 1] ?? Infinity;
|
|
7499
|
+
return Math.max(min, Math.min(max, value));
|
|
7500
|
+
}
|
|
7501
|
+
function applyPolicyActionToControls(model, data, action, options = {}) {
|
|
7502
|
+
const actuatorOffset = options.actuatorOffset ?? 0;
|
|
7503
|
+
const actionSize = options.actionSize ?? action.length;
|
|
7504
|
+
const shouldClamp = options.clamp ?? true;
|
|
7505
|
+
const shouldSkipInvalid = options.skipInvalid ?? true;
|
|
7506
|
+
const count = Math.max(
|
|
7507
|
+
0,
|
|
7508
|
+
Math.min(actionSize, action.length, data.ctrl.length - actuatorOffset, model.nu - actuatorOffset)
|
|
7509
|
+
);
|
|
7510
|
+
const applied = [];
|
|
7511
|
+
const skipped = [];
|
|
7512
|
+
for (let index = 0; index < count; index += 1) {
|
|
7513
|
+
const actuatorIndex = actuatorOffset + index;
|
|
7514
|
+
const value = Number(action[index]);
|
|
7515
|
+
if (shouldSkipInvalid && !Number.isFinite(value)) {
|
|
7516
|
+
skipped.push(actuatorIndex);
|
|
7517
|
+
continue;
|
|
7518
|
+
}
|
|
7519
|
+
const nextValue = shouldClamp ? clampPolicyActionValue(model, actuatorIndex, value) : value;
|
|
7520
|
+
data.ctrl[actuatorIndex] = nextValue;
|
|
7521
|
+
applied.push(nextValue);
|
|
7522
|
+
}
|
|
7523
|
+
return { applied, skipped, actuatorOffset };
|
|
7524
|
+
}
|
|
6537
7525
|
function useCtrlNoise(config = {}) {
|
|
6538
7526
|
const { mjModelRef } = useMujocoContext();
|
|
6539
7527
|
const configRef = useRef(config);
|
|
@@ -6585,7 +7573,7 @@ function useSelectionHighlight(bodyId, options = {}) {
|
|
|
6585
7573
|
}
|
|
6586
7574
|
}
|
|
6587
7575
|
prevRef.current = [];
|
|
6588
|
-
const highlightColor = new
|
|
7576
|
+
const highlightColor = new THREE10.Color(color);
|
|
6589
7577
|
for (const mesh of meshes) {
|
|
6590
7578
|
const mat = mesh.material;
|
|
6591
7579
|
if (mat.emissive) {
|
|
@@ -6612,15 +7600,15 @@ function useSelectionHighlight(bodyId, options = {}) {
|
|
|
6612
7600
|
}
|
|
6613
7601
|
function useCameraAnimation() {
|
|
6614
7602
|
const { camera } = useThree();
|
|
6615
|
-
const orbitTargetRef = useRef(new
|
|
7603
|
+
const orbitTargetRef = useRef(new THREE10.Vector3(0, 0, 0));
|
|
6616
7604
|
const cameraAnimRef = useRef({
|
|
6617
7605
|
active: false,
|
|
6618
|
-
startPos: new
|
|
6619
|
-
endPos: new
|
|
6620
|
-
startRot: new
|
|
6621
|
-
endRot: new
|
|
6622
|
-
startTarget: new
|
|
6623
|
-
endTarget: new
|
|
7606
|
+
startPos: new THREE10.Vector3(),
|
|
7607
|
+
endPos: new THREE10.Vector3(),
|
|
7608
|
+
startRot: new THREE10.Quaternion(),
|
|
7609
|
+
endRot: new THREE10.Quaternion(),
|
|
7610
|
+
startTarget: new THREE10.Vector3(),
|
|
7611
|
+
endTarget: new THREE10.Vector3(),
|
|
6624
7612
|
startTime: 0,
|
|
6625
7613
|
duration: 0,
|
|
6626
7614
|
resolve: null
|
|
@@ -6628,8 +7616,8 @@ function useCameraAnimation() {
|
|
|
6628
7616
|
useFrame((state) => {
|
|
6629
7617
|
const ca = cameraAnimRef.current;
|
|
6630
7618
|
if (!ca.active) return;
|
|
6631
|
-
const
|
|
6632
|
-
const progress = Math.min((
|
|
7619
|
+
const now2 = performance.now();
|
|
7620
|
+
const progress = Math.min((now2 - ca.startTime) / ca.duration, 1);
|
|
6633
7621
|
const ease = progress < 0.5 ? 4 * progress * progress * progress : 1 - Math.pow(-2 * progress + 2, 3) / 2;
|
|
6634
7622
|
camera.position.lerpVectors(ca.startPos, ca.endPos, ease);
|
|
6635
7623
|
camera.quaternion.slerpQuaternions(ca.startRot, ca.endRot, ease);
|
|
@@ -6795,12 +7783,30 @@ function useCameraAnimation() {
|
|
|
6795
7783
|
*
|
|
6796
7784
|
* useBodyState — per-body position/velocity tracking (spec 2.2)
|
|
6797
7785
|
*/
|
|
7786
|
+
/**
|
|
7787
|
+
* @license
|
|
7788
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
7789
|
+
*
|
|
7790
|
+
* Ref-based world pose hooks for named MuJoCo bodies, geoms, and sites.
|
|
7791
|
+
*/
|
|
6798
7792
|
/**
|
|
6799
7793
|
* @license
|
|
6800
7794
|
* SPDX-License-Identifier: Apache-2.0
|
|
6801
7795
|
*
|
|
6802
7796
|
* useCtrl — handle-based read/write access to a named actuator's ctrl value (spec 3.1)
|
|
6803
7797
|
*/
|
|
7798
|
+
/**
|
|
7799
|
+
* @license
|
|
7800
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
7801
|
+
*
|
|
7802
|
+
* Cooperative actuator/control ownership for policies, IK, teleop, and replay.
|
|
7803
|
+
*/
|
|
7804
|
+
/**
|
|
7805
|
+
* @license
|
|
7806
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
7807
|
+
*
|
|
7808
|
+
* Bounded contact history for rollout verification and debugging.
|
|
7809
|
+
*/
|
|
6804
7810
|
/**
|
|
6805
7811
|
* @license
|
|
6806
7812
|
* SPDX-License-Identifier: Apache-2.0
|
|
@@ -6813,6 +7819,24 @@ function useCameraAnimation() {
|
|
|
6813
7819
|
*
|
|
6814
7820
|
* usePolicy — policy decimation loop hook (spec 10.1)
|
|
6815
7821
|
*/
|
|
7822
|
+
/**
|
|
7823
|
+
* @license
|
|
7824
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
7825
|
+
*
|
|
7826
|
+
* useRemotePolicy — HTTP JSON inference wrapper around usePolicy.
|
|
7827
|
+
*/
|
|
7828
|
+
/**
|
|
7829
|
+
* @license
|
|
7830
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
7831
|
+
*
|
|
7832
|
+
* Named policy observation builders with layout and units metadata.
|
|
7833
|
+
*/
|
|
7834
|
+
/**
|
|
7835
|
+
* @license
|
|
7836
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
7837
|
+
*
|
|
7838
|
+
* Stable React handle for named policy observations.
|
|
7839
|
+
*/
|
|
6816
7840
|
/**
|
|
6817
7841
|
* @license
|
|
6818
7842
|
* SPDX-License-Identifier: Apache-2.0
|
|
@@ -6837,6 +7861,18 @@ function useCameraAnimation() {
|
|
|
6837
7861
|
*
|
|
6838
7862
|
* React state wrapper around MuJoCo/R3F offscreen camera-frame capture.
|
|
6839
7863
|
*/
|
|
7864
|
+
/**
|
|
7865
|
+
* @license
|
|
7866
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
7867
|
+
*
|
|
7868
|
+
* Helpers for turning Three/MuJoCo camera captures into policy image payloads.
|
|
7869
|
+
*/
|
|
7870
|
+
/**
|
|
7871
|
+
* @license
|
|
7872
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
7873
|
+
*
|
|
7874
|
+
* React wrapper for capturing policy image payloads from Three/MuJoCo cameras.
|
|
7875
|
+
*/
|
|
6840
7876
|
/**
|
|
6841
7877
|
* @license
|
|
6842
7878
|
* SPDX-License-Identifier: Apache-2.0
|
|
@@ -6849,6 +7885,12 @@ function useCameraAnimation() {
|
|
|
6849
7885
|
*
|
|
6850
7886
|
* React state wrapper for named MuJoCo camera/site/body sequence recording.
|
|
6851
7887
|
*/
|
|
7888
|
+
/**
|
|
7889
|
+
* @license
|
|
7890
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
7891
|
+
*
|
|
7892
|
+
* Helpers for applying policy action vectors to MuJoCo controls.
|
|
7893
|
+
*/
|
|
6852
7894
|
/**
|
|
6853
7895
|
* @license
|
|
6854
7896
|
* SPDX-License-Identifier: Apache-2.0
|
|
@@ -6879,6 +7921,6 @@ function useCameraAnimation() {
|
|
|
6879
7921
|
* useCameraAnimation — composable camera animation hook.
|
|
6880
7922
|
*/
|
|
6881
7923
|
|
|
6882
|
-
export { Body, ContactListener, ContactMarkers, Debug, DragInteraction, FlexRenderer, IkGizmo, InstancedGeomRenderer, MountedCameraFrameSequenceManifestStatus, MountedCameraFrameSequenceReadinessStatus, MountedCameraFrameSourceSuggestionMatch, MujocoCanvas, MujocoPhysics, MujocoProvider, MujocoSimProvider, SceneLights, SplatCollisionProxyPreview, TendonRenderer, TrajectoryPlayer, buildObservation, canFetchSplatCollisionProxyXml, captureFrame, captureFrameBlob, createContiguousControlGroup, createController, createControllerHook, createMountedCameraFrameSequenceManifest, createMountedCameraFrameSequencePlan, createMountedCameraFrameSequencePlanFromApi, createMountedCameraFrameSequenceReadiness, createMountedCameraFrameSourceSuggestions, fetchSplatCollisionProxyXml, findActuatorByName, findBodyByName, findGeomByName, findJointByName, findKeyframeByName, findSensorByName, findSiteByName, findTendonByName, getActuatedJoints, getCameraFrameCaptureSourceTarget, getControlMap, getMountedCameraFrameCaptureSource, getName, isMountedCameraFrameCaptureSource, loadScene, parseSplatCollisionProxyGeoms, recordMountedCameraFrameSequence, resolveControlGroup, resolveMountedCameraFrameSource, useActuators, useAfterPhysicsStep, useBeforePhysicsStep, useBodyMeshes, useBodyState, useCameraAnimation, useCameraFrameCapture, useCameraSequenceRecorder, useContactEvents, useContacts, useCtrl, useCtrlNoise, useFrameCapture, useGamepad, useGravityCompensation, useIkController, useJointState, useKeyboardIkTarget, useKeyboardTeleop, useMountedCameraSequenceRecorder, useMujoco, useMujocoWasm, useObservation, usePolicy, useSceneLights, useSelectionHighlight, useSensor, useSensors, useSitePosition, useSplatCollisionProxyGeoms, useTrajectoryPlayer, useTrajectoryRecorder, useVideoRecorder };
|
|
7924
|
+
export { Body, ContactListener, ContactMarkers, Debug, DragInteraction, FlexRenderer, IkGizmo, InstancedGeomRenderer, MountedCameraFrameSequenceManifestStatus, MountedCameraFrameSequenceReadinessStatus, MountedCameraFrameSourceSuggestionMatch, MujocoCanvas, MujocoPhysics, MujocoProvider, MujocoSimProvider, SceneLights, SplatCollisionProxyPreview, TendonRenderer, TrajectoryPlayer, applyPolicyActionToControls, bodyPositionField, buildObservation, canFetchSplatCollisionProxyXml, captureFrame, captureFrameBlob, capturePolicyCameraFrames, capturePolicyCameraFramesFromMountedStreams, clampPolicyActionValue, createContiguousControlGroup, createController, createControllerHook, createMountedCameraFrameSequenceManifest, createMountedCameraFrameSequencePlan, createMountedCameraFrameSequencePlanFromApi, createMountedCameraFrameSequenceReadiness, createMountedCameraFrameSourceSuggestions, createNamedObservationBuilder, createPolicyCameraFrameCapturePlan, createPolicyCameraFrameCapturePlanFromApi, ctrlField, fetchSplatCollisionProxyXml, findActuatorByName, findBodyByName, findGeomByName, findJointByName, findKeyframeByName, findSensorByName, findSiteByName, findTendonByName, geomPositionField, getActuatedJoints, getCameraFrameCaptureSourceTarget, getControlMap, getMountedCameraFrameCaptureSource, getName, isMountedCameraFrameCaptureSource, loadScene, parseSplatCollisionProxyGeoms, qposField, qvelField, readNamedObservation, recordMountedCameraFrameSequence, resolveControlGroup, resolveMountedCameraFrameSource, sitePositionField, useActuators, useAfterPhysicsStep, useBeforePhysicsStep, useBodyMeshes, useBodyPose, useBodyState, useCameraAnimation, useCameraFrameCapture, useCameraSequenceRecorder, useContactEvents, useContactHistory, useContacts, useControlWriter, useCtrl, useCtrlNoise, useFrameCapture, useGamepad, useGeomPose, useGravityCompensation, useIkController, useJointState, useKeyboardIkTarget, useKeyboardTeleop, useMountedCameraSequenceRecorder, useMujoco, useMujocoWasm, useNamedObservation, useObservation, usePolicy, usePolicyCameraFrames, usePolicyCameraFramesFromMountedStreams, useRemotePolicy, useSceneLights, useSelectionHighlight, useSensor, useSensors, useSitePose, useSitePosition, useSplatCollisionProxyGeoms, useTrajectoryPlayer, useTrajectoryRecorder, useVideoRecorder };
|
|
6883
7925
|
//# sourceMappingURL=index.js.map
|
|
6884
7926
|
//# sourceMappingURL=index.js.map
|