three-usd-robot 0.4.0 → 0.6.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 +136 -35
- package/dist/AssetResolver-CpIJNgWZ.d.ts +29 -0
- package/dist/{ThreeUsdRobot-Deoh7zam.d.ts → ThreeUsdRobot-CajXJqYU.d.ts} +1 -1
- package/dist/ThreeUsdRobotLoader-DrMMLzo-.d.ts +67 -0
- package/dist/{buildKinematicTree-CZjBMA1I.d.ts → buildKinematicTree-wtZPzy0B.d.ts} +53 -16
- package/dist/{chunk-FYVZ7YPW.js → chunk-4MEZM763.js} +3153 -2618
- package/dist/chunk-4MEZM763.js.map +1 -0
- package/dist/chunk-JZMCABQO.js +864 -0
- package/dist/chunk-JZMCABQO.js.map +1 -0
- package/dist/chunk-YVWSO27W.js +709 -0
- package/dist/chunk-YVWSO27W.js.map +1 -0
- package/dist/core.d.ts +297 -134
- package/dist/core.js +2 -1
- package/dist/extras.d.ts +2 -2
- package/dist/helpers.d.ts +2 -2
- package/dist/index.d.ts +229 -83
- package/dist/index.js +271 -631
- package/dist/index.js.map +1 -1
- package/dist/react.d.ts +72 -0
- package/dist/react.js +92 -0
- package/dist/react.js.map +1 -0
- package/package.json +22 -1
- package/dist/chunk-FYVZ7YPW.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -1,664 +1,304 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export {
|
|
3
|
-
|
|
1
|
+
import { stageGeometryProvider, exportRobotUsda } from './chunk-JZMCABQO.js';
|
|
2
|
+
export { PACKAGE_NAME, VERSION, exportRobotUsda, stageGeometryProvider, validateRobotDescription, writeUsdz } from './chunk-JZMCABQO.js';
|
|
3
|
+
export { JointObject, LinkObject, ThreeUsdRobot, ThreeUsdRobotLoader, axisVector, bindRobotMeshes, bindSceneMeshes, buildMeshGeometry, buildMeshMaterial, createTextureProvider } from './chunk-YVWSO27W.js';
|
|
4
|
+
import { identity4, refineJointType, multiply, invert, buildKinematicTree } from './chunk-4MEZM763.js';
|
|
5
|
+
export { ARTICULATION_ROOT_API, AssetPath, Attribute, COLLISION_API, CrateReader, DEFAULT_METERS_PER_UNIT, DEG2RAD, DefaultAssetResolver, Layer, MASS_API, MESH_COLLISION_API, PHYSICS_MATERIAL_API, ParseError, Prim, Quat, RAD2DEG, RIGID_BODY_API, Relationship, Stage, TokenizeError, UsdMatrix, buildKinematicTree, channelFromSamples, composeFile, composeLayer, computeLocalTransform, computeWorldTransform, crateToUsdaFile, createMemoryResolver, decomposeRigid, driveKindFor, extractRobotDescription, fromUsdMatrix, gatherMeshDescendants, getJointAxis, getJointBodies, getJointDrive, getJointLimits, getJointLocalFrame, getJointStatePosition, getJointType, getMassProperties, getTranslation, hasArticulationRootAPI, hasCollisionAPI, hasRigidBodyAPI, identity4, interpolate, invert, isMesh, isScope, isXform, iterDescendants, joinPosix, jointValueFromSI, jointValueToSI, makeEuler, makeRotationFromQuat, makeRotationX, makeRotationY, makeRotationZ, makeScale, makeTranslation, multiply, multiplyAll, normalizeJointLimits, openUsdz, parseOpType, parseUsda, refineJointType, resolveBoundMaterial, serializeUsda, toUsdMatrix, tokenize } from './chunk-4MEZM763.js';
|
|
6
|
+
import * as THREE from 'three';
|
|
4
7
|
|
|
5
|
-
function
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
this.axisToken = joint.axis;
|
|
30
|
-
this.axis = axisVector(joint.axis);
|
|
31
|
-
this.lower = joint.lower;
|
|
32
|
-
this.upper = joint.upper;
|
|
33
|
-
}
|
|
34
|
-
get value() {
|
|
35
|
-
return this._value;
|
|
36
|
-
}
|
|
37
|
-
get articulated() {
|
|
38
|
-
return this.jointType !== "fixed";
|
|
39
|
-
}
|
|
40
|
-
/**
|
|
41
|
-
* Set the joint value (radians for revolute/continuous, length for prismatic).
|
|
42
|
-
* Optionally clamps to authored limits. Returns the value actually applied.
|
|
43
|
-
*/
|
|
44
|
-
setValue(value, clampToLimits = true) {
|
|
45
|
-
if (!this.articulated) return this._value;
|
|
46
|
-
let v = value;
|
|
47
|
-
if (clampToLimits) {
|
|
48
|
-
if (this.lower !== void 0 && v < this.lower) v = this.lower;
|
|
49
|
-
if (this.upper !== void 0 && v > this.upper) v = this.upper;
|
|
50
|
-
}
|
|
51
|
-
this._value = v;
|
|
52
|
-
if (this.jointType === "prismatic") {
|
|
53
|
-
this.position.copy(this.axis).multiplyScalar(v);
|
|
54
|
-
this.quaternion.identity();
|
|
55
|
-
} else {
|
|
56
|
-
this.quaternion.setFromAxisAngle(this.axis, v);
|
|
57
|
-
this.position.set(0, 0, 0);
|
|
58
|
-
}
|
|
59
|
-
return v;
|
|
60
|
-
}
|
|
61
|
-
};
|
|
62
|
-
var LinkObject = class extends THREE4.Object3D {
|
|
63
|
-
isLinkObject = true;
|
|
64
|
-
linkName;
|
|
65
|
-
primPath;
|
|
66
|
-
constructor(link) {
|
|
67
|
-
super();
|
|
68
|
-
this.name = link.name;
|
|
69
|
-
this.linkName = link.name;
|
|
70
|
-
this.primPath = link.primPath;
|
|
71
|
-
this.matrixAutoUpdate = false;
|
|
72
|
-
}
|
|
73
|
-
};
|
|
74
|
-
|
|
75
|
-
// src/three/MaterialBinding.ts
|
|
76
|
-
var DIFFUSE_INPUTS = [
|
|
77
|
-
"inputs:diffuseColor",
|
|
78
|
-
// UsdPreviewSurface
|
|
79
|
-
"inputs:diffuse_color_constant",
|
|
80
|
-
// OmniPBR
|
|
81
|
-
"inputs:diffuse_tint",
|
|
82
|
-
"inputs:base_color",
|
|
83
|
-
"inputs:baseColor"
|
|
84
|
-
];
|
|
85
|
-
var OPACITY_INPUTS = ["inputs:opacity", "inputs:opacity_constant"];
|
|
86
|
-
var METALLIC_INPUTS = ["inputs:metallic", "inputs:metallic_constant"];
|
|
87
|
-
var ROUGHNESS_INPUTS = ["inputs:roughness", "inputs:reflection_roughness_constant"];
|
|
88
|
-
var SURFACE_OUTPUTS = ["outputs:surface", "outputs:mdl:surface"];
|
|
89
|
-
function resolveBoundMaterial(stage, prim) {
|
|
90
|
-
const materialPath = findBinding(prim);
|
|
91
|
-
if (!materialPath) return void 0;
|
|
92
|
-
const material = stage.GetPrimAtPath(materialPath);
|
|
93
|
-
if (!material) return void 0;
|
|
94
|
-
const shader = findSurfaceShader(material);
|
|
95
|
-
if (!shader) return void 0;
|
|
96
|
-
const result = {};
|
|
97
|
-
const color = firstColor(shader, DIFFUSE_INPUTS);
|
|
98
|
-
if (color) result.color = color;
|
|
99
|
-
const opacity = firstNumber(shader, OPACITY_INPUTS);
|
|
100
|
-
if (opacity !== void 0) result.opacity = opacity;
|
|
101
|
-
const metalness = firstNumber(shader, METALLIC_INPUTS);
|
|
102
|
-
if (metalness !== void 0) result.metalness = metalness;
|
|
103
|
-
const roughness = firstNumber(shader, ROUGHNESS_INPUTS);
|
|
104
|
-
if (roughness !== void 0) result.roughness = roughness;
|
|
105
|
-
const texture = findDiffuseTexture(shader);
|
|
106
|
-
if (texture !== void 0) result.colorTexture = texture;
|
|
107
|
-
return result;
|
|
108
|
-
}
|
|
109
|
-
var DIFFUSE_TEXTURE_INPUTS = ["inputs:diffuse_texture", "inputs:diffuse_color_texture"];
|
|
110
|
-
function findDiffuseTexture(shader) {
|
|
111
|
-
for (const name of DIFFUSE_TEXTURE_INPUTS) {
|
|
112
|
-
const v = shader.GetAttribute(name).Get();
|
|
113
|
-
if (v instanceof AssetPath && v.path) return v.path;
|
|
114
|
-
}
|
|
115
|
-
const conn = shader.GetAttribute("inputs:diffuseColor").GetConnections()[0];
|
|
116
|
-
if (conn) {
|
|
117
|
-
const texPrim = shader.GetStage().GetPrimAtPath(conn.split(".")[0]);
|
|
118
|
-
const file = texPrim?.GetAttribute("inputs:file").Get();
|
|
119
|
-
if (file instanceof AssetPath && file.path) return file.path;
|
|
120
|
-
}
|
|
121
|
-
return void 0;
|
|
122
|
-
}
|
|
123
|
-
function findBinding(prim) {
|
|
124
|
-
let p = prim;
|
|
125
|
-
while (p) {
|
|
126
|
-
const targets = p.GetRelationship("material:binding").GetTargets();
|
|
127
|
-
if (targets.length > 0) return targets[0];
|
|
128
|
-
p = p.GetParent();
|
|
129
|
-
}
|
|
130
|
-
return void 0;
|
|
131
|
-
}
|
|
132
|
-
function findSurfaceShader(material) {
|
|
133
|
-
for (const out of SURFACE_OUTPUTS) {
|
|
134
|
-
const conn = material.GetAttribute(out).GetConnections()[0];
|
|
135
|
-
if (conn) {
|
|
136
|
-
const shaderPath = conn.split(".")[0];
|
|
137
|
-
const shader = material.GetStage().GetPrimAtPath(shaderPath);
|
|
138
|
-
if (shader) return shader;
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
return material.GetChildren().find((c) => c.GetTypeName() === "Shader") ?? void 0;
|
|
142
|
-
}
|
|
143
|
-
function firstColor(shader, names) {
|
|
144
|
-
for (const name of names) {
|
|
145
|
-
const v = shader.GetAttribute(name).Get();
|
|
146
|
-
if (Array.isArray(v) && v.length >= 3 && v.every((n) => typeof n === "number")) {
|
|
147
|
-
return [v[0], v[1], v[2]];
|
|
8
|
+
function geometryToExportMesh(geometry, options) {
|
|
9
|
+
const position = geometry.getAttribute("position");
|
|
10
|
+
if (!position || position.count === 0) return null;
|
|
11
|
+
const points = [];
|
|
12
|
+
for (let i = 0; i < position.count; i++) {
|
|
13
|
+
points.push([position.getX(i), position.getY(i), position.getZ(i)]);
|
|
14
|
+
}
|
|
15
|
+
const index = geometry.getIndex();
|
|
16
|
+
let faceVertexIndices = index ? Array.from(index.array) : points.map((_, i) => i);
|
|
17
|
+
const triangles = Math.floor(faceVertexIndices.length / 3);
|
|
18
|
+
if (triangles === 0) return null;
|
|
19
|
+
faceVertexIndices = faceVertexIndices.slice(0, triangles * 3);
|
|
20
|
+
const mesh = {
|
|
21
|
+
name: options.name,
|
|
22
|
+
kind: options.kind ?? "visual",
|
|
23
|
+
points,
|
|
24
|
+
faceVertexCounts: new Array(triangles).fill(3),
|
|
25
|
+
faceVertexIndices
|
|
26
|
+
};
|
|
27
|
+
const normal = geometry.getAttribute("normal");
|
|
28
|
+
if (normal && normal.count === position.count) {
|
|
29
|
+
const normals = [];
|
|
30
|
+
for (let i = 0; i < normal.count; i++) {
|
|
31
|
+
normals.push([normal.getX(i), normal.getY(i), normal.getZ(i)]);
|
|
148
32
|
}
|
|
149
|
-
|
|
150
|
-
|
|
33
|
+
mesh.normals = normals;
|
|
34
|
+
}
|
|
35
|
+
const uv = geometry.getAttribute("uv");
|
|
36
|
+
if (uv && uv.count === position.count) {
|
|
37
|
+
const st = [];
|
|
38
|
+
for (let i = 0; i < uv.count; i++) st.push([uv.getX(i), uv.getY(i)]);
|
|
39
|
+
mesh.st = st;
|
|
40
|
+
}
|
|
41
|
+
if (options.transform && !isIdentityMat4(options.transform)) mesh.transform = options.transform;
|
|
42
|
+
if (options.material) mesh.material = options.material;
|
|
43
|
+
if (options.doubleSided) mesh.doubleSided = true;
|
|
44
|
+
return mesh;
|
|
151
45
|
}
|
|
152
|
-
function
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
function buildMeshGeometry(meshPrim) {
|
|
163
|
-
const points = meshPrim.GetAttribute("points").Get();
|
|
164
|
-
if (!isVec3Array(points) || points.length === 0) return null;
|
|
165
|
-
const geometry = new THREE4.BufferGeometry();
|
|
166
|
-
geometry.setAttribute("position", new THREE4.Float32BufferAttribute(flat3(points), 3));
|
|
167
|
-
const counts = meshPrim.GetAttribute("faceVertexCounts").Get();
|
|
168
|
-
const indices = meshPrim.GetAttribute("faceVertexIndices").Get();
|
|
169
|
-
if (isNumberArray(counts) && isNumberArray(indices)) {
|
|
170
|
-
geometry.setIndex(triangulate(counts, indices));
|
|
171
|
-
} else if (isNumberArray(indices)) {
|
|
172
|
-
geometry.setIndex(indices.slice());
|
|
173
|
-
}
|
|
174
|
-
const normals = meshPrim.GetAttribute("normals").Get();
|
|
175
|
-
if (isVec3Array(normals) && normals.length === points.length) {
|
|
176
|
-
geometry.setAttribute("normal", new THREE4.Float32BufferAttribute(flat3(normals), 3));
|
|
177
|
-
} else {
|
|
178
|
-
geometry.computeVertexNormals();
|
|
179
|
-
}
|
|
180
|
-
const st = meshPrim.GetAttribute("primvars:st").Get();
|
|
181
|
-
if (isVec2Array(st) && st.length === points.length) {
|
|
182
|
-
geometry.setAttribute("uv", new THREE4.Float32BufferAttribute(flat2(st), 2));
|
|
46
|
+
function materialToExportMaterial(material, name, onWarn) {
|
|
47
|
+
const std = material;
|
|
48
|
+
if (!std.isMeshStandardMaterial) {
|
|
49
|
+
onWarn?.(`material "${name}": only MeshStandardMaterial exports to UsdPreviewSurface; skipped`);
|
|
50
|
+
return void 0;
|
|
51
|
+
}
|
|
52
|
+
if (std.map || std.normalMap || std.roughnessMap || std.metalnessMap || std.aoMap || std.emissiveMap || std.alphaMap) {
|
|
53
|
+
onWarn?.(
|
|
54
|
+
`material "${name}": texture maps are not carried from Three.js materials (image extraction is app-side); constants only`
|
|
55
|
+
);
|
|
183
56
|
}
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
color.setRGB(bound.color[0], bound.color[1], bound.color[2]);
|
|
194
|
-
} else {
|
|
195
|
-
const displayColor = meshPrim.GetAttribute("primvars:displayColor").Get();
|
|
196
|
-
if (isVec3Array(displayColor) && displayColor[0]) {
|
|
197
|
-
const [r, g, b] = displayColor[0];
|
|
198
|
-
color.setRGB(r, g, b);
|
|
199
|
-
}
|
|
57
|
+
const out = {
|
|
58
|
+
name,
|
|
59
|
+
diffuseColor: [std.color.r, std.color.g, std.color.b],
|
|
60
|
+
metallic: std.metalness,
|
|
61
|
+
roughness: std.roughness
|
|
62
|
+
};
|
|
63
|
+
if (std.transparent && std.opacity < 1) out.opacity = std.opacity;
|
|
64
|
+
if (std.emissive.r > 0 || std.emissive.g > 0 || std.emissive.b > 0) {
|
|
65
|
+
out.emissiveColor = [std.emissive.r, std.emissive.g, std.emissive.b];
|
|
200
66
|
}
|
|
201
|
-
|
|
202
|
-
if (bound?.roughness !== void 0) roughness = bound.roughness;
|
|
203
|
-
if (bound?.opacity !== void 0) opacity = bound.opacity;
|
|
204
|
-
const map = bound?.colorTexture && textures ? textures(bound.colorTexture) : null;
|
|
205
|
-
if (map) color.setRGB(1, 1, 1);
|
|
206
|
-
const doubleSided = meshPrim.GetAttribute("doubleSided").Get() === true;
|
|
207
|
-
return new THREE4.MeshStandardMaterial({
|
|
208
|
-
color,
|
|
209
|
-
metalness,
|
|
210
|
-
roughness,
|
|
211
|
-
transparent: opacity < 1,
|
|
212
|
-
opacity,
|
|
213
|
-
side: doubleSided ? THREE4.DoubleSide : THREE4.FrontSide,
|
|
214
|
-
...map ? { map } : {}
|
|
215
|
-
});
|
|
67
|
+
return out;
|
|
216
68
|
}
|
|
217
|
-
function
|
|
218
|
-
const
|
|
219
|
-
|
|
220
|
-
const
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
if (!linkObj || !linkPrim) continue;
|
|
225
|
-
const collisionSet = new Set(link.collisionPrims ?? []);
|
|
226
|
-
if (loadVisuals) {
|
|
227
|
-
for (const meshPath of link.visualPrims) {
|
|
228
|
-
if (collisionSet.has(meshPath)) continue;
|
|
229
|
-
attachMesh(stage, linkPrim, meshPath, linkObj, "visual", textures);
|
|
230
|
-
}
|
|
69
|
+
function threeGeometryProvider(robot, onWarn) {
|
|
70
|
+
const materialNames = /* @__PURE__ */ new Map();
|
|
71
|
+
let autoId = 0;
|
|
72
|
+
const convertMaterial = (material) => {
|
|
73
|
+
if (!materialNames.has(material)) {
|
|
74
|
+
const name = material.name || `Material_${autoId++}`;
|
|
75
|
+
materialNames.set(material, materialToExportMaterial(material, name, onWarn));
|
|
231
76
|
}
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
77
|
+
return materialNames.get(material);
|
|
78
|
+
};
|
|
79
|
+
return (linkKey) => {
|
|
80
|
+
const linkObj = robot.getLinkObject(linkKey);
|
|
81
|
+
if (!linkObj) return [];
|
|
82
|
+
const out = [];
|
|
83
|
+
for (const childObj of linkObj.children) {
|
|
84
|
+
const meshObj = childObj;
|
|
85
|
+
if (!meshObj.isMesh) continue;
|
|
86
|
+
const material = Array.isArray(meshObj.material) ? meshObj.material[0] : meshObj.material;
|
|
87
|
+
if (Array.isArray(meshObj.material) && meshObj.material.length > 1) {
|
|
88
|
+
onWarn?.(`mesh "${meshObj.name}": multi-material meshes export their first material only`);
|
|
235
89
|
}
|
|
90
|
+
const exportMaterial = material ? convertMaterial(material) : void 0;
|
|
91
|
+
const mesh = geometryToExportMesh(meshObj.geometry, {
|
|
92
|
+
name: meshObj.name || "mesh",
|
|
93
|
+
kind: meshObj.userData.kind === "collision" ? "collision" : "visual",
|
|
94
|
+
transform: [...meshObj.matrix.elements],
|
|
95
|
+
...exportMaterial ? { material: exportMaterial } : {},
|
|
96
|
+
doubleSided: material?.side === THREE.DoubleSide
|
|
97
|
+
});
|
|
98
|
+
if (mesh) out.push(mesh);
|
|
236
99
|
}
|
|
237
|
-
|
|
238
|
-
}
|
|
239
|
-
function attachMesh(stage, linkPrim, meshPath, parent, kind, textures) {
|
|
240
|
-
const meshPrim = stage.GetPrimAtPath(meshPath);
|
|
241
|
-
if (!meshPrim) return;
|
|
242
|
-
const geometry = buildMeshGeometry(meshPrim);
|
|
243
|
-
if (!geometry) return;
|
|
244
|
-
const mesh = new THREE4.Mesh(geometry, buildMeshMaterial(meshPrim, stage, textures));
|
|
245
|
-
mesh.name = meshPrim.GetName();
|
|
246
|
-
mesh.userData.kind = kind;
|
|
247
|
-
mesh.userData.primPath = meshPath;
|
|
248
|
-
if (kind === "collision") mesh.visible = false;
|
|
249
|
-
mesh.matrixAutoUpdate = false;
|
|
250
|
-
mesh.matrix.fromArray(relativeTransform(linkPrim, meshPrim));
|
|
251
|
-
mesh.matrixWorldNeedsUpdate = true;
|
|
252
|
-
parent.add(mesh);
|
|
100
|
+
return out;
|
|
101
|
+
};
|
|
253
102
|
}
|
|
254
|
-
function
|
|
255
|
-
const
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
while (p && p.GetPath() !== stop) {
|
|
259
|
-
chain.push(p);
|
|
260
|
-
p = p.GetParent();
|
|
261
|
-
}
|
|
262
|
-
chain.reverse();
|
|
263
|
-
let m = identity4();
|
|
264
|
-
for (const prim of chain) {
|
|
265
|
-
m = multiply(m, computeLocalTransform(prim).matrix);
|
|
266
|
-
}
|
|
267
|
-
return m;
|
|
103
|
+
function exportThreeUsdRobot(robot, options = {}) {
|
|
104
|
+
const { stage, ...rest } = options;
|
|
105
|
+
const geometry = stage ? stageGeometryProvider(stage) : threeGeometryProvider(robot, options.onWarn);
|
|
106
|
+
return exportRobotUsda(robot.robot, { ...rest, geometry });
|
|
268
107
|
}
|
|
269
|
-
function
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
for (const count of faceVertexCounts) {
|
|
273
|
-
for (let k = 2; k < count; k++) {
|
|
274
|
-
tris.push(
|
|
275
|
-
faceVertexIndices[offset],
|
|
276
|
-
faceVertexIndices[offset + k - 1],
|
|
277
|
-
faceVertexIndices[offset + k]
|
|
278
|
-
);
|
|
279
|
-
}
|
|
280
|
-
offset += count;
|
|
108
|
+
function isIdentityMat4(m) {
|
|
109
|
+
for (let i = 0; i < 16; i++) {
|
|
110
|
+
if (m[i] !== (i % 5 === 0 ? 1 : 0)) return false;
|
|
281
111
|
}
|
|
282
|
-
return
|
|
283
|
-
}
|
|
284
|
-
function flat3(v) {
|
|
285
|
-
const out = new Array(v.length * 3);
|
|
286
|
-
for (let i = 0; i < v.length; i++) {
|
|
287
|
-
out[i * 3] = v[i][0];
|
|
288
|
-
out[i * 3 + 1] = v[i][1];
|
|
289
|
-
out[i * 3 + 2] = v[i][2];
|
|
290
|
-
}
|
|
291
|
-
return out;
|
|
112
|
+
return true;
|
|
292
113
|
}
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
const cache = /* @__PURE__ */ new Map();
|
|
313
|
-
return (assetPath) => {
|
|
314
|
-
let url;
|
|
315
|
-
try {
|
|
316
|
-
url = resolver.resolve(assetPath, baseUrl);
|
|
317
|
-
} catch {
|
|
318
|
-
return null;
|
|
319
|
-
}
|
|
320
|
-
const cached = cache.get(url);
|
|
321
|
-
if (cached) return cached;
|
|
322
|
-
const texture = loader.load(url);
|
|
323
|
-
texture.colorSpace = THREE4.SRGBColorSpace;
|
|
324
|
-
texture.wrapS = THREE4.RepeatWrapping;
|
|
325
|
-
texture.wrapT = THREE4.RepeatWrapping;
|
|
326
|
-
cache.set(url, texture);
|
|
327
|
-
return texture;
|
|
328
|
-
};
|
|
329
|
-
}
|
|
330
|
-
var ThreeUsdRobot = class extends THREE4.Object3D {
|
|
331
|
-
isThreeUsdRobot = true;
|
|
332
|
-
robot;
|
|
333
|
-
tree;
|
|
334
|
-
clampJointLimits;
|
|
335
|
-
linkObjects = /* @__PURE__ */ new Map();
|
|
336
|
-
jointObjects = /* @__PURE__ */ new Map();
|
|
337
|
-
dirty = true;
|
|
338
|
-
helperSize;
|
|
339
|
-
_showVisual = true;
|
|
340
|
-
_showCollision = false;
|
|
341
|
-
_showJointAxes = false;
|
|
342
|
-
_showLinkFrames = false;
|
|
343
|
-
jointAxesHelpers = [];
|
|
344
|
-
linkFrameHelpers = [];
|
|
345
|
-
constructor(robot, tree, options = {}) {
|
|
346
|
-
super();
|
|
347
|
-
this.name = robot.name;
|
|
348
|
-
this.robot = robot;
|
|
349
|
-
this.tree = tree;
|
|
350
|
-
this.clampJointLimits = options.clampJointLimits ?? true;
|
|
351
|
-
this.helperSize = options.helperSize ?? 0.15;
|
|
352
|
-
for (const [key, link] of Object.entries(robot.links)) {
|
|
353
|
-
this.linkObjects.set(key, new LinkObject(link));
|
|
354
|
-
}
|
|
355
|
-
this.attachRoot();
|
|
356
|
-
this.attachTreeEdges();
|
|
357
|
-
this.attachIsolatedLinks();
|
|
358
|
-
this.applyStageNormalization(robot, options);
|
|
359
|
-
if (options.applyInitialPose ?? true) this.applyInitialPose(robot);
|
|
360
|
-
}
|
|
361
|
-
/** Orient (Z-up → Y-up) and scale (metersPerUnit × unitScale) the robot root. */
|
|
362
|
-
applyStageNormalization(robot, options) {
|
|
363
|
-
const scale = (robot.metersPerUnit || 1) * (options.unitScale ?? 1);
|
|
364
|
-
if (scale !== 1) this.scale.setScalar(scale);
|
|
365
|
-
const conv = options.upAxisConversion ?? "none";
|
|
366
|
-
const toY = conv === "Z" || conv === "auto" && robot.upAxis === "Z";
|
|
367
|
-
if (toY) this.quaternion.setFromAxisAngle(new THREE4.Vector3(1, 0, 0), -Math.PI / 2);
|
|
368
|
-
}
|
|
369
|
-
/** Apply each joint's authored initial value, if any. */
|
|
370
|
-
applyInitialPose(robot) {
|
|
371
|
-
for (const [key, joint] of Object.entries(robot.joints)) {
|
|
372
|
-
if (joint.initialValue === void 0) continue;
|
|
373
|
-
this.jointObjects.get(key)?.setValue(joint.initialValue, this.clampJointLimits);
|
|
374
|
-
}
|
|
375
|
-
this.dirty = true;
|
|
376
|
-
}
|
|
377
|
-
attachRoot() {
|
|
378
|
-
const rootObj = this.linkObjects.get(this.tree.root);
|
|
379
|
-
if (!rootObj) return;
|
|
380
|
-
const rootJointKey = this.tree.rootJoint;
|
|
381
|
-
if (rootJointKey) {
|
|
382
|
-
const j = this.robot.joints[rootJointKey];
|
|
383
|
-
if (j) setMatrix(rootObj, multiply(j.jointFrame0, invert(j.jointFrame1)));
|
|
384
|
-
}
|
|
385
|
-
this.add(rootObj);
|
|
386
|
-
}
|
|
387
|
-
attachTreeEdges() {
|
|
388
|
-
for (const linkKey of this.tree.order) {
|
|
389
|
-
const node = this.tree.nodes[linkKey];
|
|
390
|
-
if (!node || node.parent === null || node.jointToParent === null) continue;
|
|
391
|
-
const parentObj = this.linkObjects.get(node.parent);
|
|
392
|
-
const childObj = this.linkObjects.get(linkKey);
|
|
393
|
-
const joint = this.robot.joints[node.jointToParent];
|
|
394
|
-
if (!parentObj || !childObj || !joint) continue;
|
|
395
|
-
this.attachJointChain(parentObj, childObj, node.jointToParent, joint);
|
|
396
|
-
}
|
|
397
|
-
}
|
|
398
|
-
/** Build `parent → frame0 → motion → frame1⁻¹ → child` for one joint. */
|
|
399
|
-
attachJointChain(parent, child, jointKey, joint) {
|
|
400
|
-
const frame0 = new THREE4.Group();
|
|
401
|
-
frame0.name = `${joint.name}:frame0`;
|
|
402
|
-
setMatrix(frame0, joint.jointFrame0);
|
|
403
|
-
const motion = new JointObject(joint);
|
|
404
|
-
const frame1Inv = new THREE4.Group();
|
|
405
|
-
frame1Inv.name = `${joint.name}:frame1Inv`;
|
|
406
|
-
setMatrix(frame1Inv, invert(joint.jointFrame1));
|
|
407
|
-
parent.add(frame0);
|
|
408
|
-
frame0.add(motion);
|
|
409
|
-
motion.add(frame1Inv);
|
|
410
|
-
frame1Inv.add(child);
|
|
411
|
-
this.jointObjects.set(jointKey, motion);
|
|
412
|
-
}
|
|
413
|
-
attachIsolatedLinks() {
|
|
414
|
-
for (const key of this.tree.isolatedLinks) {
|
|
415
|
-
const obj = this.linkObjects.get(key);
|
|
416
|
-
if (obj && !obj.parent) this.add(obj);
|
|
417
|
-
}
|
|
418
|
-
}
|
|
419
|
-
// -- Joint control -------------------------------------------------------
|
|
420
|
-
/** Set one joint value. Unknown joints are ignored. Returns whether it applied. */
|
|
421
|
-
setJointValue(name, value) {
|
|
422
|
-
const joint = this.jointObjects.get(name);
|
|
423
|
-
if (!joint) return false;
|
|
424
|
-
joint.setValue(value, this.clampJointLimits);
|
|
425
|
-
this.dirty = true;
|
|
426
|
-
return true;
|
|
114
|
+
|
|
115
|
+
// src/three/RobotBuilder.ts
|
|
116
|
+
var RobotBuilder = class {
|
|
117
|
+
robotName;
|
|
118
|
+
upAxis;
|
|
119
|
+
metersPerUnit;
|
|
120
|
+
articulationRoot;
|
|
121
|
+
warn;
|
|
122
|
+
links = /* @__PURE__ */ new Map();
|
|
123
|
+
joints = /* @__PURE__ */ new Map();
|
|
124
|
+
materialCache = /* @__PURE__ */ new Map();
|
|
125
|
+
materialAutoId = 0;
|
|
126
|
+
constructor(options) {
|
|
127
|
+
this.robotName = options.name;
|
|
128
|
+
this.upAxis = options.upAxis ?? "Z";
|
|
129
|
+
this.metersPerUnit = options.metersPerUnit ?? 1;
|
|
130
|
+
if (options.articulationRoot !== void 0) this.articulationRoot = options.articulationRoot;
|
|
131
|
+
this.warn = options.onWarn ?? (() => {
|
|
132
|
+
});
|
|
427
133
|
}
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
const joint = this.jointObjects.get(name);
|
|
432
|
-
if (joint) {
|
|
433
|
-
joint.setValue(value, this.clampJointLimits);
|
|
434
|
-
this.dirty = true;
|
|
435
|
-
}
|
|
134
|
+
addLink(options) {
|
|
135
|
+
if (this.links.has(options.name)) {
|
|
136
|
+
throw new Error(`RobotBuilder: link "${options.name}" is already defined`);
|
|
436
137
|
}
|
|
138
|
+
const world = resolveFrame(options.frame) ?? identity4();
|
|
139
|
+
const collisionExtras = {
|
|
140
|
+
...options.collisionApproximation !== void 0 ? { approximation: options.collisionApproximation } : {},
|
|
141
|
+
...options.physicsMaterial ? { material: options.physicsMaterial } : {}
|
|
142
|
+
};
|
|
143
|
+
const meshes = [
|
|
144
|
+
...this.gatherMeshes(options.visuals ?? [], world, "visual"),
|
|
145
|
+
...this.gatherMeshes(options.collisions ?? [], world, "collision", collisionExtras)
|
|
146
|
+
];
|
|
147
|
+
this.links.set(options.name, {
|
|
148
|
+
world,
|
|
149
|
+
meshes,
|
|
150
|
+
...options.inertial ? { inertial: options.inertial } : {}
|
|
151
|
+
});
|
|
152
|
+
return this;
|
|
437
153
|
}
|
|
438
|
-
|
|
439
|
-
return this.
|
|
440
|
-
}
|
|
441
|
-
/** Recompute world matrices. Called lazily by the getters; safe to call directly. */
|
|
442
|
-
updateKinematics() {
|
|
443
|
-
this.updateMatrixWorld(true);
|
|
444
|
-
this.dirty = false;
|
|
445
|
-
}
|
|
446
|
-
ensureUpdated() {
|
|
447
|
-
if (this.dirty) this.updateKinematics();
|
|
448
|
-
}
|
|
449
|
-
// -- Queries -------------------------------------------------------------
|
|
450
|
-
getLinkWorldMatrix(name) {
|
|
451
|
-
const obj = this.linkObjects.get(name);
|
|
452
|
-
if (!obj) throw new Error(`unknown link "${name}"`);
|
|
453
|
-
this.ensureUpdated();
|
|
454
|
-
return obj.matrixWorld.clone();
|
|
455
|
-
}
|
|
456
|
-
getLinkWorldPosition(name) {
|
|
457
|
-
return new THREE4.Vector3().setFromMatrixPosition(this.getLinkWorldMatrix(name));
|
|
458
|
-
}
|
|
459
|
-
getLinkObject(name) {
|
|
460
|
-
return this.linkObjects.get(name);
|
|
461
|
-
}
|
|
462
|
-
getJointObject(name) {
|
|
463
|
-
return this.jointObjects.get(name);
|
|
464
|
-
}
|
|
465
|
-
getJoints() {
|
|
466
|
-
return Object.values(this.robot.joints);
|
|
467
|
-
}
|
|
468
|
-
getLinks() {
|
|
469
|
-
return Object.values(this.robot.links);
|
|
470
|
-
}
|
|
471
|
-
/** Names of the articulated (controllable) joints. */
|
|
472
|
-
getJointNames() {
|
|
473
|
-
return [...this.jointObjects.keys()];
|
|
474
|
-
}
|
|
475
|
-
getLinkNames() {
|
|
476
|
-
return [...this.linkObjects.keys()];
|
|
477
|
-
}
|
|
478
|
-
getKinematicTree() {
|
|
479
|
-
return this.tree;
|
|
154
|
+
addFixedJoint(options) {
|
|
155
|
+
return this.addJoint("fixed", options);
|
|
480
156
|
}
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
getTimeCodesPerSecond() {
|
|
484
|
-
return this.robot.timeCodesPerSecond ?? 24;
|
|
157
|
+
addRevoluteJoint(options) {
|
|
158
|
+
return this.addJoint("revolute", options);
|
|
485
159
|
}
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
return Object.values(this.robot.joints).some((j) => j.valueSamples !== void 0);
|
|
160
|
+
addPrismaticJoint(options) {
|
|
161
|
+
return this.addJoint("prismatic", options);
|
|
489
162
|
}
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
*/
|
|
494
|
-
getTimeRange() {
|
|
495
|
-
let start = Number.POSITIVE_INFINITY;
|
|
496
|
-
let end = Number.NEGATIVE_INFINITY;
|
|
497
|
-
for (const joint of Object.values(this.robot.joints)) {
|
|
498
|
-
const times = joint.valueSamples?.times;
|
|
499
|
-
if (!times || times.length === 0) continue;
|
|
500
|
-
start = Math.min(start, times[0]);
|
|
501
|
-
end = Math.max(end, times[times.length - 1]);
|
|
502
|
-
}
|
|
503
|
-
if (start <= end) return { start, end };
|
|
504
|
-
const { startTimeCode, endTimeCode } = this.robot;
|
|
505
|
-
if (startTimeCode !== void 0 && endTimeCode !== void 0) {
|
|
506
|
-
return { start: startTimeCode, end: endTimeCode };
|
|
163
|
+
addJoint(type, options) {
|
|
164
|
+
if (this.joints.has(options.name)) {
|
|
165
|
+
throw new Error(`RobotBuilder: joint "${options.name}" is already defined`);
|
|
507
166
|
}
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
167
|
+
const world = resolveFrame(options.frame);
|
|
168
|
+
this.joints.set(options.name, { type, options, ...world ? { world } : {} });
|
|
169
|
+
return this;
|
|
170
|
+
}
|
|
171
|
+
/** Assemble the IR + geometry provider (validates the kinematic graph). */
|
|
172
|
+
build() {
|
|
173
|
+
const links = {};
|
|
174
|
+
for (const [name, link] of this.links) {
|
|
175
|
+
links[name] = {
|
|
176
|
+
name,
|
|
177
|
+
primPath: `/${this.robotName}/${name}`,
|
|
178
|
+
visualPrims: [],
|
|
179
|
+
...link.inertial ? { inertial: link.inertial } : {},
|
|
180
|
+
// Authored placement, so links no joint reaches keep their build pose.
|
|
181
|
+
...isIdentityMat42(link.world) ? {} : { worldTransform: link.world }
|
|
182
|
+
};
|
|
514
183
|
}
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
this._showVisual = v;
|
|
522
|
-
this.setKindVisibility("visual", v);
|
|
523
|
-
}
|
|
524
|
-
get showCollision() {
|
|
525
|
-
return this._showCollision;
|
|
526
|
-
}
|
|
527
|
-
set showCollision(v) {
|
|
528
|
-
this._showCollision = v;
|
|
529
|
-
this.setKindVisibility("collision", v);
|
|
530
|
-
}
|
|
531
|
-
get showJointAxes() {
|
|
532
|
-
return this._showJointAxes;
|
|
533
|
-
}
|
|
534
|
-
set showJointAxes(v) {
|
|
535
|
-
this._showJointAxes = v;
|
|
536
|
-
if (v && this.jointAxesHelpers.length === 0) {
|
|
537
|
-
for (const joint of this.jointObjects.values()) {
|
|
538
|
-
const h = new THREE4.AxesHelper(this.helperSize);
|
|
539
|
-
h.name = `${joint.jointName}:axes`;
|
|
540
|
-
joint.add(h);
|
|
541
|
-
this.jointAxesHelpers.push(h);
|
|
184
|
+
const joints = {};
|
|
185
|
+
for (const [name, pending] of this.joints) {
|
|
186
|
+
const { options } = pending;
|
|
187
|
+
const parent = options.parent ?? "";
|
|
188
|
+
if (parent !== "" && !this.links.has(parent)) {
|
|
189
|
+
throw new Error(`RobotBuilder: joint "${name}" references unknown parent "${parent}"`);
|
|
542
190
|
}
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
}
|
|
549
|
-
set showLinkFrames(v) {
|
|
550
|
-
this._showLinkFrames = v;
|
|
551
|
-
if (v && this.linkFrameHelpers.length === 0) {
|
|
552
|
-
for (const link of this.linkObjects.values()) {
|
|
553
|
-
const h = new THREE4.AxesHelper(this.helperSize);
|
|
554
|
-
h.name = `${link.linkName}:frame`;
|
|
555
|
-
link.add(h);
|
|
556
|
-
this.linkFrameHelpers.push(h);
|
|
191
|
+
const childLink = this.links.get(options.child);
|
|
192
|
+
if (!childLink) {
|
|
193
|
+
throw new Error(
|
|
194
|
+
`RobotBuilder: joint "${name}" references unknown child "${options.child}"`
|
|
195
|
+
);
|
|
557
196
|
}
|
|
197
|
+
const jointWorld = pending.world ?? childLink.world;
|
|
198
|
+
const parentWorld = parent === "" ? identity4() : this.links.get(parent).world;
|
|
199
|
+
const type = refineJointType(pending.type, options.lower, options.upper);
|
|
200
|
+
joints[name] = {
|
|
201
|
+
name,
|
|
202
|
+
primPath: `/${this.robotName}/${name}`,
|
|
203
|
+
type,
|
|
204
|
+
parent,
|
|
205
|
+
child: options.child,
|
|
206
|
+
axis: options.axis ?? "X",
|
|
207
|
+
jointFrame0: multiply(invert(parentWorld), jointWorld),
|
|
208
|
+
jointFrame1: multiply(invert(childLink.world), jointWorld),
|
|
209
|
+
...options.lower !== void 0 ? { lower: options.lower } : {},
|
|
210
|
+
...options.upper !== void 0 ? { upper: options.upper } : {},
|
|
211
|
+
...options.initialValue !== void 0 ? { initialValue: options.initialValue } : {},
|
|
212
|
+
...options.drive ? { drive: options.drive } : {}
|
|
213
|
+
};
|
|
558
214
|
}
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
setKindVisibility(kind, visible) {
|
|
562
|
-
this.traverse((o) => {
|
|
563
|
-
if (o.userData.kind === kind) o.visible = visible;
|
|
564
|
-
});
|
|
565
|
-
}
|
|
566
|
-
};
|
|
567
|
-
function setMatrix(obj, m) {
|
|
568
|
-
obj.matrixAutoUpdate = false;
|
|
569
|
-
obj.matrix.fromArray(m);
|
|
570
|
-
obj.matrixWorldNeedsUpdate = true;
|
|
571
|
-
}
|
|
572
|
-
|
|
573
|
-
// src/three/ThreeUsdRobotLoader.ts
|
|
574
|
-
var ThreeUsdRobotLoader = class {
|
|
575
|
-
options;
|
|
576
|
-
constructor(options = {}) {
|
|
577
|
-
this.options = options;
|
|
578
|
-
}
|
|
579
|
-
get resolver() {
|
|
580
|
-
return this.options.assetResolver ?? new DefaultAssetResolver();
|
|
581
|
-
}
|
|
582
|
-
/**
|
|
583
|
-
* Fetch an asset by URL and build the robot. `.usdz` packages are unzipped and
|
|
584
|
-
* composed from their entries; everything else is treated as USDA text.
|
|
585
|
-
*/
|
|
586
|
-
async loadAsync(url) {
|
|
587
|
-
if (/\.usdz$/i.test(url)) {
|
|
588
|
-
return this.parseUsdz(await this.fetchRootBytes(url));
|
|
215
|
+
if (this.articulationRoot !== void 0 && !this.links.has(this.articulationRoot)) {
|
|
216
|
+
throw new Error(`RobotBuilder: articulationRoot "${this.articulationRoot}" is not a link`);
|
|
589
217
|
}
|
|
590
|
-
const
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
}
|
|
607
|
-
/** Build
|
|
608
|
-
|
|
609
|
-
const
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
}
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
const
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
218
|
+
const desc = {
|
|
219
|
+
name: this.robotName,
|
|
220
|
+
rootLink: "",
|
|
221
|
+
links,
|
|
222
|
+
joints,
|
|
223
|
+
upAxis: this.upAxis,
|
|
224
|
+
metersPerUnit: this.metersPerUnit,
|
|
225
|
+
...this.articulationRoot !== void 0 ? { articulationRoots: [this.articulationRoot] } : {}
|
|
226
|
+
};
|
|
227
|
+
const tree = buildKinematicTree(desc, { onWarn: this.warn });
|
|
228
|
+
desc.rootLink = tree.root;
|
|
229
|
+
if (tree.loopJoints.length > 0) desc.loopJoints = tree.loopJoints;
|
|
230
|
+
if (tree.warnings.length > 0) desc.warnings = tree.warnings;
|
|
231
|
+
const byLink = this.links;
|
|
232
|
+
const geometry = (linkKey) => byLink.get(linkKey)?.meshes ?? [];
|
|
233
|
+
return { desc, geometry, tree };
|
|
234
|
+
}
|
|
235
|
+
/** Build and export in one step (pass the result to `serializeUsda`). */
|
|
236
|
+
toUsda(options = {}) {
|
|
237
|
+
const { desc, geometry } = this.build();
|
|
238
|
+
return exportRobotUsda(desc, { onWarn: this.warn, ...options, geometry });
|
|
239
|
+
}
|
|
240
|
+
/** Collect `THREE.Mesh` descendants of `roots` as link-relative export meshes. */
|
|
241
|
+
gatherMeshes(roots, linkWorld, kind, collisionExtras = {}) {
|
|
242
|
+
const linkInverse = invert(linkWorld);
|
|
243
|
+
const out = [];
|
|
244
|
+
for (const root of roots) {
|
|
245
|
+
root.updateWorldMatrix(true, true);
|
|
246
|
+
root.traverse((obj) => {
|
|
247
|
+
const meshObj = obj;
|
|
248
|
+
if (!meshObj.isMesh) return;
|
|
249
|
+
const material = Array.isArray(meshObj.material) ? meshObj.material[0] : meshObj.material;
|
|
250
|
+
if (Array.isArray(meshObj.material) && meshObj.material.length > 1) {
|
|
251
|
+
this.warn(
|
|
252
|
+
`mesh "${meshObj.name}": multi-material meshes export their first material only`
|
|
253
|
+
);
|
|
254
|
+
}
|
|
255
|
+
const exportMaterial = material ? this.convertMaterial(material) : void 0;
|
|
256
|
+
const mesh = geometryToExportMesh(meshObj.geometry, {
|
|
257
|
+
name: meshObj.name || "mesh",
|
|
258
|
+
kind,
|
|
259
|
+
transform: multiply(linkInverse, [...meshObj.matrixWorld.elements]),
|
|
260
|
+
...exportMaterial ? { material: exportMaterial } : {},
|
|
261
|
+
doubleSided: material?.side === THREE.DoubleSide
|
|
262
|
+
});
|
|
263
|
+
if (mesh) {
|
|
264
|
+
if (kind === "collision") {
|
|
265
|
+
if (collisionExtras.approximation !== void 0) {
|
|
266
|
+
mesh.collisionApproximation = collisionExtras.approximation;
|
|
267
|
+
}
|
|
268
|
+
if (collisionExtras.material) mesh.physicsMaterial = collisionExtras.material;
|
|
269
|
+
}
|
|
270
|
+
out.push(mesh);
|
|
271
|
+
} else {
|
|
272
|
+
this.warn(`mesh "${meshObj.name}": no triangle geometry; skipped`);
|
|
273
|
+
}
|
|
638
274
|
});
|
|
639
275
|
}
|
|
640
|
-
return
|
|
641
|
-
}
|
|
642
|
-
async composeStage(text, baseUrl, resolver) {
|
|
643
|
-
const composeOptions = this.options.onWarn ? { onWarn: this.options.onWarn } : {};
|
|
644
|
-
return Stage.OpenFromFile(await composeLayer(text, baseUrl, resolver, composeOptions));
|
|
276
|
+
return out;
|
|
645
277
|
}
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
};
|
|
653
|
-
}
|
|
654
|
-
extractOptions() {
|
|
655
|
-
return {
|
|
656
|
-
...this.options.robotName !== void 0 ? { robotName: this.options.robotName } : {},
|
|
657
|
-
...this.options.onWarn !== void 0 ? { onWarn: this.options.onWarn } : {}
|
|
658
|
-
};
|
|
278
|
+
convertMaterial(material) {
|
|
279
|
+
if (!this.materialCache.has(material)) {
|
|
280
|
+
const name = material.name || `Material_${this.materialAutoId++}`;
|
|
281
|
+
this.materialCache.set(material, materialToExportMaterial(material, name, this.warn));
|
|
282
|
+
}
|
|
283
|
+
return this.materialCache.get(material);
|
|
659
284
|
}
|
|
660
285
|
};
|
|
286
|
+
function isIdentityMat42(m) {
|
|
287
|
+
for (let i = 0; i < 16; i++) {
|
|
288
|
+
if (m[i] !== (i % 5 === 0 ? 1 : 0)) return false;
|
|
289
|
+
}
|
|
290
|
+
return true;
|
|
291
|
+
}
|
|
292
|
+
function resolveFrame(frame) {
|
|
293
|
+
if (!frame) return void 0;
|
|
294
|
+
if (frame.isObject3D) {
|
|
295
|
+
const obj = frame;
|
|
296
|
+
obj.updateWorldMatrix(true, false);
|
|
297
|
+
return [...obj.matrixWorld.elements];
|
|
298
|
+
}
|
|
299
|
+
return [...frame.elements];
|
|
300
|
+
}
|
|
661
301
|
|
|
662
|
-
export {
|
|
302
|
+
export { RobotBuilder, exportThreeUsdRobot, geometryToExportMesh, materialToExportMaterial, threeGeometryProvider };
|
|
663
303
|
//# sourceMappingURL=index.js.map
|
|
664
304
|
//# sourceMappingURL=index.js.map
|