1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114 |
- import BoundingSphere from '../Core/BoundingSphere.js';
- import Cartesian2 from '../Core/Cartesian2.js';
- import Cartesian3 from '../Core/Cartesian3.js';
- import Cartesian4 from '../Core/Cartesian4.js';
- import clone from '../Core/clone.js';
- import defined from '../Core/defined.js';
- import defineProperties from '../Core/defineProperties.js';
- import Matrix2 from '../Core/Matrix2.js';
- import Matrix3 from '../Core/Matrix3.js';
- import Matrix4 from '../Core/Matrix4.js';
- import Quaternion from '../Core/Quaternion.js';
- import RuntimeError from '../Core/RuntimeError.js';
- import WebGLConstants from '../Core/WebGLConstants.js';
- import ShaderSource from '../Renderer/ShaderSource.js';
- import addToArray from '../ThirdParty/GltfPipeline/addToArray.js';
- import ForEach from '../ThirdParty/GltfPipeline/ForEach.js';
- import hasExtension from '../ThirdParty/GltfPipeline/hasExtension.js';
- import AttributeType from './AttributeType.js';
- import Axis from './Axis.js';
- /**
- * @private
- */
- var ModelUtility = {};
- /**
- * Updates the model's forward axis if the model is not a 2.0 model.
- *
- * @param {Object} model The model to update.
- */
- ModelUtility.updateForwardAxis = function(model) {
- var cachedSourceVersion = model.gltf.extras.sourceVersion;
- if ((defined(cachedSourceVersion) && cachedSourceVersion !== '2.0')
- || ModelUtility.getAssetVersion(model.gltf) !== '2.0') {
- model._gltfForwardAxis = Axis.X;
- }
- };
- /**
- * Gets the string representing the glTF asset version.
- *
- * @param {Object} gltf A javascript object containing a glTF asset.
- * @returns {String} The glTF asset version string.
- */
- ModelUtility.getAssetVersion = function(gltf) {
- // In glTF 1.0 it was valid to omit the version number.
- if (!defined(gltf.asset) || !defined(gltf.asset.version)) {
- return '1.0';
- }
- return gltf.asset.version;
- };
- /**
- * Splits primitive materials with values incompatible for generating techniques.
- *
- * @param {Object} gltf A javascript object containing a glTF asset.
- * @returns {Object} The glTF asset with modified materials.
- */
- ModelUtility.splitIncompatibleMaterials = function(gltf) {
- var accessors = gltf.accessors;
- var materials = gltf.materials;
- var primitiveInfoByMaterial = {};
- ForEach.mesh(gltf, function(mesh) {
- ForEach.meshPrimitive(mesh, function(primitive) {
- var materialIndex = primitive.material;
- var material = materials[materialIndex];
- var jointAccessorId = primitive.attributes.JOINTS_0;
- var componentType;
- var type;
- if (defined(jointAccessorId)) {
- var jointAccessor = accessors[jointAccessorId];
- componentType = jointAccessor.componentType;
- type = jointAccessor.type;
- }
- var isSkinned = defined(jointAccessorId);
- var hasVertexColors = defined(primitive.attributes.COLOR_0);
- var hasMorphTargets = defined(primitive.targets);
- var hasNormals = defined(primitive.attributes.NORMAL);
- var hasTangents = defined(primitive.attributes.TANGENT);
- var hasTexCoords = defined(primitive.attributes.TEXCOORD_0);
- var primitiveInfo = primitiveInfoByMaterial[materialIndex];
- if (!defined(primitiveInfo)) {
- primitiveInfoByMaterial[materialIndex] = {
- skinning: {
- skinned: isSkinned,
- componentType: componentType,
- type: type
- },
- hasVertexColors: hasVertexColors,
- hasMorphTargets: hasMorphTargets,
- hasNormals: hasNormals,
- hasTangents: hasTangents,
- hasTexCoords: hasTexCoords
- };
- } else if ((primitiveInfo.skinning.skinned !== isSkinned) ||
- (primitiveInfo.skinning.type !== type) ||
- (primitiveInfo.hasVertexColors !== hasVertexColors) ||
- (primitiveInfo.hasMorphTargets !== hasMorphTargets) ||
- (primitiveInfo.hasNormals !== hasNormals) ||
- (primitiveInfo.hasTangents !== hasTangents) ||
- (primitiveInfo.hasTexCoords !== hasTexCoords)) {
- // This primitive uses the same material as another one that either:
- // * Isn't skinned
- // * Uses a different type to store joints and weights
- // * Doesn't have vertex colors, morph targets, normals, tangents, or texCoords
- var clonedMaterial = clone(material, true);
- // Split this off as a separate material
- materialIndex = addToArray(materials, clonedMaterial);
- primitive.material = materialIndex;
- primitiveInfoByMaterial[materialIndex] = {
- skinning: {
- skinned: isSkinned,
- componentType: componentType,
- type: type
- },
- hasVertexColors: hasVertexColors,
- hasMorphTargets: hasMorphTargets,
- hasNormals: hasNormals,
- hasTangents: hasTangents,
- hasTexCoords: hasTexCoords
- };
- }
- });
- });
- return primitiveInfoByMaterial;
- };
- ModelUtility.getShaderVariable = function(type) {
- if (type === 'SCALAR') {
- return 'float';
- }
- return type.toLowerCase();
- };
- ModelUtility.ModelState = {
- NEEDS_LOAD: 0,
- LOADING: 1,
- LOADED: 2, // Renderable, but textures can still be pending when incrementallyLoadTextures is true.
- FAILED: 3
- };
- ModelUtility.getFailedLoadFunction = function(model, type, path) {
- return function(error) {
- model._state = ModelUtility.ModelState.FAILED;
- var message = 'Failed to load ' + type + ': ' + path;
- if (defined(error)) {
- message += '\n' + error.message;
- }
- model._readyPromise.reject(new RuntimeError(message));
- };
- };
- ModelUtility.parseBuffers = function(model, bufferLoad) {
- var loadResources = model._loadResources;
- ForEach.buffer(model.gltf, function(buffer, bufferViewId) {
- if (defined(buffer.extras._pipeline.source)) {
- loadResources.buffers[bufferViewId] = buffer.extras._pipeline.source;
- } else if (defined(bufferLoad)) {
- var bufferResource = model._resource.getDerivedResource({
- url: buffer.uri
- });
- ++loadResources.pendingBufferLoads;
- bufferResource.fetchArrayBuffer()
- .then(bufferLoad(model, bufferViewId))
- .otherwise(ModelUtility.getFailedLoadFunction(model, 'buffer', bufferResource.url));
- }
- });
- };
- var aMinScratch = new Cartesian3();
- var aMaxScratch = new Cartesian3();
- ModelUtility.computeBoundingSphere = function(model) {
- var gltf = model.gltf;
- var gltfNodes = gltf.nodes;
- var gltfMeshes = gltf.meshes;
- var rootNodes = gltf.scenes[gltf.scene].nodes;
- var rootNodesLength = rootNodes.length;
- var nodeStack = [];
- var min = new Cartesian3(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE);
- var max = new Cartesian3(-Number.MAX_VALUE, -Number.MAX_VALUE, -Number.MAX_VALUE);
- for (var i = 0; i < rootNodesLength; ++i) {
- var n = gltfNodes[rootNodes[i]];
- n._transformToRoot = ModelUtility.getTransform(n);
- nodeStack.push(n);
- while (nodeStack.length > 0) {
- n = nodeStack.pop();
- var transformToRoot = n._transformToRoot;
- var meshId = n.mesh;
- if (defined(meshId)) {
- var mesh = gltfMeshes[meshId];
- var primitives = mesh.primitives;
- var primitivesLength = primitives.length;
- for (var m = 0; m < primitivesLength; ++m) {
- var positionAccessor = primitives[m].attributes.POSITION;
- if (defined(positionAccessor)) {
- var minMax = ModelUtility.getAccessorMinMax(gltf, positionAccessor);
- var aMin = Cartesian3.fromArray(minMax.min, 0, aMinScratch);
- var aMax = Cartesian3.fromArray(minMax.max, 0, aMaxScratch);
- if (defined(min) && defined(max)) {
- Matrix4.multiplyByPoint(transformToRoot, aMin, aMin);
- Matrix4.multiplyByPoint(transformToRoot, aMax, aMax);
- Cartesian3.minimumByComponent(min, aMin, min);
- Cartesian3.maximumByComponent(max, aMax, max);
- }
- }
- }
- }
- var children = n.children;
- if (defined(children)) {
- var childrenLength = children.length;
- for (var k = 0; k < childrenLength; ++k) {
- var child = gltfNodes[children[k]];
- child._transformToRoot = ModelUtility.getTransform(child);
- Matrix4.multiplyTransformation(transformToRoot, child._transformToRoot, child._transformToRoot);
- nodeStack.push(child);
- }
- }
- delete n._transformToRoot;
- }
- }
- var boundingSphere = BoundingSphere.fromCornerPoints(min, max);
- if (model._forwardAxis === Axis.Z) {
- // glTF 2.0 has a Z-forward convention that must be adapted here to X-forward.
- BoundingSphere.transformWithoutScale(boundingSphere, Axis.Z_UP_TO_X_UP, boundingSphere);
- }
- if (model._upAxis === Axis.Y) {
- BoundingSphere.transformWithoutScale(boundingSphere, Axis.Y_UP_TO_Z_UP, boundingSphere);
- } else if (model._upAxis === Axis.X) {
- BoundingSphere.transformWithoutScale(boundingSphere, Axis.X_UP_TO_Z_UP, boundingSphere);
- }
- return boundingSphere;
- };
- function techniqueAttributeForSemantic(technique, semantic) {
- return ForEach.techniqueAttribute(technique, function(attribute, attributeName) {
- if (attribute.semantic === semantic) {
- return attributeName;
- }
- });
- }
- function ensureSemanticExistenceForPrimitive(gltf, primitive) {
- var accessors = gltf.accessors;
- var materials = gltf.materials;
- var techniquesWebgl = gltf.extensions.KHR_techniques_webgl;
- var techniques = techniquesWebgl.techniques;
- var programs = techniquesWebgl.programs;
- var shaders = techniquesWebgl.shaders;
- var targets = primitive.targets;
- var attributes = primitive.attributes;
- for (var target in targets) {
- if (targets.hasOwnProperty(target)) {
- var targetAttributes = targets[target];
- for (var attribute in targetAttributes) {
- if (attribute !== 'extras') {
- attributes[attribute + '_' + target] = targetAttributes[attribute];
- }
- }
- }
- }
- var material = materials[primitive.material];
- var technique = techniques[material.extensions.KHR_techniques_webgl.technique];
- var program = programs[technique.program];
- var vertexShader = shaders[program.vertexShader];
- for (var semantic in attributes) {
- if (attributes.hasOwnProperty(semantic)) {
- if (!defined(techniqueAttributeForSemantic(technique, semantic))) {
- var accessorId = attributes[semantic];
- var accessor = accessors[accessorId];
- var lowerCase = semantic.toLowerCase();
- if (lowerCase.charAt(0) === '_') {
- lowerCase = lowerCase.slice(1);
- }
- var attributeName = 'a_' + lowerCase;
- technique.attributes[attributeName] = {
- semantic: semantic,
- type: accessor.componentType
- };
- var pipelineExtras = vertexShader.extras._pipeline;
- var shaderText = pipelineExtras.source;
- shaderText = 'attribute ' + ModelUtility.getShaderVariable(accessor.type) + ' ' + attributeName + ';\n' + shaderText;
- pipelineExtras.source = shaderText;
- }
- }
- }
- }
- /**
- * Ensures all attributes present on the primitive are present in the technique and
- * vertex shader.
- *
- * @param {Object} gltf A javascript object containing a glTF asset.
- * @returns {Object} The glTF asset, including any additional attributes.
- */
- ModelUtility.ensureSemanticExistence = function (gltf) {
- ForEach.mesh(gltf, function(mesh) {
- ForEach.meshPrimitive(mesh, function(primitive) {
- ensureSemanticExistenceForPrimitive(gltf, primitive);
- });
- });
- return gltf;
- };
- /**
- * Creates attribute location for all attributes required by a technique.
- *
- * @param {Object} technique A glTF KHR_techniques_webgl technique object.
- * @param {Object} precreatedAttributes A dictionary object of pre-created attributes for which to also create locations.
- * @returns {Object} A dictionary object containing attribute names and their locations.
- */
- ModelUtility.createAttributeLocations = function(technique, precreatedAttributes) {
- var attributeLocations = {};
- var hasIndex0 = false;
- var i = 1;
- ForEach.techniqueAttribute(technique, function (attribute, attributeName) {
- // Set the position attribute to the 0th index. In some WebGL implementations the shader
- // will not work correctly if the 0th attribute is not active. For example, some glTF models
- // list the normal attribute first but derived shaders like the cast-shadows shader do not use
- // the normal attribute.
- if (/pos/i.test(attributeName) && !hasIndex0) {
- attributeLocations[attributeName] = 0;
- hasIndex0 = true;
- } else {
- attributeLocations[attributeName] = i++;
- }
- });
- if (defined(precreatedAttributes)) {
- for (var attributeName in precreatedAttributes) {
- if (precreatedAttributes.hasOwnProperty(attributeName)) {
- attributeLocations[attributeName] = i++;
- }
- }
- }
- return attributeLocations;
- };
- ModelUtility.getAccessorMinMax = function(gltf, accessorId) {
- var accessor = gltf.accessors[accessorId];
- var extensions = accessor.extensions;
- var accessorMin = accessor.min;
- var accessorMax = accessor.max;
- // If this accessor is quantized, we should use the decoded min and max
- if (defined(extensions)) {
- var quantizedAttributes = extensions.WEB3D_quantized_attributes;
- if (defined(quantizedAttributes)) {
- accessorMin = quantizedAttributes.decodedMin;
- accessorMax = quantizedAttributes.decodedMax;
- }
- }
- return {
- min : accessorMin,
- max : accessorMax
- };
- };
- function getTechniqueAttributeOrUniformFunction(gltf, technique, semantic, ignoreNodes) {
- if (hasExtension(gltf, 'KHR_techniques_webgl')) {
- return function(attributeOrUniform, attributeOrUniformName) {
- if (attributeOrUniform.semantic === semantic && (!ignoreNodes || !defined(attributeOrUniform.node))) {
- return attributeOrUniformName;
- }
- };
- }
- return function(parameterName, attributeOrUniformName) {
- var attributeOrUniform = technique.parameters[parameterName];
- if (attributeOrUniform.semantic === semantic && (!ignoreNodes || !defined(attributeOrUniform.node))) {
- return attributeOrUniformName;
- }
- };
- }
- ModelUtility.getAttributeOrUniformBySemantic = function(gltf, semantic, programId, ignoreNodes) {
- return ForEach.technique(gltf, function(technique) {
- if (defined(programId) && (technique.program !== programId)) {
- return;
- }
- var value = ForEach.techniqueAttribute(technique, getTechniqueAttributeOrUniformFunction(gltf, technique, semantic, ignoreNodes));
- if (defined(value)) {
- return value;
- }
- return ForEach.techniqueUniform(technique, getTechniqueAttributeOrUniformFunction(gltf, technique, semantic, ignoreNodes));
- });
- };
- ModelUtility.getDiffuseAttributeOrUniform = function(gltf, programId) {
- var diffuseUniformName = ModelUtility.getAttributeOrUniformBySemantic(gltf, 'COLOR_0', programId);
- if (!defined(diffuseUniformName)) {
- diffuseUniformName = ModelUtility.getAttributeOrUniformBySemantic(gltf, '_3DTILESDIFFUSE', programId);
- }
- return diffuseUniformName;
- };
- var nodeTranslationScratch = new Cartesian3();
- var nodeQuaternionScratch = new Quaternion();
- var nodeScaleScratch = new Cartesian3();
- ModelUtility.getTransform = function(node, result) {
- if (defined(node.matrix)) {
- return Matrix4.fromColumnMajorArray(node.matrix, result);
- }
- return Matrix4.fromTranslationQuaternionRotationScale(
- Cartesian3.fromArray(node.translation, 0, nodeTranslationScratch),
- Quaternion.unpack(node.rotation, 0, nodeQuaternionScratch),
- Cartesian3.fromArray(node.scale, 0, nodeScaleScratch),
- result);
- };
- ModelUtility.getUsedExtensions = function(gltf) {
- var extensionsUsed = gltf.extensionsUsed;
- var cachedExtensionsUsed = {};
- if (defined(extensionsUsed)) {
- var extensionsUsedLength = extensionsUsed.length;
- for (var i = 0; i < extensionsUsedLength; i++) {
- var extension = extensionsUsed[i];
- cachedExtensionsUsed[extension] = true;
- }
- }
- return cachedExtensionsUsed;
- };
- ModelUtility.getRequiredExtensions = function(gltf) {
- var extensionsRequired = gltf.extensionsRequired;
- var cachedExtensionsRequired = {};
- if (defined(extensionsRequired)) {
- var extensionsRequiredLength = extensionsRequired.length;
- for (var i = 0; i < extensionsRequiredLength; i++) {
- var extension = extensionsRequired[i];
- cachedExtensionsRequired[extension] = true;
- }
- }
- return cachedExtensionsRequired;
- };
- ModelUtility.supportedExtensions = {
- 'AGI_articulations' : true,
- 'CESIUM_RTC' : true,
- 'EXT_texture_webp' : true,
- 'KHR_blend' : true,
- 'KHR_binary_glTF' : true,
- 'KHR_draco_mesh_compression' : true,
- 'KHR_materials_common' : true,
- 'KHR_techniques_webgl' : true,
- 'KHR_materials_unlit' : true,
- 'KHR_materials_pbrSpecularGlossiness' : true,
- 'KHR_texture_transform' : true,
- 'WEB3D_quantized_attributes' : true
- };
- ModelUtility.checkSupportedExtensions = function(extensionsRequired, browserSupportsWebp) {
- for (var extension in extensionsRequired) {
- if (extensionsRequired.hasOwnProperty(extension)) {
- if (!ModelUtility.supportedExtensions[extension]) {
- throw new RuntimeError('Unsupported glTF Extension: ' + extension);
- }
- if (extension === 'EXT_texture_webp' && browserSupportsWebp === false) {
- throw new RuntimeError('Loaded model requires WebP but browser does not support it.');
- }
- }
- }
- };
- ModelUtility.checkSupportedGlExtensions = function(extensionsUsed, context) {
- if (defined(extensionsUsed)) {
- var glExtensionsUsedLength = extensionsUsed.length;
- for (var i = 0; i < glExtensionsUsedLength; i++) {
- var extension = extensionsUsed[i];
- if (extension !== 'OES_element_index_uint') {
- throw new RuntimeError('Unsupported WebGL Extension: ' + extension);
- } else if (!context.elementIndexUint) {
- throw new RuntimeError('OES_element_index_uint WebGL extension is not enabled.');
- }
- }
- }
- };
- function replaceAllButFirstInString(string, find, replace) {
- // Limit search to strings that are not a subset of other tokens.
- find += '(?!\\w)';
- find = new RegExp(find, 'g');
- var index = string.search(find);
- return string.replace(find, function(match, offset) {
- return index === offset ? match : replace;
- });
- }
- function getQuantizedAttributes(gltf, accessorId) {
- var accessor = gltf.accessors[accessorId];
- var extensions = accessor.extensions;
- if (defined(extensions)) {
- return extensions.WEB3D_quantized_attributes;
- }
- return undefined;
- }
- function getAttributeVariableName(gltf, primitive, attributeSemantic) {
- var materialId = primitive.material;
- var material = gltf.materials[materialId];
- if (!hasExtension(gltf, 'KHR_techniques_webgl')
- || !defined(material.extensions)
- || !defined(material.extensions.KHR_techniques_webgl)) {
- return;
- }
- var techniqueId = material.extensions.KHR_techniques_webgl.technique;
- var techniquesWebgl = gltf.extensions.KHR_techniques_webgl;
- var technique = techniquesWebgl.techniques[techniqueId];
- return ForEach.techniqueAttribute(technique, function(attribute, attributeName) {
- var semantic = attribute.semantic;
- if (semantic === attributeSemantic) {
- return attributeName;
- }
- });
- }
- ModelUtility.modifyShaderForDracoQuantizedAttributes = function(gltf, primitive, shader, decodedAttributes) {
- var quantizedUniforms = {};
- for (var attributeSemantic in decodedAttributes) {
- if (decodedAttributes.hasOwnProperty(attributeSemantic)) {
- var attribute = decodedAttributes[attributeSemantic];
- var quantization = attribute.quantization;
- if (!defined(quantization)) {
- continue;
- }
- var attributeVarName = getAttributeVariableName(gltf, primitive, attributeSemantic);
- if (attributeSemantic.charAt(0) === '_') {
- attributeSemantic = attributeSemantic.substring(1);
- }
- var decodeUniformVarName = 'gltf_u_dec_' + attributeSemantic.toLowerCase();
- if (!defined(quantizedUniforms[decodeUniformVarName])) {
- var newMain = 'gltf_decoded_' + attributeSemantic;
- var decodedAttributeVarName = attributeVarName.replace('a_', 'gltf_a_dec_');
- var size = attribute.componentsPerAttribute;
- // replace usages of the original attribute with the decoded version, but not the declaration
- shader = replaceAllButFirstInString(shader, attributeVarName, decodedAttributeVarName);
- // declare decoded attribute
- var variableType;
- if (quantization.octEncoded) {
- variableType = 'vec3';
- } else if (size > 1) {
- variableType = 'vec' + size;
- } else {
- variableType = 'float';
- }
- shader = variableType + ' ' + decodedAttributeVarName + ';\n' + shader;
- // The gltf 2.0 COLOR_0 vertex attribute can be VEC4 or VEC3
- var vec3Color = size === 3 && attributeSemantic === 'COLOR_0';
- if (vec3Color) {
- shader = replaceAllButFirstInString(shader, decodedAttributeVarName, 'vec4(' + decodedAttributeVarName + ', 1.0)');
- }
- // splice decode function into the shader
- var decode = '';
- if (quantization.octEncoded) {
- var decodeUniformVarNameRangeConstant = decodeUniformVarName + '_rangeConstant';
- shader = 'uniform float ' + decodeUniformVarNameRangeConstant + ';\n' + shader;
- decode = '\n' +
- 'void main() {\n' +
- // Draco oct-encoding decodes to zxy order
- ' ' + decodedAttributeVarName + ' = czm_octDecode(' + attributeVarName + '.xy, ' + decodeUniformVarNameRangeConstant + ').zxy;\n' +
- ' ' + newMain + '();\n' +
- '}\n';
- } else {
- var decodeUniformVarNameNormConstant = decodeUniformVarName + '_normConstant';
- var decodeUniformVarNameMin = decodeUniformVarName + '_min';
- shader = 'uniform float ' + decodeUniformVarNameNormConstant + ';\n' +
- 'uniform ' + variableType + ' ' + decodeUniformVarNameMin + ';\n' + shader;
- var attributeVarAccess = vec3Color ? '.xyz' : '';
- decode = '\n' +
- 'void main() {\n' +
- ' ' + decodedAttributeVarName + ' = ' + decodeUniformVarNameMin + ' + ' + attributeVarName + attributeVarAccess + ' * ' + decodeUniformVarNameNormConstant + ';\n' +
- ' ' + newMain + '();\n' +
- '}\n';
- }
- shader = ShaderSource.replaceMain(shader, newMain);
- shader += decode;
- }
- }
- }
- return {
- shader : shader
- };
- };
- ModelUtility.modifyShaderForQuantizedAttributes = function(gltf, primitive, shader) {
- var quantizedUniforms = {};
- var attributes = primitive.attributes;
- for (var attributeSemantic in attributes) {
- if (attributes.hasOwnProperty(attributeSemantic)) {
- var attributeVarName = getAttributeVariableName(gltf, primitive, attributeSemantic);
- var accessorId = primitive.attributes[attributeSemantic];
- if (attributeSemantic.charAt(0) === '_') {
- attributeSemantic = attributeSemantic.substring(1);
- }
- var decodeUniformVarName = 'gltf_u_dec_' + attributeSemantic.toLowerCase();
- var decodeUniformVarNameScale = decodeUniformVarName + '_scale';
- var decodeUniformVarNameTranslate = decodeUniformVarName + '_translate';
- if (!defined(quantizedUniforms[decodeUniformVarName]) && !defined(quantizedUniforms[decodeUniformVarNameScale])) {
- var quantizedAttributes = getQuantizedAttributes(gltf, accessorId);
- if (defined(quantizedAttributes)) {
- var decodeMatrix = quantizedAttributes.decodeMatrix;
- var newMain = 'gltf_decoded_' + attributeSemantic;
- var decodedAttributeVarName = attributeVarName.replace('a_', 'gltf_a_dec_');
- var size = Math.floor(Math.sqrt(decodeMatrix.length));
- // replace usages of the original attribute with the decoded version, but not the declaration
- shader = replaceAllButFirstInString(shader, attributeVarName, decodedAttributeVarName);
- // declare decoded attribute
- var variableType;
- if (size > 2) {
- variableType = 'vec' + (size - 1);
- } else {
- variableType = 'float';
- }
- shader = variableType + ' ' + decodedAttributeVarName + ';\n' + shader;
- // splice decode function into the shader - attributes are pre-multiplied with the decode matrix
- // uniform in the shader (32-bit floating point)
- var decode = '';
- if (size === 5) {
- // separate scale and translate since glsl doesn't have mat5
- shader = 'uniform mat4 ' + decodeUniformVarNameScale + ';\n' + shader;
- shader = 'uniform vec4 ' + decodeUniformVarNameTranslate + ';\n' + shader;
- decode = '\n' +
- 'void main() {\n' +
- ' ' + decodedAttributeVarName + ' = ' + decodeUniformVarNameScale + ' * ' + attributeVarName + ' + ' + decodeUniformVarNameTranslate + ';\n' +
- ' ' + newMain + '();\n' +
- '}\n';
- quantizedUniforms[decodeUniformVarNameScale] = {mat : 4};
- quantizedUniforms[decodeUniformVarNameTranslate] = {vec : 4};
- }
- else {
- shader = 'uniform mat' + size + ' ' + decodeUniformVarName + ';\n' + shader;
- decode = '\n' +
- 'void main() {\n' +
- ' ' + decodedAttributeVarName + ' = ' + variableType + '(' + decodeUniformVarName + ' * vec' + size + '(' + attributeVarName + ',1.0));\n' +
- ' ' + newMain + '();\n' +
- '}\n';
- quantizedUniforms[decodeUniformVarName] = {mat : size};
- }
- shader = ShaderSource.replaceMain(shader, newMain);
- shader += decode;
- }
- }
- }
- }
- return {
- shader : shader,
- uniforms : quantizedUniforms
- };
- };
- ModelUtility.toClipCoordinatesGLSL = function(gltf, shader) {
- var positionName = ModelUtility.getAttributeOrUniformBySemantic(gltf, 'POSITION');
- var decodedPositionName = positionName.replace('a_', 'gltf_a_dec_');
- if (shader.indexOf(decodedPositionName) !== -1) {
- positionName = decodedPositionName;
- }
- var modelViewProjectionName = ModelUtility.getAttributeOrUniformBySemantic(gltf, 'MODELVIEWPROJECTION', undefined, true);
- if (!defined(modelViewProjectionName) || shader.indexOf(modelViewProjectionName) === -1) {
- var projectionName = ModelUtility.getAttributeOrUniformBySemantic(gltf, 'PROJECTION', undefined, true);
- var modelViewName = ModelUtility.getAttributeOrUniformBySemantic(gltf, 'MODELVIEW', undefined, true);
- if (shader.indexOf('czm_instanced_modelView ') !== -1) {
- modelViewName = 'czm_instanced_modelView';
- } else if (!defined(modelViewName)) {
- modelViewName = ModelUtility.getAttributeOrUniformBySemantic(gltf, 'CESIUM_RTC_MODELVIEW', undefined, true);
- }
- modelViewProjectionName = projectionName + ' * ' + modelViewName;
- }
- return modelViewProjectionName + ' * vec4(' + positionName + '.xyz, 1.0)';
- };
- ModelUtility.modifyFragmentShaderForLogDepth = function(shader) {
- shader = ShaderSource.replaceMain(shader, 'czm_depth_main');
- shader +=
- '\n' +
- 'void main() \n' +
- '{ \n' +
- ' czm_depth_main(); \n' +
- ' czm_writeLogDepth(); \n' +
- '} \n';
- return shader;
- };
- ModelUtility.modifyVertexShaderForLogDepth = function(shader, toClipCoordinatesGLSL) {
- shader = ShaderSource.replaceMain(shader, 'czm_depth_main');
- shader +=
- '\n' +
- 'void main() \n' +
- '{ \n' +
- ' czm_depth_main(); \n' +
- ' czm_vertexLogDepth(' + toClipCoordinatesGLSL + '); \n' +
- '} \n';
- return shader;
- };
- function getScalarUniformFunction(value) {
- var that = {
- value : value,
- clone : function(source, result) {
- return source;
- },
- func : function() {
- return that.value;
- }
- };
- return that;
- }
- function getVec2UniformFunction(value) {
- var that = {
- value : Cartesian2.fromArray(value),
- clone : Cartesian2.clone,
- func : function() {
- return that.value;
- }
- };
- return that;
- }
- function getVec3UniformFunction(value) {
- var that = {
- value : Cartesian3.fromArray(value),
- clone : Cartesian3.clone,
- func : function() {
- return that.value;
- }
- };
- return that;
- }
- function getVec4UniformFunction(value) {
- var that = {
- value : Cartesian4.fromArray(value),
- clone : Cartesian4.clone,
- func : function() {
- return that.value;
- }
- };
- return that;
- }
- function getMat2UniformFunction(value) {
- var that = {
- value : Matrix2.fromColumnMajorArray(value),
- clone : Matrix2.clone,
- func : function() {
- return that.value;
- }
- };
- return that;
- }
- function getMat3UniformFunction(value) {
- var that = {
- value : Matrix3.fromColumnMajorArray(value),
- clone : Matrix3.clone,
- func : function() {
- return that.value;
- }
- };
- return that;
- }
- function getMat4UniformFunction(value) {
- var that = {
- value : Matrix4.fromColumnMajorArray(value),
- clone : Matrix4.clone,
- func : function() {
- return that.value;
- }
- };
- return that;
- }
- ///////////////////////////////////////////////////////////////////////////
- function DelayLoadedTextureUniform(value, textures, defaultTexture) {
- this._value = undefined;
- this._textureId = value.index;
- this._textures = textures;
- this._defaultTexture = defaultTexture;
- }
- defineProperties(DelayLoadedTextureUniform.prototype, {
- value : {
- get : function() {
- // Use the default texture (1x1 white) until the model's texture is loaded
- if (!defined(this._value)) {
- var texture = this._textures[this._textureId];
- if (defined(texture)) {
- this._value = texture;
- } else {
- return this._defaultTexture;
- }
- }
- return this._value;
- },
- set : function(value) {
- this._value = value;
- }
- }
- });
- DelayLoadedTextureUniform.prototype.clone = function(source) {
- return source;
- };
- DelayLoadedTextureUniform.prototype.func = undefined;
- ///////////////////////////////////////////////////////////////////////////
- function getTextureUniformFunction(value, textures, defaultTexture) {
- var uniform = new DelayLoadedTextureUniform(value, textures, defaultTexture);
- // Define function here to access closure since 'this' can't be
- // used when the Renderer sets uniforms.
- uniform.func = function() {
- return uniform.value;
- };
- return uniform;
- }
- var gltfUniformFunctions = {};
- gltfUniformFunctions[WebGLConstants.FLOAT] = getScalarUniformFunction;
- gltfUniformFunctions[WebGLConstants.FLOAT_VEC2] = getVec2UniformFunction;
- gltfUniformFunctions[WebGLConstants.FLOAT_VEC3] = getVec3UniformFunction;
- gltfUniformFunctions[WebGLConstants.FLOAT_VEC4] = getVec4UniformFunction;
- gltfUniformFunctions[WebGLConstants.INT] = getScalarUniformFunction;
- gltfUniformFunctions[WebGLConstants.INT_VEC2] = getVec2UniformFunction;
- gltfUniformFunctions[WebGLConstants.INT_VEC3] = getVec3UniformFunction;
- gltfUniformFunctions[WebGLConstants.INT_VEC4] = getVec4UniformFunction;
- gltfUniformFunctions[WebGLConstants.BOOL] = getScalarUniformFunction;
- gltfUniformFunctions[WebGLConstants.BOOL_VEC2] = getVec2UniformFunction;
- gltfUniformFunctions[WebGLConstants.BOOL_VEC3] = getVec3UniformFunction;
- gltfUniformFunctions[WebGLConstants.BOOL_VEC4] = getVec4UniformFunction;
- gltfUniformFunctions[WebGLConstants.FLOAT_MAT2] = getMat2UniformFunction;
- gltfUniformFunctions[WebGLConstants.FLOAT_MAT3] = getMat3UniformFunction;
- gltfUniformFunctions[WebGLConstants.FLOAT_MAT4] = getMat4UniformFunction;
- gltfUniformFunctions[WebGLConstants.SAMPLER_2D] = getTextureUniformFunction;
- // GLTF_SPEC: Support SAMPLER_CUBE. https://github.com/KhronosGroup/glTF/issues/40
- ModelUtility.createUniformFunction = function(type, value, textures, defaultTexture) {
- return gltfUniformFunctions[type](value, textures, defaultTexture);
- };
- function scaleFromMatrix5Array(matrix) {
- return [matrix[0], matrix[1], matrix[2], matrix[3],
- matrix[5], matrix[6], matrix[7], matrix[8],
- matrix[10], matrix[11], matrix[12], matrix[13],
- matrix[15], matrix[16], matrix[17], matrix[18]];
- }
- function translateFromMatrix5Array(matrix) {
- return [matrix[20], matrix[21], matrix[22], matrix[23]];
- }
- ModelUtility.createUniformsForDracoQuantizedAttributes = function(decodedAttributes) {
- var uniformMap = {};
- for (var attribute in decodedAttributes) {
- if (decodedAttributes.hasOwnProperty(attribute)) {
- var decodedData = decodedAttributes[attribute];
- var quantization = decodedData.quantization;
- if (!defined(quantization)) {
- continue;
- }
- if (attribute.charAt(0) === '_'){
- attribute = attribute.substring(1);
- }
- var uniformVarName = 'gltf_u_dec_' + attribute.toLowerCase();
- if (quantization.octEncoded) {
- var uniformVarNameRangeConstant = uniformVarName + '_rangeConstant';
- var rangeConstant = (1 << quantization.quantizationBits) - 1.0;
- uniformMap[uniformVarNameRangeConstant] = getScalarUniformFunction(rangeConstant).func;
- continue;
- }
- var uniformVarNameNormConstant = uniformVarName + '_normConstant';
- var normConstant = quantization.range / (1 << quantization.quantizationBits);
- uniformMap[uniformVarNameNormConstant] = getScalarUniformFunction(normConstant).func;
- var uniformVarNameMin = uniformVarName + '_min';
- switch (decodedData.componentsPerAttribute) {
- case 1:
- uniformMap[uniformVarNameMin] = getScalarUniformFunction(quantization.minValues).func;
- break;
- case 2:
- uniformMap[uniformVarNameMin] = getVec2UniformFunction(quantization.minValues).func;
- break;
- case 3:
- uniformMap[uniformVarNameMin] = getVec3UniformFunction(quantization.minValues).func;
- break;
- case 4:
- uniformMap[uniformVarNameMin] = getVec4UniformFunction(quantization.minValues).func;
- break;
- }
- }
- }
- return uniformMap;
- };
- ModelUtility.createUniformsForQuantizedAttributes = function(gltf, primitive, quantizedUniforms) {
- var accessors = gltf.accessors;
- var setUniforms = {};
- var uniformMap = {};
- var attributes = primitive.attributes;
- for (var attribute in attributes) {
- if (attributes.hasOwnProperty(attribute)) {
- var accessorId = attributes[attribute];
- var a = accessors[accessorId];
- var extensions = a.extensions;
- if (attribute.charAt(0) === '_') {
- attribute = attribute.substring(1);
- }
- if (defined(extensions)) {
- var quantizedAttributes = extensions.WEB3D_quantized_attributes;
- if (defined(quantizedAttributes)) {
- var decodeMatrix = quantizedAttributes.decodeMatrix;
- var uniformVariable = 'gltf_u_dec_' + attribute.toLowerCase();
- switch (a.type) {
- case AttributeType.SCALAR:
- uniformMap[uniformVariable] = getMat2UniformFunction(decodeMatrix).func;
- setUniforms[uniformVariable] = true;
- break;
- case AttributeType.VEC2:
- uniformMap[uniformVariable] = getMat3UniformFunction(decodeMatrix).func;
- setUniforms[uniformVariable] = true;
- break;
- case AttributeType.VEC3:
- uniformMap[uniformVariable] = getMat4UniformFunction(decodeMatrix).func;
- setUniforms[uniformVariable] = true;
- break;
- case AttributeType.VEC4:
- // VEC4 attributes are split into scale and translate because there is no mat5 in GLSL
- var uniformVariableScale = uniformVariable + '_scale';
- var uniformVariableTranslate = uniformVariable + '_translate';
- uniformMap[uniformVariableScale] = getMat4UniformFunction(scaleFromMatrix5Array(decodeMatrix)).func;
- uniformMap[uniformVariableTranslate] = getVec4UniformFunction(translateFromMatrix5Array(decodeMatrix)).func;
- setUniforms[uniformVariableScale] = true;
- setUniforms[uniformVariableTranslate] = true;
- break;
- }
- }
- }
- }
- }
- // If there are any unset quantized uniforms in this program, they should be set to the identity
- for (var quantizedUniform in quantizedUniforms) {
- if (quantizedUniforms.hasOwnProperty(quantizedUniform)) {
- if (!setUniforms[quantizedUniform]) {
- var properties = quantizedUniforms[quantizedUniform];
- if (defined(properties.mat)) {
- if (properties.mat === 2) {
- uniformMap[quantizedUniform] = getMat2UniformFunction(Matrix2.IDENTITY).func;
- } else if (properties.mat === 3) {
- uniformMap[quantizedUniform] = getMat3UniformFunction(Matrix3.IDENTITY).func;
- } else if (properties.mat === 4) {
- uniformMap[quantizedUniform] = getMat4UniformFunction(Matrix4.IDENTITY).func;
- }
- }
- if (defined(properties.vec)) {
- if (properties.vec === 4) {
- uniformMap[quantizedUniform] = getVec4UniformFunction([0, 0, 0, 0]).func;
- }
- }
- }
- }
- }
- return uniformMap;
- };
- // This doesn't support LOCAL, which we could add if it is ever used.
- var scratchTranslationRtc = new Cartesian3();
- var gltfSemanticUniforms = {
- MODEL : function(uniformState, model) {
- return function() {
- return uniformState.model;
- };
- },
- VIEW : function(uniformState, model) {
- return function() {
- return uniformState.view;
- };
- },
- PROJECTION : function(uniformState, model) {
- return function() {
- return uniformState.projection;
- };
- },
- MODELVIEW : function(uniformState, model) {
- return function() {
- return uniformState.modelView;
- };
- },
- CESIUM_RTC_MODELVIEW : function(uniformState, model) {
- // CESIUM_RTC extension
- var mvRtc = new Matrix4();
- return function() {
- if (defined(model._rtcCenter)) {
- Matrix4.getTranslation(uniformState.model, scratchTranslationRtc);
- Cartesian3.add(scratchTranslationRtc, model._rtcCenter, scratchTranslationRtc);
- Matrix4.multiplyByPoint(uniformState.view, scratchTranslationRtc, scratchTranslationRtc);
- return Matrix4.setTranslation(uniformState.modelView, scratchTranslationRtc, mvRtc);
- }
- return uniformState.modelView;
- };
- },
- MODELVIEWPROJECTION : function(uniformState, model) {
- return function() {
- return uniformState.modelViewProjection;
- };
- },
- MODELINVERSE : function(uniformState, model) {
- return function() {
- return uniformState.inverseModel;
- };
- },
- VIEWINVERSE : function(uniformState, model) {
- return function() {
- return uniformState.inverseView;
- };
- },
- PROJECTIONINVERSE : function(uniformState, model) {
- return function() {
- return uniformState.inverseProjection;
- };
- },
- MODELVIEWINVERSE : function(uniformState, model) {
- return function() {
- return uniformState.inverseModelView;
- };
- },
- MODELVIEWPROJECTIONINVERSE : function(uniformState, model) {
- return function() {
- return uniformState.inverseModelViewProjection;
- };
- },
- MODELINVERSETRANSPOSE : function(uniformState, model) {
- return function() {
- return uniformState.inverseTransposeModel;
- };
- },
- MODELVIEWINVERSETRANSPOSE : function(uniformState, model) {
- return function() {
- return uniformState.normal;
- };
- },
- VIEWPORT : function(uniformState, model) {
- return function() {
- return uniformState.viewportCartesian4;
- };
- }
- // JOINTMATRIX created in createCommand()
- };
- ModelUtility.getGltfSemanticUniforms = function() {
- return gltfSemanticUniforms;
- };
- export default ModelUtility;
|