1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036 |
- 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 defineProperties from '../Core/defineProperties.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
- }
- 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_depthClampFarPlane(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_writeDepthClampedToFarPlane();\n' +
- '}\n';
- if (model.extensionsUsed.WEB3D_quantized_attributes) {
- vs = modifyShaderForQuantizedAttributes(vs, model);
- }
- var drawVS = modifyShader(vs, model._vertexShaderLoaded);
- var drawFS = modifyShader(fs, model._classificationShaderLoaded);
- drawVS = ModelUtility.modifyVertexShaderForLogDepth(drawVS, toClip);
- drawFS = ModelUtility.modifyFragmentShaderForLogDepth(drawFS);
- 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;
|