Files
syncro_multi_agente/THREEJS_USAGE.md

120 lines
4.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Three.js — come usare plotter.glb
## Caricamento e accesso a joints/motion links
```javascript
import * as THREE from 'three';
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
const loader = new GLTFLoader();
loader.load('plotter.glb', (gltf) => {
const root = gltf.scene;
scene.add(root);
// ----------------------------------------------------------
// 1) Dati Fusion (joints, asBuiltJoints, motionLinks)
// Salvati in scene.extras.fusion come stringa JSON
// ----------------------------------------------------------
const sceneIndex = gltf.parser.json.scene ?? 0;
const sceneJson = gltf.parser.json.scenes[sceneIndex];
let fusion = null;
try {
const raw = sceneJson?.extras?.fusion;
fusion = raw ? JSON.parse(raw) : null;
} catch (e) {
console.warn('Fusion extras non parsabile', e);
}
if (fusion) {
console.log('Joints:', fusion.joints.length);
console.log('AsBuilt:', fusion.asBuiltJoints.length);
console.log('MotionLinks:', fusion.motionLinks.length);
console.log('Metadata:', fusion.metadata);
}
// ----------------------------------------------------------
// 2) Indice nome -> Object3D per trovare i nodi del joint
// Ogni Empty ha userData.fusion_fullPathName
// ----------------------------------------------------------
const byFullPath = new Map();
root.traverse((obj) => {
const fp = obj.userData?.fusion_fullPathName;
if (fp) byFullPath.set(fp, obj);
});
// ----------------------------------------------------------
// 3) Esempio: applicare un joint slider
// ----------------------------------------------------------
const j = fusion.joints.find(jt => jt.type === 'slider');
if (j) {
const child = byFullPath.get(j.childFullPath);
if (child) {
const axis = new THREE.Vector3(...j.axis).normalize();
// Sposta il child lungo l'asse di 100 mm = 0.1 m
child.position.addScaledVector(axis, 0.1);
}
}
// ----------------------------------------------------------
// 4) Esempio: applicare un joint revolute
// ----------------------------------------------------------
const r = fusion.joints.find(jt => jt.type === 'revolute');
if (r) {
const child = byFullPath.get(r.childFullPath);
if (child) {
const axis = new THREE.Vector3(...r.axis).normalize();
const angle = Math.PI / 4; // 45 gradi
// Rotazione attorno all'asse, applicata in local space
child.rotateOnAxis(axis, angle);
}
}
});
```
## Struttura di `scene.extras.fusion`
```jsonc
{
"metadata": { "units": "mm", "scaleFactor": 0.01, ... },
"joints": [
{
"name": "joint_carrello_y",
"type": "slider", // rigid | revolute | slider | cylindrical | pin_slot | planar | ball
"parent": "CARRELLO_X",
"child": "CARRELLO_Y",
"parentFullPath": "TELAIO:1+CARRELLO_X:1",
"childFullPath": "TELAIO:1+CARRELLO_X:1+CARRELLO_Y:1",
"origin": [x, y, z], // in metri
"axis": [x, y, z], // direzione unitaria
"secondaryAxis": [...], // solo pin_slot / planar
"slideLimits": { "minimumValue": 0, "maximumValue": 0.22, ... }, // metri
"rotationLimits": { ... }, // radianti
"slideValue": 0.05, // metri (posizione corrente)
"rotationValue": 0.5, // radianti
"isSuppressed": false,
"isLightBulbOn": true,
"isLocked": false
}
],
"asBuiltJoints": [ /* stessa shape di joints */ ],
"motionLinks": [
{
"name": "ML1",
"joint1": "joint_motor",
"joint2": "joint_belt",
"ratio": 2.5,
"reversed": false,
"isSuppressed": false
}
]
}
```
## Note
- **Unità:** GLB e dati joint sono in **metri**.
- **Asse Y-up:** convenzione glTF (cambiata da Blender al momento dell'export).
- **Nodi Fusion:** ogni Empty Blender ha `userData.fusion_fullPathName`, `userData.fusion_componentName`, `userData.fusion_id` (visibili in `Object3D.userData` lato Three.js).
- **Mesh:** sono parentate sotto gli Empty corrispondenti. Per muovere un sotto-assieme, sposta l'Empty (Three.js eredita le trasformazioni come ti aspetti).
- **Motion links:** la logica di "vincolo" tra joints (ratio, reversed) la devi implementare tu nel render loop: leggi `slideValue/rotationValue` di joint1, calcola joint2 = joint1 × ratio (con segno), applica a `byFullPath.get(joint2.childFullPath)`.