Communitygithub.com

johannstark/GeminiRobotics-Skills

使用Three.js渲染MuJoCo仿真(浏览器内WASM、流式Python MuJoCo进程或日志)。支持Z-up场景设置、将MuJoCo几何体和网格转换为Three.js网格、每帧刚体位姿同步(wxyz四元数)、为Gemini Robotics-ER捕获相机快照和画布视频、通过射线投射将ER [y, x] 0-1000点映射到3D、将3D投影回图像坐标,以及调试侧倒、扭曲、尺寸错误或空白渲染。

GeminiRobotics-Skills 是什么?

该技能实现了基于Three.js的MuJoCo仿真渲染管道。它处理了MuJoCo(Z-up、半尺寸、Z对齐圆柱体和胶囊、wxyz四元数)与Three.js(Y-up、全尺寸、Y对齐圆柱体、xyzw四元数)之间的关键坐标系差异,避免了常见的渲染错误。技能支持三种方法:A) 为每个刚体创建组(默认,推荐用于通用场景),B) 使用mjv_updateScene同步所有MuJoCo几何体(适用于官方装饰),C) 通过WebSocket从远程Python进程流式传输位姿数据(适用于GPU/ROS桥梁)。它提供了Gemini Robotics-ER中像素坐标与3D空间双向映射的实用函数,以及场景设置、每帧同步、相机控制和调试典型问题(如侧倒、扭曲、空白快照)的代码示例。随附的Franka演示应用程序(​https://ai.studio/apps/bundled/robotics_franka_pick_and_place​)展示了这些技术的实际应用。

兼容平台~Claude Code~Codex CLI~Cursor✓Gemini CLI
npx skills add https://github.com/johannstark/GeminiRobotics-Skills/tree/HEAD/threejs-rendering

在你喜欢的 AI 中提问

打开一个已预加载此 Agent Skill 的新对话。

文档

用于MuJoCo的Three.js渲染

静态几何体仅构建一次,每帧仅更新变换。 MuJoCo采用Z-up坐标系,使用半尺寸、Z对齐的圆柱体和胶囊体,以及wxyz四元数。Three.js默认采用Y-up坐标系,使用全尺寸、Y对齐的圆柱体和xyzw四元数。几乎所有的渲染错误都源于这些差异。

1. 场景设置(Z-up,可用于捕获)

import * as THREE from 'three';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js'; // 路径在0.164和0.18x版本中有效

const renderer = new THREE.WebGLRenderer({ antialias: true, preserveDrawingBuffer: true }); // toDataURL需要
renderer.setPixelRatio(Math.min(devicePixelRatio, 2));
renderer.shadowMap.enabled = true;
const camera = new THREE.PerspectiveCamera(45, w / h, 0.01, 100);
camera.up.set(0, 0, 1);                       // MuJoCo是Z-up的。这样设置后,任何地方都不需要进行轴转换。
camera.position.set(2, -1.5, 2.5);
const controls = new OrbitControls(camera, renderer.domElement);
const grid = new THREE.GridHelper(5, 50); grid.rotation.x = Math.PI / 2;   // 将网格平放在XY平面上

务必在创建OrbitControls之前设置camera.up,因为控制器会缓存up向量。

2. 选择一种方法

方法实现方式使用场景
A. 每个刚体一个Group(Franka演示采用)每个刚体组在其局部geom_pos/geom_quat处保存几何体。每帧复制xpos/xquat。默认方法。通过userData.bodyID进行拾取。适用于任何位姿来源。
B. mjv_updateScene(官方演示)为每个scene.geoms条目同步一个池化网格当你需要MuJoCo自身的装饰(接触、肌腱、站点)时
C. 远程PythonPython执行步骤,并通过WebSocket流式传输xpos/xquat。浏览器运行方法A。GPU、ROS或真实机器人桥接,计算密集型任务

几何体转换:references/geom-conversion.md。Python流式传输(经过测试的服务器):references/remote-python.md。 快照、感知相机、视频以及像素与3D的互相转换:references/perception-and-video.md。

3. 每帧同步(方法A)

for (let i = 0; i < model.nbody; i++) {
  bodies[i].position.set(data.xpos[3*i], data.xpos[3*i+1], data.xpos[3*i+2]);
  bodies[i].quaternion.set(data.xquat[4*i+1], data.xquat[4*i+2], data.xquat[4*i+3], data.xquat[4*i]); // wxyz -> xyzw
}
renderer.render(scene, camera);

循环顺序:输入 → mj_step(根据仿真时间预算执行尽可能多的次数)→ 同步 → 渲染 (参见MujocoSim.startLoop)。另一种方法是每几何体使用data.geom_xpos和data.geom_xmat (行主序3×3 → Matrix4.set(r00,r01,r02,0, r10,…)),此时几何体处于单位位姿。

4. ER点 ↔ 3D

// ER [y, x] 0-1000 在捕获图像上 -> 从捕获该图像的同一个相机发出的射线
const ndc = new THREE.Vector2((x / 1000) * 2 - 1, 1 - (y / 1000) * 2);
raycaster.setFromCamera(ndc, captureCamera);
const hit = raycaster.intersectObjects(simMeshes, false)[0];     // 或 raycaster.ray.intersectPlane(table, out)

// 3D -> ER风格的 [y, x](用于绘制期望或构建提示)
const v = p.clone().project(captureCamera);
const yx = [(1 - v.y) * 500, (v.x + 1) * 500];

这在任意宽高比下都有效,前提是图像恰好是相机的完整视口(无裁剪、无黑边)且相机在捕获和射线投射之间没有移动。通过检查userData.bodyID跳过机器人或地板上的命中。命中的是顶面,因此需将其降低到抓取高度。

5. 常见问题

现象原因
机器人侧倒,轨道控制翻转camera.up未设置为(0,0,1),或在创建OrbitControls之后设置
链接扭曲缺少wxyz→xyzw的重新排序
方块大了一倍忘记尺寸是半长
圆柱体或胶囊指向错误方向缺少geometry.rotateX(Math.PI/2)
空白或黑色快照preserveDrawingBuffer: false,或者像素在与渲染不同的任务中读取
感知图像比屏幕暗渲染目标输出线性颜色(在three r186中已验证)。转换为sRGB(参见感知参考)。
ER标记偏移相机移动了,[y, x]交换了,图像被裁剪或添加了黑边,或者设备像素比画布大小调整不一致
重新加载时内存增长需要调用geometry.dispose()、material.dispose()、renderTarget.dispose()并删除WASM模型和数据
高速时卡顿每帧mj_step调用过多。限制步数,或将物理引擎移至Worker。

6. 在Franka演示中

Franka拾放演示是这些技能所基于的参考应用程序。以下文件名即指该演示。

  • RenderSystem.ts使用preserveDrawingBuffer: true、Z-up的PerspectiveCamera(45)、带阻尼的OrbitControls、 simGroup(每个刚体一个组,userData.bodyID)、erGroup(上下浮动的锥形标记)、实例化接触标记、 相机缓动动画(moveCameraTo)和getCanvasSnapshot(w, h, mime)。
  • project2DTo3D(x, y, camPos, lookAt)克隆主相机,将其定位在捕获视点 ((0, -0.01, 2.0)看向原点),并对simGroup网格进行射线投射。
  • rendering/GeomBuilder.ts处理几何体到网格的工厂函数。组3的几何体被跳过,平面变为Reflector地板, 网格几何体读取mesh_vert/mesh_face。
  • DragStateManager.ts和SelectionManager.ts通过xfrc_applied处理鼠标拾取和拖拽力。
  • index.html的导入映射将three.js固定在0.164.1版本,而package.json指定了^0.181。请保持使用three/examples/jsm/... 导入,它在两个版本中都有效。

Individual skills in this repo

This repo contains 1 individual skill — each has its own dedicated page.

相关技能