UNPKG

gltf-pipeline

Version:

Content pipeline tools for optimizing glTF assets.

188 lines (169 loc) 6.1 kB
"use strict"; const Cesium = require("cesium"); const ForEach = require("./ForEach"); const defined = Cesium.defined; const isDataUri = Cesium.isDataUri; const WebGLConstants = Cesium.WebGLConstants; module.exports = getStatistics; /** * Returns an object containing the statistics for the glTF asset. * * @param {object} gltf A javascript object containing a glTF asset. * @param {number} [nodeId] If defined, statistics will only process number of draw calls and rendered primitives for the specified node. * @returns {Statistics} Object containing the statistics of the glTF asset. * * @see Statistics */ function getStatistics(gltf, nodeId) { const statistics = new Statistics(); if (defined(nodeId)) { const nodeDrawStats = getDrawCallStatisticsForNode(gltf, nodeId); statistics.numberOfDrawCalls = nodeDrawStats.numberOfDrawCalls; statistics.numberOfRenderedPrimitives = nodeDrawStats.numberOfRenderedPrimitives; return statistics; } const drawStats = getDrawCallStatistics(gltf); statistics.buffersByteLength = getBuffersByteLength(gltf); statistics.numberOfImages = defined(gltf.images) ? gltf.images.length : 0; statistics.numberOfExternalRequests = getNumberOfExternalRequests(gltf); statistics.numberOfDrawCalls = drawStats.numberOfDrawCalls; statistics.numberOfRenderedPrimitives = drawStats.numberOfRenderedPrimitives; statistics.numberOfNodes = defined(gltf.nodes) ? gltf.nodes.length : 0; statistics.numberOfMeshes = defined(gltf.meshes) ? gltf.meshes.length : 0; statistics.numberOfMaterials = defined(gltf.materials) ? gltf.materials.length : 0; statistics.numberOfAnimations = defined(gltf.animations) ? gltf.animations.length : 0; return statistics; } function getBuffersByteLength(gltf) { let byteLength = 0; ForEach.buffer(gltf, function (buffer) { byteLength += buffer.byteLength; }); return byteLength; } function getNumberOfExternalRequests(gltf) { let count = 0; ForEach.buffer(gltf, function (buffer) { if (defined(buffer.uri) && !isDataUri(buffer.uri)) { count++; } }); ForEach.image(gltf, function (image) { if (defined(image.uri) && !isDataUri(image.uri)) { count++; } }); ForEach.shader(gltf, function (shader) { if (defined(shader.uri) && !isDataUri(shader.uri)) { count++; } }); return count; } function getNumberOfRenderedPrimitives(gltf, primitive) { let count = 0; if (defined(primitive.indices)) { count = gltf.accessors[primitive.indices].count; } else if (defined(primitive.attributes.POSITION)) { count = gltf.accessors[primitive.attributes.POSITION].count; } switch (primitive.mode) { case WebGLConstants.POINTS: return count; case WebGLConstants.LINES: return count / 2; case WebGLConstants.LINE_LOOP: return count; case WebGLConstants.LINE_STRIP: return Math.max(count - 1, 0); case WebGLConstants.TRIANGLES: return count / 3; case WebGLConstants.TRIANGLE_STRIP: case WebGLConstants.TRIANGLE_FAN: return Math.max(count - 2, 0); default: // TRIANGLES return count / 3; } } function getDrawCallStatisticsForNode(gltf, nodeId) { let numberOfDrawCalls = 0; let numberOfRenderedPrimitives = 0; ForEach.nodeInTree(gltf, [nodeId], function (node) { const mesh = gltf.meshes[node.mesh]; if (defined(mesh)) { ForEach.meshPrimitive(mesh, function (primitive) { numberOfDrawCalls++; numberOfRenderedPrimitives += getNumberOfRenderedPrimitives( gltf, primitive, ); }); } }); return { numberOfDrawCalls: numberOfDrawCalls, numberOfRenderedPrimitives: numberOfRenderedPrimitives, }; } function getDrawCallStatistics(gltf) { let numberOfDrawCalls = 0; let numberOfRenderedPrimitives = 0; ForEach.mesh(gltf, function (mesh) { ForEach.meshPrimitive(mesh, function (primitive) { numberOfDrawCalls++; numberOfRenderedPrimitives += getNumberOfRenderedPrimitives( gltf, primitive, ); }); }); return { numberOfDrawCalls: numberOfDrawCalls, numberOfRenderedPrimitives: numberOfRenderedPrimitives, }; } /** * Contains statistics for a glTF asset. * * @property {number} buffersByteLength The total byte length of all buffers. * @property {number} numberOfImages The number of images in the asset. * @property {number} numberOfExternalRequests The number of external requests required to fetch the asset data. * @property {number} numberOfDrawCalls The number of draw calls required to render the asset. * @property {number} numberOfRenderedPrimitives The total number of rendered primitives in the asset (e.g. triangles). * @property {number} numberOfNodes The total number of nodes in the asset. * @property {number} numberOfMeshes The total number of meshes in the asset. * @property {number} numberOfMaterials The total number of materials in the asset. * @property {number} numberOfAnimations The total number of animations in the asset. * * @constructor * * @see getStatistics */ function Statistics() { this.buffersByteLength = 0; this.numberOfImages = 0; this.numberOfExternalRequests = 0; this.numberOfDrawCalls = 0; this.numberOfRenderedPrimitives = 0; this.numberOfNodes = 0; this.numberOfMeshes = 0; this.numberOfMaterials = 0; this.numberOfAnimations = 0; } /** * Creates a string listing the statistics along with their descriptions. * * @returns {string} A string describing the statistics for the glTF asset. */ Statistics.prototype.toString = function () { return ( `Total byte length of all buffers: ${this.buffersByteLength} bytes` + `\nImages: ${this.numberOfImages}\nDraw calls: ${this.numberOfDrawCalls}\nRendered primitives (e.g., triangles): ${this.numberOfRenderedPrimitives}\nNodes: ${this.numberOfNodes}\nMeshes: ${this.numberOfMeshes}\nMaterials: ${this.numberOfMaterials}\nAnimations: ${this.numberOfAnimations}\nExternal requests (not data uris): ${this.numberOfExternalRequests}` ); };