Add configurable area asset budgets
This commit is contained in:
@@ -59,6 +59,10 @@ function materialDigest(material) {
|
||||
|
||||
function digest(file) {
|
||||
const gltf = readGlbJson(file);
|
||||
return digestGltf(gltf, { file: path.basename(file), fileBytes: fs.statSync(file).size });
|
||||
}
|
||||
|
||||
function digestGltf(gltf, fileInfo = {}) {
|
||||
const meshes = (gltf.meshes || []).map((mesh) => ({
|
||||
name: mesh.name || null,
|
||||
primitives: (mesh.primitives || []).map((primitive) => ({
|
||||
@@ -68,18 +72,37 @@ function digest(file) {
|
||||
// fingerprint and stay stable regardless of buffer layout.
|
||||
count: gltf.accessors?.[primitive.attributes?.POSITION]?.count ?? null,
|
||||
indices: gltf.accessors?.[primitive.indices]?.count ?? null,
|
||||
triangles: primitiveTriangleCount(primitive, gltf.accessors || []),
|
||||
})),
|
||||
}));
|
||||
const sourceSummary = summarizeNodeSources(gltf.nodes || [], meshes);
|
||||
const images = (gltf.images || [])
|
||||
.map((image) => ({
|
||||
name: image.name || null,
|
||||
mimeType: image.mimeType || null,
|
||||
bytes: gltf.bufferViews?.[image.bufferView]?.byteLength ?? 0,
|
||||
}))
|
||||
.sort((a, b) => b.bytes - a.bytes || String(a.name).localeCompare(String(b.name)));
|
||||
const triangles = meshes.reduce(
|
||||
(total, mesh) => total + mesh.primitives.reduce((sum, primitive) => sum + primitive.triangles, 0),
|
||||
0,
|
||||
);
|
||||
const renderTriangles = sourceSummary.reduce((total, source) => total + source.triangles, 0);
|
||||
const embeddedImageBytes = images.reduce((total, image) => total + image.bytes, 0);
|
||||
return {
|
||||
file: path.basename(file),
|
||||
fileBytes: fs.statSync(file).size,
|
||||
file: fileInfo.file || null,
|
||||
fileBytes: fileInfo.fileBytes ?? 0,
|
||||
counts: {
|
||||
nodes: (gltf.nodes || []).length,
|
||||
meshes: meshes.length,
|
||||
materials: (gltf.materials || []).length,
|
||||
images: (gltf.images || []).length,
|
||||
accessors: (gltf.accessors || []).length,
|
||||
triangles,
|
||||
renderTriangles,
|
||||
},
|
||||
embeddedImageBytes,
|
||||
sourceSummary,
|
||||
extensionsUsed: (gltf.extensionsUsed || []).slice().sort(),
|
||||
buffers: (gltf.buffers || []).map((buffer) => buffer.byteLength),
|
||||
nodes: (gltf.nodes || [])
|
||||
@@ -96,12 +119,44 @@ function digest(file) {
|
||||
materials: (gltf.materials || [])
|
||||
.map(materialDigest)
|
||||
.sort((a, b) => String(a.name).localeCompare(String(b.name))),
|
||||
images: (gltf.images || [])
|
||||
.map((image) => ({ name: image.name || null, mimeType: image.mimeType || null }))
|
||||
.sort((a, b) => String(a.name).localeCompare(String(b.name))),
|
||||
images,
|
||||
};
|
||||
}
|
||||
|
||||
function primitiveTriangleCount(primitive, accessors) {
|
||||
if (primitive.mode !== undefined && primitive.mode !== 4) return 0;
|
||||
const count = primitive.indices === undefined
|
||||
? accessors[primitive.attributes?.POSITION]?.count
|
||||
: accessors[primitive.indices]?.count;
|
||||
return Number.isFinite(count) ? Math.floor(count / 3) : 0;
|
||||
}
|
||||
|
||||
function summarizeNodeSources(nodes, meshes) {
|
||||
const summaries = new Map();
|
||||
for (const node of nodes) {
|
||||
if (node.mesh === undefined || !meshes[node.mesh]) continue;
|
||||
const source = nodeSource(node.name || meshes[node.mesh].name || "");
|
||||
const summary = summaries.get(source) || { source, nodes: 0, meshInstances: 0, triangles: 0 };
|
||||
const triangles = meshes[node.mesh].primitives.reduce((sum, primitive) => sum + primitive.triangles, 0);
|
||||
summary.nodes += 1;
|
||||
summary.meshInstances += 1;
|
||||
summary.triangles += triangles;
|
||||
summaries.set(source, summary);
|
||||
}
|
||||
return [...summaries.values()].sort((a, b) => b.triangles - a.triangles || a.source.localeCompare(b.source));
|
||||
}
|
||||
|
||||
function nodeSource(name) {
|
||||
const value = String(name).toLowerCase();
|
||||
if (value.includes("building")) return "buildings";
|
||||
if (/(shapespark|tree|bush|shrub|grass|branch|trunk|leaf)/.test(value)) return "vegetation";
|
||||
if (/(road|sidewalk|lane|crosswalk|stop|intersection)/.test(value)) return "roads";
|
||||
if (/(lake|water)/.test(value)) return "water";
|
||||
if (value.includes("fountain")) return "fountain";
|
||||
if (/(vehicle|car)/.test(value)) return "vehicles";
|
||||
return "other";
|
||||
}
|
||||
|
||||
function main() {
|
||||
const argv = process.argv.slice(2);
|
||||
const file = argv.find((arg) => !arg.startsWith("--"));
|
||||
@@ -128,5 +183,6 @@ if (require.main === module) {
|
||||
|
||||
module.exports = {
|
||||
digest,
|
||||
digestGltf,
|
||||
readGlbJson,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user