mujoco-react 9.1.0 → 9.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +28 -10
- package/dist/index.d.ts +43 -5
- package/dist/index.js +463 -132
- package/dist/index.js.map +1 -1
- package/dist/spark.d.ts +1 -1
- package/dist/{types-C5gTvR7b.d.ts → types-S8ggQY2n.d.ts} +72 -1
- package/package.json +1 -1
- package/src/core/MujocoSimProvider.tsx +119 -1
- package/src/core/createController.tsx +6 -2
- package/src/hooks/useCameraFrameCapture.ts +94 -0
- package/src/hooks/useCameraSequenceRecorder.ts +59 -0
- package/src/index.ts +18 -0
- package/src/rendering/cameraFrameCapture.ts +184 -0
- package/src/types.ts +90 -0
package/dist/index.js
CHANGED
|
@@ -4,7 +4,7 @@ import defaultMujocoWasmUrl from '@mujoco/mujoco/mujoco.wasm?url';
|
|
|
4
4
|
import { createContext, forwardRef, useEffect, useContext, useState, useRef, useCallback, useMemo, useLayoutEffect } from 'react';
|
|
5
5
|
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
6
6
|
import { Canvas, useThree, useFrame } from '@react-three/fiber';
|
|
7
|
-
import * as
|
|
7
|
+
import * as THREE12 from 'three';
|
|
8
8
|
import { PivotControls } from '@react-three/drei';
|
|
9
9
|
|
|
10
10
|
var MujocoContext = createContext({
|
|
@@ -178,16 +178,16 @@ function withContacts(data, read) {
|
|
|
178
178
|
contacts.delete?.();
|
|
179
179
|
}
|
|
180
180
|
}
|
|
181
|
-
var CapsuleGeometry = class extends
|
|
181
|
+
var CapsuleGeometry = class extends THREE12.BufferGeometry {
|
|
182
182
|
parameters;
|
|
183
183
|
constructor(radius = 1, length = 1, capSegments = 4, radialSegments = 8) {
|
|
184
184
|
super();
|
|
185
185
|
this.type = "CapsuleGeometry";
|
|
186
186
|
this.parameters = { radius, length, capSegments, radialSegments };
|
|
187
|
-
const path = new
|
|
187
|
+
const path = new THREE12.Path();
|
|
188
188
|
path.absarc(0, -length / 2, radius, Math.PI * 1.5, 0, false);
|
|
189
189
|
path.absarc(0, length / 2, radius, 0, Math.PI * 0.5, false);
|
|
190
|
-
const latheGeometry = new
|
|
190
|
+
const latheGeometry = new THREE12.LatheGeometry(path.getPoints(capSegments), radialSegments);
|
|
191
191
|
const self = this;
|
|
192
192
|
self.setIndex(latheGeometry.getIndex());
|
|
193
193
|
self.setAttribute("position", latheGeometry.getAttribute("position"));
|
|
@@ -195,27 +195,27 @@ var CapsuleGeometry = class extends THREE11.BufferGeometry {
|
|
|
195
195
|
self.setAttribute("uv", latheGeometry.getAttribute("uv"));
|
|
196
196
|
}
|
|
197
197
|
};
|
|
198
|
-
var Reflector = class extends
|
|
198
|
+
var Reflector = class extends THREE12.Mesh {
|
|
199
199
|
isReflector = true;
|
|
200
200
|
camera;
|
|
201
|
-
reflectorPlane = new
|
|
202
|
-
normal = new
|
|
203
|
-
reflectorWorldPosition = new
|
|
204
|
-
cameraWorldPosition = new
|
|
205
|
-
rotationMatrix = new
|
|
206
|
-
lookAtPosition = new
|
|
207
|
-
clipPlane = new
|
|
208
|
-
view = new
|
|
209
|
-
target = new
|
|
210
|
-
q = new
|
|
211
|
-
textureMatrix = new
|
|
201
|
+
reflectorPlane = new THREE12.Plane();
|
|
202
|
+
normal = new THREE12.Vector3();
|
|
203
|
+
reflectorWorldPosition = new THREE12.Vector3();
|
|
204
|
+
cameraWorldPosition = new THREE12.Vector3();
|
|
205
|
+
rotationMatrix = new THREE12.Matrix4();
|
|
206
|
+
lookAtPosition = new THREE12.Vector3(0, 0, -1);
|
|
207
|
+
clipPlane = new THREE12.Vector4();
|
|
208
|
+
view = new THREE12.Vector3();
|
|
209
|
+
target = new THREE12.Vector3();
|
|
210
|
+
q = new THREE12.Vector4();
|
|
211
|
+
textureMatrix = new THREE12.Matrix4();
|
|
212
212
|
virtualCamera;
|
|
213
213
|
renderTarget;
|
|
214
214
|
constructor(geometry, options = {}) {
|
|
215
215
|
super(geometry);
|
|
216
216
|
this.type = "Reflector";
|
|
217
|
-
this.camera = new
|
|
218
|
-
const color = options.color !== void 0 ? new
|
|
217
|
+
this.camera = new THREE12.PerspectiveCamera();
|
|
218
|
+
const color = options.color !== void 0 ? new THREE12.Color(options.color) : new THREE12.Color(8355711);
|
|
219
219
|
const textureWidth = options.textureWidth || 512;
|
|
220
220
|
const textureHeight = options.textureHeight || 512;
|
|
221
221
|
const clipBias = options.clipBias || 0;
|
|
@@ -223,11 +223,11 @@ var Reflector = class extends THREE11.Mesh {
|
|
|
223
223
|
const blendTexture = options.texture || void 0;
|
|
224
224
|
const mixStrength = options.mixStrength !== void 0 ? options.mixStrength : 0.25;
|
|
225
225
|
this.virtualCamera = this.camera;
|
|
226
|
-
this.renderTarget = new
|
|
226
|
+
this.renderTarget = new THREE12.WebGLRenderTarget(textureWidth, textureHeight, {
|
|
227
227
|
samples: multisample,
|
|
228
|
-
type:
|
|
228
|
+
type: THREE12.HalfFloatType
|
|
229
229
|
});
|
|
230
|
-
this.material = new
|
|
230
|
+
this.material = new THREE12.MeshPhysicalMaterial({
|
|
231
231
|
map: blendTexture,
|
|
232
232
|
color,
|
|
233
233
|
roughness: 0.5,
|
|
@@ -353,7 +353,7 @@ var GeomBuilder = class {
|
|
|
353
353
|
const pos = mjModel.geom_pos.subarray(g * 3, g * 3 + 3);
|
|
354
354
|
const quat = mjModel.geom_quat.subarray(g * 4, g * 4 + 4);
|
|
355
355
|
const matId = mjModel.geom_matid[g];
|
|
356
|
-
const color = new
|
|
356
|
+
const color = new THREE12.Color(16777215);
|
|
357
357
|
let opacity = 1;
|
|
358
358
|
if (matId >= 0) {
|
|
359
359
|
const rgba = mjModel.mat_rgba.subarray(matId * 4, matId * 4 + 4);
|
|
@@ -368,16 +368,16 @@ var GeomBuilder = class {
|
|
|
368
368
|
let geo = null;
|
|
369
369
|
const getVal = (v) => v?.value ?? v;
|
|
370
370
|
if (type === getVal(MG.mjGEOM_PLANE)) {
|
|
371
|
-
geo = new
|
|
371
|
+
geo = new THREE12.PlaneGeometry(size[0] * 2 || 5, size[1] * 2 || 5);
|
|
372
372
|
} else if (type === getVal(MG.mjGEOM_SPHERE)) {
|
|
373
|
-
geo = new
|
|
373
|
+
geo = new THREE12.SphereGeometry(size[0], 24, 24);
|
|
374
374
|
} else if (type === getVal(MG.mjGEOM_CAPSULE)) {
|
|
375
375
|
geo = new CapsuleGeometry(size[0], size[1] * 2, 24, 12);
|
|
376
376
|
geo.rotateX(Math.PI / 2);
|
|
377
377
|
} else if (type === getVal(MG.mjGEOM_BOX)) {
|
|
378
|
-
geo = new
|
|
378
|
+
geo = new THREE12.BoxGeometry(size[0] * 2, size[1] * 2, size[2] * 2);
|
|
379
379
|
} else if (type === getVal(MG.mjGEOM_CYLINDER)) {
|
|
380
|
-
geo = new
|
|
380
|
+
geo = new THREE12.CylinderGeometry(size[0], size[0], size[1] * 2, 24);
|
|
381
381
|
geo.rotateX(Math.PI / 2);
|
|
382
382
|
} else if (type === getVal(MG.mjGEOM_MESH)) {
|
|
383
383
|
const mId = mjModel.geom_dataid[g];
|
|
@@ -385,8 +385,8 @@ var GeomBuilder = class {
|
|
|
385
385
|
const vNum = mjModel.mesh_vertnum[mId];
|
|
386
386
|
const fAdr = mjModel.mesh_faceadr[mId];
|
|
387
387
|
const fNum = mjModel.mesh_facenum[mId];
|
|
388
|
-
geo = new
|
|
389
|
-
geo.setAttribute("position", new
|
|
388
|
+
geo = new THREE12.BufferGeometry();
|
|
389
|
+
geo.setAttribute("position", new THREE12.Float32BufferAttribute(mjModel.mesh_vert.subarray(vAdr * 3, (vAdr + vNum) * 3), 3));
|
|
390
390
|
geo.setIndex(Array.from(mjModel.mesh_face.subarray(fAdr * 3, (fAdr + fNum) * 3)));
|
|
391
391
|
geo.computeVertexNormals();
|
|
392
392
|
}
|
|
@@ -401,7 +401,7 @@ var GeomBuilder = class {
|
|
|
401
401
|
mixStrength: 0.25
|
|
402
402
|
});
|
|
403
403
|
} else {
|
|
404
|
-
mesh = new
|
|
404
|
+
mesh = new THREE12.Mesh(geo, new THREE12.MeshStandardMaterial({
|
|
405
405
|
color,
|
|
406
406
|
transparent: opacity < 1,
|
|
407
407
|
opacity,
|
|
@@ -1206,7 +1206,7 @@ function SceneRenderer(props) {
|
|
|
1206
1206
|
}
|
|
1207
1207
|
const refs = [];
|
|
1208
1208
|
for (let i = 0; i < model.nbody; i++) {
|
|
1209
|
-
const bodyGroup = new
|
|
1209
|
+
const bodyGroup = new THREE12.Group();
|
|
1210
1210
|
bodyGroup.userData.bodyID = i;
|
|
1211
1211
|
const bodyName = getName(model, model.name_bodyadr[i]);
|
|
1212
1212
|
if (!hiddenBodiesRef.current.has(bodyName)) {
|
|
@@ -1235,9 +1235,9 @@ function SceneRenderer(props) {
|
|
|
1235
1235
|
const alpha = interpolation.alpha;
|
|
1236
1236
|
const i3 = i * 3;
|
|
1237
1237
|
ref.position.set(
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1238
|
+
THREE12.MathUtils.lerp(interpolation.previousXpos[i3], interpolation.currentXpos[i3], alpha),
|
|
1239
|
+
THREE12.MathUtils.lerp(interpolation.previousXpos[i3 + 1], interpolation.currentXpos[i3 + 1], alpha),
|
|
1240
|
+
THREE12.MathUtils.lerp(interpolation.previousXpos[i3 + 2], interpolation.currentXpos[i3 + 2], alpha)
|
|
1241
1241
|
);
|
|
1242
1242
|
const i4 = i * 4;
|
|
1243
1243
|
_previousQuat.set(
|
|
@@ -1292,8 +1292,8 @@ function SceneRenderer(props) {
|
|
|
1292
1292
|
}
|
|
1293
1293
|
);
|
|
1294
1294
|
}
|
|
1295
|
-
var _previousQuat = new
|
|
1296
|
-
var _currentQuat = new
|
|
1295
|
+
var _previousQuat = new THREE12.Quaternion();
|
|
1296
|
+
var _currentQuat = new THREE12.Quaternion();
|
|
1297
1297
|
function isTargetRef(target) {
|
|
1298
1298
|
return Boolean(target && typeof target === "object" && "current" in target);
|
|
1299
1299
|
}
|
|
@@ -1402,6 +1402,124 @@ function useFrameCapture(defaultOptions = {}) {
|
|
|
1402
1402
|
reset
|
|
1403
1403
|
};
|
|
1404
1404
|
}
|
|
1405
|
+
function toVector3(value, fallback) {
|
|
1406
|
+
if (!value) return fallback.clone();
|
|
1407
|
+
return value instanceof THREE12.Vector3 ? value.clone() : new THREE12.Vector3(value[0], value[1], value[2]);
|
|
1408
|
+
}
|
|
1409
|
+
function applyCameraPose(camera, options, fallbackCamera) {
|
|
1410
|
+
camera.position.copy(toVector3(options.position, fallbackCamera.position));
|
|
1411
|
+
camera.up.copy(toVector3(options.up, fallbackCamera.up));
|
|
1412
|
+
if (options.quaternion) {
|
|
1413
|
+
if (options.quaternion instanceof THREE12.Quaternion) {
|
|
1414
|
+
camera.quaternion.copy(options.quaternion);
|
|
1415
|
+
} else {
|
|
1416
|
+
camera.quaternion.set(
|
|
1417
|
+
options.quaternion[0],
|
|
1418
|
+
options.quaternion[1],
|
|
1419
|
+
options.quaternion[2],
|
|
1420
|
+
options.quaternion[3]
|
|
1421
|
+
);
|
|
1422
|
+
}
|
|
1423
|
+
} else if (options.lookAt) {
|
|
1424
|
+
camera.lookAt(toVector3(options.lookAt, new THREE12.Vector3()));
|
|
1425
|
+
} else {
|
|
1426
|
+
camera.quaternion.copy(fallbackCamera.quaternion);
|
|
1427
|
+
}
|
|
1428
|
+
camera.updateMatrixWorld();
|
|
1429
|
+
}
|
|
1430
|
+
function createCaptureCamera(options, fallbackCamera, width, height) {
|
|
1431
|
+
const camera = options.camera ? options.camera.clone() : fallbackCamera instanceof THREE12.PerspectiveCamera ? fallbackCamera.clone() : new THREE12.PerspectiveCamera(45, width / height, 0.01, 100);
|
|
1432
|
+
if (camera instanceof THREE12.PerspectiveCamera) {
|
|
1433
|
+
camera.aspect = width / height;
|
|
1434
|
+
camera.fov = options.fov ?? camera.fov;
|
|
1435
|
+
camera.near = options.near ?? camera.near;
|
|
1436
|
+
camera.far = options.far ?? camera.far;
|
|
1437
|
+
camera.updateProjectionMatrix();
|
|
1438
|
+
}
|
|
1439
|
+
applyCameraPose(camera, options, fallbackCamera);
|
|
1440
|
+
return camera;
|
|
1441
|
+
}
|
|
1442
|
+
function readRenderTargetToCanvas(renderer, target, width, height) {
|
|
1443
|
+
const pixels = new Uint8Array(width * height * 4);
|
|
1444
|
+
renderer.readRenderTargetPixels(target, 0, 0, width, height, pixels);
|
|
1445
|
+
const canvas = document.createElement("canvas");
|
|
1446
|
+
canvas.width = width;
|
|
1447
|
+
canvas.height = height;
|
|
1448
|
+
const context = canvas.getContext("2d");
|
|
1449
|
+
if (!context) {
|
|
1450
|
+
throw new Error("Unable to create a 2D canvas for camera frame capture.");
|
|
1451
|
+
}
|
|
1452
|
+
const imageData = context.createImageData(width, height);
|
|
1453
|
+
const rowBytes = width * 4;
|
|
1454
|
+
for (let y = 0; y < height; y += 1) {
|
|
1455
|
+
const sourceStart = (height - y - 1) * rowBytes;
|
|
1456
|
+
const targetStart = y * rowBytes;
|
|
1457
|
+
imageData.data.set(
|
|
1458
|
+
pixels.subarray(sourceStart, sourceStart + rowBytes),
|
|
1459
|
+
targetStart
|
|
1460
|
+
);
|
|
1461
|
+
}
|
|
1462
|
+
context.putImageData(imageData, 0, 0);
|
|
1463
|
+
return canvas;
|
|
1464
|
+
}
|
|
1465
|
+
function renderCameraFrameToCanvas(renderer, scene, fallbackCamera, options = {}) {
|
|
1466
|
+
const width = Math.max(1, Math.floor(options.width ?? renderer.domElement.width));
|
|
1467
|
+
const height = Math.max(1, Math.floor(options.height ?? renderer.domElement.height));
|
|
1468
|
+
const camera = createCaptureCamera(options, fallbackCamera, width, height);
|
|
1469
|
+
const target = new THREE12.WebGLRenderTarget(width, height, {
|
|
1470
|
+
format: THREE12.RGBAFormat,
|
|
1471
|
+
type: THREE12.UnsignedByteType
|
|
1472
|
+
});
|
|
1473
|
+
const previousTarget = renderer.getRenderTarget();
|
|
1474
|
+
const previousXrEnabled = renderer.xr.enabled;
|
|
1475
|
+
scene.updateMatrixWorld(true);
|
|
1476
|
+
try {
|
|
1477
|
+
renderer.xr.enabled = false;
|
|
1478
|
+
renderer.setRenderTarget(target);
|
|
1479
|
+
renderer.clear();
|
|
1480
|
+
renderer.render(scene, camera);
|
|
1481
|
+
const canvas = readRenderTargetToCanvas(renderer, target, width, height);
|
|
1482
|
+
return { canvas, camera, width, height };
|
|
1483
|
+
} finally {
|
|
1484
|
+
renderer.setRenderTarget(previousTarget);
|
|
1485
|
+
renderer.xr.enabled = previousXrEnabled;
|
|
1486
|
+
target.dispose();
|
|
1487
|
+
}
|
|
1488
|
+
}
|
|
1489
|
+
async function captureCameraFrame(renderer, scene, fallbackCamera, options = {}) {
|
|
1490
|
+
const type = options.type ?? "image/png";
|
|
1491
|
+
const result = renderCameraFrameToCanvas(
|
|
1492
|
+
renderer,
|
|
1493
|
+
scene,
|
|
1494
|
+
fallbackCamera,
|
|
1495
|
+
options
|
|
1496
|
+
);
|
|
1497
|
+
return {
|
|
1498
|
+
...result,
|
|
1499
|
+
dataUrl: result.canvas.toDataURL(type, options.quality),
|
|
1500
|
+
type
|
|
1501
|
+
};
|
|
1502
|
+
}
|
|
1503
|
+
async function captureCameraFrameBlob(renderer, scene, fallbackCamera, options = {}) {
|
|
1504
|
+
const type = options.type ?? "image/png";
|
|
1505
|
+
const result = renderCameraFrameToCanvas(
|
|
1506
|
+
renderer,
|
|
1507
|
+
scene,
|
|
1508
|
+
fallbackCamera,
|
|
1509
|
+
options
|
|
1510
|
+
);
|
|
1511
|
+
const blob = await new Promise((resolve, reject) => {
|
|
1512
|
+
result.canvas.toBlob(
|
|
1513
|
+
(nextBlob) => {
|
|
1514
|
+
if (nextBlob) resolve(nextBlob);
|
|
1515
|
+
else reject(new Error("Camera frame capture did not produce a Blob."));
|
|
1516
|
+
},
|
|
1517
|
+
type,
|
|
1518
|
+
options.quality
|
|
1519
|
+
);
|
|
1520
|
+
});
|
|
1521
|
+
return { ...result, blob, type };
|
|
1522
|
+
}
|
|
1405
1523
|
var JOINT_TYPE_NAMES2 = ["free", "ball", "slide", "hinge"];
|
|
1406
1524
|
var GEOM_TYPE_NAMES = ["plane", "hfield", "sphere", "capsule", "ellipsoid", "cylinder", "box", "mesh"];
|
|
1407
1525
|
var SENSOR_TYPE_NAMES = {
|
|
@@ -1477,8 +1595,13 @@ var _applyPoint = new Float64Array(3);
|
|
|
1477
1595
|
var _rayPnt = new Float64Array(3);
|
|
1478
1596
|
var _rayVec = new Float64Array(3);
|
|
1479
1597
|
var _rayGeomId = new Int32Array(1);
|
|
1480
|
-
var _projRaycaster = new
|
|
1481
|
-
var _projNdc = new
|
|
1598
|
+
var _projRaycaster = new THREE12.Raycaster();
|
|
1599
|
+
var _projNdc = new THREE12.Vector2();
|
|
1600
|
+
function waitForNextAnimationFrame2() {
|
|
1601
|
+
return new Promise((resolve) => {
|
|
1602
|
+
requestAnimationFrame(() => resolve());
|
|
1603
|
+
});
|
|
1604
|
+
}
|
|
1482
1605
|
var MujocoSimContext = createContext(null);
|
|
1483
1606
|
function useMujocoContext() {
|
|
1484
1607
|
const ctx = useContext(MujocoSimContext);
|
|
@@ -1563,7 +1686,7 @@ function MujocoSimProvider({
|
|
|
1563
1686
|
interpolate,
|
|
1564
1687
|
children
|
|
1565
1688
|
}) {
|
|
1566
|
-
const { gl, camera } = useThree();
|
|
1689
|
+
const { gl, camera, scene } = useThree();
|
|
1567
1690
|
const [status, setStatus] = useState("loading");
|
|
1568
1691
|
const mjModelRef = useRef(null);
|
|
1569
1692
|
const mjDataRef = useRef(null);
|
|
@@ -1812,6 +1935,27 @@ function MujocoSimProvider({
|
|
|
1812
1935
|
const step = useCallback((n = 1) => {
|
|
1813
1936
|
stepsToRunRef.current = n;
|
|
1814
1937
|
}, []);
|
|
1938
|
+
const stepImmediately = useCallback((steps = 1) => {
|
|
1939
|
+
const model = mjModelRef.current;
|
|
1940
|
+
const data = mjDataRef.current;
|
|
1941
|
+
if (!model || !data) return false;
|
|
1942
|
+
for (let stepIndex = 0; stepIndex < steps; stepIndex += 1) {
|
|
1943
|
+
for (let i = 0; i < model.nv; i += 1) {
|
|
1944
|
+
data.qfrc_applied[i] = 0;
|
|
1945
|
+
}
|
|
1946
|
+
for (const cb of beforeStepCallbacks.current) {
|
|
1947
|
+
cb({ model, data });
|
|
1948
|
+
}
|
|
1949
|
+
mujoco.mj_step(model, data);
|
|
1950
|
+
for (const cb of afterStepCallbacks.current) {
|
|
1951
|
+
cb({ model, data });
|
|
1952
|
+
}
|
|
1953
|
+
onStepRef.current?.({ time: data.time, model, data });
|
|
1954
|
+
}
|
|
1955
|
+
physicsAccumulatorRef.current = 0;
|
|
1956
|
+
interpolationStateRef.current.valid = false;
|
|
1957
|
+
return true;
|
|
1958
|
+
}, [mujoco]);
|
|
1815
1959
|
const getTime = useCallback(() => {
|
|
1816
1960
|
return mjDataRef.current?.time ?? 0;
|
|
1817
1961
|
}, []);
|
|
@@ -2122,7 +2266,7 @@ function MujocoSimProvider({
|
|
|
2122
2266
|
const geomId = _rayGeomId[0];
|
|
2123
2267
|
const bodyId = geomId >= 0 ? model.geom_bodyid[geomId] : -1;
|
|
2124
2268
|
return {
|
|
2125
|
-
point: new
|
|
2269
|
+
point: new THREE12.Vector3(
|
|
2126
2270
|
origin.x + dir.x * dist,
|
|
2127
2271
|
origin.y + dir.y * dist,
|
|
2128
2272
|
origin.z + dir.z * dist
|
|
@@ -2268,6 +2412,70 @@ function MujocoSimProvider({
|
|
|
2268
2412
|
},
|
|
2269
2413
|
[gl]
|
|
2270
2414
|
);
|
|
2415
|
+
const captureCameraFrameApi = useCallback(
|
|
2416
|
+
(options = {}) => {
|
|
2417
|
+
return captureCameraFrame(gl, scene, camera, options);
|
|
2418
|
+
},
|
|
2419
|
+
[camera, gl, scene]
|
|
2420
|
+
);
|
|
2421
|
+
const captureCameraFrameBlobApi = useCallback(
|
|
2422
|
+
(options = {}) => {
|
|
2423
|
+
return captureCameraFrameBlob(gl, scene, camera, options);
|
|
2424
|
+
},
|
|
2425
|
+
[camera, gl, scene]
|
|
2426
|
+
);
|
|
2427
|
+
const recordCameraSequenceApi = useCallback(
|
|
2428
|
+
async (options) => {
|
|
2429
|
+
const frameCount = Math.max(0, Math.floor(options.frames));
|
|
2430
|
+
const stepsPerFrame = Math.max(1, Math.floor(options.stepsPerFrame ?? 1));
|
|
2431
|
+
const cameras = options.cameras;
|
|
2432
|
+
const frames = [];
|
|
2433
|
+
const wasPaused = pausedRef.current;
|
|
2434
|
+
if (frameCount === 0 || cameras.length === 0) {
|
|
2435
|
+
return {
|
|
2436
|
+
frames,
|
|
2437
|
+
cameraKeys: cameras.map((sequenceCamera) => sequenceCamera.key),
|
|
2438
|
+
frameCount: 0
|
|
2439
|
+
};
|
|
2440
|
+
}
|
|
2441
|
+
try {
|
|
2442
|
+
pausedRef.current = true;
|
|
2443
|
+
stepsToRunRef.current = 0;
|
|
2444
|
+
if (options.reset) reset();
|
|
2445
|
+
for (let frameIndex = 0; frameIndex < frameCount; frameIndex += 1) {
|
|
2446
|
+
if (frameIndex > 0 || options.captureInitialFrame === false) {
|
|
2447
|
+
stepImmediately(stepsPerFrame);
|
|
2448
|
+
}
|
|
2449
|
+
await waitForNextAnimationFrame2();
|
|
2450
|
+
const cameraFrames = {};
|
|
2451
|
+
for (const sequenceCamera of cameras) {
|
|
2452
|
+
const { key, ...captureOptions } = sequenceCamera;
|
|
2453
|
+
cameraFrames[key] = await captureCameraFrame(
|
|
2454
|
+
gl,
|
|
2455
|
+
scene,
|
|
2456
|
+
camera,
|
|
2457
|
+
captureOptions
|
|
2458
|
+
);
|
|
2459
|
+
}
|
|
2460
|
+
const frame = {
|
|
2461
|
+
frameIndex,
|
|
2462
|
+
time: getTime(),
|
|
2463
|
+
cameras: cameraFrames
|
|
2464
|
+
};
|
|
2465
|
+
frames.push(frame);
|
|
2466
|
+
await options.onFrame?.(frame);
|
|
2467
|
+
}
|
|
2468
|
+
} finally {
|
|
2469
|
+
pausedRef.current = wasPaused;
|
|
2470
|
+
}
|
|
2471
|
+
return {
|
|
2472
|
+
frames,
|
|
2473
|
+
cameraKeys: cameras.map((sequenceCamera) => sequenceCamera.key),
|
|
2474
|
+
frameCount: frames.length
|
|
2475
|
+
};
|
|
2476
|
+
},
|
|
2477
|
+
[camera, getTime, gl, reset, scene, stepImmediately]
|
|
2478
|
+
);
|
|
2271
2479
|
const project2DTo3D = useCallback(
|
|
2272
2480
|
(x, y, cameraPos, lookAt) => {
|
|
2273
2481
|
const virtCam = camera.clone();
|
|
@@ -2278,9 +2486,9 @@ function MujocoSimProvider({
|
|
|
2278
2486
|
_projNdc.set(x * 2 - 1, -(y * 2 - 1));
|
|
2279
2487
|
_projRaycaster.setFromCamera(_projNdc, virtCam);
|
|
2280
2488
|
const objects = [];
|
|
2281
|
-
const
|
|
2282
|
-
if (
|
|
2283
|
-
|
|
2489
|
+
const scene2 = camera.parent;
|
|
2490
|
+
if (scene2) {
|
|
2491
|
+
scene2.traverse((c) => {
|
|
2284
2492
|
if (c.isMesh) objects.push(c);
|
|
2285
2493
|
});
|
|
2286
2494
|
}
|
|
@@ -2378,6 +2586,9 @@ function MujocoSimProvider({
|
|
|
2378
2586
|
getCanvasSnapshot,
|
|
2379
2587
|
captureFrame: captureFrameApi,
|
|
2380
2588
|
captureFrameBlob: captureFrameBlobApi,
|
|
2589
|
+
captureCameraFrame: captureCameraFrameApi,
|
|
2590
|
+
captureCameraFrameBlob: captureCameraFrameBlobApi,
|
|
2591
|
+
recordCameraSequence: recordCameraSequenceApi,
|
|
2381
2592
|
project2DTo3D,
|
|
2382
2593
|
setBodyMass,
|
|
2383
2594
|
setGeomFriction,
|
|
@@ -2433,6 +2644,9 @@ function MujocoSimProvider({
|
|
|
2433
2644
|
getCanvasSnapshot,
|
|
2434
2645
|
captureFrameApi,
|
|
2435
2646
|
captureFrameBlobApi,
|
|
2647
|
+
captureCameraFrameApi,
|
|
2648
|
+
captureCameraFrameBlobApi,
|
|
2649
|
+
recordCameraSequenceApi,
|
|
2436
2650
|
project2DTo3D,
|
|
2437
2651
|
setBodyMass,
|
|
2438
2652
|
setGeomFriction,
|
|
@@ -2899,7 +3113,7 @@ function solve6x6(A, b, x) {
|
|
|
2899
3113
|
}
|
|
2900
3114
|
|
|
2901
3115
|
// src/hooks/useIkController.ts
|
|
2902
|
-
var _syncMat4 = new
|
|
3116
|
+
var _syncMat4 = new THREE12.Matrix4();
|
|
2903
3117
|
function syncGizmoToSite(data, siteId, target) {
|
|
2904
3118
|
if (siteId === -1) return;
|
|
2905
3119
|
const sitePos = data.site_xpos.subarray(siteId * 3, siteId * 3 + 3);
|
|
@@ -2931,7 +3145,7 @@ var useIkController = createControllerHook(
|
|
|
2931
3145
|
const { mjModelRef, mjDataRef, mujocoRef, resetCallbacks, status } = useMujocoContext();
|
|
2932
3146
|
const ikEnabledRef = useRef(false);
|
|
2933
3147
|
const ikCalculatingRef = useRef(false);
|
|
2934
|
-
const ikTargetRef = useRef(new
|
|
3148
|
+
const ikTargetRef = useRef(new THREE12.Group());
|
|
2935
3149
|
const siteIdRef = useRef(-1);
|
|
2936
3150
|
const controlGroupRef = useRef(null);
|
|
2937
3151
|
const genericIkRef = useRef(new GenericIK(mujocoRef.current));
|
|
@@ -2939,10 +3153,10 @@ var useIkController = createControllerHook(
|
|
|
2939
3153
|
const needsInitialSync = useRef(true);
|
|
2940
3154
|
const gizmoAnimRef = useRef({
|
|
2941
3155
|
active: false,
|
|
2942
|
-
startPos: new
|
|
2943
|
-
endPos: new
|
|
2944
|
-
startRot: new
|
|
2945
|
-
endRot: new
|
|
3156
|
+
startPos: new THREE12.Vector3(),
|
|
3157
|
+
endPos: new THREE12.Vector3(),
|
|
3158
|
+
startRot: new THREE12.Quaternion(),
|
|
3159
|
+
endRot: new THREE12.Quaternion(),
|
|
2946
3160
|
startTime: 0,
|
|
2947
3161
|
duration: 1e3
|
|
2948
3162
|
});
|
|
@@ -3087,8 +3301,8 @@ var useIkController = createControllerHook(
|
|
|
3087
3301
|
const target = ikTargetRef.current;
|
|
3088
3302
|
if (!target) return;
|
|
3089
3303
|
const targetPos = pos.clone();
|
|
3090
|
-
const targetRot = new
|
|
3091
|
-
new
|
|
3304
|
+
const targetRot = new THREE12.Quaternion().setFromEuler(
|
|
3305
|
+
new THREE12.Euler(Math.PI, 0, 0)
|
|
3092
3306
|
);
|
|
3093
3307
|
if (duration > 0) {
|
|
3094
3308
|
const ga = gizmoAnimRef.current;
|
|
@@ -3113,7 +3327,7 @@ var useIkController = createControllerHook(
|
|
|
3113
3327
|
if (!ikCalculatingRef.current || !target) return null;
|
|
3114
3328
|
return {
|
|
3115
3329
|
pos: target.position.clone(),
|
|
3116
|
-
rot: new
|
|
3330
|
+
rot: new THREE12.Euler().setFromQuaternion(target.quaternion)
|
|
3117
3331
|
};
|
|
3118
3332
|
},
|
|
3119
3333
|
[]
|
|
@@ -3209,10 +3423,10 @@ function Body({
|
|
|
3209
3423
|
if (!hasChildren) return null;
|
|
3210
3424
|
return /* @__PURE__ */ jsx("group", { ref: groupRef, children });
|
|
3211
3425
|
}
|
|
3212
|
-
var _mat4 = new
|
|
3213
|
-
var _pos = new
|
|
3214
|
-
var _quat = new
|
|
3215
|
-
var _scale = new
|
|
3426
|
+
var _mat4 = new THREE12.Matrix4();
|
|
3427
|
+
var _pos = new THREE12.Vector3();
|
|
3428
|
+
var _quat = new THREE12.Quaternion();
|
|
3429
|
+
var _scale = new THREE12.Vector3(1, 1, 1);
|
|
3216
3430
|
function IkGizmo({ controller, siteName, scale = 0.18, onDrag }) {
|
|
3217
3431
|
const { mjModelRef, mjDataRef, status } = useMujocoContext();
|
|
3218
3432
|
const { ikTargetRef, siteIdRef, ikEnabledRef, setIkEnabled } = controller;
|
|
@@ -3304,7 +3518,7 @@ function IkGizmo({ controller, siteName, scale = 0.18, onDrag }) {
|
|
|
3304
3518
|
}
|
|
3305
3519
|
) });
|
|
3306
3520
|
}
|
|
3307
|
-
var _dummy = new
|
|
3521
|
+
var _dummy = new THREE12.Object3D();
|
|
3308
3522
|
function ContactMarkers({
|
|
3309
3523
|
maxContacts = 100,
|
|
3310
3524
|
radius = 8e-3,
|
|
@@ -3348,11 +3562,11 @@ function ContactMarkers({
|
|
|
3348
3562
|
var _force = new Float64Array(3);
|
|
3349
3563
|
var _torque = new Float64Array(3);
|
|
3350
3564
|
var _point = new Float64Array(3);
|
|
3351
|
-
var _bodyPos = new
|
|
3352
|
-
var _bodyQuat = new
|
|
3353
|
-
var _worldHit = new
|
|
3354
|
-
var _raycaster = new
|
|
3355
|
-
var _mouse = new
|
|
3565
|
+
var _bodyPos = new THREE12.Vector3();
|
|
3566
|
+
var _bodyQuat = new THREE12.Quaternion();
|
|
3567
|
+
var _worldHit = new THREE12.Vector3();
|
|
3568
|
+
var _raycaster = new THREE12.Raycaster();
|
|
3569
|
+
var _mouse = new THREE12.Vector2();
|
|
3356
3570
|
function DragInteraction({
|
|
3357
3571
|
stiffness = 250,
|
|
3358
3572
|
showArrow = true,
|
|
@@ -3363,16 +3577,16 @@ function DragInteraction({
|
|
|
3363
3577
|
const draggingRef = useRef(false);
|
|
3364
3578
|
const bodyIdRef = useRef(-1);
|
|
3365
3579
|
const grabDistanceRef = useRef(0);
|
|
3366
|
-
const localHitRef = useRef(new
|
|
3367
|
-
const grabWorldRef = useRef(new
|
|
3368
|
-
const mouseWorldRef = useRef(new
|
|
3580
|
+
const localHitRef = useRef(new THREE12.Vector3());
|
|
3581
|
+
const grabWorldRef = useRef(new THREE12.Vector3());
|
|
3582
|
+
const mouseWorldRef = useRef(new THREE12.Vector3());
|
|
3369
3583
|
const arrowRef = useRef(null);
|
|
3370
3584
|
const groupRef = useRef(null);
|
|
3371
3585
|
useEffect(() => {
|
|
3372
3586
|
if (!showArrow || !groupRef.current) return;
|
|
3373
|
-
const arrow = new
|
|
3374
|
-
new
|
|
3375
|
-
new
|
|
3587
|
+
const arrow = new THREE12.ArrowHelper(
|
|
3588
|
+
new THREE12.Vector3(0, 1, 0),
|
|
3589
|
+
new THREE12.Vector3(),
|
|
3376
3590
|
0.1,
|
|
3377
3591
|
16729156
|
|
3378
3592
|
);
|
|
@@ -3554,7 +3768,7 @@ function useSceneLights(intensity = 1) {
|
|
|
3554
3768
|
const dr = lightDiffuse ? lightDiffuse[3 * i] : 1;
|
|
3555
3769
|
const dg = lightDiffuse ? lightDiffuse[3 * i + 1] : 1;
|
|
3556
3770
|
const db = lightDiffuse ? lightDiffuse[3 * i + 2] : 1;
|
|
3557
|
-
const color = new
|
|
3771
|
+
const color = new THREE12.Color(dr, dg, db);
|
|
3558
3772
|
const px = lightPos[3 * i];
|
|
3559
3773
|
const py = lightPos[3 * i + 1];
|
|
3560
3774
|
const pz = lightPos[3 * i + 2];
|
|
@@ -3562,7 +3776,7 @@ function useSceneLights(intensity = 1) {
|
|
|
3562
3776
|
const dy = lightDir[3 * i + 1];
|
|
3563
3777
|
const dz = lightDir[3 * i + 2];
|
|
3564
3778
|
if (isDirectional) {
|
|
3565
|
-
const light = new
|
|
3779
|
+
const light = new THREE12.DirectionalLight(color, finalIntensity);
|
|
3566
3780
|
light.position.set(px, py, pz);
|
|
3567
3781
|
light.target.position.set(px + dx, py + dy, pz + dz);
|
|
3568
3782
|
light.castShadow = castShadow;
|
|
@@ -3585,7 +3799,7 @@ function useSceneLights(intensity = 1) {
|
|
|
3585
3799
|
const cutoff = lightCutoff ? lightCutoff[i] : 45;
|
|
3586
3800
|
const exponent = lightExponent ? lightExponent[i] : 10;
|
|
3587
3801
|
const angle = cutoff * Math.PI / 180;
|
|
3588
|
-
const light = new
|
|
3802
|
+
const light = new THREE12.SpotLight(color, finalIntensity, 0, angle, exponent / 128);
|
|
3589
3803
|
light.position.set(px, py, pz);
|
|
3590
3804
|
light.target.position.set(px + dx, py + dy, pz + dz);
|
|
3591
3805
|
light.castShadow = castShadow;
|
|
@@ -3643,11 +3857,11 @@ var JOINT_COLORS = {
|
|
|
3643
3857
|
3: 16776960
|
|
3644
3858
|
// hinge - yellow
|
|
3645
3859
|
};
|
|
3646
|
-
var _v3a = new
|
|
3647
|
-
new
|
|
3648
|
-
var _quat2 = new
|
|
3649
|
-
var _contactPos = new
|
|
3650
|
-
var _contactNormal = new
|
|
3860
|
+
var _v3a = new THREE12.Vector3();
|
|
3861
|
+
new THREE12.Vector3();
|
|
3862
|
+
var _quat2 = new THREE12.Quaternion();
|
|
3863
|
+
var _contactPos = new THREE12.Vector3();
|
|
3864
|
+
var _contactNormal = new THREE12.Vector3();
|
|
3651
3865
|
var MAX_CONTACT_ARROWS = 50;
|
|
3652
3866
|
function Debug({
|
|
3653
3867
|
showGeoms = false,
|
|
@@ -3676,21 +3890,21 @@ function Debug({
|
|
|
3676
3890
|
let geometry = null;
|
|
3677
3891
|
switch (type) {
|
|
3678
3892
|
case 2:
|
|
3679
|
-
geometry = new
|
|
3893
|
+
geometry = new THREE12.SphereGeometry(s[3 * i], 12, 8);
|
|
3680
3894
|
break;
|
|
3681
3895
|
case 3:
|
|
3682
|
-
geometry = new
|
|
3896
|
+
geometry = new THREE12.CapsuleGeometry(s[3 * i], s[3 * i + 1] * 2, 6, 8);
|
|
3683
3897
|
break;
|
|
3684
3898
|
case 5:
|
|
3685
|
-
geometry = new
|
|
3899
|
+
geometry = new THREE12.CylinderGeometry(s[3 * i], s[3 * i], s[3 * i + 1] * 2, 12);
|
|
3686
3900
|
break;
|
|
3687
3901
|
case 6:
|
|
3688
|
-
geometry = new
|
|
3902
|
+
geometry = new THREE12.BoxGeometry(s[3 * i] * 2, s[3 * i + 1] * 2, s[3 * i + 2] * 2);
|
|
3689
3903
|
break;
|
|
3690
3904
|
}
|
|
3691
3905
|
if (geometry) {
|
|
3692
|
-
const mat = new
|
|
3693
|
-
const mesh = new
|
|
3906
|
+
const mat = new THREE12.MeshBasicMaterial({ color: 65280, wireframe: true, transparent: true, opacity: 0.3 });
|
|
3907
|
+
const mesh = new THREE12.Mesh(geometry, mat);
|
|
3694
3908
|
mesh.userData.geomId = i;
|
|
3695
3909
|
mesh.userData.bodyId = model.geom_bodyid[i];
|
|
3696
3910
|
geoms.push(mesh);
|
|
@@ -3713,9 +3927,9 @@ function Debug({
|
|
|
3713
3927
|
}
|
|
3714
3928
|
if (maxGeomSize > 0) radius = maxGeomSize * 0.15;
|
|
3715
3929
|
}
|
|
3716
|
-
const geometry = new
|
|
3717
|
-
const mat = new
|
|
3718
|
-
const mesh = new
|
|
3930
|
+
const geometry = new THREE12.OctahedronGeometry(radius);
|
|
3931
|
+
const mat = new THREE12.MeshBasicMaterial({ color: 16711935, depthTest: false });
|
|
3932
|
+
const mesh = new THREE12.Mesh(geometry, mat);
|
|
3719
3933
|
mesh.renderOrder = 999;
|
|
3720
3934
|
mesh.frustumCulled = false;
|
|
3721
3935
|
mesh.userData.siteId = i;
|
|
@@ -3727,9 +3941,9 @@ function Debug({
|
|
|
3727
3941
|
ctx.font = "bold 36px monospace";
|
|
3728
3942
|
ctx.textAlign = "center";
|
|
3729
3943
|
ctx.fillText(getName(model, model.name_siteadr[i]), 128, 42);
|
|
3730
|
-
const tex = new
|
|
3731
|
-
const spriteMat = new
|
|
3732
|
-
const sprite = new
|
|
3944
|
+
const tex = new THREE12.CanvasTexture(canvas);
|
|
3945
|
+
const spriteMat = new THREE12.SpriteMaterial({ map: tex, depthTest: false, transparent: true });
|
|
3946
|
+
const sprite = new THREE12.Sprite(spriteMat);
|
|
3733
3947
|
const labelScale = radius * 15;
|
|
3734
3948
|
sprite.scale.set(labelScale, labelScale * 0.25, 1);
|
|
3735
3949
|
sprite.position.y = radius * 2;
|
|
@@ -3752,9 +3966,9 @@ function Debug({
|
|
|
3752
3966
|
}
|
|
3753
3967
|
}
|
|
3754
3968
|
const arrowLen = Math.max(maxGeomSize * 0.8, 0.05);
|
|
3755
|
-
const arrow = new
|
|
3756
|
-
new
|
|
3757
|
-
new
|
|
3969
|
+
const arrow = new THREE12.ArrowHelper(
|
|
3970
|
+
new THREE12.Vector3(0, 0, 1),
|
|
3971
|
+
new THREE12.Vector3(),
|
|
3758
3972
|
arrowLen,
|
|
3759
3973
|
color,
|
|
3760
3974
|
arrowLen * 0.25,
|
|
@@ -3762,7 +3976,7 @@ function Debug({
|
|
|
3762
3976
|
);
|
|
3763
3977
|
arrow.renderOrder = 999;
|
|
3764
3978
|
arrow.frustumCulled = false;
|
|
3765
|
-
arrow.line.material = new
|
|
3979
|
+
arrow.line.material = new THREE12.LineBasicMaterial({ color, depthTest: false });
|
|
3766
3980
|
arrow.cone.material.depthTest = false;
|
|
3767
3981
|
arrow.line.renderOrder = 999;
|
|
3768
3982
|
arrow.line.frustumCulled = false;
|
|
@@ -3777,9 +3991,9 @@ function Debug({
|
|
|
3777
3991
|
}
|
|
3778
3992
|
if (showCOM) {
|
|
3779
3993
|
for (let i = 1; i < model.nbody; i++) {
|
|
3780
|
-
const geometry = new
|
|
3781
|
-
const mat = new
|
|
3782
|
-
const mesh = new
|
|
3994
|
+
const geometry = new THREE12.SphereGeometry(5e-3, 6, 6);
|
|
3995
|
+
const mat = new THREE12.MeshBasicMaterial({ color: 16711680 });
|
|
3996
|
+
const mesh = new THREE12.Mesh(geometry, mat);
|
|
3783
3997
|
mesh.userData.bodyId = i;
|
|
3784
3998
|
comMarkers.push(mesh);
|
|
3785
3999
|
}
|
|
@@ -3870,9 +4084,9 @@ function Debug({
|
|
|
3870
4084
|
contactPoolInitRef.current = true;
|
|
3871
4085
|
const pool = [];
|
|
3872
4086
|
for (let i = 0; i < MAX_CONTACT_ARROWS; i++) {
|
|
3873
|
-
const arrow = new
|
|
3874
|
-
new
|
|
3875
|
-
new
|
|
4087
|
+
const arrow = new THREE12.ArrowHelper(
|
|
4088
|
+
new THREE12.Vector3(0, 1, 0),
|
|
4089
|
+
new THREE12.Vector3(),
|
|
3876
4090
|
0.1,
|
|
3877
4091
|
16729156,
|
|
3878
4092
|
0.03,
|
|
@@ -3927,9 +4141,9 @@ function Debug({
|
|
|
3927
4141
|
showContacts && /* @__PURE__ */ jsx("group", { ref: contactGroupRef })
|
|
3928
4142
|
] });
|
|
3929
4143
|
}
|
|
3930
|
-
var DEFAULT_TENDON_COLOR = new
|
|
4144
|
+
var DEFAULT_TENDON_COLOR = new THREE12.Color(0.3, 0.3, 0.8);
|
|
3931
4145
|
var DEFAULT_TENDON_WIDTH = 2e-3;
|
|
3932
|
-
new
|
|
4146
|
+
new THREE12.Vector3();
|
|
3933
4147
|
function TendonRenderer(props) {
|
|
3934
4148
|
const { mjModelRef, mjDataRef, status } = useMujocoContext();
|
|
3935
4149
|
const groupRef = useRef(null);
|
|
@@ -3943,7 +4157,7 @@ function TendonRenderer(props) {
|
|
|
3943
4157
|
if (!model || !data || !group) return;
|
|
3944
4158
|
const ntendon = model.ntendon ?? 0;
|
|
3945
4159
|
if (ntendon === 0) return;
|
|
3946
|
-
const material = new
|
|
4160
|
+
const material = new THREE12.MeshStandardMaterial({
|
|
3947
4161
|
color: DEFAULT_TENDON_COLOR,
|
|
3948
4162
|
roughness: 0.6,
|
|
3949
4163
|
metalness: 0.1
|
|
@@ -3958,11 +4172,11 @@ function TendonRenderer(props) {
|
|
|
3958
4172
|
curves.push(null);
|
|
3959
4173
|
continue;
|
|
3960
4174
|
}
|
|
3961
|
-
const points = Array.from({ length: wrapNum }, () => new
|
|
3962
|
-
const curve = new
|
|
4175
|
+
const points = Array.from({ length: wrapNum }, () => new THREE12.Vector3());
|
|
4176
|
+
const curve = new THREE12.CatmullRomCurve3(points, false);
|
|
3963
4177
|
const segments = Math.max(wrapNum * 2, 4);
|
|
3964
|
-
const geometry = new
|
|
3965
|
-
const mesh = new
|
|
4178
|
+
const geometry = new THREE12.TubeGeometry(curve, segments, DEFAULT_TENDON_WIDTH, 6, false);
|
|
4179
|
+
const mesh = new THREE12.Mesh(geometry, material);
|
|
3966
4180
|
mesh.frustumCulled = false;
|
|
3967
4181
|
group.add(mesh);
|
|
3968
4182
|
meshes.push(mesh);
|
|
@@ -4017,11 +4231,11 @@ function TendonRenderer(props) {
|
|
|
4017
4231
|
if (curve.points.length !== validCount) {
|
|
4018
4232
|
curve.points.length = validCount;
|
|
4019
4233
|
while (curve.points.length < validCount) {
|
|
4020
|
-
curve.points.push(new
|
|
4234
|
+
curve.points.push(new THREE12.Vector3());
|
|
4021
4235
|
}
|
|
4022
4236
|
}
|
|
4023
4237
|
mesh.geometry.dispose();
|
|
4024
|
-
mesh.geometry = new
|
|
4238
|
+
mesh.geometry = new THREE12.TubeGeometry(
|
|
4025
4239
|
curve,
|
|
4026
4240
|
Math.max(validCount * 2, 4),
|
|
4027
4241
|
DEFAULT_TENDON_WIDTH,
|
|
@@ -4048,24 +4262,24 @@ function FlexRenderer(props) {
|
|
|
4048
4262
|
const vertAdr = model.flex_vertadr[f];
|
|
4049
4263
|
const vertNum = model.flex_vertnum[f];
|
|
4050
4264
|
if (vertNum === 0) continue;
|
|
4051
|
-
const geometry = new
|
|
4265
|
+
const geometry = new THREE12.BufferGeometry();
|
|
4052
4266
|
const positions = new Float32Array(vertNum * 3);
|
|
4053
|
-
geometry.setAttribute("position", new
|
|
4267
|
+
geometry.setAttribute("position", new THREE12.BufferAttribute(positions, 3));
|
|
4054
4268
|
geometry.computeVertexNormals();
|
|
4055
|
-
let color = new
|
|
4269
|
+
let color = new THREE12.Color(0.5, 0.5, 0.5);
|
|
4056
4270
|
if (model.flex_rgba) {
|
|
4057
|
-
color = new
|
|
4271
|
+
color = new THREE12.Color(
|
|
4058
4272
|
model.flex_rgba[4 * f],
|
|
4059
4273
|
model.flex_rgba[4 * f + 1],
|
|
4060
4274
|
model.flex_rgba[4 * f + 2]
|
|
4061
4275
|
);
|
|
4062
4276
|
}
|
|
4063
|
-
const material = new
|
|
4277
|
+
const material = new THREE12.MeshStandardMaterial({
|
|
4064
4278
|
color,
|
|
4065
4279
|
roughness: 0.7,
|
|
4066
|
-
side:
|
|
4280
|
+
side: THREE12.DoubleSide
|
|
4067
4281
|
});
|
|
4068
|
-
const mesh = new
|
|
4282
|
+
const mesh = new THREE12.Mesh(geometry, material);
|
|
4069
4283
|
mesh.userData.flexId = f;
|
|
4070
4284
|
mesh.userData.vertAdr = vertAdr;
|
|
4071
4285
|
mesh.userData.vertNum = vertNum;
|
|
@@ -4101,7 +4315,7 @@ function FlexRenderer(props) {
|
|
|
4101
4315
|
return /* @__PURE__ */ jsx("group", { ...props, ref: groupRef });
|
|
4102
4316
|
}
|
|
4103
4317
|
var GEOM_TYPE_NAMES2 = ["plane", "hfield", "sphere", "capsule", "ellipsoid", "cylinder", "box", "mesh"];
|
|
4104
|
-
var _matrix = new
|
|
4318
|
+
var _matrix = new THREE12.Matrix4();
|
|
4105
4319
|
function getGeomInfo(model, geomId) {
|
|
4106
4320
|
const size = model.geom_size.subarray(geomId * 3, geomId * 3 + 3);
|
|
4107
4321
|
const type = model.geom_type[geomId];
|
|
@@ -4123,10 +4337,10 @@ function geomSignature(model, geomId) {
|
|
|
4123
4337
|
return [type, size, mat, data, rgba].join("|");
|
|
4124
4338
|
}
|
|
4125
4339
|
function firstMesh(object) {
|
|
4126
|
-
if (object instanceof
|
|
4340
|
+
if (object instanceof THREE12.Mesh) return object;
|
|
4127
4341
|
let mesh = null;
|
|
4128
4342
|
object.traverse((child) => {
|
|
4129
|
-
if (!mesh && child instanceof
|
|
4343
|
+
if (!mesh && child instanceof THREE12.Mesh) mesh = child;
|
|
4130
4344
|
});
|
|
4131
4345
|
return mesh;
|
|
4132
4346
|
}
|
|
@@ -4555,12 +4769,12 @@ function useActuators() {
|
|
|
4555
4769
|
return actuators;
|
|
4556
4770
|
}, [status, mjModelRef]);
|
|
4557
4771
|
}
|
|
4558
|
-
var _mat42 = new
|
|
4772
|
+
var _mat42 = new THREE12.Matrix4();
|
|
4559
4773
|
function useSitePosition(siteName) {
|
|
4560
4774
|
const { mjModelRef, mjDataRef, status } = useMujocoContext();
|
|
4561
4775
|
const siteIdRef = useRef(-1);
|
|
4562
|
-
const positionRef = useRef(new
|
|
4563
|
-
const quaternionRef = useRef(new
|
|
4776
|
+
const positionRef = useRef(new THREE12.Vector3());
|
|
4777
|
+
const quaternionRef = useRef(new THREE12.Quaternion());
|
|
4564
4778
|
useEffect(() => {
|
|
4565
4779
|
const model = mjModelRef.current;
|
|
4566
4780
|
if (!model || status !== "ready") {
|
|
@@ -4751,10 +4965,10 @@ function useJointState(name) {
|
|
|
4751
4965
|
function useBodyState(name) {
|
|
4752
4966
|
const { mjModelRef, status } = useMujocoContext();
|
|
4753
4967
|
const bodyIdRef = useRef(-1);
|
|
4754
|
-
const position = useRef(new
|
|
4755
|
-
const quaternion = useRef(new
|
|
4756
|
-
const linearVelocity = useRef(new
|
|
4757
|
-
const angularVelocity = useRef(new
|
|
4968
|
+
const position = useRef(new THREE12.Vector3());
|
|
4969
|
+
const quaternion = useRef(new THREE12.Quaternion());
|
|
4970
|
+
const linearVelocity = useRef(new THREE12.Vector3());
|
|
4971
|
+
const angularVelocity = useRef(new THREE12.Vector3());
|
|
4758
4972
|
useEffect(() => {
|
|
4759
4973
|
const model = mjModelRef.current;
|
|
4760
4974
|
if (!model || status !== "ready") return;
|
|
@@ -5108,6 +5322,105 @@ function useVideoRecorder(options = {}) {
|
|
|
5108
5322
|
}
|
|
5109
5323
|
};
|
|
5110
5324
|
}
|
|
5325
|
+
function useCameraFrameCapture(defaultOptions = {}) {
|
|
5326
|
+
const mujoco = useMujoco();
|
|
5327
|
+
const [status, setStatus] = useState("idle");
|
|
5328
|
+
const [error, setError] = useState(null);
|
|
5329
|
+
const reset = useCallback(() => {
|
|
5330
|
+
setStatus("idle");
|
|
5331
|
+
setError(null);
|
|
5332
|
+
}, []);
|
|
5333
|
+
const capture = useCallback(
|
|
5334
|
+
async (options = {}) => {
|
|
5335
|
+
if (!mujoco.api) {
|
|
5336
|
+
throw new Error("MuJoCo scene is not ready for camera frame capture.");
|
|
5337
|
+
}
|
|
5338
|
+
setStatus("capturing");
|
|
5339
|
+
setError(null);
|
|
5340
|
+
try {
|
|
5341
|
+
const result = await mujoco.api.captureCameraFrame({
|
|
5342
|
+
...defaultOptions,
|
|
5343
|
+
...options
|
|
5344
|
+
});
|
|
5345
|
+
setStatus("captured");
|
|
5346
|
+
return result;
|
|
5347
|
+
} catch (nextError) {
|
|
5348
|
+
const error2 = nextError instanceof Error ? nextError : new Error("Unable to capture the requested camera frame.");
|
|
5349
|
+
setError(error2);
|
|
5350
|
+
setStatus("error");
|
|
5351
|
+
throw error2;
|
|
5352
|
+
}
|
|
5353
|
+
},
|
|
5354
|
+
[defaultOptions, mujoco.api]
|
|
5355
|
+
);
|
|
5356
|
+
const captureBlob = useCallback(
|
|
5357
|
+
async (options = {}) => {
|
|
5358
|
+
if (!mujoco.api) {
|
|
5359
|
+
throw new Error("MuJoCo scene is not ready for camera frame capture.");
|
|
5360
|
+
}
|
|
5361
|
+
setStatus("capturing");
|
|
5362
|
+
setError(null);
|
|
5363
|
+
try {
|
|
5364
|
+
const result = await mujoco.api.captureCameraFrameBlob({
|
|
5365
|
+
...defaultOptions,
|
|
5366
|
+
...options
|
|
5367
|
+
});
|
|
5368
|
+
setStatus("captured");
|
|
5369
|
+
return result;
|
|
5370
|
+
} catch (nextError) {
|
|
5371
|
+
const error2 = nextError instanceof Error ? nextError : new Error("Unable to capture the requested camera frame.");
|
|
5372
|
+
setError(error2);
|
|
5373
|
+
setStatus("error");
|
|
5374
|
+
throw error2;
|
|
5375
|
+
}
|
|
5376
|
+
},
|
|
5377
|
+
[defaultOptions, mujoco.api]
|
|
5378
|
+
);
|
|
5379
|
+
return {
|
|
5380
|
+
status,
|
|
5381
|
+
error,
|
|
5382
|
+
isCapturing: status === "capturing",
|
|
5383
|
+
capture,
|
|
5384
|
+
captureBlob,
|
|
5385
|
+
reset
|
|
5386
|
+
};
|
|
5387
|
+
}
|
|
5388
|
+
function useCameraSequenceRecorder() {
|
|
5389
|
+
const mujoco = useMujoco();
|
|
5390
|
+
const [status, setStatus] = useState("idle");
|
|
5391
|
+
const [error, setError] = useState(null);
|
|
5392
|
+
const reset = useCallback(() => {
|
|
5393
|
+
setStatus("idle");
|
|
5394
|
+
setError(null);
|
|
5395
|
+
}, []);
|
|
5396
|
+
const record = useCallback(
|
|
5397
|
+
async (options) => {
|
|
5398
|
+
if (!mujoco.api) {
|
|
5399
|
+
throw new Error("MuJoCo scene is not ready for camera sequence recording.");
|
|
5400
|
+
}
|
|
5401
|
+
setStatus("capturing");
|
|
5402
|
+
setError(null);
|
|
5403
|
+
try {
|
|
5404
|
+
const result = await mujoco.api.recordCameraSequence(options);
|
|
5405
|
+
setStatus("captured");
|
|
5406
|
+
return result;
|
|
5407
|
+
} catch (nextError) {
|
|
5408
|
+
const error2 = nextError instanceof Error ? nextError : new Error("Unable to record the requested camera sequence.");
|
|
5409
|
+
setError(error2);
|
|
5410
|
+
setStatus("error");
|
|
5411
|
+
throw error2;
|
|
5412
|
+
}
|
|
5413
|
+
},
|
|
5414
|
+
[mujoco.api]
|
|
5415
|
+
);
|
|
5416
|
+
return {
|
|
5417
|
+
status,
|
|
5418
|
+
error,
|
|
5419
|
+
isRecording: status === "capturing",
|
|
5420
|
+
record,
|
|
5421
|
+
reset
|
|
5422
|
+
};
|
|
5423
|
+
}
|
|
5111
5424
|
function useCtrlNoise(config = {}) {
|
|
5112
5425
|
const { mjModelRef } = useMujocoContext();
|
|
5113
5426
|
const configRef = useRef(config);
|
|
@@ -5159,7 +5472,7 @@ function useSelectionHighlight(bodyId, options = {}) {
|
|
|
5159
5472
|
}
|
|
5160
5473
|
}
|
|
5161
5474
|
prevRef.current = [];
|
|
5162
|
-
const highlightColor = new
|
|
5475
|
+
const highlightColor = new THREE12.Color(color);
|
|
5163
5476
|
for (const mesh of meshes) {
|
|
5164
5477
|
const mat = mesh.material;
|
|
5165
5478
|
if (mat.emissive) {
|
|
@@ -5186,15 +5499,15 @@ function useSelectionHighlight(bodyId, options = {}) {
|
|
|
5186
5499
|
}
|
|
5187
5500
|
function useCameraAnimation() {
|
|
5188
5501
|
const { camera } = useThree();
|
|
5189
|
-
const orbitTargetRef = useRef(new
|
|
5502
|
+
const orbitTargetRef = useRef(new THREE12.Vector3(0, 0, 0));
|
|
5190
5503
|
const cameraAnimRef = useRef({
|
|
5191
5504
|
active: false,
|
|
5192
|
-
startPos: new
|
|
5193
|
-
endPos: new
|
|
5194
|
-
startRot: new
|
|
5195
|
-
endRot: new
|
|
5196
|
-
startTarget: new
|
|
5197
|
-
endTarget: new
|
|
5505
|
+
startPos: new THREE12.Vector3(),
|
|
5506
|
+
endPos: new THREE12.Vector3(),
|
|
5507
|
+
startRot: new THREE12.Quaternion(),
|
|
5508
|
+
endRot: new THREE12.Quaternion(),
|
|
5509
|
+
startTarget: new THREE12.Vector3(),
|
|
5510
|
+
endTarget: new THREE12.Vector3(),
|
|
5198
5511
|
startTime: 0,
|
|
5199
5512
|
duration: 0,
|
|
5200
5513
|
resolve: null
|
|
@@ -5266,6 +5579,12 @@ function useCameraAnimation() {
|
|
|
5266
5579
|
*
|
|
5267
5580
|
* useFrameCapture — still-frame capture for canvas-backed MuJoCo/R3F scenes.
|
|
5268
5581
|
*/
|
|
5582
|
+
/**
|
|
5583
|
+
* @license
|
|
5584
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5585
|
+
*
|
|
5586
|
+
* Offscreen camera-frame capture for R3F/MuJoCo scenes.
|
|
5587
|
+
*/
|
|
5269
5588
|
/**
|
|
5270
5589
|
* @license
|
|
5271
5590
|
* SPDX-License-Identifier: Apache-2.0
|
|
@@ -5399,6 +5718,18 @@ function useCameraAnimation() {
|
|
|
5399
5718
|
*
|
|
5400
5719
|
* useVideoRecorder — canvas video recording hook (spec 13.3)
|
|
5401
5720
|
*/
|
|
5721
|
+
/**
|
|
5722
|
+
* @license
|
|
5723
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5724
|
+
*
|
|
5725
|
+
* React state wrapper around MuJoCo/R3F offscreen camera-frame capture.
|
|
5726
|
+
*/
|
|
5727
|
+
/**
|
|
5728
|
+
* @license
|
|
5729
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5730
|
+
*
|
|
5731
|
+
* React state wrapper around fixed-camera simulation sequence recording.
|
|
5732
|
+
*/
|
|
5402
5733
|
/**
|
|
5403
5734
|
* @license
|
|
5404
5735
|
* SPDX-License-Identifier: Apache-2.0
|
|
@@ -5429,6 +5760,6 @@ function useCameraAnimation() {
|
|
|
5429
5760
|
* useCameraAnimation — composable camera animation hook.
|
|
5430
5761
|
*/
|
|
5431
5762
|
|
|
5432
|
-
export { Body, ContactListener, ContactMarkers, Debug, DragInteraction, FlexRenderer, IkGizmo, InstancedGeomRenderer, MujocoCanvas, MujocoPhysics, MujocoProvider, MujocoSimProvider, RobotActuators, RobotBodies, RobotGeoms, RobotJoints, RobotKeyframes, RobotResources, RobotSensors, RobotSites, SceneLights, TendonRenderer, TrajectoryPlayer, buildObservation, captureFrame, captureFrameBlob, createContiguousControlGroup, createController, createControllerHook, findActuatorByName, findBodyByName, findGeomByName, findJointByName, findKeyframeByName, findSensorByName, findSiteByName, findTendonByName, getActuatedJoints, getContact, getControlMap, getName, loadScene, registerRobotResources, resolveControlGroup, useActuators, useAfterPhysicsStep, useBeforePhysicsStep, useBodyMeshes, useBodyState, useCameraAnimation, useContactEvents, useContacts, useCtrl, useCtrlNoise, useFrameCapture, useGamepad, useGravityCompensation, useIkController, useJointState, useKeyboardTeleop, useMujoco, useMujocoWasm, useObservation, usePolicy, useSceneLights, useSelectionHighlight, useSensor, useSensors, useSitePosition, useTrajectoryPlayer, useTrajectoryRecorder, useVideoRecorder };
|
|
5763
|
+
export { Body, ContactListener, ContactMarkers, Debug, DragInteraction, FlexRenderer, IkGizmo, InstancedGeomRenderer, MujocoCanvas, MujocoPhysics, MujocoProvider, MujocoSimProvider, RobotActuators, RobotBodies, RobotGeoms, RobotJoints, RobotKeyframes, RobotResources, RobotSensors, RobotSites, SceneLights, TendonRenderer, TrajectoryPlayer, buildObservation, captureCameraFrame, captureCameraFrameBlob, captureFrame, captureFrameBlob, createContiguousControlGroup, createController, createControllerHook, findActuatorByName, findBodyByName, findGeomByName, findJointByName, findKeyframeByName, findSensorByName, findSiteByName, findTendonByName, getActuatedJoints, getContact, getControlMap, getName, loadScene, registerRobotResources, renderCameraFrameToCanvas, resolveControlGroup, useActuators, useAfterPhysicsStep, useBeforePhysicsStep, useBodyMeshes, useBodyState, useCameraAnimation, useCameraFrameCapture, useCameraSequenceRecorder, useContactEvents, useContacts, useCtrl, useCtrlNoise, useFrameCapture, useGamepad, useGravityCompensation, useIkController, useJointState, useKeyboardTeleop, useMujoco, useMujocoWasm, useObservation, usePolicy, useSceneLights, useSelectionHighlight, useSensor, useSensors, useSitePosition, useTrajectoryPlayer, useTrajectoryRecorder, useVideoRecorder };
|
|
5433
5764
|
//# sourceMappingURL=index.js.map
|
|
5434
5765
|
//# sourceMappingURL=index.js.map
|