circuit-json-to-gltf 0.0.17 → 0.0.19
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/dist/index.js +369 -9
- package/package.json +4 -1
package/dist/index.js
CHANGED
|
@@ -1078,6 +1078,180 @@ async function renderBoardTextures(circuitJson, resolution = 1024) {
|
|
|
1078
1078
|
return { top, bottom };
|
|
1079
1079
|
}
|
|
1080
1080
|
|
|
1081
|
+
// lib/utils/pcb-board-geometry.ts
|
|
1082
|
+
import { extrudeLinear } from "@jscad/modeling/src/operations/extrusions";
|
|
1083
|
+
import {
|
|
1084
|
+
polygon,
|
|
1085
|
+
rectangle,
|
|
1086
|
+
roundedRectangle,
|
|
1087
|
+
cylinder
|
|
1088
|
+
} from "@jscad/modeling/src/primitives";
|
|
1089
|
+
import {
|
|
1090
|
+
translate,
|
|
1091
|
+
rotateZ,
|
|
1092
|
+
rotateX
|
|
1093
|
+
} from "@jscad/modeling/src/operations/transforms";
|
|
1094
|
+
import { subtract } from "@jscad/modeling/src/operations/booleans";
|
|
1095
|
+
import * as geom3 from "@jscad/modeling/src/geometries/geom3";
|
|
1096
|
+
import measureBoundingBox from "@jscad/modeling/src/measurements/measureBoundingBox";
|
|
1097
|
+
var DEFAULT_SEGMENTS = 64;
|
|
1098
|
+
var RADIUS_EPSILON = 1e-4;
|
|
1099
|
+
var toVec2 = (point, center) => [
|
|
1100
|
+
point.x - center.x,
|
|
1101
|
+
point.y - center.y
|
|
1102
|
+
];
|
|
1103
|
+
var arePointsClockwise = (points) => {
|
|
1104
|
+
let area = 0;
|
|
1105
|
+
for (let i = 0; i < points.length; i++) {
|
|
1106
|
+
const j = (i + 1) % points.length;
|
|
1107
|
+
area += points[i][0] * points[j][1];
|
|
1108
|
+
area -= points[j][0] * points[i][1];
|
|
1109
|
+
}
|
|
1110
|
+
const signedArea = area / 2;
|
|
1111
|
+
return signedArea <= 0;
|
|
1112
|
+
};
|
|
1113
|
+
var getNumberProperty = (obj, key) => {
|
|
1114
|
+
const value = obj[key];
|
|
1115
|
+
return typeof value === "number" ? value : void 0;
|
|
1116
|
+
};
|
|
1117
|
+
var createBoardOutlineGeom = (board, center, thickness) => {
|
|
1118
|
+
if (board.outline && board.outline.length >= 3) {
|
|
1119
|
+
let outlinePoints = board.outline.map((pt) => toVec2(pt, center));
|
|
1120
|
+
if (arePointsClockwise(outlinePoints)) {
|
|
1121
|
+
outlinePoints = outlinePoints.slice().reverse();
|
|
1122
|
+
}
|
|
1123
|
+
const shape2d = polygon({ points: outlinePoints });
|
|
1124
|
+
let geom2 = extrudeLinear({ height: thickness }, shape2d);
|
|
1125
|
+
geom2 = translate([0, 0, -thickness / 2], geom2);
|
|
1126
|
+
return geom2;
|
|
1127
|
+
}
|
|
1128
|
+
const baseRect = rectangle({ size: [board.width, board.height] });
|
|
1129
|
+
let geom = extrudeLinear({ height: thickness }, baseRect);
|
|
1130
|
+
geom = translate([0, 0, -thickness / 2], geom);
|
|
1131
|
+
return geom;
|
|
1132
|
+
};
|
|
1133
|
+
var createCircularHole = (x, y, radius, thickness) => cylinder({
|
|
1134
|
+
center: [x, y, 0],
|
|
1135
|
+
height: thickness + 1,
|
|
1136
|
+
radius,
|
|
1137
|
+
segments: DEFAULT_SEGMENTS
|
|
1138
|
+
});
|
|
1139
|
+
var createPillHole = (x, y, width, height, thickness, rotate) => {
|
|
1140
|
+
const minDimension = Math.min(width, height);
|
|
1141
|
+
const maxAllowedRadius = Math.max(0, minDimension / 2 - RADIUS_EPSILON);
|
|
1142
|
+
const roundRadius = maxAllowedRadius <= 0 ? 0 : Math.min(height / 2, maxAllowedRadius);
|
|
1143
|
+
const hole2d = roundedRectangle({
|
|
1144
|
+
size: [width, height],
|
|
1145
|
+
roundRadius,
|
|
1146
|
+
segments: DEFAULT_SEGMENTS
|
|
1147
|
+
});
|
|
1148
|
+
let hole3d = extrudeLinear({ height: thickness + 1 }, hole2d);
|
|
1149
|
+
hole3d = translate([0, 0, -(thickness + 1) / 2], hole3d);
|
|
1150
|
+
if (rotate) {
|
|
1151
|
+
hole3d = rotateZ(Math.PI / 2, hole3d);
|
|
1152
|
+
}
|
|
1153
|
+
return translate([x, y, 0], hole3d);
|
|
1154
|
+
};
|
|
1155
|
+
var createHoleGeoms = (boardCenter, thickness, holes = [], platedHoles = []) => {
|
|
1156
|
+
const holeGeoms = [];
|
|
1157
|
+
for (const hole of holes) {
|
|
1158
|
+
const holeRecord = hole;
|
|
1159
|
+
const diameter = getNumberProperty(holeRecord, "hole_diameter") ?? getNumberProperty(holeRecord, "diameter");
|
|
1160
|
+
if (!diameter) continue;
|
|
1161
|
+
const radius = diameter / 2;
|
|
1162
|
+
const relX = hole.x - boardCenter.x;
|
|
1163
|
+
const relY = -(hole.y - boardCenter.y);
|
|
1164
|
+
holeGeoms.push(createCircularHole(relX, relY, radius, thickness));
|
|
1165
|
+
}
|
|
1166
|
+
for (const plated of platedHoles) {
|
|
1167
|
+
const relX = plated.x - boardCenter.x;
|
|
1168
|
+
const relY = -(plated.y - boardCenter.y);
|
|
1169
|
+
const platedRecord = plated;
|
|
1170
|
+
if (plated.shape === "pill" || plated.shape === "pill_hole_with_rect_pad") {
|
|
1171
|
+
const holeWidth = getNumberProperty(platedRecord, "hole_width") ?? getNumberProperty(platedRecord, "outer_diameter") ?? 0;
|
|
1172
|
+
const holeHeight = getNumberProperty(platedRecord, "hole_height") ?? getNumberProperty(platedRecord, "hole_diameter") ?? 0;
|
|
1173
|
+
if (!holeWidth || !holeHeight) continue;
|
|
1174
|
+
const rotate = holeHeight > holeWidth;
|
|
1175
|
+
const width = rotate ? holeHeight : holeWidth;
|
|
1176
|
+
const height = rotate ? holeWidth : holeHeight;
|
|
1177
|
+
holeGeoms.push(
|
|
1178
|
+
createPillHole(relX, relY, width, height, thickness, rotate)
|
|
1179
|
+
);
|
|
1180
|
+
continue;
|
|
1181
|
+
}
|
|
1182
|
+
const diameter = getNumberProperty(platedRecord, "hole_diameter") ?? getNumberProperty(platedRecord, "outer_diameter");
|
|
1183
|
+
if (!diameter) continue;
|
|
1184
|
+
holeGeoms.push(createCircularHole(relX, relY, diameter / 2, thickness));
|
|
1185
|
+
}
|
|
1186
|
+
return holeGeoms;
|
|
1187
|
+
};
|
|
1188
|
+
var geom3ToTriangles = (geometry, polygons) => {
|
|
1189
|
+
const sourcePolygons = polygons ?? geom3.toPolygons(geometry);
|
|
1190
|
+
const triangles = [];
|
|
1191
|
+
for (const poly of sourcePolygons) {
|
|
1192
|
+
if (!poly || poly.vertices.length < 3) continue;
|
|
1193
|
+
const base = poly.vertices[0];
|
|
1194
|
+
const next = poly.vertices[1];
|
|
1195
|
+
const next2 = poly.vertices[2];
|
|
1196
|
+
const ab = [next[0] - base[0], next[1] - base[1], next[2] - base[2]];
|
|
1197
|
+
const ac = [
|
|
1198
|
+
next2[0] - base[0],
|
|
1199
|
+
next2[1] - base[1],
|
|
1200
|
+
next2[2] - base[2]
|
|
1201
|
+
];
|
|
1202
|
+
const cross = [
|
|
1203
|
+
ab[1] * ac[2] - ab[2] * ac[1],
|
|
1204
|
+
ab[2] * ac[0] - ab[0] * ac[2],
|
|
1205
|
+
ab[0] * ac[1] - ab[1] * ac[0]
|
|
1206
|
+
];
|
|
1207
|
+
const length = Math.sqrt(cross[0] ** 2 + cross[1] ** 2 + cross[2] ** 2) || 1;
|
|
1208
|
+
const normal = {
|
|
1209
|
+
x: cross[0] / length,
|
|
1210
|
+
y: cross[1] / length,
|
|
1211
|
+
z: cross[2] / length
|
|
1212
|
+
};
|
|
1213
|
+
for (let i = 1; i < poly.vertices.length - 1; i++) {
|
|
1214
|
+
const v1 = poly.vertices[i];
|
|
1215
|
+
const v2 = poly.vertices[i + 1];
|
|
1216
|
+
const triangle = {
|
|
1217
|
+
vertices: [
|
|
1218
|
+
{ x: base[0], y: base[1], z: base[2] },
|
|
1219
|
+
{ x: v1[0], y: v1[1], z: v1[2] },
|
|
1220
|
+
{ x: v2[0], y: v2[1], z: v2[2] }
|
|
1221
|
+
],
|
|
1222
|
+
normal
|
|
1223
|
+
};
|
|
1224
|
+
triangles.push(triangle);
|
|
1225
|
+
}
|
|
1226
|
+
}
|
|
1227
|
+
return triangles;
|
|
1228
|
+
};
|
|
1229
|
+
var createBoundingBox = (bbox) => {
|
|
1230
|
+
const [min, max] = bbox;
|
|
1231
|
+
return {
|
|
1232
|
+
min: { x: min[0], y: min[1], z: min[2] },
|
|
1233
|
+
max: { x: max[0], y: max[1], z: max[2] }
|
|
1234
|
+
};
|
|
1235
|
+
};
|
|
1236
|
+
var createBoardMesh = (board, options) => {
|
|
1237
|
+
const { thickness, holes = [], platedHoles = [] } = options;
|
|
1238
|
+
const center = board.center ?? { x: 0, y: 0 };
|
|
1239
|
+
let boardGeom = createBoardOutlineGeom(board, center, thickness);
|
|
1240
|
+
const holeGeoms = createHoleGeoms(center, thickness, holes, platedHoles);
|
|
1241
|
+
if (holeGeoms.length > 0) {
|
|
1242
|
+
boardGeom = subtract(boardGeom, ...holeGeoms);
|
|
1243
|
+
}
|
|
1244
|
+
boardGeom = rotateX(-Math.PI / 2, boardGeom);
|
|
1245
|
+
const polygons = geom3.toPolygons(boardGeom);
|
|
1246
|
+
const triangles = geom3ToTriangles(boardGeom, polygons);
|
|
1247
|
+
const bboxValues = measureBoundingBox(boardGeom);
|
|
1248
|
+
const boundingBox = createBoundingBox(bboxValues);
|
|
1249
|
+
return {
|
|
1250
|
+
triangles,
|
|
1251
|
+
boundingBox
|
|
1252
|
+
};
|
|
1253
|
+
};
|
|
1254
|
+
|
|
1081
1255
|
// lib/converters/circuit-to-3d.ts
|
|
1082
1256
|
var DEFAULT_BOARD_THICKNESS = 1.6;
|
|
1083
1257
|
var DEFAULT_COMPONENT_HEIGHT = 2;
|
|
@@ -1101,7 +1275,17 @@ async function convertCircuitJsonTo3D(circuitJson, options = {}) {
|
|
|
1101
1275
|
const db = cju(circuitJson);
|
|
1102
1276
|
const boxes = [];
|
|
1103
1277
|
const pcbBoard = db.pcb_board?.list?.()[0];
|
|
1278
|
+
const effectiveBoardThickness = pcbBoard?.thickness ?? boardThickness;
|
|
1104
1279
|
if (pcbBoard) {
|
|
1280
|
+
const pcbHoles = db.pcb_hole?.list?.() ?? [];
|
|
1281
|
+
const pcbPlatedHoles = db.pcb_plated_hole?.list?.() ?? [];
|
|
1282
|
+
const boardMesh = createBoardMesh(pcbBoard, {
|
|
1283
|
+
thickness: effectiveBoardThickness,
|
|
1284
|
+
holes: pcbHoles,
|
|
1285
|
+
platedHoles: pcbPlatedHoles
|
|
1286
|
+
});
|
|
1287
|
+
const meshWidth = boardMesh.boundingBox.max.x - boardMesh.boundingBox.min.x;
|
|
1288
|
+
const meshHeight = boardMesh.boundingBox.max.z - boardMesh.boundingBox.min.z;
|
|
1105
1289
|
const boardBox = {
|
|
1106
1290
|
center: {
|
|
1107
1291
|
x: pcbBoard.center.x,
|
|
@@ -1109,10 +1293,12 @@ async function convertCircuitJsonTo3D(circuitJson, options = {}) {
|
|
|
1109
1293
|
z: pcbBoard.center.y
|
|
1110
1294
|
},
|
|
1111
1295
|
size: {
|
|
1112
|
-
x: pcbBoard.width,
|
|
1113
|
-
y:
|
|
1114
|
-
z: pcbBoard.height
|
|
1115
|
-
}
|
|
1296
|
+
x: Number.isFinite(meshWidth) ? meshWidth : pcbBoard.width,
|
|
1297
|
+
y: effectiveBoardThickness,
|
|
1298
|
+
z: Number.isFinite(meshHeight) ? meshHeight : pcbBoard.height
|
|
1299
|
+
},
|
|
1300
|
+
mesh: boardMesh,
|
|
1301
|
+
color: pcbColor
|
|
1116
1302
|
};
|
|
1117
1303
|
if (shouldRenderTextures && textureResolution > 0) {
|
|
1118
1304
|
try {
|
|
@@ -1137,14 +1323,14 @@ async function convertCircuitJsonTo3D(circuitJson, options = {}) {
|
|
|
1137
1323
|
const pcbComponentIdsWith3D = /* @__PURE__ */ new Set();
|
|
1138
1324
|
for (const cad of cadComponents) {
|
|
1139
1325
|
let { model_stl_url, model_obj_url, model_glb_url, model_gltf_url } = cad;
|
|
1140
|
-
|
|
1326
|
+
let hasModelUrl = Boolean(
|
|
1141
1327
|
model_stl_url || model_obj_url || model_glb_url || model_gltf_url
|
|
1142
1328
|
);
|
|
1143
1329
|
if (!hasModelUrl && cad.footprinter_string) {
|
|
1144
1330
|
model_glb_url = `https://modelcdn.tscircuit.com/jscad_models/${cad.footprinter_string}.glb`;
|
|
1331
|
+
hasModelUrl = true;
|
|
1145
1332
|
}
|
|
1146
|
-
if (!
|
|
1147
|
-
continue;
|
|
1333
|
+
if (!hasModelUrl) continue;
|
|
1148
1334
|
pcbComponentIdsWith3D.add(cad.pcb_component_id);
|
|
1149
1335
|
const pcbComponent = db.pcb_component.get(cad.pcb_component_id);
|
|
1150
1336
|
const isBottomLayer = pcbComponent?.layer === "bottom";
|
|
@@ -1159,7 +1345,7 @@ async function convertCircuitJsonTo3D(circuitJson, options = {}) {
|
|
|
1159
1345
|
z: cad.position.y
|
|
1160
1346
|
} : {
|
|
1161
1347
|
x: pcbComponent?.center.x ?? 0,
|
|
1162
|
-
y: isBottomLayer ? -(
|
|
1348
|
+
y: isBottomLayer ? -(effectiveBoardThickness / 2 + size.y / 2) : effectiveBoardThickness / 2 + size.y / 2,
|
|
1163
1349
|
z: pcbComponent?.center.y ?? 0
|
|
1164
1350
|
};
|
|
1165
1351
|
const meshType = model_stl_url ? "stl" : model_obj_url ? "obj" : model_gltf_url ? "gltf" : "glb";
|
|
@@ -1228,7 +1414,7 @@ async function convertCircuitJsonTo3D(circuitJson, options = {}) {
|
|
|
1228
1414
|
boxes.push({
|
|
1229
1415
|
center: {
|
|
1230
1416
|
x: component.center.x,
|
|
1231
|
-
y: isBottomLayer ? -(
|
|
1417
|
+
y: isBottomLayer ? -(effectiveBoardThickness / 2 + compHeight / 2) : effectiveBoardThickness / 2 + compHeight / 2,
|
|
1232
1418
|
z: component.center.y
|
|
1233
1419
|
},
|
|
1234
1420
|
size: {
|
|
@@ -2017,7 +2203,181 @@ var GLTFBuilder = class {
|
|
|
2017
2203
|
});
|
|
2018
2204
|
this.gltf.scenes[0].nodes.push(nodeIndex);
|
|
2019
2205
|
}
|
|
2206
|
+
async addMeshWithFaceTextures(box, defaultMaterialIndex) {
|
|
2207
|
+
const topTriangles = [];
|
|
2208
|
+
const bottomTriangles = [];
|
|
2209
|
+
const sideTriangles = [];
|
|
2210
|
+
const yThreshold = 0.8;
|
|
2211
|
+
for (const triangle of box.mesh.triangles) {
|
|
2212
|
+
const ny = Math.abs(triangle.normal.y);
|
|
2213
|
+
if (ny > yThreshold) {
|
|
2214
|
+
if (triangle.normal.y > 0) {
|
|
2215
|
+
topTriangles.push(triangle);
|
|
2216
|
+
} else {
|
|
2217
|
+
bottomTriangles.push(triangle);
|
|
2218
|
+
}
|
|
2219
|
+
} else {
|
|
2220
|
+
sideTriangles.push(triangle);
|
|
2221
|
+
}
|
|
2222
|
+
}
|
|
2223
|
+
const materials = [];
|
|
2224
|
+
if (topTriangles.length > 0 && box.texture?.top) {
|
|
2225
|
+
const topMaterialIndex = this.addMaterial({
|
|
2226
|
+
name: `TopMaterial_${this.materials.length}`,
|
|
2227
|
+
pbrMetallicRoughness: {
|
|
2228
|
+
baseColorFactor: [1, 1, 1, 1],
|
|
2229
|
+
metallicFactor: 0,
|
|
2230
|
+
roughnessFactor: 0.8
|
|
2231
|
+
},
|
|
2232
|
+
alphaMode: "OPAQUE",
|
|
2233
|
+
doubleSided: true
|
|
2234
|
+
});
|
|
2235
|
+
const textureIndex = await this.addTextureFromDataUrl(box.texture.top);
|
|
2236
|
+
if (textureIndex !== -1) {
|
|
2237
|
+
const material = this.materials[topMaterialIndex];
|
|
2238
|
+
if (material.pbrMetallicRoughness) {
|
|
2239
|
+
material.pbrMetallicRoughness.baseColorTexture = {
|
|
2240
|
+
index: textureIndex
|
|
2241
|
+
};
|
|
2242
|
+
}
|
|
2243
|
+
}
|
|
2244
|
+
materials.push({
|
|
2245
|
+
triangles: topTriangles,
|
|
2246
|
+
materialIndex: topMaterialIndex
|
|
2247
|
+
});
|
|
2248
|
+
}
|
|
2249
|
+
if (bottomTriangles.length > 0 && box.texture?.bottom) {
|
|
2250
|
+
const bottomMaterialIndex = this.addMaterial({
|
|
2251
|
+
name: `BottomMaterial_${this.materials.length}`,
|
|
2252
|
+
pbrMetallicRoughness: {
|
|
2253
|
+
baseColorFactor: [1, 1, 1, 1],
|
|
2254
|
+
metallicFactor: 0,
|
|
2255
|
+
roughnessFactor: 0.8
|
|
2256
|
+
},
|
|
2257
|
+
alphaMode: "OPAQUE",
|
|
2258
|
+
doubleSided: true
|
|
2259
|
+
});
|
|
2260
|
+
const textureIndex = await this.addTextureFromDataUrl(box.texture.bottom);
|
|
2261
|
+
if (textureIndex !== -1) {
|
|
2262
|
+
const material = this.materials[bottomMaterialIndex];
|
|
2263
|
+
if (material.pbrMetallicRoughness) {
|
|
2264
|
+
material.pbrMetallicRoughness.baseColorTexture = {
|
|
2265
|
+
index: textureIndex
|
|
2266
|
+
};
|
|
2267
|
+
}
|
|
2268
|
+
}
|
|
2269
|
+
materials.push({
|
|
2270
|
+
triangles: bottomTriangles,
|
|
2271
|
+
materialIndex: bottomMaterialIndex
|
|
2272
|
+
});
|
|
2273
|
+
}
|
|
2274
|
+
if (sideTriangles.length > 0) {
|
|
2275
|
+
const sideMaterialIndex = this.addMaterial({
|
|
2276
|
+
name: `GreenSideMaterial_${this.materials.length}`,
|
|
2277
|
+
pbrMetallicRoughness: {
|
|
2278
|
+
baseColorFactor: [0, 0.55, 0, 1],
|
|
2279
|
+
metallicFactor: 0,
|
|
2280
|
+
roughnessFactor: 0.8
|
|
2281
|
+
},
|
|
2282
|
+
alphaMode: "OPAQUE",
|
|
2283
|
+
doubleSided: true
|
|
2284
|
+
});
|
|
2285
|
+
materials.push({
|
|
2286
|
+
triangles: sideTriangles,
|
|
2287
|
+
materialIndex: sideMaterialIndex
|
|
2288
|
+
});
|
|
2289
|
+
}
|
|
2290
|
+
const primitives = [];
|
|
2291
|
+
const bounds = getBounds([]);
|
|
2292
|
+
let minX = Infinity, minY = Infinity, minZ = Infinity;
|
|
2293
|
+
let maxX = -Infinity, maxY = -Infinity, maxZ = -Infinity;
|
|
2294
|
+
for (const triangle of box.mesh.triangles) {
|
|
2295
|
+
for (const v of triangle.vertices) {
|
|
2296
|
+
minX = Math.min(minX, v.x);
|
|
2297
|
+
minY = Math.min(minY, v.y);
|
|
2298
|
+
minZ = Math.min(minZ, v.z);
|
|
2299
|
+
maxX = Math.max(maxX, v.x);
|
|
2300
|
+
maxY = Math.max(maxY, v.y);
|
|
2301
|
+
maxZ = Math.max(maxZ, v.z);
|
|
2302
|
+
}
|
|
2303
|
+
}
|
|
2304
|
+
const sizeX = maxX - minX;
|
|
2305
|
+
const sizeZ = maxZ - minZ;
|
|
2306
|
+
for (const { triangles, materialIndex } of materials) {
|
|
2307
|
+
const positions = [];
|
|
2308
|
+
const normals = [];
|
|
2309
|
+
const texcoords = [];
|
|
2310
|
+
const indices = [];
|
|
2311
|
+
let vertexIndex = 0;
|
|
2312
|
+
for (const triangle of triangles) {
|
|
2313
|
+
for (const v of triangle.vertices) {
|
|
2314
|
+
positions.push(v.x, v.y, v.z);
|
|
2315
|
+
normals.push(triangle.normal.x, triangle.normal.y, triangle.normal.z);
|
|
2316
|
+
const u = sizeX > 0 ? (v.x - minX) / sizeX : 0.5;
|
|
2317
|
+
const v_coord = sizeZ > 0 ? (v.z - minZ) / sizeZ : 0.5;
|
|
2318
|
+
texcoords.push(u, 1 - v_coord);
|
|
2319
|
+
}
|
|
2320
|
+
indices.push(vertexIndex, vertexIndex + 1, vertexIndex + 2);
|
|
2321
|
+
vertexIndex += 3;
|
|
2322
|
+
}
|
|
2323
|
+
const meshData = { positions, normals, texcoords, indices };
|
|
2324
|
+
const transformedMeshData = transformMesh(
|
|
2325
|
+
meshData,
|
|
2326
|
+
box.center,
|
|
2327
|
+
box.rotation
|
|
2328
|
+
);
|
|
2329
|
+
const positionAccessorIndex = this.addAccessor(
|
|
2330
|
+
transformedMeshData.positions,
|
|
2331
|
+
"VEC3",
|
|
2332
|
+
COMPONENT_TYPE.FLOAT,
|
|
2333
|
+
TARGET.ARRAY_BUFFER
|
|
2334
|
+
);
|
|
2335
|
+
const normalAccessorIndex = this.addAccessor(
|
|
2336
|
+
transformedMeshData.normals,
|
|
2337
|
+
"VEC3",
|
|
2338
|
+
COMPONENT_TYPE.FLOAT,
|
|
2339
|
+
TARGET.ARRAY_BUFFER
|
|
2340
|
+
);
|
|
2341
|
+
const texcoordAccessorIndex = this.addAccessor(
|
|
2342
|
+
transformedMeshData.texcoords,
|
|
2343
|
+
"VEC2",
|
|
2344
|
+
COMPONENT_TYPE.FLOAT,
|
|
2345
|
+
TARGET.ARRAY_BUFFER
|
|
2346
|
+
);
|
|
2347
|
+
const indicesAccessorIndex = this.addAccessor(
|
|
2348
|
+
transformedMeshData.indices,
|
|
2349
|
+
"SCALAR",
|
|
2350
|
+
COMPONENT_TYPE.UNSIGNED_SHORT,
|
|
2351
|
+
TARGET.ELEMENT_ARRAY_BUFFER
|
|
2352
|
+
);
|
|
2353
|
+
primitives.push({
|
|
2354
|
+
attributes: {
|
|
2355
|
+
POSITION: positionAccessorIndex,
|
|
2356
|
+
NORMAL: normalAccessorIndex,
|
|
2357
|
+
TEXCOORD_0: texcoordAccessorIndex
|
|
2358
|
+
},
|
|
2359
|
+
indices: indicesAccessorIndex,
|
|
2360
|
+
material: materialIndex,
|
|
2361
|
+
mode: PRIMITIVE_MODE.TRIANGLES
|
|
2362
|
+
});
|
|
2363
|
+
}
|
|
2364
|
+
const meshIndex = this.meshes.length;
|
|
2365
|
+
this.meshes.push({
|
|
2366
|
+
name: box.label || `MeshWithTextures${meshIndex}`,
|
|
2367
|
+
primitives
|
|
2368
|
+
});
|
|
2369
|
+
const nodeIndex = this.nodes.length;
|
|
2370
|
+
this.nodes.push({
|
|
2371
|
+
name: box.label || `Box${nodeIndex}`,
|
|
2372
|
+
mesh: meshIndex
|
|
2373
|
+
});
|
|
2374
|
+
this.gltf.scenes[0].nodes.push(nodeIndex);
|
|
2375
|
+
}
|
|
2020
2376
|
async addBoxWithFaceMaterials(box, defaultMaterialIndex) {
|
|
2377
|
+
if (box.mesh) {
|
|
2378
|
+
await this.addMeshWithFaceTextures(box, defaultMaterialIndex);
|
|
2379
|
+
return;
|
|
2380
|
+
}
|
|
2021
2381
|
const faceMeshes = createBoxMeshByFaces(box.size);
|
|
2022
2382
|
const faceMaterials = {};
|
|
2023
2383
|
if (box.texture?.top) {
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "circuit-json-to-gltf",
|
|
3
3
|
"main": "dist/index.js",
|
|
4
4
|
"type": "module",
|
|
5
|
-
"version": "0.0.
|
|
5
|
+
"version": "0.0.19",
|
|
6
6
|
"scripts": {
|
|
7
7
|
"test": "bun test tests/",
|
|
8
8
|
"format": "biome format --write .",
|
|
@@ -53,5 +53,8 @@
|
|
|
53
53
|
"@resvg/resvg-js": {
|
|
54
54
|
"optional": true
|
|
55
55
|
}
|
|
56
|
+
},
|
|
57
|
+
"dependencies": {
|
|
58
|
+
"@jscad/modeling": "^2.12.6"
|
|
56
59
|
}
|
|
57
60
|
}
|