123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215 |
- import arraySlice from "../Core/arraySlice.js";
- import BoundingSphere from "../Core/BoundingSphere.js";
- import Cartesian3 from "../Core/Cartesian3.js";
- import Cartesian4 from "../Core/Cartesian4.js";
- import Color from "../Core/Color.js";
- import combine from "../Core/combine.js";
- import ComponentDatatype from "../Core/ComponentDatatype.js";
- import defaultValue from "../Core/defaultValue.js";
- import defined from "../Core/defined.js";
- import destroyObject from "../Core/destroyObject.js";
- import DeveloperError from "../Core/DeveloperError.js";
- import FeatureDetection from "../Core/FeatureDetection.js";
- import IndexDatatype from "../Core/IndexDatatype.js";
- import Matrix4 from "../Core/Matrix4.js";
- import PrimitiveType from "../Core/PrimitiveType.js";
- import RuntimeError from "../Core/RuntimeError.js";
- import Transforms from "../Core/Transforms.js";
- import WebGLConstants from "../Core/WebGLConstants.js";
- import addDefaults from "../ThirdParty/GltfPipeline/addDefaults.js";
- import ForEach from "../ThirdParty/GltfPipeline/ForEach.js";
- import getAccessorByteStride from "../ThirdParty/GltfPipeline/getAccessorByteStride.js";
- import numberOfComponentsForType from "../ThirdParty/GltfPipeline/numberOfComponentsForType.js";
- import parseGlb from "../ThirdParty/GltfPipeline/parseGlb.js";
- import updateVersion from "../ThirdParty/GltfPipeline/updateVersion.js";
- import when from "../ThirdParty/when.js";
- import Axis from "./Axis.js";
- import ModelLoadResources from "./ModelLoadResources.js";
- import ModelUtility from "./ModelUtility.js";
- import processModelMaterialsCommon from "./processModelMaterialsCommon.js";
- import processPbrMaterials from "./processPbrMaterials.js";
- import SceneMode from "./SceneMode.js";
- import Vector3DTileBatch from "./Vector3DTileBatch.js";
- import Vector3DTilePrimitive from "./Vector3DTilePrimitive.js";
- var boundingSphereCartesian3Scratch = new Cartesian3();
- var ModelState = ModelUtility.ModelState;
- ///////////////////////////////////////////////////////////////////////////
- /**
- * A 3D model for classifying other 3D assets based on glTF, the runtime 3D asset format.
- * This is a special case when a model of a 3D tileset becomes a classifier when setting {@link Cesium3DTileset#classificationType}.
- *
- * @alias ClassificationModel
- * @constructor
- *
- * @private
- *
- * @param {Object} options Object with the following properties:
- * @param {ArrayBuffer|Uint8Array} options.gltf A binary glTF buffer.
- * @param {Boolean} [options.show=true] Determines if the model primitive will be shown.
- * @param {Matrix4} [options.modelMatrix=Matrix4.IDENTITY] The 4x4 transformation matrix that transforms the model from model to world coordinates.
- * @param {Boolean} [options.debugShowBoundingVolume=false] For debugging only. Draws the bounding sphere for each draw command in the model.
- * @param {Boolean} [options.debugWireframe=false] For debugging only. Draws the model in wireframe.
- * @param {ClassificationType} [options.classificationType] What this model will classify.
- *
- * @exception {RuntimeError} Only binary glTF is supported.
- * @exception {RuntimeError} Buffer data must be embedded in the binary glTF.
- * @exception {RuntimeError} Only one node is supported for classification and it must have a mesh.
- * @exception {RuntimeError} Only one mesh is supported when using b3dm for classification.
- * @exception {RuntimeError} Only one primitive per mesh is supported when using b3dm for classification.
- * @exception {RuntimeError} The mesh must have a position attribute.
- * @exception {RuntimeError} The mesh must have a batch id attribute.
- */
- function ClassificationModel(options) {
- options = defaultValue(options, defaultValue.EMPTY_OBJECT);
- var gltf = options.gltf;
- if (gltf instanceof ArrayBuffer) {
- gltf = new Uint8Array(gltf);
- }
- if (gltf instanceof Uint8Array) {
- // Parse and update binary glTF
- gltf = parseGlb(gltf);
- updateVersion(gltf);
- addDefaults(gltf);
- processModelMaterialsCommon(gltf);
- processPbrMaterials(gltf);
- } else {
- throw new RuntimeError("Only binary glTF is supported as a classifier.");
- }
- ForEach.buffer(gltf, function (buffer) {
- if (!defined(buffer.extras._pipeline.source)) {
- throw new RuntimeError(
- "Buffer data must be embedded in the binary gltf."
- );
- }
- });
- var gltfNodes = gltf.nodes;
- var gltfMeshes = gltf.meshes;
- var gltfNode = gltfNodes[0];
- var meshId = gltfNode.mesh;
- if (gltfNodes.length !== 1 || !defined(meshId)) {
- throw new RuntimeError(
- "Only one node is supported for classification and it must have a mesh."
- );
- }
- if (gltfMeshes.length !== 1) {
- throw new RuntimeError(
- "Only one mesh is supported when using b3dm for classification."
- );
- }
- var gltfPrimitives = gltfMeshes[0].primitives;
- if (gltfPrimitives.length !== 1) {
- throw new RuntimeError(
- "Only one primitive per mesh is supported when using b3dm for classification."
- );
- }
- var gltfPositionAttribute = gltfPrimitives[0].attributes.POSITION;
- if (!defined(gltfPositionAttribute)) {
- throw new RuntimeError("The mesh must have a position attribute.");
- }
- var gltfBatchIdAttribute = gltfPrimitives[0].attributes._BATCHID;
- if (!defined(gltfBatchIdAttribute)) {
- throw new RuntimeError("The mesh must have a batch id attribute.");
- }
- this._gltf = gltf;
- /**
- * Determines if the model primitive will be shown.
- *
- * @type {Boolean}
- *
- * @default true
- */
- this.show = defaultValue(options.show, true);
- /**
- * The 4x4 transformation matrix that transforms the model from model to world coordinates.
- * When this is the identity matrix, the model is drawn in world coordinates, i.e., Earth's WGS84 coordinates.
- * Local reference frames can be used by providing a different transformation matrix, like that returned
- * by {@link Transforms.eastNorthUpToFixedFrame}.
- *
- * @type {Matrix4}
- *
- * @default {@link Matrix4.IDENTITY}
- *
- * @example
- * var origin = Cesium.Cartesian3.fromDegrees(-95.0, 40.0, 200000.0);
- * m.modelMatrix = Cesium.Transforms.eastNorthUpToFixedFrame(origin);
- */
- this.modelMatrix = Matrix4.clone(
- defaultValue(options.modelMatrix, Matrix4.IDENTITY)
- );
- this._modelMatrix = Matrix4.clone(this.modelMatrix);
- this._ready = false;
- this._readyPromise = when.defer();
- /**
- * This property is for debugging only; it is not for production use nor is it optimized.
- * <p>
- * Draws the bounding sphere for each draw command in the model. A glTF primitive corresponds
- * to one draw command. A glTF mesh has an array of primitives, often of length one.
- * </p>
- *
- * @type {Boolean}
- *
- * @default false
- */
- this.debugShowBoundingVolume = defaultValue(
- options.debugShowBoundingVolume,
- false
- );
- this._debugShowBoundingVolume = false;
- /**
- * This property is for debugging only; it is not for production use nor is it optimized.
- * <p>
- * Draws the model in wireframe.
- * </p>
- *
- * @type {Boolean}
- *
- * @default false
- */
- this.debugWireframe = defaultValue(options.debugWireframe, false);
- this._debugWireframe = false;
- this._classificationType = options.classificationType;
- // Undocumented options
- this._vertexShaderLoaded = options.vertexShaderLoaded;
- this._classificationShaderLoaded = options.classificationShaderLoaded;
- this._uniformMapLoaded = options.uniformMapLoaded;
- this._pickIdLoaded = options.pickIdLoaded;
- this._ignoreCommands = defaultValue(options.ignoreCommands, false);
- this._upAxis = defaultValue(options.upAxis, Axis.Y);
- this._batchTable = options.batchTable;
- this._computedModelMatrix = new Matrix4(); // Derived from modelMatrix and axis
- this._initialRadius = undefined; // Radius without model's scale property, model-matrix scale, animations, or skins
- this._boundingSphere = undefined;
- this._scaledBoundingSphere = new BoundingSphere();
- this._state = ModelState.NEEDS_LOAD;
- this._loadResources = undefined;
- this._mode = undefined;
- this._dirty = false; // true when the model was transformed this frame
- this._nodeMatrix = new Matrix4();
- this._primitive = undefined;
- this._extensionsUsed = undefined; // Cached used glTF extensions
- this._extensionsRequired = undefined; // Cached required glTF extensions
- this._quantizedUniforms = undefined; // Quantized uniforms for WEB3D_quantized_attributes
- this._buffers = {};
- this._vertexArray = undefined;
- this._shaderProgram = undefined;
- this._uniformMap = undefined;
- this._geometryByteLength = 0;
- this._trianglesLength = 0;
- // CESIUM_RTC extension
- this._rtcCenter = undefined; // reference to either 3D or 2D
- this._rtcCenterEye = undefined; // in eye coordinates
- this._rtcCenter3D = undefined; // in world coordinates
- this._rtcCenter2D = undefined; // in projected world coordinates
- }
- Object.defineProperties(ClassificationModel.prototype, {
- /**
- * The object for the glTF JSON, including properties with default values omitted
- * from the JSON provided to this model.
- *
- * @memberof ClassificationModel.prototype
- *
- * @type {Object}
- * @readonly
- *
- * @default undefined
- */
- gltf: {
- get: function () {
- return this._gltf;
- },
- },
- /**
- * The model's bounding sphere in its local coordinate system.
- *
- * @memberof ClassificationModel.prototype
- *
- * @type {BoundingSphere}
- * @readonly
- *
- * @default undefined
- *
- * @exception {DeveloperError} The model is not loaded. Use ClassificationModel.readyPromise or wait for ClassificationModel.ready to be true.
- *
- * @example
- * // Center in WGS84 coordinates
- * var center = Cesium.Matrix4.multiplyByPoint(model.modelMatrix, model.boundingSphere.center, new Cesium.Cartesian3());
- */
- boundingSphere: {
- get: function () {
- //>>includeStart('debug', pragmas.debug);
- if (this._state !== ModelState.LOADED) {
- throw new DeveloperError(
- "The model is not loaded. Use ClassificationModel.readyPromise or wait for ClassificationModel.ready to be true."
- );
- }
- //>>includeEnd('debug');
- var modelMatrix = this.modelMatrix;
- var nonUniformScale = Matrix4.getScale(
- modelMatrix,
- boundingSphereCartesian3Scratch
- );
- var scaledBoundingSphere = this._scaledBoundingSphere;
- scaledBoundingSphere.center = Cartesian3.multiplyComponents(
- this._boundingSphere.center,
- nonUniformScale,
- scaledBoundingSphere.center
- );
- scaledBoundingSphere.radius =
- Cartesian3.maximumComponent(nonUniformScale) * this._initialRadius;
- if (defined(this._rtcCenter)) {
- Cartesian3.add(
- this._rtcCenter,
- scaledBoundingSphere.center,
- scaledBoundingSphere.center
- );
- }
- return scaledBoundingSphere;
- },
- },
- /**
- * When <code>true</code>, this model is ready to render, i.e., the external binary, image,
- * and shader files were downloaded and the WebGL resources were created. This is set to
- * <code>true</code> right before {@link ClassificationModel#readyPromise} is resolved.
- *
- * @memberof ClassificationModel.prototype
- *
- * @type {Boolean}
- * @readonly
- *
- * @default false
- */
- ready: {
- get: function () {
- return this._ready;
- },
- },
- /**
- * Gets the promise that will be resolved when this model is ready to render, i.e., when the external binary, image,
- * and shader files were downloaded and the WebGL resources were created.
- * <p>
- * This promise is resolved at the end of the frame before the first frame the model is rendered in.
- * </p>
- *
- * @memberof ClassificationModel.prototype
- * @type {Promise.<ClassificationModel>}
- * @readonly
- *
- * @see ClassificationModel#ready
- */
- readyPromise: {
- get: function () {
- return this._readyPromise.promise;
- },
- },
- /**
- * Returns true if the model was transformed this frame
- *
- * @memberof ClassificationModel.prototype
- *
- * @type {Boolean}
- * @readonly
- *
- * @private
- */
- dirty: {
- get: function () {
- return this._dirty;
- },
- },
- /**
- * Returns an object with all of the glTF extensions used.
- *
- * @memberof ClassificationModel.prototype
- *
- * @type {Object}
- * @readonly
- */
- extensionsUsed: {
- get: function () {
- if (!defined(this._extensionsUsed)) {
- this._extensionsUsed = ModelUtility.getUsedExtensions(this.gltf);
- }
- return this._extensionsUsed;
- },
- },
- /**
- * Returns an object with all of the glTF extensions required.
- *
- * @memberof ClassificationModel.prototype
- *
- * @type {Object}
- * @readonly
- */
- extensionsRequired: {
- get: function () {
- if (!defined(this._extensionsRequired)) {
- this._extensionsRequired = ModelUtility.getRequiredExtensions(
- this.gltf
- );
- }
- return this._extensionsRequired;
- },
- },
- /**
- * Gets the model's up-axis.
- * By default models are y-up according to the glTF spec, however geo-referenced models will typically be z-up.
- *
- * @memberof ClassificationModel.prototype
- *
- * @type {Number}
- * @default Axis.Y
- * @readonly
- *
- * @private
- */
- upAxis: {
- get: function () {
- return this._upAxis;
- },
- },
- /**
- * Gets the model's triangle count.
- *
- * @private
- */
- trianglesLength: {
- get: function () {
- return this._trianglesLength;
- },
- },
- /**
- * Gets the model's geometry memory in bytes. This includes all vertex and index buffers.
- *
- * @private
- */
- geometryByteLength: {
- get: function () {
- return this._geometryByteLength;
- },
- },
- /**
- * Gets the model's texture memory in bytes.
- *
- * @private
- */
- texturesByteLength: {
- get: function () {
- return 0;
- },
- },
- /**
- * Gets the model's classification type.
- * @memberof ClassificationModel.prototype
- * @type {ClassificationType}
- */
- classificationType: {
- get: function () {
- return this._classificationType;
- },
- },
- });
- ///////////////////////////////////////////////////////////////////////////
- function addBuffersToLoadResources(model) {
- var gltf = model.gltf;
- var loadResources = model._loadResources;
- ForEach.buffer(gltf, function (buffer, id) {
- loadResources.buffers[id] = buffer.extras._pipeline.source;
- });
- }
- function parseBufferViews(model) {
- var bufferViews = model.gltf.bufferViews;
- var vertexBuffersToCreate = model._loadResources.vertexBuffersToCreate;
- // Only ARRAY_BUFFER here. ELEMENT_ARRAY_BUFFER created below.
- ForEach.bufferView(model.gltf, function (bufferView, id) {
- if (bufferView.target === WebGLConstants.ARRAY_BUFFER) {
- vertexBuffersToCreate.enqueue(id);
- }
- });
- var indexBuffersToCreate = model._loadResources.indexBuffersToCreate;
- var indexBufferIds = {};
- // The Cesium Renderer requires knowing the datatype for an index buffer
- // at creation type, which is not part of the glTF bufferview so loop
- // through glTF accessors to create the bufferview's index buffer.
- ForEach.accessor(model.gltf, function (accessor) {
- var bufferViewId = accessor.bufferView;
- var bufferView = bufferViews[bufferViewId];
- if (
- bufferView.target === WebGLConstants.ELEMENT_ARRAY_BUFFER &&
- !defined(indexBufferIds[bufferViewId])
- ) {
- indexBufferIds[bufferViewId] = true;
- indexBuffersToCreate.enqueue({
- id: bufferViewId,
- componentType: accessor.componentType,
- });
- }
- });
- }
- function createVertexBuffer(bufferViewId, model) {
- var loadResources = model._loadResources;
- var bufferViews = model.gltf.bufferViews;
- var bufferView = bufferViews[bufferViewId];
- var vertexBuffer = loadResources.getBuffer(bufferView);
- model._buffers[bufferViewId] = vertexBuffer;
- model._geometryByteLength += vertexBuffer.byteLength;
- }
- function createIndexBuffer(bufferViewId, componentType, model) {
- var loadResources = model._loadResources;
- var bufferViews = model.gltf.bufferViews;
- var bufferView = bufferViews[bufferViewId];
- var indexBuffer = {
- typedArray: loadResources.getBuffer(bufferView),
- indexDatatype: componentType,
- };
- model._buffers[bufferViewId] = indexBuffer;
- model._geometryByteLength += indexBuffer.typedArray.byteLength;
- }
- function createBuffers(model) {
- var loadResources = model._loadResources;
- if (loadResources.pendingBufferLoads !== 0) {
- return;
- }
- var vertexBuffersToCreate = loadResources.vertexBuffersToCreate;
- var indexBuffersToCreate = loadResources.indexBuffersToCreate;
- while (vertexBuffersToCreate.length > 0) {
- createVertexBuffer(vertexBuffersToCreate.dequeue(), model);
- }
- while (indexBuffersToCreate.length > 0) {
- var i = indexBuffersToCreate.dequeue();
- createIndexBuffer(i.id, i.componentType, model);
- }
- }
- function modifyShaderForQuantizedAttributes(shader, model) {
- var primitive = model.gltf.meshes[0].primitives[0];
- var result = ModelUtility.modifyShaderForQuantizedAttributes(
- model.gltf,
- primitive,
- shader
- );
- model._quantizedUniforms = result.uniforms;
- return result.shader;
- }
- function modifyShader(shader, callback) {
- if (defined(callback)) {
- shader = callback(shader);
- }
- return shader;
- }
- function createProgram(model) {
- var gltf = model.gltf;
- var positionName = ModelUtility.getAttributeOrUniformBySemantic(
- gltf,
- "POSITION"
- );
- var batchIdName = ModelUtility.getAttributeOrUniformBySemantic(
- gltf,
- "_BATCHID"
- );
- var attributeLocations = {};
- attributeLocations[positionName] = 0;
- attributeLocations[batchIdName] = 1;
- var modelViewProjectionName = ModelUtility.getAttributeOrUniformBySemantic(
- gltf,
- "MODELVIEWPROJECTION"
- );
- var uniformDecl;
- var toClip;
- if (!defined(modelViewProjectionName)) {
- var projectionName = ModelUtility.getAttributeOrUniformBySemantic(
- gltf,
- "PROJECTION"
- );
- var modelViewName = ModelUtility.getAttributeOrUniformBySemantic(
- gltf,
- "MODELVIEW"
- );
- if (!defined(modelViewName)) {
- modelViewName = ModelUtility.getAttributeOrUniformBySemantic(
- gltf,
- "CESIUM_RTC_MODELVIEW"
- );
- }
- uniformDecl =
- "uniform mat4 " +
- modelViewName +
- ";\n" +
- "uniform mat4 " +
- projectionName +
- ";\n";
- toClip =
- projectionName +
- " * " +
- modelViewName +
- " * vec4(" +
- positionName +
- ", 1.0)";
- } else {
- uniformDecl = "uniform mat4 " + modelViewProjectionName + ";\n";
- toClip = modelViewProjectionName + " * vec4(" + positionName + ", 1.0)";
- }
- var computePosition = " vec4 positionInClipCoords = " + toClip + ";\n";
- var vs =
- "attribute vec3 " +
- positionName +
- ";\n" +
- "attribute float " +
- batchIdName +
- ";\n" +
- uniformDecl +
- "void main() {\n" +
- computePosition +
- " gl_Position = czm_depthClamp(positionInClipCoords);\n" +
- "}\n";
- var fs =
- "#ifdef GL_EXT_frag_depth\n" +
- "#extension GL_EXT_frag_depth : enable\n" +
- "#endif\n" +
- "void main() \n" +
- "{ \n" +
- " gl_FragColor = vec4(1.0); \n" +
- " czm_writeDepthClamp();\n" +
- "}\n";
- if (model.extensionsUsed.WEB3D_quantized_attributes) {
- vs = modifyShaderForQuantizedAttributes(vs, model);
- }
- var drawVS = modifyShader(vs, model._vertexShaderLoaded);
- var drawFS = modifyShader(fs, model._classificationShaderLoaded);
- model._shaderProgram = {
- vertexShaderSource: drawVS,
- fragmentShaderSource: drawFS,
- attributeLocations: attributeLocations,
- };
- }
- function getAttributeLocations() {
- return {
- POSITION: 0,
- _BATCHID: 1,
- };
- }
- function createVertexArray(model) {
- var loadResources = model._loadResources;
- if (!loadResources.finishedBuffersCreation() || defined(model._vertexArray)) {
- return;
- }
- var rendererBuffers = model._buffers;
- var gltf = model.gltf;
- var accessors = gltf.accessors;
- var meshes = gltf.meshes;
- var primitives = meshes[0].primitives;
- var primitive = primitives[0];
- var attributeLocations = getAttributeLocations();
- var attributes = {};
- ForEach.meshPrimitiveAttribute(primitive, function (
- accessorId,
- attributeName
- ) {
- // Skip if the attribute is not used by the material, e.g., because the asset
- // was exported with an attribute that wasn't used and the asset wasn't optimized.
- var attributeLocation = attributeLocations[attributeName];
- if (defined(attributeLocation)) {
- var a = accessors[accessorId];
- attributes[attributeName] = {
- index: attributeLocation,
- vertexBuffer: rendererBuffers[a.bufferView],
- componentsPerAttribute: numberOfComponentsForType(a.type),
- componentDatatype: a.componentType,
- offsetInBytes: a.byteOffset,
- strideInBytes: getAccessorByteStride(gltf, a),
- };
- }
- });
- var indexBuffer;
- if (defined(primitive.indices)) {
- var accessor = accessors[primitive.indices];
- indexBuffer = rendererBuffers[accessor.bufferView];
- }
- model._vertexArray = {
- attributes: attributes,
- indexBuffer: indexBuffer,
- };
- }
- var gltfSemanticUniforms = {
- PROJECTION: function (uniformState, model) {
- return ModelUtility.getGltfSemanticUniforms().PROJECTION(
- uniformState,
- model
- );
- },
- MODELVIEW: function (uniformState, model) {
- return ModelUtility.getGltfSemanticUniforms().MODELVIEW(
- uniformState,
- model
- );
- },
- CESIUM_RTC_MODELVIEW: function (uniformState, model) {
- return ModelUtility.getGltfSemanticUniforms().CESIUM_RTC_MODELVIEW(
- uniformState,
- model
- );
- },
- MODELVIEWPROJECTION: function (uniformState, model) {
- return ModelUtility.getGltfSemanticUniforms().MODELVIEWPROJECTION(
- uniformState,
- model
- );
- },
- };
- function createUniformMap(model, context) {
- if (defined(model._uniformMap)) {
- return;
- }
- var uniformMap = {};
- ForEach.technique(model.gltf, function (technique) {
- ForEach.techniqueUniform(technique, function (uniform, uniformName) {
- if (
- !defined(uniform.semantic) ||
- !defined(gltfSemanticUniforms[uniform.semantic])
- ) {
- return;
- }
- uniformMap[uniformName] = gltfSemanticUniforms[uniform.semantic](
- context.uniformState,
- model
- );
- });
- });
- model._uniformMap = uniformMap;
- }
- function createUniformsForQuantizedAttributes(model, primitive) {
- return ModelUtility.createUniformsForQuantizedAttributes(
- model.gltf,
- primitive,
- model._quantizedUniforms
- );
- }
- function triangleCountFromPrimitiveIndices(primitive, indicesCount) {
- switch (primitive.mode) {
- case PrimitiveType.TRIANGLES:
- return indicesCount / 3;
- case PrimitiveType.TRIANGLE_STRIP:
- case PrimitiveType.TRIANGLE_FAN:
- return Math.max(indicesCount - 2, 0);
- default:
- return 0;
- }
- }
- function createPrimitive(model) {
- var batchTable = model._batchTable;
- var uniformMap = model._uniformMap;
- var vertexArray = model._vertexArray;
- var gltf = model.gltf;
- var accessors = gltf.accessors;
- var gltfMeshes = gltf.meshes;
- var primitive = gltfMeshes[0].primitives[0];
- var ix = accessors[primitive.indices];
- var positionAccessor = primitive.attributes.POSITION;
- var minMax = ModelUtility.getAccessorMinMax(gltf, positionAccessor);
- var boundingSphere = BoundingSphere.fromCornerPoints(
- Cartesian3.fromArray(minMax.min),
- Cartesian3.fromArray(minMax.max)
- );
- var offset;
- var count;
- if (defined(ix)) {
- count = ix.count;
- offset = ix.byteOffset / IndexDatatype.getSizeInBytes(ix.componentType); // glTF has offset in bytes. Cesium has offsets in indices
- } else {
- var positions = accessors[primitive.attributes.POSITION];
- count = positions.count;
- offset = 0;
- }
- // Update model triangle count using number of indices
- model._trianglesLength += triangleCountFromPrimitiveIndices(primitive, count);
- // Allow callback to modify the uniformMap
- if (defined(model._uniformMapLoaded)) {
- uniformMap = model._uniformMapLoaded(uniformMap);
- }
- // Add uniforms for decoding quantized attributes if used
- if (model.extensionsUsed.WEB3D_quantized_attributes) {
- var quantizedUniformMap = createUniformsForQuantizedAttributes(
- model,
- primitive
- );
- uniformMap = combine(uniformMap, quantizedUniformMap);
- }
- var attribute = vertexArray.attributes.POSITION;
- var componentDatatype = attribute.componentDatatype;
- var typedArray = attribute.vertexBuffer;
- var byteOffset = typedArray.byteOffset;
- var bufferLength =
- typedArray.byteLength / ComponentDatatype.getSizeInBytes(componentDatatype);
- var positionsBuffer = ComponentDatatype.createArrayBufferView(
- componentDatatype,
- typedArray.buffer,
- byteOffset,
- bufferLength
- );
- attribute = vertexArray.attributes._BATCHID;
- componentDatatype = attribute.componentDatatype;
- typedArray = attribute.vertexBuffer;
- byteOffset = typedArray.byteOffset;
- bufferLength =
- typedArray.byteLength / ComponentDatatype.getSizeInBytes(componentDatatype);
- var vertexBatchIds = ComponentDatatype.createArrayBufferView(
- componentDatatype,
- typedArray.buffer,
- byteOffset,
- bufferLength
- );
- var buffer = vertexArray.indexBuffer.typedArray;
- var indices;
- if (vertexArray.indexBuffer.indexDatatype === IndexDatatype.UNSIGNED_SHORT) {
- indices = new Uint16Array(
- buffer.buffer,
- buffer.byteOffset,
- buffer.byteLength / Uint16Array.BYTES_PER_ELEMENT
- );
- } else {
- indices = new Uint32Array(
- buffer.buffer,
- buffer.byteOffset,
- buffer.byteLength / Uint32Array.BYTES_PER_ELEMENT
- );
- }
- positionsBuffer = arraySlice(positionsBuffer);
- vertexBatchIds = arraySlice(vertexBatchIds);
- indices = arraySlice(indices, offset, offset + count);
- var batchIds = [];
- var indexCounts = [];
- var indexOffsets = [];
- var batchedIndices = [];
- var currentId = vertexBatchIds[indices[0]];
- batchIds.push(currentId);
- indexOffsets.push(0);
- var batchId;
- var indexOffset;
- var indexCount;
- var indicesLength = indices.length;
- for (var j = 1; j < indicesLength; ++j) {
- batchId = vertexBatchIds[indices[j]];
- if (batchId !== currentId) {
- indexOffset = indexOffsets[indexOffsets.length - 1];
- indexCount = j - indexOffset;
- batchIds.push(batchId);
- indexCounts.push(indexCount);
- indexOffsets.push(j);
- batchedIndices.push(
- new Vector3DTileBatch({
- offset: indexOffset,
- count: indexCount,
- batchIds: [currentId],
- color: Color.WHITE,
- })
- );
- currentId = batchId;
- }
- }
- indexOffset = indexOffsets[indexOffsets.length - 1];
- indexCount = indicesLength - indexOffset;
- indexCounts.push(indexCount);
- batchedIndices.push(
- new Vector3DTileBatch({
- offset: indexOffset,
- count: indexCount,
- batchIds: [currentId],
- color: Color.WHITE,
- })
- );
- var shader = model._shaderProgram;
- var vertexShaderSource = shader.vertexShaderSource;
- var fragmentShaderSource = shader.fragmentShaderSource;
- var attributeLocations = shader.attributeLocations;
- var pickId = defined(model._pickIdLoaded) ? model._pickIdLoaded() : undefined;
- model._primitive = new Vector3DTilePrimitive({
- classificationType: model._classificationType,
- positions: positionsBuffer,
- indices: indices,
- indexOffsets: indexOffsets,
- indexCounts: indexCounts,
- batchIds: batchIds,
- vertexBatchIds: vertexBatchIds,
- batchedIndices: batchedIndices,
- batchTable: batchTable,
- boundingVolume: new BoundingSphere(), // updated in update()
- _vertexShaderSource: vertexShaderSource,
- _fragmentShaderSource: fragmentShaderSource,
- _attributeLocations: attributeLocations,
- _uniformMap: uniformMap,
- _pickId: pickId,
- _modelMatrix: new Matrix4(), // updated in update()
- _boundingSphere: boundingSphere, // used to update boundingVolume
- });
- // Release CPU resources
- model._buffers = undefined;
- model._vertexArray = undefined;
- model._shaderProgram = undefined;
- model._uniformMap = undefined;
- }
- function createRuntimeNodes(model) {
- var loadResources = model._loadResources;
- if (!loadResources.finished()) {
- return;
- }
- if (defined(model._primitive)) {
- return;
- }
- var gltf = model.gltf;
- var nodes = gltf.nodes;
- var gltfNode = nodes[0];
- model._nodeMatrix = ModelUtility.getTransform(gltfNode, model._nodeMatrix);
- createPrimitive(model);
- }
- function createResources(model, frameState) {
- var context = frameState.context;
- ModelUtility.checkSupportedGlExtensions(model.gltf.glExtensionsUsed, context);
- createBuffers(model); // using glTF bufferViews
- createProgram(model);
- createVertexArray(model); // using glTF meshes
- createUniformMap(model, context); // using glTF materials/techniques
- createRuntimeNodes(model); // using glTF scene
- }
- ///////////////////////////////////////////////////////////////////////////
- var scratchComputedTranslation = new Cartesian4();
- var scratchComputedMatrixIn2D = new Matrix4();
- function updateNodeModelMatrix(
- model,
- modelTransformChanged,
- justLoaded,
- projection
- ) {
- var computedModelMatrix = model._computedModelMatrix;
- if (model._mode !== SceneMode.SCENE3D && !model._ignoreCommands) {
- var translation = Matrix4.getColumn(
- computedModelMatrix,
- 3,
- scratchComputedTranslation
- );
- if (!Cartesian4.equals(translation, Cartesian4.UNIT_W)) {
- computedModelMatrix = Transforms.basisTo2D(
- projection,
- computedModelMatrix,
- scratchComputedMatrixIn2D
- );
- model._rtcCenter = model._rtcCenter3D;
- } else {
- var center = model.boundingSphere.center;
- var to2D = Transforms.wgs84To2DModelMatrix(
- projection,
- center,
- scratchComputedMatrixIn2D
- );
- computedModelMatrix = Matrix4.multiply(
- to2D,
- computedModelMatrix,
- scratchComputedMatrixIn2D
- );
- if (defined(model._rtcCenter)) {
- Matrix4.setTranslation(
- computedModelMatrix,
- Cartesian4.UNIT_W,
- computedModelMatrix
- );
- model._rtcCenter = model._rtcCenter2D;
- }
- }
- }
- var primitive = model._primitive;
- if (modelTransformChanged || justLoaded) {
- Matrix4.multiplyTransformation(
- computedModelMatrix,
- model._nodeMatrix,
- primitive._modelMatrix
- );
- BoundingSphere.transform(
- primitive._boundingSphere,
- primitive._modelMatrix,
- primitive._boundingVolume
- );
- if (defined(model._rtcCenter)) {
- Cartesian3.add(
- model._rtcCenter,
- primitive._boundingVolume.center,
- primitive._boundingVolume.center
- );
- }
- }
- }
- ///////////////////////////////////////////////////////////////////////////
- ClassificationModel.prototype.updateCommands = function (batchId, color) {
- this._primitive.updateCommands(batchId, color);
- };
- ClassificationModel.prototype.update = function (frameState) {
- if (frameState.mode === SceneMode.MORPHING) {
- return;
- }
- if (!FeatureDetection.supportsWebP.initialized) {
- FeatureDetection.supportsWebP.initialize();
- return;
- }
- var supportsWebP = FeatureDetection.supportsWebP();
- if (this._state === ModelState.NEEDS_LOAD && defined(this.gltf)) {
- this._state = ModelState.LOADING;
- if (this._state !== ModelState.FAILED) {
- var extensions = this.gltf.extensions;
- if (defined(extensions) && defined(extensions.CESIUM_RTC)) {
- var center = Cartesian3.fromArray(extensions.CESIUM_RTC.center);
- if (!Cartesian3.equals(center, Cartesian3.ZERO)) {
- this._rtcCenter3D = center;
- var projection = frameState.mapProjection;
- var ellipsoid = projection.ellipsoid;
- var cartographic = ellipsoid.cartesianToCartographic(
- this._rtcCenter3D
- );
- var projectedCart = projection.project(cartographic);
- Cartesian3.fromElements(
- projectedCart.z,
- projectedCart.x,
- projectedCart.y,
- projectedCart
- );
- this._rtcCenter2D = projectedCart;
- this._rtcCenterEye = new Cartesian3();
- this._rtcCenter = this._rtcCenter3D;
- }
- }
- this._loadResources = new ModelLoadResources();
- ModelUtility.parseBuffers(this);
- }
- }
- var loadResources = this._loadResources;
- var justLoaded = false;
- if (this._state === ModelState.LOADING) {
- // Transition from LOADING -> LOADED once resources are downloaded and created.
- // Textures may continue to stream in while in the LOADED state.
- if (loadResources.pendingBufferLoads === 0) {
- ModelUtility.checkSupportedExtensions(
- this.extensionsRequired,
- supportsWebP
- );
- addBuffersToLoadResources(this);
- parseBufferViews(this);
- this._boundingSphere = ModelUtility.computeBoundingSphere(this);
- this._initialRadius = this._boundingSphere.radius;
- createResources(this, frameState);
- }
- if (loadResources.finished()) {
- this._state = ModelState.LOADED;
- justLoaded = true;
- }
- }
- if (defined(loadResources) && this._state === ModelState.LOADED) {
- if (!justLoaded) {
- createResources(this, frameState);
- }
- if (loadResources.finished()) {
- this._loadResources = undefined; // Clear CPU memory since WebGL resources were created.
- }
- }
- var show = this.show;
- if ((show && this._state === ModelState.LOADED) || justLoaded) {
- this._dirty = false;
- var modelMatrix = this.modelMatrix;
- var modeChanged = frameState.mode !== this._mode;
- this._mode = frameState.mode;
- // ClassificationModel's model matrix needs to be updated
- var modelTransformChanged =
- !Matrix4.equals(this._modelMatrix, modelMatrix) || modeChanged;
- if (modelTransformChanged || justLoaded) {
- Matrix4.clone(modelMatrix, this._modelMatrix);
- var computedModelMatrix = this._computedModelMatrix;
- Matrix4.clone(modelMatrix, computedModelMatrix);
- if (this._upAxis === Axis.Y) {
- Matrix4.multiplyTransformation(
- computedModelMatrix,
- Axis.Y_UP_TO_Z_UP,
- computedModelMatrix
- );
- } else if (this._upAxis === Axis.X) {
- Matrix4.multiplyTransformation(
- computedModelMatrix,
- Axis.X_UP_TO_Z_UP,
- computedModelMatrix
- );
- }
- }
- // Update modelMatrix throughout the graph as needed
- if (modelTransformChanged || justLoaded) {
- updateNodeModelMatrix(
- this,
- modelTransformChanged,
- justLoaded,
- frameState.mapProjection
- );
- this._dirty = true;
- }
- }
- if (justLoaded) {
- // Called after modelMatrix update.
- var model = this;
- frameState.afterRender.push(function () {
- model._ready = true;
- model._readyPromise.resolve(model);
- });
- return;
- }
- if (show && !this._ignoreCommands) {
- this._primitive.debugShowBoundingVolume = this.debugShowBoundingVolume;
- this._primitive.debugWireframe = this.debugWireframe;
- this._primitive.update(frameState);
- }
- };
- ClassificationModel.prototype.isDestroyed = function () {
- return false;
- };
- ClassificationModel.prototype.destroy = function () {
- this._primitive = this._primitive && this._primitive.destroy();
- return destroyObject(this);
- };
- export default ClassificationModel;
|