Communitygithub.com

johannstark/GeminiRobotics-Skills

Renderiza simulações MuJoCo com Three.js (WASM no navegador, processo Python MuJoCo em streaming ou logs). Ideal para configurar cenas com eixo Z para cima, converter geoms e malhas do MuJoCo para malhas Three.js, sincronizar poses de corpos por quadro (quatérnios wxyz), capturar snapshots da câmera e vídeo do canvas para o Gemini Robotics-ER, mapear pontos ER [y, x] 0-1000 para 3D via raycasting, projetar 3D de volta para coordenadas de imagem e depurar problemas de renderização (girados, torcidos, com tamanho errado ou em branco).

O que é GeminiRobotics-Skills?

Esta skill fornece uma implementação de renderização Three.js para ambientes MuJoCo, permitindo visualizações 3D interativas e captura de dados para o Gemini Robotics-ER. Ela suporta três abordagens principais: (A) um Group por corpo, que é a opção padrão e mais flexível, sincronizando poses via `xpos`/`xquat`; (B) `mjv_updateScene` para usar decorações nativas do MuJoCo; e (C) um modo remoto onde um servidor Python envia dados de pose via WebSocket, ideal para integrações com GPU, ROS ou robôs reais. A skill lida automaticamente com as diferenças fundamentais entre os sistemas de coordenadas: MuJoCo usa Z-up, half-sizes, cilindros e cápsulas alinhados em Z e quatérnios wxyz, enquanto Three.js usa Y-up, tamanhos completos, cilindros alinhados em Y e quatérnios xyzw. Todo o processo de conversão é encapsulado em funções e exemplos reutilizáveis, incluindo a conversão de geometria, sincronização por quadro e mapeamento de pontos de referência ER entre coordenadas 2D da imagem e 3D da cena via raycasting.

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

Perguntar na sua IA favorita

Abre um novo chat com esta habilidade de agente já pré-carregada.

Documentação

Renderização Three.js para MuJoCo

Construa a geometria estática uma vez, depois atualize apenas as transformações a cada quadro. MuJoCo usa Z-up, half-sizes, cilindros e cápsulas alinhados em Z, e quatérnios wxyz. Three.js usa Y-up, tamanhos completos, cilindros alinhados em Y e quatérnios xyzw. Quase todo bug de renderização vem de um desses.

1. Configuração da cena (Z-up, pronta para captura)

import * as THREE from 'three';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';   // caminho válido em 0.164 e 0.18x

const renderer = new THREE.WebGLRenderer({ antialias: true, preserveDrawingBuffer: true }); // necessário para 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. Com isso, nenhuma conversão de eixo é necessária.
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;   // coloca a grade no XY

Defina camera.up antes de criar OrbitControls, pois os controles armazenam em cache o vetor up.

2. Escolha uma abordagem

AbordagemComoQuando usar
A. Um Group por corpo (demo Franka)Cada grupo de corpo contém seus geoms em geom_pos/geom_quat locais. Copie xpos/xquat a cada quadro.Padrão. Seleção via userData.bodyID. Funciona com qualquer fonte de pose.
B. mjv_updateScene (demo oficial)Sincroniza uma malha por entrada em scene.geomsVocê quer as decorações próprias do MuJoCo (contatos, tendões, sites)
C. Python remotoPython executa passos e envia xpos/xquat via WebSocket. O navegador executa a abordagem A.Pontes GPU, ROS ou robô real, computação pesada

Conversão de geometria: references/geom-conversion.md. Streaming Python (servidor testado): references/remote-python.md. Snapshots, câmera de percepção, vídeo e pixel↔3D: references/perception-and-video.md.

3. Sincronização por quadro (abordagem 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);

Ordem do loop: entradas → mj_step (quantas vezes o orçamento de tempo da simulação permitir) → sincronização → renderização (veja MujocoSim.startLoop). A alternativa por geom usa data.geom_xpos e data.geom_xmat (3×3 linha principal → Matrix4.set(r00,r01,r02,0, r10,…)), com geometria na pose identidade.

4. Pontos ER ↔ 3D

// ER [y, x] 0-1000 na imagem capturada -> raio da MESMA câmera que capturou
const ndc = new THREE.Vector2((x / 1000) * 2 - 1, 1 - (y / 1000) * 2);
raycaster.setFromCamera(ndc, captureCamera);
const hit = raycaster.intersectObjects(simMeshes, false)[0];     // ou raycaster.ray.intersectPlane(table, out)

// 3D -> ER-style [y, x] (para desenhar expectativas ou construir prompts)
const v = p.clone().project(captureCamera);
const yx = [(1 - v.y) * 500, (v.x + 1) * 500];

Isso é válido para qualquer proporção de aspecto desde que a imagem seja exatamente o viewport completo da câmera (sem corte, sem letterbox) e a câmera não tenha se movido entre a captura e o raycast. Pule acertos no robô ou no chão subindo até userData.bodyID. O acerto é na superfície superior, então abaixe-o até a altura da garra.

5. Problemas comuns

SintomaCausa
Robô deitado de lado, órbita instávelcamera.up não é (0,0,1), ou definido depois de OrbitControls ser criado
Links torcidosFalta reordenar wxyz→xyzw
Caixas duas vezes maioresEsqueceu que os tamanhos são half-extents
Cilindros ou cápsulas apontando para o lado erradoFalta geometry.rotateX(Math.PI/2)
Snapshot em branco ou pretopreserveDrawingBuffer: false, ou os pixels foram lidos em uma tarefa diferente da renderização
Imagem de percepção mais escura que a telaOs render targets geram cor linear (verificado no three r186). Converta para sRGB (veja a referência de percepção).
Marcadores ER deslocadosCâmera moveu, [y, x] trocado, imagem cortada ou com letterbox, ou o canvas com device-pixel-ratio foi redimensionado de forma diferente
Memória cresce ao recarregargeometry.dispose(), material.dispose(), renderTarget.dispose(), e delete o modelo e dados WASM
Travamentos em alta velocidadeMuitas chamadas mj_step por quadro. Limite os passos, ou mova a física para um Worker.

6. No demo Franka

O demo Franka de pick-and-place é o aplicativo de referência a partir do qual estas skills foram construídas. Os nomes de arquivos abaixo se referem a ele.

  • RenderSystem.ts usa preserveDrawingBuffer: true, uma PerspectiveCamera(45) Z-up, OrbitControls amortecidos, simGroup (um grupo por corpo, userData.bodyID), erGroup (marcadores cônicos oscilantes), marcadores de contato instanciados, animações de câmera (moveCameraTo), e getCanvasSnapshot(w, h, mime).
  • project2DTo3D(x, y, camPos, lookAt) clona a câmera principal, a posiciona no ponto de vista da captura ((0, -0.01, 2.0) olhando para a origem), e faz raycast nas malhas de simGroup.
  • rendering/GeomBuilder.ts lida com a fábrica geom→mesh. Geoms do grupo 3 são ignorados, planos viram um piso Reflector, e geoms de malha leem mesh_vert/mesh_face.
  • DragStateManager.ts e SelectionManager.ts lidam com seleção por mouse e forças de arrasto através de xfrc_applied.
  • O index.html import map fixa three 0.164.1, enquanto package.json tem ^0.181. Mantenha imports three/examples/jsm/..., que funcionam em ambos.

Individual skills in this repo

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

Habilidades Relacionadas