1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198 |
- 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 defer from "../Core/defer.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 "./GltfPipeline/addDefaults.js";
- import ForEach from "./GltfPipeline/ForEach.js";
- import getAccessorByteStride from "./GltfPipeline/getAccessorByteStride.js";
- import numberOfComponentsForType from "./GltfPipeline/numberOfComponentsForType.js";
- import parseGlb from "./GltfPipeline/parseGlb.js";
- import updateVersion from "./GltfPipeline/updateVersion.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";
- const boundingSphereCartesian3Scratch = new Cartesian3();
- const 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);
- let 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."
- );
- }
- });
- const gltfNodes = gltf.nodes;
- const gltfMeshes = gltf.meshes;
- const gltfNode = gltfNodes[0];
- const 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."
- );
- }
- const gltfPrimitives = gltfMeshes[0].primitives;
- if (gltfPrimitives.length !== 1) {
- throw new RuntimeError(
- "Only one primitive per mesh is supported when using b3dm for classification."
- );
- }
- const gltfPositionAttribute = gltfPrimitives[0].attributes.POSITION;
- if (!defined(gltfPositionAttribute)) {
- throw new RuntimeError("The mesh must have a position attribute.");
- }
- const 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
- * const 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 = 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
- * const 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');
- const modelMatrix = this.modelMatrix;
- const nonUniformScale = Matrix4.getScale(
- modelMatrix,
- boundingSphereCartesian3Scratch
- );
- const 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) {
- const gltf = model.gltf;
- const loadResources = model._loadResources;
- ForEach.buffer(gltf, function (buffer, id) {
- loadResources.buffers[id] = buffer.extras._pipeline.source;
- });
- }
- function parseBufferViews(model) {
- const bufferViews = model.gltf.bufferViews;
- const 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);
- }
- });
- const indexBuffersToCreate = model._loadResources.indexBuffersToCreate;
- const 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) {
- const bufferViewId = accessor.bufferView;
- const 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) {
- const loadResources = model._loadResources;
- const bufferViews = model.gltf.bufferViews;
- const bufferView = bufferViews[bufferViewId];
- const vertexBuffer = loadResources.getBuffer(bufferView);
- model._buffers[bufferViewId] = vertexBuffer;
- model._geometryByteLength += vertexBuffer.byteLength;
- }
- function createIndexBuffer(bufferViewId, componentType, model) {
- const loadResources = model._loadResources;
- const bufferViews = model.gltf.bufferViews;
- const bufferView = bufferViews[bufferViewId];
- const indexBuffer = {
- typedArray: loadResources.getBuffer(bufferView),
- indexDatatype: componentType,
- };
- model._buffers[bufferViewId] = indexBuffer;
- model._geometryByteLength += indexBuffer.typedArray.byteLength;
- }
- function createBuffers(model) {
- const loadResources = model._loadResources;
- if (loadResources.pendingBufferLoads !== 0) {
- return;
- }
- const vertexBuffersToCreate = loadResources.vertexBuffersToCreate;
- const indexBuffersToCreate = loadResources.indexBuffersToCreate;
- while (vertexBuffersToCreate.length > 0) {
- createVertexBuffer(vertexBuffersToCreate.dequeue(), model);
- }
- while (indexBuffersToCreate.length > 0) {
- const i = indexBuffersToCreate.dequeue();
- createIndexBuffer(i.id, i.componentType, model);
- }
- }
- function modifyShaderForQuantizedAttributes(shader, model) {
- const primitive = model.gltf.meshes[0].primitives[0];
- const 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) {
- const gltf = model.gltf;
- const positionName = ModelUtility.getAttributeOrUniformBySemantic(
- gltf,
- "POSITION"
- );
- const batchIdName = ModelUtility.getAttributeOrUniformBySemantic(
- gltf,
- "_BATCHID"
- );
- const attributeLocations = {};
- attributeLocations[positionName] = 0;
- attributeLocations[batchIdName] = 1;
- const modelViewProjectionName = ModelUtility.getAttributeOrUniformBySemantic(
- gltf,
- "MODELVIEWPROJECTION"
- );
- let uniformDecl;
- let toClip;
- if (!defined(modelViewProjectionName)) {
- const projectionName = ModelUtility.getAttributeOrUniformBySemantic(
- gltf,
- "PROJECTION"
- );
- let 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)`;
- }
- const computePosition = ` vec4 positionInClipCoords = ${toClip};\n`;
- let vs =
- `attribute vec3 ${positionName};\n` +
- `attribute float ${batchIdName};\n${uniformDecl}void main() {\n${computePosition} gl_Position = czm_depthClamp(positionInClipCoords);\n` +
- `}\n`;
- const 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);
- }
- const drawVS = modifyShader(vs, model._vertexShaderLoaded);
- const drawFS = modifyShader(fs, model._classificationShaderLoaded);
- model._shaderProgram = {
- vertexShaderSource: drawVS,
- fragmentShaderSource: drawFS,
- attributeLocations: attributeLocations,
- };
- }
- function getAttributeLocations() {
- return {
- POSITION: 0,
- _BATCHID: 1,
- };
- }
- function createVertexArray(model) {
- const loadResources = model._loadResources;
- if (!loadResources.finishedBuffersCreation() || defined(model._vertexArray)) {
- return;
- }
- const rendererBuffers = model._buffers;
- const gltf = model.gltf;
- const accessors = gltf.accessors;
- const meshes = gltf.meshes;
- const primitives = meshes[0].primitives;
- const primitive = primitives[0];
- const attributeLocations = getAttributeLocations();
- const 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.
- const attributeLocation = attributeLocations[attributeName];
- if (defined(attributeLocation)) {
- const 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),
- };
- }
- });
- let indexBuffer;
- if (defined(primitive.indices)) {
- const accessor = accessors[primitive.indices];
- indexBuffer = rendererBuffers[accessor.bufferView];
- }
- model._vertexArray = {
- attributes: attributes,
- indexBuffer: indexBuffer,
- };
- }
- const 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;
- }
- const 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) {
- const batchTable = model._batchTable;
- let uniformMap = model._uniformMap;
- const vertexArray = model._vertexArray;
- const gltf = model.gltf;
- const accessors = gltf.accessors;
- const gltfMeshes = gltf.meshes;
- const primitive = gltfMeshes[0].primitives[0];
- const ix = accessors[primitive.indices];
- const positionAccessor = primitive.attributes.POSITION;
- const minMax = ModelUtility.getAccessorMinMax(gltf, positionAccessor);
- const boundingSphere = BoundingSphere.fromCornerPoints(
- Cartesian3.fromArray(minMax.min),
- Cartesian3.fromArray(minMax.max)
- );
- let offset;
- let 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 {
- const 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) {
- const quantizedUniformMap = createUniformsForQuantizedAttributes(
- model,
- primitive
- );
- uniformMap = combine(uniformMap, quantizedUniformMap);
- }
- let attribute = vertexArray.attributes.POSITION;
- let componentDatatype = attribute.componentDatatype;
- let typedArray = attribute.vertexBuffer;
- let byteOffset = typedArray.byteOffset;
- let bufferLength =
- typedArray.byteLength / ComponentDatatype.getSizeInBytes(componentDatatype);
- let 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);
- let vertexBatchIds = ComponentDatatype.createArrayBufferView(
- componentDatatype,
- typedArray.buffer,
- byteOffset,
- bufferLength
- );
- const buffer = vertexArray.indexBuffer.typedArray;
- let 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);
- const batchIds = [];
- const indexCounts = [];
- const indexOffsets = [];
- const batchedIndices = [];
- let currentId = vertexBatchIds[indices[0]];
- batchIds.push(currentId);
- indexOffsets.push(0);
- let batchId;
- let indexOffset;
- let indexCount;
- const indicesLength = indices.length;
- for (let 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,
- })
- );
- const shader = model._shaderProgram;
- const vertexShaderSource = shader.vertexShaderSource;
- const fragmentShaderSource = shader.fragmentShaderSource;
- const attributeLocations = shader.attributeLocations;
- const 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) {
- const loadResources = model._loadResources;
- if (!loadResources.finished()) {
- return;
- }
- if (defined(model._primitive)) {
- return;
- }
- const gltf = model.gltf;
- const nodes = gltf.nodes;
- const gltfNode = nodes[0];
- model._nodeMatrix = ModelUtility.getTransform(gltfNode, model._nodeMatrix);
- createPrimitive(model);
- }
- function createResources(model, frameState) {
- const 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
- }
- ///////////////////////////////////////////////////////////////////////////
- const scratchComputedTranslation = new Cartesian4();
- const scratchComputedMatrixIn2D = new Matrix4();
- function updateNodeModelMatrix(
- model,
- modelTransformChanged,
- justLoaded,
- projection
- ) {
- let computedModelMatrix = model._computedModelMatrix;
- if (model._mode !== SceneMode.SCENE3D && !model._ignoreCommands) {
- const translation = Matrix4.getColumn(
- computedModelMatrix,
- 3,
- scratchComputedTranslation
- );
- if (!Cartesian4.equals(translation, Cartesian4.UNIT_W)) {
- computedModelMatrix = Transforms.basisTo2D(
- projection,
- computedModelMatrix,
- scratchComputedMatrixIn2D
- );
- model._rtcCenter = model._rtcCenter3D;
- } else {
- const center = model.boundingSphere.center;
- const 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;
- }
- }
- }
- const 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;
- }
- const supportsWebP = FeatureDetection.supportsWebP();
- if (this._state === ModelState.NEEDS_LOAD && defined(this.gltf)) {
- this._state = ModelState.LOADING;
- if (this._state !== ModelState.FAILED) {
- const extensions = this.gltf.extensions;
- if (defined(extensions) && defined(extensions.CESIUM_RTC)) {
- const center = Cartesian3.fromArray(extensions.CESIUM_RTC.center);
- if (!Cartesian3.equals(center, Cartesian3.ZERO)) {
- this._rtcCenter3D = center;
- const projection = frameState.mapProjection;
- const ellipsoid = projection.ellipsoid;
- const cartographic = ellipsoid.cartesianToCartographic(
- this._rtcCenter3D
- );
- const 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);
- }
- }
- const loadResources = this._loadResources;
- let 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.
- }
- }
- const show = this.show;
- if ((show && this._state === ModelState.LOADED) || justLoaded) {
- this._dirty = false;
- const modelMatrix = this.modelMatrix;
- const modeChanged = frameState.mode !== this._mode;
- this._mode = frameState.mode;
- // ClassificationModel's model matrix needs to be updated
- const modelTransformChanged =
- !Matrix4.equals(this._modelMatrix, modelMatrix) || modeChanged;
- if (modelTransformChanged || justLoaded) {
- Matrix4.clone(modelMatrix, this._modelMatrix);
- const 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.
- const 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;
|