From be6fffa227cde101fab1c5dcb8f4272e4a3ac1c9 Mon Sep 17 00:00:00 2001 From: ggetz Date: Mon, 16 Jul 2018 16:13:33 -0400 Subject: [PATCH 01/52] Update gltf pipeline files and support KHR_techniques_webgl and KHR_blend extensions --- .../webGLConstantToGlslType.js | 2 +- Source/Scene/ClassificationModel.js | 54 +- Source/Scene/Model.js | 663 +++++++++--------- Source/Scene/ModelInstanceCollection.js | 41 +- Source/Scene/ModelMaterial.js | 4 + Source/Scene/ModelUtility.js | 359 ++++++++-- .../processModelMaterialsCommon.js | 500 ++++--------- .../processPbrMetallicRoughness.js | 575 +++++---------- Source/ThirdParty/GltfPipeline/ForEach.js | 326 +++++++-- Source/ThirdParty/GltfPipeline/addDefaults.js | 593 ++++------------ .../GltfPipeline/addExtensionsRequired.js | 5 +- .../GltfPipeline/addExtensionsUsed.js | 5 +- .../GltfPipeline/addPipelineExtras.js | 77 +- Source/ThirdParty/GltfPipeline/addToArray.js | 9 + .../byteLengthForComponentType.js | 34 - .../GltfPipeline/findAccessorMinMax.js | 67 +- .../GltfPipeline/getAccessorByteStride.js | 18 +- .../GltfPipeline/getComponentReader.js | 80 +++ .../GltfPipeline/getJointCountForMaterials.js | 44 -- .../GltfPipeline/glslTypeToWebGLConstant.js | 28 - .../ThirdParty/GltfPipeline/hasExtension.js | 21 + .../GltfPipeline/moveTechniqueRenderStates.js | 138 ++++ .../GltfPipeline/moveTechniquesToExtension.js | 128 ++++ .../GltfPipeline/numberOfComponentsForType.js | 11 +- .../GltfPipeline/parseBinaryGltf.js | 122 ---- Source/ThirdParty/GltfPipeline/parseGlb.js | 126 ++++ .../GltfPipeline/removeExtensionsRequired.js | 2 + .../GltfPipeline/removeExtensionsUsed.js | 3 + .../GltfPipeline/removePipelineExtras.js | 34 - .../GltfPipeline/removeUnusedElements.js | 266 +++++++ .../techniqueParameterForSemantic.js | 29 - .../ThirdParty/GltfPipeline/updateVersion.js | 507 ++++++-------- 32 files changed, 2505 insertions(+), 2366 deletions(-) rename Source/{ThirdParty/GltfPipeline => Core}/webGLConstantToGlslType.js (96%) rename Source/{ThirdParty/GltfPipeline => Scene}/processModelMaterialsCommon.js (62%) rename Source/{ThirdParty/GltfPipeline => Scene}/processPbrMetallicRoughness.js (52%) delete mode 100644 Source/ThirdParty/GltfPipeline/byteLengthForComponentType.js create mode 100644 Source/ThirdParty/GltfPipeline/getComponentReader.js delete mode 100644 Source/ThirdParty/GltfPipeline/getJointCountForMaterials.js delete mode 100644 Source/ThirdParty/GltfPipeline/glslTypeToWebGLConstant.js create mode 100644 Source/ThirdParty/GltfPipeline/hasExtension.js create mode 100644 Source/ThirdParty/GltfPipeline/moveTechniqueRenderStates.js create mode 100644 Source/ThirdParty/GltfPipeline/moveTechniquesToExtension.js delete mode 100644 Source/ThirdParty/GltfPipeline/parseBinaryGltf.js create mode 100644 Source/ThirdParty/GltfPipeline/parseGlb.js delete mode 100644 Source/ThirdParty/GltfPipeline/removePipelineExtras.js create mode 100644 Source/ThirdParty/GltfPipeline/removeUnusedElements.js delete mode 100644 Source/ThirdParty/GltfPipeline/techniqueParameterForSemantic.js diff --git a/Source/ThirdParty/GltfPipeline/webGLConstantToGlslType.js b/Source/Core/webGLConstantToGlslType.js similarity index 96% rename from Source/ThirdParty/GltfPipeline/webGLConstantToGlslType.js rename to Source/Core/webGLConstantToGlslType.js index 1a7a03716250..dce11822bc26 100644 --- a/Source/ThirdParty/GltfPipeline/webGLConstantToGlslType.js +++ b/Source/Core/webGLConstantToGlslType.js @@ -1,5 +1,5 @@ define([ - '../../Core/WebGLConstants' + './WebGLConstants' ], function( WebGLConstants) { 'use strict'; diff --git a/Source/Scene/ClassificationModel.js b/Source/Scene/ClassificationModel.js index 60d67a11dd62..e628df0e348e 100644 --- a/Source/Scene/ClassificationModel.js +++ b/Source/Scene/ClassificationModel.js @@ -24,7 +24,7 @@ define([ '../ThirdParty/GltfPipeline/ForEach', '../ThirdParty/GltfPipeline/getAccessorByteStride', '../ThirdParty/GltfPipeline/numberOfComponentsForType', - '../ThirdParty/GltfPipeline/parseBinaryGltf', + '../ThirdParty/GltfPipeline/parseGlb', '../ThirdParty/when', './Axis', './ClassificationType', @@ -59,7 +59,7 @@ define([ ForEach, getAccessorByteStride, numberOfComponentsForType, - parseBinaryGltf, + parseGlb, when, Axis, ClassificationType, @@ -124,7 +124,7 @@ define([ if (gltf instanceof Uint8Array) { // Binary glTF - gltf = parseBinaryGltf(gltf); + gltf = parseGlb(gltf); } else { throw new RuntimeError('Only binary glTF is supported as a classifier.'); } @@ -132,17 +132,17 @@ define([ var gltfNodes = gltf.nodes; var gltfMeshes = gltf.meshes; - var gltfNode = gltfNodes[0]; - var meshId = gltfNode.mesh; - if (gltfNodes.length !== 1 || !defined(meshId)) { + var gltfNode = gltfNodes.rootNode; + if (!defined(gltfNode)) { 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 nodeMesh = gltfNode.meshes[0]; + if (!defined(nodeMesh)) { + throw new RuntimeError('Only one node is supported for classification and it must have a mesh.'); } - var gltfPrimitives = gltfMeshes[0].primitives; + var gltfPrimitives = gltfMeshes[nodeMesh].primitives; if (gltfPrimitives.length !== 1) { throw new RuntimeError('Only one primitive per mesh is supported when using b3dm for classification.'); } @@ -499,8 +499,8 @@ define([ 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); - var n = gltfNodes[0]; - var meshId = n.mesh; + var n = gltfNodes.rootNode; + var meshId = n.meshes[0]; var transformToRoot = ModelUtility.getTransform(n); var mesh = gltfMeshes[meshId]; @@ -646,7 +646,9 @@ define([ } function modifyShaderForQuantizedAttributes(shader, model) { - var primitive = model.gltf.meshes[0].primitives[0]; + var gltfMeshes = model.gltf.meshes; + var gltfRootNode = model.gltf.nodes.rootNode; + var primitive = gltfMeshes[gltfRootNode.meshes[0]].primitives[0]; var result = ModelUtility.modifyShaderForQuantizedAttributes(model.gltf, primitive, shader); model._quantizedUniforms = result.uniforms; return result.shader; @@ -748,7 +750,8 @@ define([ var gltf = model.gltf; var accessors = gltf.accessors; var meshes = gltf.meshes; - var primitives = meshes[0].primitives; + var rootNode = gltf.nodes.rootNode; + var primitives = meshes[rootNode.meshes[0]].primitives; var primitive = primitives[0]; var attributeLocations = getAttributeLocations(); @@ -804,23 +807,19 @@ define([ return; } - var techniques = model.gltf.techniques; - var technique = techniques[0]; - var parameters = technique.parameters; - var uniforms = technique.uniforms; - var uniformMap = {}; - for (var name in uniforms) { - if (uniforms.hasOwnProperty(name) && name !== 'extras') { - var parameterName = uniforms[name]; + ForEach.technique(model.gltf, function(technique) { + var parameters = technique.parameters; + ForEach.techniqueUniform(technique, function(parameterName, uniformName) { var parameter = parameters[parameterName]; if (!defined(parameter.semantic) || !defined(gltfSemanticUniforms[parameter.semantic])) { - continue; + return; } - uniformMap[name] = gltfSemanticUniforms[parameter.semantic](context.uniformState, model); - } - } + + uniformMap[uniformName] = gltfSemanticUniforms[parameter.semantic](context.uniformState, model); + }); + }); model._uniformMap = uniformMap; } @@ -850,7 +849,8 @@ define([ var gltf = model.gltf; var accessors = gltf.accessors; var gltfMeshes = gltf.meshes; - var primitive = gltfMeshes[0].primitives[0]; + var gltfRootNode = gltf.nodes.rootNode; + var primitive = gltfMeshes[gltfRootNode.meshes[0]].primitives[0]; var ix = accessors[primitive.indices]; var positionAccessor = primitive.attributes.POSITION; @@ -999,7 +999,7 @@ define([ var gltf = model.gltf; var nodes = gltf.nodes; - var gltfNode = nodes[0]; + var gltfNode = nodes.rootNode; model._nodeMatrix = ModelUtility.getTransform(gltfNode, model._nodeMatrix); createPrimitive(model); diff --git a/Source/Scene/Model.js b/Source/Scene/Model.js index bcb23f30f26d..63bd0356e635 100644 --- a/Source/Scene/Model.js +++ b/Source/Scene/Model.js @@ -1,6 +1,5 @@ define([ '../Core/BoundingSphere', - '../Core/Cartesian2', '../Core/Cartesian3', '../Core/Cartesian4', '../Core/Cartographic', @@ -22,14 +21,11 @@ define([ '../Core/loadImageFromTypedArray', '../Core/loadKTX', '../Core/Math', - '../Core/Matrix2', '../Core/Matrix3', '../Core/Matrix4', '../Core/PixelFormat', - '../Core/Plane', '../Core/PrimitiveType', '../Core/Quaternion', - '../Core/Queue', '../Core/Resource', '../Core/RuntimeError', '../Core/Transforms', @@ -50,14 +46,11 @@ define([ '../ThirdParty/GltfPipeline/addPipelineExtras', '../ThirdParty/GltfPipeline/ForEach', '../ThirdParty/GltfPipeline/getAccessorByteStride', + '../ThirdParty/GltfPipeline/hasExtension', '../ThirdParty/GltfPipeline/numberOfComponentsForType', - '../ThirdParty/GltfPipeline/parseBinaryGltf', - '../ThirdParty/GltfPipeline/processModelMaterialsCommon', - '../ThirdParty/GltfPipeline/processPbrMetallicRoughness', + '../ThirdParty/GltfPipeline/parseGlb', '../ThirdParty/GltfPipeline/updateVersion', - '../ThirdParty/Uri', '../ThirdParty/when', - './AttributeType', './Axis', './BlendingState', './ClippingPlaneCollection', @@ -74,11 +67,12 @@ define([ './ModelMesh', './ModelNode', './ModelUtility', + './processModelMaterialsCommon', + './processPbrMetallicRoughness', './SceneMode', './ShadowMode' ], function( BoundingSphere, - Cartesian2, Cartesian3, Cartesian4, Cartographic, @@ -100,14 +94,11 @@ define([ loadImageFromTypedArray, loadKTX, CesiumMath, - Matrix2, Matrix3, Matrix4, PixelFormat, - Plane, PrimitiveType, Quaternion, - Queue, Resource, RuntimeError, Transforms, @@ -128,14 +119,11 @@ define([ addPipelineExtras, ForEach, getAccessorByteStride, + hasExtension, numberOfComponentsForType, - parseBinaryGltf, - processModelMaterialsCommon, - processPbrMetallicRoughness, + parseGlb, updateVersion, - Uri, when, - AttributeType, Axis, BlendingState, ClippingPlaneCollection, @@ -152,6 +140,8 @@ define([ ModelMesh, ModelNode, ModelUtility, + processModelMaterialsCommon, + processPbrMetallicRoughness, SceneMode, ShadowMode) { 'use strict'; @@ -249,6 +239,10 @@ define([ * {@link https://github.com/KhronosGroup/glTF/blob/master/extensions/1.0/Vendor/WEB3D_quantized_attributes/README.md|WEB3D_quantized_attributes} *
  • * {@link https://github.com/KhronosGroup/glTF/blob/master/extensions/2.0/Khronos/KHR_draco_mesh_compression/README.md|KHR_draco_mesh_compression} + *
  • + * {@link https://github.com/KhronosGroup/glTF/blob/master/extensions/2.0/Khronos/KHR_techniques_webgl/README.md|KHR_techniques_webgl} + *
  • + * {@link https://github.com/KhronosGroup/glTF/blob/master/extensions/2.0/Khronos/KHR_blend/README.md|KHR_blend} *
  • * *

    @@ -319,7 +313,7 @@ define([ if (gltf instanceof Uint8Array) { // Binary glTF - var parsedGltf = parseBinaryGltf(gltf); + var parsedGltf = parseGlb(gltf); cachedGltf = new CachedGltf({ gltf : parsedGltf, @@ -644,10 +638,10 @@ define([ this._texturesByteLength = 0; this._trianglesLength = 0; - // Hold references to programs and shaders for shader reconstruction. + // Hold references for shader reconstruction. // Hold these separately because _cachedGltf may get released (this.releaseGltfJson) - this._sourcePrograms = undefined; - this._sourceShaders = undefined; + this._sourceTechniques = {}; + this._sourceShaders = {}; this._quantizedVertexShaders = {}; this._nodeCommands = []; @@ -1123,6 +1117,10 @@ define([ * {@link https://github.com/KhronosGroup/glTF/blob/master/extensions/1.0/Vendor/WEB3D_quantized_attributes/README.md|WEB3D_quantized_attributes} *
  • * {@link https://github.com/KhronosGroup/glTF/blob/master/extensions/2.0/Khronos/KHR_draco_mesh_compression/README.md|KHR_draco_mesh_compression} + *
  • + * {@link https://github.com/KhronosGroup/glTF/blob/master/extensions/2.0/Khronos/KHR_techniques_webgl/README.md|KHR_techniques_webgl} + *
  • + * {@link https://github.com/KhronosGroup/glTF/blob/master/extensions/2.0/Khronos/KHR_blend/README.md|KHR_blend} *
  • * *

    @@ -1239,7 +1237,7 @@ define([ var array = new Uint8Array(arrayBuffer); if (containsGltfMagic(array)) { // Load binary glTF - var parsedGltf = parseBinaryGltf(array); + var parsedGltf = parseGlb(array); // KHR_binary_glTF is from the beginning of the binary section cachedGltf.makeReady(parsedGltf, array); } else { @@ -1370,27 +1368,29 @@ define([ } var children = n.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); + 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); } - 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); - } return boundingSphere; } @@ -1490,7 +1490,7 @@ define([ bufferView : undefined }; --loadResources.pendingShaderLoads; - model.gltf.shaders[id].extras._pipeline.source = source; + model._shaders[id].extras._pipeline.source = source; }; } @@ -1523,14 +1523,34 @@ define([ url : shader.uri }); - shaderResource.fetchText().then(shaderLoad(model, shader.type, id)).otherwise(getFailedLoadFunction(model, 'shader', shaderResource.url)); + shaderResource.fetchText() + .then(shaderLoad(model, shader.type, id)) + .otherwise(getFailedLoadFunction(model, 'shader', shaderResource.url)); } + + // retain reference to source shader + model._sourceShaders[id] = clone(shader); }); } function parsePrograms(model) { - ForEach.program(model.gltf, function(program, id) { - model._loadResources.programsToCreate.enqueue(id); + var sourcePrograms = model._sourcePrograms = {}; + var gltf = model.gltf; + + if (!hasExtension(gltf, 'KHR_techniques_webgl')) { + return; + } + + var programs = gltf.extensions.KHR_techniques_webgl.programs; + ForEach.technique(model.gltf, function(technique, techniqueId) { + var programId = technique.program; + if (!defined(sourcePrograms[programId])) { + sourcePrograms[programId] = clone(programs[programId]); + model._loadResources.programsToCreate.enqueue({ + id: programId, + technique: techniqueId + }); + } }); } @@ -1694,22 +1714,47 @@ define([ } function parseMaterials(model) { + var gltf = model.gltf; + var techniques = model._sourceTechniques = {}; + + ForEach.technique(model.gltf, function(technique, index) { + techniques[index] = clone(technique); + }); + var runtimeMaterialsByName = {}; var runtimeMaterialsById = {}; var uniformMaps = model._uniformMaps; - ForEach.material(model.gltf, function(material, id) { + ForEach.material(gltf, function(material, materialId) { // Allocated now so ModelMaterial can keep a reference to it. - uniformMaps[id] = { + uniformMaps[materialId] = { uniformMap : undefined, values : undefined, jointMatrixUniformName : undefined, morphWeightsUniformName : undefined }; - var modelMaterial = new ModelMaterial(model, material, id); + var modelMaterial = new ModelMaterial(model, material, materialId); + + if (defined(material.extensions) && defined(material.extensions.KHR_techniques_webgl)) { + var techniqueId = material.extensions.KHR_techniques_webgl.technique; + modelMaterial._technique = techniqueId; + modelMaterial._program = techniques[techniqueId].program; + + var values = material.extensions.KHR_techniques_webgl.values; + for (var uniformName in values) { + if (values.hasOwnProperty(uniformName)) { + if (!defined(modelMaterial._values)) { + modelMaterial._values = {}; + } + + modelMaterial._values[uniformName] = clone(values[uniformName]); + } + } + } + runtimeMaterialsByName[material.name] = modelMaterial; - runtimeMaterialsById[id] = modelMaterial; + runtimeMaterialsById[materialId] = modelMaterial; }); model._runtime.materialsByName = runtimeMaterialsByName; @@ -1869,38 +1914,13 @@ define([ } } - function createAttributeLocations(model, attributes) { - var attributeLocations = {}; - var length = attributes.length; - var i; - - // 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. - for (i = 1; i < length; ++i) { - var attribute = attributes[i]; - if (/pos/i.test(attribute)) { - attributes[i] = attributes[0]; - attributes[0] = attribute; - break; - } - } - - for (i = 0; i < length; ++i) { - attributeLocations[attributes[i]] = i; + function getProgramForPrimitive(model, primitive) { + var material = model._runtime.materialsById[primitive.material]; + if (!defined(material)) { + return; } - return attributeLocations; - } - - function getProgramForPrimitive(model, primitive) { - var gltf = model.gltf; - var materialId = primitive.material; - var material = gltf.materials[materialId]; - var techniqueId = material.technique; - var technique = gltf.techniques[techniqueId]; - return technique.program; + return material._program; } function modifyShaderForQuantizedAttributes(shader, programName, model) { @@ -2004,26 +2024,29 @@ define([ // When building programs for the first time, do not include modifiers for clipping planes and color // since this is the version of the program that will be cached for use with other Models. - function createProgram(id, model, context) { - var program = model._sourcePrograms[id]; + function createProgram(programToCreate, model, context) { + var programId = programToCreate.id; + var techniqueId = programToCreate.technique; + var program = model._sourcePrograms[programId]; var shaders = model._sourceShaders; - var quantizedVertexShaders = model._quantizedVertexShaders; - var toClipCoordinatesGLSL = model._toClipCoordinatesGLSL[id]; var vs = shaders[program.vertexShader].extras._pipeline.source; var fs = shaders[program.fragmentShader].extras._pipeline.source; + var quantizedVertexShaders = model._quantizedVertexShaders; + var toClipCoordinatesGLSL = model._toClipCoordinatesGLSL[programId]; + if (model.extensionsUsed.WEB3D_quantized_attributes || model._dequantizeInShader) { - var quantizedVS = quantizedVertexShaders[id]; + var quantizedVS = quantizedVertexShaders[programId]; if (!defined(quantizedVS)) { - quantizedVS = modifyShaderForQuantizedAttributes(vs, id, model); - quantizedVertexShaders[id] = quantizedVS; + quantizedVS = modifyShaderForQuantizedAttributes(vs, programId, model); + quantizedVertexShaders[programId] = quantizedVS; } vs = quantizedVS; } - var drawVS = modifyShader(vs, id, model._vertexShaderLoaded); - var drawFS = modifyShader(fs, id, model._fragmentShaderLoaded); + var drawVS = modifyShader(vs, programId, model._vertexShaderLoaded); + var drawFS = modifyShader(fs, programId, model._fragmentShaderLoaded); // Internet Explorer seems to have problems with discard (for clipping planes) after too many levels of indirection: // https://github.com/AnalyticalGraphicsInc/cesium/issues/6575. @@ -2037,14 +2060,17 @@ define([ drawFS = 'uniform vec4 czm_pickColor;\n' + drawFS; } - createAttributesAndProgram(id, drawFS, drawVS, model, context); + createAttributesAndProgram(programId, techniqueId, drawFS, drawVS, model, context); } - function recreateProgram(id, model, context) { - var program = model._sourcePrograms[id]; + function recreateProgram(programToCreate, model, context) { + var programId = programToCreate.id; + var techniqueId = programToCreate.technique; + var program = model._sourcePrograms[programId]; var shaders = model._sourceShaders; + var quantizedVertexShaders = model._quantizedVertexShaders; - var toClipCoordinatesGLSL = model._toClipCoordinatesGLSL[id]; + var toClipCoordinatesGLSL = model._toClipCoordinatesGLSL[programId]; var clippingPlaneCollection = model.clippingPlanes; var addClippingPlaneCode = isClippingEnabled(model); @@ -2053,7 +2079,7 @@ define([ var fs = shaders[program.fragmentShader].extras._pipeline.source; if (model.extensionsUsed.WEB3D_quantized_attributes || model._dequantizeInShader) { - vs = quantizedVertexShaders[id]; + vs = quantizedVertexShaders[programId]; } var finalFS = fs; @@ -2064,8 +2090,8 @@ define([ finalFS = modifyShaderForClippingPlanes(finalFS, clippingPlaneCollection, context); } - var drawVS = modifyShader(vs, id, model._vertexShaderLoaded); - var drawFS = modifyShader(finalFS, id, model._fragmentShaderLoaded); + var drawVS = modifyShader(vs, programId, model._vertexShaderLoaded); + var drawFS = modifyShader(finalFS, programId, model._fragmentShaderLoaded); if (!FeatureDetection.isInternetExplorer()) { drawVS = ModelUtility.modifyVertexShaderForLogDepth(drawVS, toClipCoordinatesGLSL); @@ -2076,25 +2102,14 @@ define([ drawFS = 'uniform vec4 czm_pickColor;\n' + drawFS; } - createAttributesAndProgram(id, drawFS, drawVS, model, context); + createAttributesAndProgram(programId, techniqueId, drawFS, drawVS, model, context); } - function createAttributesAndProgram(id, drawFS, drawVS, model, context) { - var program = model._sourcePrograms[id]; - var attributeLocations = createAttributeLocations(model, program.attributes); - - // Add pre-created attributes to attributeLocations - var attributesLength = program.attributes.length; - var precreatedAttributes = model._precreatedAttributes; - if (defined(precreatedAttributes)) { - for (var attrName in precreatedAttributes) { - if (precreatedAttributes.hasOwnProperty(attrName)) { - attributeLocations[attrName] = attributesLength++; - } - } - } + function createAttributesAndProgram(programId, techniqueId, drawFS, drawVS, model, context) { + var technique = model._sourceTechniques[techniqueId]; + var attributeLocations = ModelUtility.createAttributeLocations(technique, model._precreatedAttributes); - model._rendererResources.programs[id] = ShaderProgram.fromCache({ + model._rendererResources.programs[programId] = ShaderProgram.fromCache({ context : context, vertexShaderSource : drawVS, fragmentShaderSource : drawFS, @@ -2250,7 +2265,7 @@ define([ var tx; var source = gltfTexture.image; - if (defined(internalFormat) && texture.target === WebGLConstants.TEXTURE_2D) { + if (defined(internalFormat)) { tx = new Texture({ context : context, source : { @@ -2274,19 +2289,17 @@ define([ source = canvas; } - if (texture.target === WebGLConstants.TEXTURE_2D) { - tx = new Texture({ - context : context, - source : source, - pixelFormat : texture.internalFormat, - pixelDatatype : texture.type, - sampler : sampler, - flipY : false - }); - // GLTF_SPEC: Support TEXTURE_CUBE_MAP. https://github.com/KhronosGroup/glTF/issues/40 - if (mipmap) { - tx.generateMipmap(); - } + tx = new Texture({ + context : context, + source : source, + pixelFormat : texture.internalFormat, + pixelDatatype : texture.type, + sampler : sampler, + flipY : false + }); + // GLTF_SPEC: Support TEXTURE_CUBE_MAP. https://github.com/KhronosGroup/glTF/issues/40 + if (mipmap) { + tx.generateMipmap(); } } if (defined(tx)) { @@ -2318,17 +2331,22 @@ define([ } function getAttributeLocations(model, primitive) { - var gltf = model.gltf; - var techniques = gltf.techniques; - var materials = gltf.materials; + var techniques = model._sourceTechniques; // Retrieve the compiled shader program to assign index values to attributes var attributeLocations = {}; var location; var index; - var technique = techniques[materials[primitive.material].technique]; - var parameters = technique.parameters; + var material = model._runtime.materialsById[primitive.material]; + if (!defined(material)) { + return attributeLocations; + } + var technique = techniques[material._technique]; + if (!defined(technique)) { + return; + } + var attributes = technique.attributes; var program = model._rendererResources.programs[technique.program]; var programVertexAttributes = program.vertexAttributes; @@ -2338,10 +2356,9 @@ define([ for (location in programVertexAttributes) { if (programVertexAttributes.hasOwnProperty(location)) { var attribute = attributes[location]; - index = programVertexAttributes[location].index; if (defined(attribute)) { - var parameter = parameters[attribute]; - attributeLocations[parameter.semantic] = index; + index = programAttributeLocations[location]; + attributeLocations[attribute.semantic] = index; } } } @@ -2379,9 +2396,11 @@ define([ } var children = n.children; - var childrenLength = children.length; - for (var k = 0; k < childrenLength; ++k) { - stack.push(children[k]); + if (defined(children)) { + var childrenLength = children.length; + for (var k = 0; k < childrenLength; ++k) { + stack.push(children[k]); + } } } } @@ -2489,12 +2508,9 @@ define([ model._runtime.animations = []; var runtimeNodes = model._runtime.nodes; - var animations = model.gltf.animations; var accessors = model.gltf.accessors; - var length = animations.length; - for (var i = 0; i < length; ++i) { - var animation = animations[i]; + ForEach.animation(model.gltf, function (animation, i) { var channels = animation.channels; var samplers = animation.samplers; @@ -2528,7 +2544,7 @@ define([ stopTime : stopTime, channelEvaluators : channelEvaluators }; - } + }); } function createVertexArrays(model, context) { @@ -2565,6 +2581,7 @@ define([ // https://github.com/KhronosGroup/glTF/issues/258 var attributeLocations = getAttributeLocations(model, primitive); + var attributeName; var attributeLocation; var attribute; @@ -2652,59 +2669,55 @@ define([ } } - function getBooleanStates(states) { - // GLTF_SPEC: SAMPLE_ALPHA_TO_COVERAGE not used by Cesium + function getBooleanStates(material) { var booleanStates = {}; - booleanStates[WebGLConstants.BLEND] = false; - booleanStates[WebGLConstants.CULL_FACE] = false; - booleanStates[WebGLConstants.DEPTH_TEST] = false; + booleanStates[WebGLConstants.BLEND] = (defined(material.alphaMode) && material.alphaMode !== 'OPAQUE'); + booleanStates[WebGLConstants.CULL_FACE] = !material.doubleSided; + booleanStates[WebGLConstants.DEPTH_TEST] = true; booleanStates[WebGLConstants.POLYGON_OFFSET_FILL] = false; - var enable = states.enable; - var length = enable.length; - var i; - for (i = 0; i < length; ++i) { - booleanStates[enable[i]] = true; - } - return booleanStates; } function createRenderStates(model, context) { var loadResources = model._loadResources; - var techniques = model.gltf.techniques; if (loadResources.createRenderStates) { loadResources.createRenderStates = false; - for (var id in techniques) { - if (techniques.hasOwnProperty(id)) { - createRenderStateForTechnique(model, id, context); - } - } + + ForEach.material(model.gltf, function (material, materialId) { + createRenderStateForMaterial(model, material, materialId, context); + }); } } - function createRenderStateForTechnique(model, id, context) { + function createRenderStateForMaterial(model, material, materialId, context) { var rendererRenderStates = model._rendererResources.renderStates; - var techniques = model.gltf.techniques; - var technique = techniques[id]; - var states = technique.states; - - var booleanStates = getBooleanStates(states); - var statesFunctions = defaultValue(states.functions, defaultValue.EMPTY_OBJECT); - var blendColor = defaultValue(statesFunctions.blendColor, [0.0, 0.0, 0.0, 0.0]); - var blendEquationSeparate = defaultValue(statesFunctions.blendEquationSeparate, [ + + var blendEquationSeparate = [ WebGLConstants.FUNC_ADD, - WebGLConstants.FUNC_ADD]); - var blendFuncSeparate = defaultValue(statesFunctions.blendFuncSeparate, [ + WebGLConstants.FUNC_ADD + ]; + var blendFuncSeparate = [ WebGLConstants.ONE, - WebGLConstants.ZERO, + WebGLConstants.ONE_MINUS_SRC_ALPHA, WebGLConstants.ONE, - WebGLConstants.ZERO]); - var colorMask = defaultValue(statesFunctions.colorMask, [true, true, true, true]); - var depthRange = defaultValue(statesFunctions.depthRange, [0.0, 1.0]); - var polygonOffset = defaultValue(statesFunctions.polygonOffset, [0.0, 0.0]); + WebGLConstants.ONE_MINUS_SRC_ALPHA + ]; + if (defined(material.extensions) && defined(material.extensions.KHR_blend)) { + blendEquationSeparate = material.extensions.KHR_blend.blendEquation; + blendFuncSeparate = material.extensions.KHR_blend.blendFactors; + } + + var statesFunctions = { + blendColor : [0.0, 0.0, 0.0, 0.0], + colorMask : [true, true, true, true], + depthRange : [0.0, 1.0], + polygonOffset : [0.0, 0.0] + }; + + var booleanStates = getBooleanStates(material); // Change the render state to use traditional alpha blending instead of premultiplied alpha blending if (booleanStates[WebGLConstants.BLEND] && model._hasPremultipliedAlpha) { if ((blendFuncSeparate[0] === WebGLConstants.ONE) && (blendFuncSeparate[1] === WebGLConstants.ONE_MINUS_SRC_ALPHA)) { @@ -2715,7 +2728,7 @@ define([ } } - rendererRenderStates[id] = RenderState.fromCache({ + rendererRenderStates[materialId] = RenderState.fromCache({ frontFace : defined(statesFunctions.frontFace) ? statesFunctions.frontFace[0] : WebGLConstants.CCW, cull : { enabled : booleanStates[WebGLConstants.CULL_FACE], @@ -2724,31 +2737,31 @@ define([ lineWidth : defined(statesFunctions.lineWidth) ? statesFunctions.lineWidth[0] : 1.0, polygonOffset : { enabled : booleanStates[WebGLConstants.POLYGON_OFFSET_FILL], - factor : polygonOffset[0], - units : polygonOffset[1] + factor: statesFunctions.polygonOffset[0], + units: statesFunctions.polygonOffset[1] }, depthRange : { - near : depthRange[0], - far : depthRange[1] + near: statesFunctions.depthRange[0], + far: statesFunctions.depthRange[1] }, depthTest : { enabled : booleanStates[WebGLConstants.DEPTH_TEST], func : defined(statesFunctions.depthFunc) ? statesFunctions.depthFunc[0] : WebGLConstants.LESS }, colorMask : { - red : colorMask[0], - green : colorMask[1], - blue : colorMask[2], - alpha : colorMask[3] + red: statesFunctions.colorMask[0], + green: statesFunctions.colorMask[1], + blue: statesFunctions.colorMask[2], + alpha: statesFunctions.colorMask[3] }, depthMask : defined(statesFunctions.depthMask) ? statesFunctions.depthMask[0] : true, blending : { enabled : booleanStates[WebGLConstants.BLEND], color : { - red : blendColor[0], - green : blendColor[1], - blue : blendColor[2], - alpha : blendColor[3] + red: statesFunctions.blendColor[0], + green: statesFunctions.blendColor[1], + blue: statesFunctions.blendColor[2], + alpha: statesFunctions.blendColor[3] }, equationRgb : blendEquationSeparate[0], equationAlpha : blendEquationSeparate[1], @@ -2864,6 +2877,56 @@ define([ return gltfUniformsFromNode[semantic](uniformState, model, runtimeNode); } + function createUniformsForMaterial(model, technique, instanceValues, context, textures, defaultTexture) { + var uniformMap = {}; + var uniformValues = {}; + var jointMatrixUniformName; + var morphWeightsUniformName; + + ForEach.techniqueUniform(technique, function(uniform, uniformName) { + // GLTF_SPEC: This does not take into account uniform arrays, + // indicated by uniforms with a count property. + // + // https://github.com/KhronosGroup/glTF/issues/258 + + // GLTF_SPEC: In this implementation, material parameters with a + // semantic or targeted via a source (for animation) are not + // targetable for material animations. Is this too strict? + // + // https://github.com/KhronosGroup/glTF/issues/142 + + if (defined(instanceValues[uniformName])) { + // Parameter overrides by the instance technique + var uv = ModelUtility.createUniformFunction(uniform.type, instanceValues[uniformName], textures, defaultTexture); + uniformMap[uniformName] = uv.func; + uniformValues[uniformName] = uv; + } else if (defined(uniform.node)) { + uniformMap[uniformName] = getUniformFunctionFromSource(uniform.node, model, uniform.semantic, context.uniformState); + } else if (defined(uniform.semantic)) { + if (uniform.semantic === 'JOINTMATRIX') { + jointMatrixUniformName = uniformName; + } else if (uniform.semantic === 'MORPHWEIGHTS') { + morphWeightsUniformName = uniformName; + } else { + // Map glTF semantic to Cesium automatic uniform + uniformMap[uniformName] = ModelUtility.getGltfSemanticUniforms()[uniform.semantic](context.uniformState, model); + } + } else if (defined(uniform.value)) { + // Technique value that isn't overridden by a material + var uv2 = ModelUtility.createUniformFunction(uniform.type, uniform.value, textures, defaultTexture); + uniformMap[uniformName] = uv2.func; + uniformValues[uniformName] = uv2; + } + }); + + return { + map : uniformMap, // uniform name -> function for the renderer + values : uniformValues, // material parameter name -> ModelMaterial for modifying the parameter at runtime + jointMatrixUniformName : jointMatrixUniformName, + morphWeightsUniformName : morphWeightsUniformName + }; + } + function createUniformMaps(model, context) { var loadResources = model._loadResources; @@ -2877,76 +2940,25 @@ define([ loadResources.createUniformMaps = false; var gltf = model.gltf; - var materials = gltf.materials; - var techniques = gltf.techniques; + var techniques = model._sourceTechniques; var uniformMaps = model._uniformMaps; var textures = model._rendererResources.textures; var defaultTexture = model._defaultTexture; - for (var materialId in materials) { - if (materials.hasOwnProperty(materialId)) { - var material = materials[materialId]; - var instanceParameters; - instanceParameters = material.values; - var technique = techniques[material.technique]; - var parameters = technique.parameters; - var uniforms = technique.uniforms; - - var uniformMap = {}; - var uniformValues = {}; - var jointMatrixUniformName; - var morphWeightsUniformName; - - // Uniform parameters - for (var name in uniforms) { - if (uniforms.hasOwnProperty(name) && name !== 'extras') { - var parameterName = uniforms[name]; - var parameter = parameters[parameterName]; - - // GLTF_SPEC: This does not take into account uniform arrays, - // indicated by parameters with a count property. - // - // https://github.com/KhronosGroup/glTF/issues/258 - - // GLTF_SPEC: In this implementation, material parameters with a - // semantic or targeted via a source (for animation) are not - // targetable for material animations. Is this too strict? - // - // https://github.com/KhronosGroup/glTF/issues/142 - - if (defined(instanceParameters[parameterName])) { - // Parameter overrides by the instance technique - var uv = ModelUtility.createUniformFunction(parameter.type, instanceParameters[parameterName], textures, defaultTexture); - uniformMap[name] = uv.func; - uniformValues[parameterName] = uv; - } else if (defined(parameter.node)) { - uniformMap[name] = getUniformFunctionFromSource(parameter.node, model, parameter.semantic, context.uniformState); - } else if (defined(parameter.semantic)) { - if (parameter.semantic === 'JOINTMATRIX') { - jointMatrixUniformName = name; - } else if (parameter.semantic === 'MORPHWEIGHTS') { - morphWeightsUniformName = name; - } else { - // Map glTF semantic to Cesium automatic uniform - uniformMap[name] = ModelUtility.getGltfSemanticUniforms()[parameter.semantic](context.uniformState, model); - } - } else if (defined(parameter.value)) { - // Technique value that isn't overridden by a material - var uv2 = ModelUtility.createUniformFunction(parameter.type, parameter.value, textures, defaultTexture); - uniformMap[name] = uv2.func; - uniformValues[parameterName] = uv2; - } - } - } + ForEach.material(gltf, function (material, materialId) { + var modelMaterial = model._runtime.materialsById[materialId]; + var technique = techniques[modelMaterial._technique]; + var instanceValues = modelMaterial._values; - var u = uniformMaps[materialId]; - u.uniformMap = uniformMap; // uniform name -> function for the renderer - u.values = uniformValues; // material parameter name -> ModelMaterial for modifying the parameter at runtime - u.jointMatrixUniformName = jointMatrixUniformName; - u.morphWeightsUniformName = morphWeightsUniformName; - } - } + var uniforms = createUniformsForMaterial(model, technique, instanceValues, context, textures, defaultTexture); + + var u = uniformMaps[materialId]; + u.uniformMap = uniforms.map; // uniform name -> function for the renderer + u.values = uniforms.values; // material parameter name -> ModelMaterial for modifying the parameter at runtime + u.jointMatrixUniformName = uniforms.jointMatrixUniformName; + u.morphWeightsUniformName = uniforms.morphWeightsUniformName; + }); } function createUniformsForDracoQuantizedAttributes(decodedData) { @@ -3059,8 +3071,6 @@ define([ var gltf = model.gltf; var accessors = gltf.accessors; var gltfMeshes = gltf.meshes; - var techniques = gltf.techniques; - var materials = gltf.materials; var id = gltfNode.mesh; var mesh = gltfMeshes[id]; @@ -3075,9 +3085,8 @@ define([ for (var i = 0; i < length; ++i) { var primitive = primitives[i]; var ix = accessors[primitive.indices]; - var material = materials[primitive.material]; - var technique = techniques[material.technique]; - var programId = technique.program; + var material = model._runtime.materialsById[primitive.material]; + var programId = material._program; var decodedData = model._decodedData[id + '.primitive.' + i]; var boundingSphere; @@ -3146,9 +3155,9 @@ define([ } uniformMap = combine(uniformMap, quantizedUniformMap); - var rs = rendererRenderStates[material.technique]; + var rs = rendererRenderStates[primitive.material]; - // GLTF_SPEC: Offical means to determine translucency. https://github.com/KhronosGroup/glTF/issues/105 + // GLTF_SPEC: Official means to determine translucency. https://github.com/KhronosGroup/glTF/issues/105 var isTranslucent = rs.blending.enabled; var owner = model._pickObject; @@ -3294,15 +3303,17 @@ define([ } var children = gltfNode.children; - var childrenLength = children.length; - for (var j = 0; j < childrenLength; j++) { - var childId = children[j]; - if (!seen[childId]) { - stack.push({ - parentRuntimeNode : runtimeNode, - gltfNode : nodes[childId], - id : children[j] - }); + if (defined(children)) { + var childrenLength = children.length; + for (var j = 0; j < childrenLength; j++) { + var childId = children[j]; + if (!seen[childId]) { + stack.push({ + parentRuntimeNode : runtimeNode, + gltfNode : nodes[childId], + id : children[j] + }); + } } } @@ -3354,28 +3365,28 @@ define([ var context = frameState.context; var scene3DOnly = frameState.scene3DOnly; - // Retain references to updated source shaders and programs for rebuilding as needed - var programs = model._sourcePrograms = model.gltf.programs; - var shaders = model._sourceShaders = model.gltf.shaders; + // Retain references to updated source shaders for rebuilding as needed + var shaders = model._sourceShaders; model._hasPremultipliedAlpha = hasPremultipliedAlpha(model); var quantizedVertexShaders = model._quantizedVertexShaders; var toClipCoordinates = model._toClipCoordinatesGLSL = {}; - for (var id in programs) { - if (programs.hasOwnProperty(id)) { - var program = programs[id]; + var programs = model._sourcePrograms; + for (var programId in programs) { + if (programs.hasOwnProperty(programId)) { + var program = programs[programId]; var shader = shaders[program.vertexShader].extras._pipeline.source; if (model.extensionsUsed.WEB3D_quantized_attributes || model._dequantizeInShader) { - var quantizedVS = quantizedVertexShaders[id]; + var quantizedVS = quantizedVertexShaders[programId]; if (!defined(quantizedVS)) { - quantizedVS = modifyShaderForQuantizedAttributes(shader, id, model); - quantizedVertexShaders[id] = quantizedVS; + quantizedVS = modifyShaderForQuantizedAttributes(shader, programId, model); + quantizedVertexShaders[programId] = quantizedVS; } shader = quantizedVS; } - shader = modifyShader(shader, id, model._vertexShaderLoaded); - toClipCoordinates[id] = ModelUtility.toClipCoordinatesGLSL(model.gltf, shader); + shader = modifyShader(shader, programId, model._vertexShaderLoaded); + toClipCoordinates[programId] = ModelUtility.toClipCoordinatesGLSL(model.gltf, shader); } } @@ -3429,7 +3440,7 @@ define([ var publicMatrix = publicNode.matrix; if (publicNode.useMatrix && defined(publicMatrix)) { - // Public matrix overrides orginial glTF matrix and glTF animations + // Public matrix overrides original glTF matrix and glTF animations Matrix4.clone(publicMatrix, result); } else if (defined(node.matrix)) { Matrix4.clone(node.matrix, result); @@ -3513,28 +3524,30 @@ define([ } var children = n.children; - var childrenLength = children.length; - for (var k = 0; k < childrenLength; ++k) { - var child = children[k]; - - // A node's transform needs to be updated if - // - It was targeted for animation this frame, or - // - Any of its ancestors were targeted for animation this frame - - // PERFORMANCE_IDEA: if a child has multiple parents and only one of the parents - // is dirty, all the subtrees for each child instance will be dirty; we probably - // won't see this in the wild often. - child.dirtyNumber = Math.max(child.dirtyNumber, n.dirtyNumber); - - if ((child.dirtyNumber === maxDirtyNumber) || justLoaded) { - // Don't check for modelTransformChanged since if only the model's model matrix changed, - // we do not need to rebuild the local transform-to-root, only the final - // [model's-model-matrix][transform-to-root] above. - getNodeMatrix(child, child.transformToRoot); - Matrix4.multiplyTransformation(transformToRoot, child.transformToRoot, child.transformToRoot); - } + if (defined(children)) { + var childrenLength = children.length; + for (var k = 0; k < childrenLength; ++k) { + var child = children[k]; + + // A node's transform needs to be updated if + // - It was targeted for animation this frame, or + // - Any of its ancestors were targeted for animation this frame + + // PERFORMANCE_IDEA: if a child has multiple parents and only one of the parents + // is dirty, all the subtrees for each child instance will be dirty; we probably + // won't see this in the wild often. + child.dirtyNumber = Math.max(child.dirtyNumber, n.dirtyNumber); + + if ((child.dirtyNumber === maxDirtyNumber) || justLoaded) { + // Don't check for modelTransformChanged since if only the model's model matrix changed, + // we do not need to rebuild the local transform-to-root, only the final + // [model's-model-matrix][transform-to-root] above. + getNodeMatrix(child, child.transformToRoot); + Matrix4.multiplyTransformation(transformToRoot, child.transformToRoot, child.transformToRoot); + } - nodeStack.push(child); + nodeStack.push(child); + } } } } @@ -3600,12 +3613,14 @@ define([ // if commandsLength is zero, the node has a light or camera var children = n.children; - var childrenLength = children.length; - for (var k = 0; k < childrenLength; ++k) { - var child = children[k]; - // Parent needs to be shown for child to be shown. - child.computedShow = show && child.publicNode.show; - nodeStack.push(child); + if (defined(children)) { + var childrenLength = children.length; + for (var k = 0; k < childrenLength; ++k) { + var child = children[k]; + // Parent needs to be shown for child to be shown. + child.computedShow = show && child.publicNode.show; + nodeStack.push(child); + } } } } @@ -4242,20 +4257,24 @@ define([ // Textures may continue to stream in while in the LOADED state. if (loadResources.pendingBufferLoads === 0) { if (!loadResources.initialized) { - // glTF pipeline updates - var options = { - optimizeForCesium: true, - addBatchIdToGeneratedShaders : this._addBatchIdToGeneratedShaders - }; frameState.brdfLutGenerator.update(frameState); + + ModelUtility.checkSupportedExtensions(this.extensionsRequired); + + // glTF pipeline updates + addPipelineExtras(this.gltf); + updateVersion(this.gltf); if (defined(this.gltf.asset) && defined(this.gltf.asset.extras) && this.gltf.asset.extras.gltf_pipeline_upgrade_10to20) { - this._forwardAxis = Axis.X; + this._forwardAxis = Axis.X; } - ModelUtility.checkSupportedExtensions(this.extensionsRequired); - addPipelineExtras(this.gltf); + addDefaults(this.gltf); + + var options = { + addBatchIdToGeneratedShaders: this._addBatchIdToGeneratedShaders + }; processModelMaterialsCommon(this.gltf, options); processPbrMetallicRoughness(this.gltf, options); @@ -4314,6 +4333,8 @@ define([ } if (loadResources.finished()) { + ModelUtility.removePipelineExtras(this.gltf); + this._loadResources = undefined; // Clear CPU memory since WebGL resources were created. var resources = this._rendererResources; @@ -4415,7 +4436,7 @@ define([ updateShadows(this); updateClippingPlanes(this, frameState); - // Regnerate shaders if ClippingPlaneCollection state changed or it was removed + // Regenerate shaders if ClippingPlaneCollection state changed or it was removed var clippingPlanes = this._clippingPlanes; var currentClippingPlanesState = 0; if (defined(clippingPlanes) && clippingPlanes.enabled) { @@ -4531,15 +4552,28 @@ define([ var cachedRendererResources = model._cachedRendererResources; destroyIfNotCached(rendererResources, cachedRendererResources); + var programId; if (isClippingEnabled(model) || isColorShadingEnabled(model)) { rendererResources.programs = {}; rendererResources.silhouettePrograms = {}; - var sourcePrograms = model._sourcePrograms; - - ForEach.object(sourcePrograms, function(program, id) { - recreateProgram(id, model, frameState.context); - }); + var visitedPrograms = {}; + var techniques = model._sourceTechniques; + var technique; + + for (var techniqueId in techniques) { + if (techniques.hasOwnProperty(techniqueId)) { + technique = techniques[techniqueId]; + programId = technique.program; + if (!visitedPrograms[programId]) { + visitedPrograms[programId] = true; + recreateProgram({ + id: programId, + technique: techniqueId + }, model, frameState.context); + } + } + } } else { rendererResources.programs = cachedRendererResources.programs; rendererResources.silhouettePrograms = cachedRendererResources.silhouettePrograms; @@ -4552,7 +4586,7 @@ define([ var commandCount = nodeCommands.length; for (var i = 0; i < commandCount; ++i) { var nodeCommand = nodeCommands[i]; - var programId = nodeCommand.programId; + programId = nodeCommand.programId; var renderProgram = rendererPrograms[programId]; nodeCommand.command.shaderProgram = renderProgram; @@ -4628,7 +4662,6 @@ define([ } releaseCachedGltf(this); - this._sourcePrograms = undefined; this._sourceShaders = undefined; this._quantizedVertexShaders = undefined; diff --git a/Source/Scene/ModelInstanceCollection.js b/Source/Scene/ModelInstanceCollection.js index d79691f689bb..678dd4c0251b 100644 --- a/Source/Scene/ModelInstanceCollection.js +++ b/Source/Scene/ModelInstanceCollection.js @@ -19,6 +19,7 @@ define([ '../Renderer/DrawCommand', '../Renderer/Pass', '../Renderer/ShaderSource', + '../ThirdParty/GltfPipeline/ForEach', '../ThirdParty/when', './Model', './ModelInstance', @@ -46,6 +47,7 @@ define([ DrawCommand, Pass, ShaderSource, + ForEach, when, Model, ModelInstance, @@ -225,6 +227,22 @@ define([ BoundingSphere.expand(this._boundingSphere, translation, this._boundingSphere); }; + function getCheckUniformSemanticFunction(modelSemantics, supportedSemantics, programId, uniformMap) { + return function(uniform, uniformName) { + var semantic = uniform.semantic; + if (defined(semantic) && (modelSemantics.indexOf(semantic) > -1)) { + if (supportedSemantics.indexOf(semantic) > -1) { + uniformMap[uniformName] = semantic; + } else { + throw new RuntimeError('Shader program cannot be optimized for instancing. ' + + 'Uniform "' + uniformName + '" in program "' + programId + + '" uses unsupported semantic "' + semantic + '"' + ); + } + } + }; + } + function getInstancedUniforms(collection, programId) { if (defined(collection._instancedUniformsByProgram)) { return collection._instancedUniformsByProgram[programId]; @@ -237,13 +255,10 @@ define([ var modelSemantics = ['MODEL', 'MODELVIEW', 'CESIUM_RTC_MODELVIEW', 'MODELVIEWPROJECTION', 'MODELINVERSE', 'MODELVIEWINVERSE', 'MODELVIEWPROJECTIONINVERSE', 'MODELINVERSETRANSPOSE', 'MODELVIEWINVERSETRANSPOSE']; var supportedSemantics = ['MODELVIEW', 'CESIUM_RTC_MODELVIEW', 'MODELVIEWPROJECTION', 'MODELVIEWINVERSETRANSPOSE']; - var gltf = collection._model.gltf; - var techniques = gltf.techniques; + var techniques = collection._model._sourceTechniques; for (var techniqueName in techniques) { if (techniques.hasOwnProperty(techniqueName)) { var technique = techniques[techniqueName]; - var parameters = technique.parameters; - var uniforms = technique.uniforms; var program = technique.program; // Different techniques may share the same program, skip if already processed. @@ -251,23 +266,7 @@ define([ if (!defined(instancedUniformsByProgram[program])) { var uniformMap = {}; instancedUniformsByProgram[program] = uniformMap; - for (var uniformName in uniforms) { - if (uniforms.hasOwnProperty(uniformName)) { - var parameterName = uniforms[uniformName]; - var parameter = parameters[parameterName]; - var semantic = parameter.semantic; - if (defined(semantic) && (modelSemantics.indexOf(semantic) > -1)) { - if (supportedSemantics.indexOf(semantic) > -1) { - uniformMap[uniformName] = semantic; - } else { - throw new RuntimeError('Shader program cannot be optimized for instancing. ' + - 'Parameter "' + parameter + '" in program "' + programId + - '" uses unsupported semantic "' + semantic + '"' - ); - } - } - } - } + ForEach.techniqueUniform(technique, getCheckUniformSemanticFunction(modelSemantics, supportedSemantics, programId, uniformMap)); } } } diff --git a/Source/Scene/ModelMaterial.js b/Source/Scene/ModelMaterial.js index cc149d1be3dd..5726a532ef14 100644 --- a/Source/Scene/ModelMaterial.js +++ b/Source/Scene/ModelMaterial.js @@ -26,6 +26,10 @@ define([ this._name = material.name; this._id = id; this._uniformMap = model._uniformMaps[id]; + + this._technique = undefined; + this._program = undefined; + this._values = undefined; } defineProperties(ModelMaterial.prototype, { diff --git a/Source/Scene/ModelUtility.js b/Source/Scene/ModelUtility.js index 9e7524ef3f05..d1cdd8cb83c4 100644 --- a/Source/Scene/ModelUtility.js +++ b/Source/Scene/ModelUtility.js @@ -2,6 +2,7 @@ define([ '../Core/Cartesian2', '../Core/Cartesian3', '../Core/Cartesian4', + '../Core/clone', '../Core/defined', '../Core/defineProperties', '../Core/Matrix2', @@ -11,11 +12,15 @@ define([ '../Core/RuntimeError', '../Core/WebGLConstants', '../Renderer/ShaderSource', + '../ThirdParty/GltfPipeline/addToArray', + '../ThirdParty/GltfPipeline/ForEach', + '../ThirdParty/GltfPipeline/hasExtension', './AttributeType' ], function( Cartesian2, Cartesian3, Cartesian4, + clone, defined, defineProperties, Matrix2, @@ -25,6 +30,9 @@ define([ RuntimeError, WebGLConstants, ShaderSource, + addToArray, + ForEach, + hasExtension, AttributeType) { 'use strict'; @@ -33,6 +41,245 @@ define([ */ var ModelUtility = {}; + function removeExtrasIfEmpty(object) { + if (!defined(object.extras)) { + return; + } + + var pipeline = object.extras._pipeline; + if (!defined(pipeline)) { + return; + } + + if (Object.keys(pipeline).length === 0) { + delete object.extras; + } + } + + /** + * Removes empty extra._pipeline object from each object that can have extras in the glTF asset. + * + * @param {Object} gltf A javascript object containing a glTF asset. + * @returns {Object} The glTF asset with the added pipeline extras. + */ + ModelUtility.removePipelineExtras = function(gltf) { + ForEach.shader(gltf, function(shader) { + removeExtrasIfEmpty(shader); + }); + ForEach.buffer(gltf, function(buffer) { + removeExtrasIfEmpty(buffer); + }); + ForEach.image(gltf, function(image) { + removeExtrasIfEmpty(image); + ForEach.compressedImage(image, function(compressedImage) { + removeExtrasIfEmpty(compressedImage); + }); + }); + + removeExtrasIfEmpty(gltf); + + return gltf; + }; + + /** + * 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; + ForEach.mesh(gltf, function(mesh) { + ForEach.meshPrimitive(mesh, function(primitive) { + var materialId = primitive.material; + var material = materials[materialId]; + + 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); + + if (!defined(material.extras) || !defined(material.extras._pipeline)) { + material.extras = { + _pipeline: {} + }; + } + + var primitiveInfo = material.extras._pipeline.primitive; + if (!defined(primitiveInfo)) { + material.extras._pipeline.primitive = { + 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); + clonedMaterial.extras._pipeline.primitive = { + skinning: { + skinned: isSkinned, + componentType: componentType, + type: type + }, + hasVertexColors: hasVertexColors, + hasMorphTargets: hasMorphTargets, + hasNormals: hasNormals, + hasTangents: hasTangents, + hasTexCoords: hasTexCoords + }; + // Split this off as a separate material + materialId = addToArray(materials, clonedMaterial); + primitive.material = materialId; + } + }); + }); + + return gltf; + }; + + ModelUtility.getShaderVariable = function(type) { + if (type === 'SCALAR') { + return 'float'; + } + return type.toLowerCase(); + }; + + 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 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)) { + attributeLocations[attributeName] = 0; + } 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; @@ -52,37 +299,37 @@ define([ }; }; - ModelUtility.getAttributeOrUniformBySemantic = function(gltf, semantic, programId, ignoreNodes) { - var techniques = gltf.techniques; - var parameter; - for (var techniqueName in techniques) { - if (techniques.hasOwnProperty(techniqueName)) { - var technique = techniques[techniqueName]; - if (defined(programId) && (technique.program !== programId)) { - continue; - } - var parameters = technique.parameters; - var attributes = technique.attributes; - var uniforms = technique.uniforms; - for (var attributeName in attributes) { - if (attributes.hasOwnProperty(attributeName)) { - parameter = parameters[attributes[attributeName]]; - if (defined(parameter) && parameter.semantic === semantic && (!ignoreNodes || !defined(parameter.node))) { - return attributeName; - } - } - } - for (var uniformName in uniforms) { - if (uniforms.hasOwnProperty(uniformName)) { - parameter = parameters[uniforms[uniformName]]; - if (defined(parameter) && parameter.semantic === semantic && (!ignoreNodes || !defined(parameter.node))) { - return uniformName; - } - } + 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 undefined; + + 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) { @@ -138,15 +385,20 @@ define([ return cachedExtensionsRequired; }; + ModelUtility.supportedExtensions = { + 'CESIUM_RTC' : true, + 'EXT_blend' : true, + 'KHR_binary_glTF' : true, + 'KHR_draco_mesh_compression' : true, + 'KHR_materials_common' : true, + 'KHR_techniques_webgl': true, + 'WEB3D_quantized_attributes' : true + }; + ModelUtility.checkSupportedExtensions = function(extensionsRequired) { for (var extension in extensionsRequired) { if (extensionsRequired.hasOwnProperty(extension)) { - if (extension !== 'CESIUM_RTC' && - extension !== 'KHR_technique_webgl' && - extension !== 'KHR_binary_glTF' && - extension !== 'KHR_materials_common' && - extension !== 'WEB3D_quantized_attributes' && - extension !== 'KHR_draco_mesh_compression') { + if (!ModelUtility.supportedExtensions[extension]) { throw new RuntimeError('Unsupported glTF Extension: ' + extension); } } @@ -190,25 +442,22 @@ define([ function getAttributeVariableName(gltf, primitive, attributeSemantic) { var materialId = primitive.material; var material = gltf.materials[materialId]; - var techniqueId = material.technique; - var technique = gltf.techniques[techniqueId]; - for (var parameter in technique.parameters) { - if (technique.parameters.hasOwnProperty(parameter)) { - var semantic = technique.parameters[parameter].semantic; - if (semantic === attributeSemantic) { - var attributes = technique.attributes; - for (var attributeVarName in attributes) { - if (attributes.hasOwnProperty(attributeVarName)) { - var name = attributes[attributeVarName]; - if (name === parameter) { - return attributeVarName; - } - } - } - } - } + + if (!hasExtension(gltf, 'KHR_techniques_webgl') + || !defined(material.extensions) + || !defined(material.extensions.KHR_techniques_webgl)) { + return; } - return undefined; + + 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) { @@ -516,8 +765,8 @@ define([ /////////////////////////////////////////////////////////////////////////// - function getTextureUniformFunction(value, texture, defaultTexture) { - var uniform = new DelayLoadedTextureUniform(value, texture, defaultTexture); + 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() { diff --git a/Source/ThirdParty/GltfPipeline/processModelMaterialsCommon.js b/Source/Scene/processModelMaterialsCommon.js similarity index 62% rename from Source/ThirdParty/GltfPipeline/processModelMaterialsCommon.js rename to Source/Scene/processModelMaterialsCommon.js index bcf942379723..c8fd54254680 100644 --- a/Source/ThirdParty/GltfPipeline/processModelMaterialsCommon.js +++ b/Source/Scene/processModelMaterialsCommon.js @@ -1,25 +1,24 @@ define([ - './addToArray', - './ForEach', - './numberOfComponentsForType', - './techniqueParameterForSemantic', - './webGLConstantToGlslType', - './glslTypeToWebGLConstant', - '../../Core/clone', - '../../Core/defined', - '../../Core/defaultValue', - '../../Core/WebGLConstants' + './ModelUtility', + '../Core/defined', + '../Core/defaultValue', + '../Core/WebGLConstants', + '../Core/webGLConstantToGlslType', + '../ThirdParty/GltfPipeline/addToArray', + '../ThirdParty/GltfPipeline/ForEach', + '../ThirdParty/GltfPipeline/hasExtension', + '../ThirdParty/GltfPipeline/numberOfComponentsForType' ], function( - addToArray, - ForEach, - numberOfComponentsForType, - techniqueParameterForSemantic, - webGLConstantToGlslType, - glslTypeToWebGLConstant, - clone, + ModelUtility, defined, defaultValue, - WebGLConstants) { + WebGLConstants, + webGLConstantToGlslType, + addToArray, + ForEach, + hasExtension, + numberOfComponentsForType + ) { 'use strict'; /** @@ -29,85 +28,81 @@ define([ options = defaultValue(options, {}); if (!defined(gltf)) { - return undefined; + return; } - var hasExtension = false; - var extensionsRequired = gltf.extensionsRequired; - var extensionsUsed = gltf.extensionsUsed; - if (defined(extensionsUsed)) { - var index = extensionsUsed.indexOf('KHR_materials_common'); - if (index >= 0) { - extensionsUsed.splice(index, 1); - hasExtension = true; - } - if (defined(extensionsRequired)) { - index = extensionsRequired.indexOf('KHR_materials_common'); - if (index >= 0) { - extensionsRequired.splice(index, 1); - } - } + if (!hasExtension(gltf, 'KHR_materials_common')) { + return; } - if (hasExtension) { - if (!defined(gltf.programs)) { - gltf.programs = []; - } - if (!defined(gltf.shaders)) { - gltf.shaders = []; - } - if (!defined(gltf.techniques)) { - gltf.techniques = []; - } - lightDefaults(gltf); - - var lightParameters = generateLightParameters(gltf); - - // Pre-processing to address incompatibilities between primitives using the same materials. Handles skinning and vertex color incompatibilities. - splitIncompatibleMaterials(gltf); - - var techniques = {}; - ForEach.material(gltf, function(material) { - if (defined(material.extensions) && defined(material.extensions.KHR_materials_common)) { - var khrMaterialsCommon = material.extensions.KHR_materials_common; - var techniqueKey = getTechniqueKey(khrMaterialsCommon); - var technique = techniques[techniqueKey]; - if (!defined(technique)) { - technique = generateTechnique(gltf, khrMaterialsCommon, lightParameters, options); - techniques[techniqueKey] = technique; - } + if (!hasExtension('KHR_techniques_webgl')) { + gltf.extensions.KHR_techniques_webgl = { + programs : [], + shaders : [], + techniques : [] + }; + gltf.extensionsUsed.push('KHR_techniques_webgl'); + gltf.extensionsRequired.push('KHR_techniques_webgl'); + } - // Take advantage of the fact that we generate techniques that use the - // same parameter names as the extension values. - material.values = {}; - var values = khrMaterialsCommon.values; - for (var valueName in values) { - if (values.hasOwnProperty(valueName)) { - var value = values[valueName]; - material.values[valueName] = value; - } - } + var techniquesWebgl = gltf.extensions.KHR_techniques_webgl; + + lightDefaults(gltf); - material.technique = technique; + var lightParameters = generateLightParameters(gltf); - delete material.extensions.KHR_materials_common; - if (Object.keys(material.extensions).length === 0) { - delete material.extensions; + ModelUtility.splitIncompatibleMaterials (gltf); + + var techniques = {}; + ForEach.material(gltf, function(material) { + if (defined(material.extensions) && defined(material.extensions.KHR_materials_common)) { + var khrMaterialsCommon = material.extensions.KHR_materials_common; + var techniqueKey = getTechniqueKey(material, khrMaterialsCommon); + var technique = techniques[techniqueKey]; + var primitiveInfo = material.extras._pipeline.primitive; + + if (!defined(technique)) { + technique = generateTechnique(gltf, techniquesWebgl, primitiveInfo, khrMaterialsCommon, lightParameters, options.addBatchIdToGeneratedShaders); + techniques[techniqueKey] = technique; + } + + var materialValues = {}; + var values = khrMaterialsCommon.values; + var uniformName; + for (var valueName in values) { + if (values.hasOwnProperty(valueName) && (valueName !== 'transparent') && (valueName !== 'doubleSided')) { + uniformName = 'u_' + valueName.toLowerCase(); + materialValues[uniformName] = values[valueName]; } } - }); - if (defined(gltf.extensions)) { - delete gltf.extensions.KHR_materials_common; - if (Object.keys(gltf.extensions).length === 0) { - delete gltf.extensions; + material.extensions.KHR_techniques_webgl = { + technique: technique, + values: materialValues + }; + + if (khrMaterialsCommon.transparent) { + material.alphaMode = 'BLEND'; + material.extensions.KHR_blend = { + blendFactors: [ + WebGLConstants.ONE, + WebGLConstants.ONE_MINUS_SRC_ALPHA, + WebGLConstants.ONE, + WebGLConstants.ONE_MINUS_SRC_ALPHA + ] + }; + if (!hasExtension(gltf, 'KHR_blend')) { + gltf.extensions.push('KHR_blend'); + } + } else if (khrMaterialsCommon.doubleSided) { + material.doubleSided = true; } } + }); - // If any primitives have semantics that aren't declared in the generated - // shaders, we want to preserve them. - ensureSemanticExistence(gltf); - } + // If any primitives have semantics that aren't declared in the generated + // shaders, we want to preserve them. + ModelUtility.ensureSemanticExistence(gltf); return gltf; } @@ -226,28 +221,17 @@ define([ return result; } - function generateTechnique(gltf, khrMaterialsCommon, lightParameters, options) { - var optimizeForCesium = defaultValue(options.optimizeForCesium, false); - var hasCesiumRTCExtension = defined(gltf.extensions) && defined(gltf.extensions.CESIUM_RTC); - var addBatchIdToGeneratedShaders = defaultValue(options.addBatchIdToGeneratedShaders, false); + function generateTechnique(gltf, techniquesWebgl, primitiveInfo, khrMaterialsCommon, lightParameters, addBatchIdToGeneratedShaders) { + addBatchIdToGeneratedShaders = defaultValue(addBatchIdToGeneratedShaders, false); - var techniques = gltf.techniques; - var shaders = gltf.shaders; - var programs = gltf.programs; + var techniques = techniquesWebgl.techniques; + var shaders = techniquesWebgl.shaders; + var programs = techniquesWebgl.programs; var lightingModel = khrMaterialsCommon.technique.toUpperCase(); - var lights; - if (defined(gltf.extensions) && defined(gltf.extensions.KHR_materials_common)) { - lights = gltf.extensions.KHR_materials_common.lights; - } + var lights = gltf.extensions.KHR_materials_common.lights; + var parameterValues = khrMaterialsCommon.values; - if (defined(khrMaterialsCommon.transparent)) { - parameterValues.transparent = khrMaterialsCommon.transparent; - } - if (defined(khrMaterialsCommon.doubleSided)) { - parameterValues.doubleSided = khrMaterialsCommon.doubleSided; - } var jointCount = defaultValue(khrMaterialsCommon.jointCount, 0); - var primitiveInfo = khrMaterialsCommon.extras._pipeline.primitive; var skinningInfo; var hasSkinning = false; @@ -265,78 +249,77 @@ define([ var hasNormals = (lightingModel !== 'CONSTANT'); // Add techniques - var techniqueParameters = { - // Add matrices - modelViewMatrix: { - semantic: hasCesiumRTCExtension ? 'CESIUM_RTC_MODELVIEW' : 'MODELVIEW', + var techniqueUniforms = { + u_modelViewMatrix: { + semantic: hasExtension(gltf, 'CESIUM_RTC') ? 'CESIUM_RTC_MODELVIEW' : 'MODELVIEW', type: WebGLConstants.FLOAT_MAT4 }, - projectionMatrix: { + u_projectionMatrix: { semantic: 'PROJECTION', type: WebGLConstants.FLOAT_MAT4 } }; if (hasNormals) { - techniqueParameters.normalMatrix = { + techniqueUniforms.u_normalMatrix = { semantic: 'MODELVIEWINVERSETRANSPOSE', type: WebGLConstants.FLOAT_MAT3 }; } if (hasSkinning) { - techniqueParameters.jointMatrix = { + techniqueUniforms.u_jointMatrix = { count: jointCount, semantic: 'JOINTMATRIX', type: WebGLConstants.FLOAT_MAT4 }; } - // Add material parameters - var lowerCase; + // Add material values + var uniformName; var hasTexCoords = false; for (var name in parameterValues) { //generate shader parameters for KHR_materials_common attributes //(including a check, because some boolean flags should not be used as shader parameters) if (parameterValues.hasOwnProperty(name) && (name !== 'transparent') && (name !== 'doubleSided')) { - var valType = getKHRMaterialsCommonValueType(name, parameterValues[name]); - lowerCase = name.toLowerCase(); - if (!hasTexCoords && (valType === WebGLConstants.SAMPLER_2D)) { + var uniformType = getKHRMaterialsCommonValueType(name, parameterValues[name]); + uniformName = 'u_' + name.toLowerCase(); + if (!hasTexCoords && (uniformType === WebGLConstants.SAMPLER_2D)) { hasTexCoords = true; } - techniqueParameters[lowerCase] = { - type: valType + + techniqueUniforms[uniformName] = { + type : uniformType }; } } // Give the diffuse uniform a semantic to support color replacement in 3D Tiles - if (defined(techniqueParameters.diffuse) && optimizeForCesium) { - techniqueParameters.diffuse.semantic = '_3DTILESDIFFUSE'; + if (defined(techniqueUniforms.u_diffuse)) { + techniqueUniforms.u_diffuse.semantic = '_3DTILESDIFFUSE'; } // Copy light parameters into technique parameters if (defined(lightParameters)) { for (var lightParamName in lightParameters) { if (lightParameters.hasOwnProperty(lightParamName)) { - techniqueParameters[lightParamName] = lightParameters[lightParamName]; + uniformName = 'u_' + lightParamName; + techniqueUniforms[uniformName] = lightParameters[lightParamName]; } } } - // Generate uniforms object before attributes are added - var techniqueUniforms = {}; - for (var paramName in techniqueParameters) { - if (techniqueParameters.hasOwnProperty(paramName) && paramName !== 'extras') { - var param = techniqueParameters[paramName]; - techniqueUniforms['u_' + paramName] = paramName; - var arraySize = defined(param.count) ? '[' + param.count + ']' : ''; - if (((param.type !== WebGLConstants.FLOAT_MAT3) && (param.type !== WebGLConstants.FLOAT_MAT4)) || - param.useInFragment) { - fragmentShader += 'uniform ' + webGLConstantToGlslType(param.type) + ' u_' + paramName + arraySize + ';\n'; - delete param.useInFragment; + // Add uniforms to shaders + for (uniformName in techniqueUniforms) { + if (techniqueUniforms.hasOwnProperty(uniformName)) { + var uniform = techniqueUniforms[uniformName]; + var arraySize = defined(uniform.count) ? '[' + uniform.count + ']' : ''; + if (((uniform.type !== WebGLConstants.FLOAT_MAT3) && (uniform.type !== WebGLConstants.FLOAT_MAT4)) || + uniform.useInFragment) { + fragmentShader += 'uniform ' + webGLConstantToGlslType(uniform.type) + ' ' + uniformName + arraySize + ';\n'; + delete uniform.useInFragment; } else { - vertexShader += 'uniform ' + webGLConstantToGlslType(param.type) + ' u_' + paramName + arraySize + ';\n'; + vertexShader += 'uniform ' + webGLConstantToGlslType(uniform.type) + ' ' + uniformName + arraySize + ';\n'; } } } @@ -376,11 +359,9 @@ define([ // Add position always var techniqueAttributes = { - a_position: 'position' - }; - techniqueParameters.position = { - semantic: 'POSITION', - type: WebGLConstants.FLOAT_VEC3 + a_position: { + semantic : 'POSITION' + } }; vertexShader += 'attribute vec3 a_position;\n'; vertexShader += 'varying vec3 v_positionEC;\n'; @@ -395,10 +376,8 @@ define([ // Add normal if we don't have constant lighting if (hasNormals) { - techniqueAttributes.a_normal = 'normal'; - techniqueParameters.normal = { - semantic: 'NORMAL', - type: WebGLConstants.FLOAT_VEC3 + techniqueAttributes.a_normal = { + semantic: 'NORMAL' }; vertexShader += 'attribute vec3 a_normal;\n'; vertexShader += 'varying vec3 v_normal;\n'; @@ -414,10 +393,8 @@ define([ // Add texture coordinates if the material uses them var v_texcoord; if (hasTexCoords) { - techniqueAttributes.a_texcoord_0 = 'texcoord_0'; - techniqueParameters.texcoord_0 = { - semantic: 'TEXCOORD_0', - type: WebGLConstants.FLOAT_VEC2 + techniqueAttributes.a_texcoord_0 = { + semantic: 'TEXCOORD_0' }; v_texcoord = 'v_texcoord_0'; @@ -429,18 +406,12 @@ define([ } if (hasSkinning) { - techniqueAttributes.a_joint = 'joint'; - var attributeType = getShaderVariable(skinningInfo.type); - var webGLConstant = glslTypeToWebGLConstant(attributeType); - - techniqueParameters.joint = { - semantic: 'JOINT', - type: webGLConstant + var attributeType = ModelUtility.getShaderVariable(skinningInfo.type); + techniqueAttributes.a_joint = { + semantic: 'JOINT' }; - techniqueAttributes.a_weight = 'weight'; - techniqueParameters.weight = { - semantic: 'WEIGHT', - type: webGLConstant + techniqueAttributes.a_weight = { + semantic: 'WEIGHT' }; vertexShader += 'attribute ' + attributeType + ' a_joint;\n'; @@ -448,10 +419,8 @@ define([ } if (hasVertexColors) { - techniqueAttributes.a_vertexColor = 'vertexColor'; - techniqueParameters.vertexColor = { - semantic: 'COLOR_0', - type: WebGLConstants.FLOAT_VEC4 + techniqueAttributes.a_vertexColor = { + semantic: 'COLOR_0' }; vertexShader += 'attribute vec4 a_vertexColor;\n'; vertexShader += 'varying vec4 v_vertexColor;\n'; @@ -460,17 +429,15 @@ define([ } if (addBatchIdToGeneratedShaders) { - techniqueAttributes.a_batchId = 'batchId'; - techniqueParameters.batchId = { - semantic: '_BATCHID', - type: WebGLConstants.FLOAT + techniqueAttributes.a_batchId = { + semantic: '_BATCHID' }; vertexShader += 'attribute float a_batchId;\n'; } var hasSpecular = hasNormals && ((lightingModel === 'BLINN') || (lightingModel === 'PHONG')) && - defined(techniqueParameters.specular) && defined(techniqueParameters.shininess) && - (techniqueParameters.shininess > 0.0); + defined(techniqueUniforms.u_specular) && defined(techniqueUniforms.u_shininess) && + (techniqueUniforms.u_shininess > 0.0); // Generate lighting code blocks var hasNonAmbientLights = false; @@ -553,12 +520,8 @@ define([ } if (!hasNonAmbientLights && (lightingModel !== 'CONSTANT')) { - if (optimizeForCesium) { - fragmentLightingBlock += ' vec3 l = normalize(czm_sunDirectionEC);\n'; - } else { - fragmentLightingBlock += ' vec3 l = vec3(0.0, 0.0, 1.0);\n'; - } - var minimumLighting = optimizeForCesium ? '0.2' : '0.0'; // Use strings instead of values as 0.0 -> 0 when stringified + fragmentLightingBlock += ' vec3 l = normalize(czm_sunDirectionEC);\n'; + var minimumLighting = '0.2'; // Use strings instead of values as 0.0 -> 0 when stringified fragmentLightingBlock += ' diffuseLight += vec3(1.0, 1.0, 1.0) * max(dot(normal,l), ' + minimumLighting + ');\n'; if (hasSpecular) { @@ -592,8 +555,8 @@ define([ var finalColorComputation; if (lightingModel !== 'CONSTANT') { - if (defined(techniqueParameters.diffuse)) { - if (techniqueParameters.diffuse.type === WebGLConstants.SAMPLER_2D) { + if (defined(techniqueUniforms.u_diffuse)) { + if (techniqueUniforms.u_diffuse.type === WebGLConstants.SAMPLER_2D) { fragmentShader += ' vec4 diffuse = texture2D(u_diffuse, ' + v_texcoord + ');\n'; } else { fragmentShader += ' vec4 diffuse = u_diffuse;\n'; @@ -603,7 +566,7 @@ define([ } if (hasSpecular) { - if (techniqueParameters.specular.type === WebGLConstants.SAMPLER_2D) { + if (techniqueUniforms.u_specular.type === WebGLConstants.SAMPLER_2D) { fragmentShader += ' vec3 specular = texture2D(u_specular, ' + v_texcoord + ').rgb;\n'; } else { fragmentShader += ' vec3 specular = u_specular.rgb;\n'; @@ -612,25 +575,23 @@ define([ colorCreationBlock += ' color += specular * specularLight;\n'; } - if (defined(techniqueParameters.transparency)) { + if (defined(techniqueUniforms.u_transparency)) { finalColorComputation = ' gl_FragColor = vec4(color * diffuse.a * u_transparency, diffuse.a * u_transparency);\n'; } else { finalColorComputation = ' gl_FragColor = vec4(color * diffuse.a, diffuse.a);\n'; } - } else { - if (defined(techniqueParameters.transparency)) { + } else if (defined(techniqueUniforms.u_transparency)) { finalColorComputation = ' gl_FragColor = vec4(color * u_transparency, u_transparency);\n'; } else { finalColorComputation = ' gl_FragColor = vec4(color, 1.0);\n'; } - } if (hasVertexColors) { colorCreationBlock += ' color *= v_vertexColor.rgb;\n'; } - if (defined(techniqueParameters.emission)) { - if (techniqueParameters.emission.type === WebGLConstants.SAMPLER_2D) { + if (defined(techniqueUniforms.u_emission)) { + if (techniqueUniforms.u_emission.type === WebGLConstants.SAMPLER_2D) { fragmentShader += ' vec3 emission = texture2D(u_emission, ' + v_texcoord + ').rgb;\n'; } else { fragmentShader += ' vec3 emission = u_emission.rgb;\n'; @@ -638,9 +599,9 @@ define([ colorCreationBlock += ' color += emission;\n'; } - if (defined(techniqueParameters.ambient) || (lightingModel !== 'CONSTANT')) { - if (defined(techniqueParameters.ambient)) { - if (techniqueParameters.ambient.type === WebGLConstants.SAMPLER_2D) { + if (defined(techniqueUniforms.u_ambient) || (lightingModel !== 'CONSTANT')) { + if (defined(techniqueUniforms.u_ambient)) { + if (techniqueUniforms.u_ambient.type === WebGLConstants.SAMPLER_2D) { fragmentShader += ' vec3 ambient = texture2D(u_ambient, ' + v_texcoord + ').rgb;\n'; } else { fragmentShader += ' vec3 ambient = u_ambient.rgb;\n'; @@ -660,49 +621,13 @@ define([ fragmentShader += finalColorComputation; fragmentShader += '}\n'; - var techniqueStates; - if (parameterValues.transparent) { - techniqueStates = { - enable: [ - WebGLConstants.DEPTH_TEST, - WebGLConstants.BLEND - ], - functions: { - depthMask : [false], - blendEquationSeparate: [ - WebGLConstants.FUNC_ADD, - WebGLConstants.FUNC_ADD - ], - blendFuncSeparate: [ - WebGLConstants.ONE, - WebGLConstants.ONE_MINUS_SRC_ALPHA, - WebGLConstants.ONE, - WebGLConstants.ONE_MINUS_SRC_ALPHA - ] - } - }; - } else if (khrMaterialsCommon.doubleSided) { - techniqueStates = { - enable: [ - WebGLConstants.DEPTH_TEST - ] - }; - } else { // Not transparent or double sided - techniqueStates = { - enable: [ - WebGLConstants.CULL_FACE, - WebGLConstants.DEPTH_TEST - ] - }; - } - // Add shaders var vertexShaderId = addToArray(shaders, { type: WebGLConstants.VERTEX_SHADER, - extras: { - _pipeline: { - source: vertexShader, - extension: '.glsl' + extras: { + _pipeline: { + source: vertexShader, + extension: '.glsl' } } }); @@ -718,18 +643,14 @@ define([ }); // Add program - var programAttributes = Object.keys(techniqueAttributes); var programId = addToArray(programs, { - attributes: programAttributes, fragmentShader: fragmentShaderId, vertexShader: vertexShaderId }); var techniqueId = addToArray(techniques, { attributes: techniqueAttributes, - parameters: techniqueParameters, program: programId, - states: techniqueStates, uniforms: techniqueUniforms }); @@ -772,7 +693,7 @@ define([ } } - function getTechniqueKey(khrMaterialsCommon) { + function getTechniqueKey(material, khrMaterialsCommon) { var techniqueKey = ''; techniqueKey += 'technique:' + khrMaterialsCommon.technique + ';'; @@ -787,13 +708,9 @@ define([ } } - var doubleSided = defaultValue(khrMaterialsCommon.doubleSided, defaultValue(khrMaterialsCommon.values.doubleSided, false)); - techniqueKey += doubleSided.toString() + ';'; - var transparent = defaultValue(khrMaterialsCommon.transparent, defaultValue(khrMaterialsCommon.values.transparent, false)); - techniqueKey += transparent.toString() + ';'; var jointCount = defaultValue(khrMaterialsCommon.jointCount, 0); techniqueKey += jointCount.toString() + ';'; - var primitiveInfo = khrMaterialsCommon.extras._pipeline.primitive; + var primitiveInfo = material.extras._pipeline.primitive; if (defined(primitiveInfo)) { var skinningInfo = primitiveInfo.skinning; if (jointCount > 0) { @@ -806,15 +723,7 @@ define([ } function lightDefaults(gltf) { - if (!defined(gltf.extensions)) { - gltf.extensions = {}; - } - var extensions = gltf.extensions; - - if (!defined(extensions.KHR_materials_common)) { - extensions.KHR_materials_common = {}; - } - var khrMaterialsCommon = extensions.KHR_materials_common; + var khrMaterialsCommon = gltf.extensions.KHR_materials_common; if (!defined(khrMaterialsCommon.lights)) { khrMaterialsCommon.lights = {}; @@ -874,112 +783,5 @@ define([ } } - function getShaderVariable(type) { - if (type === 'SCALAR') { - return 'float'; - } - return type.toLowerCase(); - } - - function ensureSemanticExistenceForPrimitive(gltf, primitive) { - var accessors = gltf.accessors; - var materials = gltf.materials; - var techniques = gltf.techniques; - var programs = gltf.programs; - var shaders = gltf.shaders; - - var attributes = primitive.attributes; - var material = materials[primitive.material]; - var technique = techniques[material.technique]; - var program = programs[technique.program]; - var vertexShader = shaders[program.vertexShader]; - - for (var semantic in attributes) { - if (attributes.hasOwnProperty(semantic)) { - if (!defined(techniqueParameterForSemantic(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.parameters[lowerCase] = { - semantic: semantic, - type: accessor.componentType - }; - technique.attributes[attributeName] = lowerCase; - program.attributes.push(attributeName); - var pipelineExtras = vertexShader.extras._pipeline; - var shaderText = pipelineExtras.source; - shaderText = 'attribute ' + getShaderVariable(accessor.type) + ' ' + attributeName + ';\n' + shaderText; - pipelineExtras.source = shaderText; - } - } - } - } - - function ensureSemanticExistence(gltf) { - ForEach.mesh(gltf, function(mesh) { - ForEach.meshPrimitive(mesh, function(primitive) { - ensureSemanticExistenceForPrimitive(gltf, primitive); - }); - }); - } - - function splitIncompatibleMaterials(gltf) { - var accessors = gltf.accessors; - var materials = gltf.materials; - ForEach.mesh(gltf, function(mesh) { - ForEach.meshPrimitive(mesh, function(primitive) { - var materialId = primitive.material; - var material = materials[materialId]; - - if (defined(material.extensions) && defined(material.extensions.KHR_materials_common)) { - var khrMaterialsCommon = material.extensions.KHR_materials_common; - var jointAccessorId = primitive.attributes.JOINT; - 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 primitiveInfo = khrMaterialsCommon.extras._pipeline.primitive; - if (!defined(primitiveInfo)) { - khrMaterialsCommon.extras._pipeline.primitive = { - skinning : { - skinned: isSkinned, - componentType: componentType, - type: type - }, - hasVertexColors : hasVertexColors - }; - } else if ((primitiveInfo.skinning.skinned !== isSkinned) || (primitiveInfo.skinning.type !== type) || (primitiveInfo.hasVertexColors !== hasVertexColors)) { - // 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 - var clonedMaterial = clone(material, true); - clonedMaterial.extensions.KHR_materials_common.extras._pipeline.primitive = { - skinning : { - skinned: isSkinned, - componentType: componentType, - type: type - }, - hasVertexColors : hasVertexColors - }; - // Split this off as a separate material - materialId = addToArray(materials, clonedMaterial); - primitive.material = materialId; - } - } - }); - }); - } - return processModelMaterialsCommon; }); diff --git a/Source/ThirdParty/GltfPipeline/processPbrMetallicRoughness.js b/Source/Scene/processPbrMetallicRoughness.js similarity index 52% rename from Source/ThirdParty/GltfPipeline/processPbrMetallicRoughness.js rename to Source/Scene/processPbrMetallicRoughness.js index 54383682051f..17458246ab48 100644 --- a/Source/ThirdParty/GltfPipeline/processPbrMetallicRoughness.js +++ b/Source/Scene/processPbrMetallicRoughness.js @@ -1,25 +1,24 @@ define([ - './addToArray', - './ForEach', - './numberOfComponentsForType', - './techniqueParameterForSemantic', - './webGLConstantToGlslType', - './glslTypeToWebGLConstant', - '../../Core/clone', - '../../Core/defined', - '../../Core/defaultValue', - '../../Core/WebGLConstants' + './ModelUtility', + '../Core/defined', + '../Core/defaultValue', + '../Core/WebGLConstants', + '../Core/webGLConstantToGlslType', + '../ThirdParty/GltfPipeline/addToArray', + '../ThirdParty/GltfPipeline/ForEach', + '../ThirdParty/GltfPipeline/hasExtension', + '../ThirdParty/GltfPipeline/numberOfComponentsForType' ], function( - addToArray, - ForEach, - numberOfComponentsForType, - techniqueParameterForSemantic, - webGLConstantToGlslType, - glslTypeToWebGLConstant, - clone, + ModelUtility, defined, defaultValue, - WebGLConstants) { + WebGLConstants, + webGLConstantToGlslType, + addToArray, + ForEach, + hasExtension, + numberOfComponentsForType +) { 'use strict'; /** @@ -35,36 +34,53 @@ define([ } }); - if (hasPbrMetallicRoughness) { - if (!defined(gltf.programs)) { - gltf.programs = []; - } - if (!defined(gltf.shaders)) { - gltf.shaders = []; - } - if (!defined(gltf.techniques)) { - gltf.techniques = []; - } + if (!hasPbrMetallicRoughness) { + return gltf; + } - // Pre-processing to address incompatibilities between primitives using the same materials. - splitIncompatibleMaterials(gltf); - - ForEach.material(gltf, function(material, materialIndex) { - if (isPbrMaterial(material)) { - var values = {}; - var technique = generateTechnique(gltf, material, materialIndex, values, options); - gltf.materials[materialIndex] = { - values : values, - technique : technique - }; - } - }); + // No need to create new techniques if they already exist, + // the shader should handle these values + if (hasExtension(gltf, 'KHR_techniques_webgl')) { + // TODO: Modify shader values for alphaMode or doubleSided? + return gltf; + } - // If any primitives have semantics that aren't declared in the generated - // shaders, we want to preserve them. - ensureSemanticExistence(gltf); + if (!defined(gltf.extensions)) { + gltf.extensions = {}; + gltf.extensionsUsed = []; + gltf.extensionsRequired = []; } + gltf.extensions.KHR_techniques_webgl = { + programs: [], + shaders: [], + techniques: [] + }; + gltf.extensionsUsed.push('KHR_techniques_webgl'); + gltf.extensionsRequired.push('KHR_techniques_webgl'); + + ModelUtility.splitIncompatibleMaterials(gltf); + + ForEach.material(gltf, function(material, materialIndex) { + if (isPbrMaterial(material)) { + var values = {}; + var technique = generateTechnique(gltf, material, materialIndex, values, options); + + if (!defined(material.extensions)) { + material.extensions = {}; + } + + material.extensions.KHR_techniques_webgl = { + values : values, + technique : technique + }; + } + }); + + // If any primitives have semantics that aren't declared in the generated + // shaders, we want to preserve them. + ModelUtility.ensureSemanticExistence(gltf); + return gltf; } @@ -80,26 +96,28 @@ define([ } function generateTechnique(gltf, material, materialIndex, values, options) { - var optimizeForCesium = defaultValue(options.optimizeForCesium, false); - var hasCesiumRTCExtension = defined(gltf.extensions) && defined(gltf.extensions.CESIUM_RTC); var addBatchIdToGeneratedShaders = defaultValue(options.addBatchIdToGeneratedShaders, false); - var techniques = gltf.techniques; - var shaders = gltf.shaders; - var programs = gltf.programs; + var techniquesWebgl = gltf.extensions.KHR_techniques_webgl; + var techniques = techniquesWebgl.techniques; + var shaders = techniquesWebgl.shaders; + var programs = techniquesWebgl.programs; var parameterValues = values; + var uniformName; var pbrMetallicRoughness = material.pbrMetallicRoughness; if (defined(pbrMetallicRoughness)) { for (var parameterName in pbrMetallicRoughness) { if (pbrMetallicRoughness.hasOwnProperty(parameterName)) { - parameterValues[parameterName] = pbrMetallicRoughness[parameterName]; + uniformName = 'u_' + parameterName; + parameterValues[uniformName] = pbrMetallicRoughness[parameterName]; } } } for (var additional in material) { - if (material.hasOwnProperty(additional) && ((additional.indexOf('Texture') >= 0) || additional.indexOf('Factor') >= 0) || additional === 'doubleSided') { - parameterValues[additional] = material[additional]; + if (material.hasOwnProperty(additional) && ((additional.indexOf('Texture') >= 0) || additional.indexOf('Factor') >= 0)) { + uniformName = 'u_' + additional; + parameterValues[uniformName] = material[additional]; } } @@ -147,27 +165,27 @@ define([ } // Add techniques - var techniqueParameters = { + var techniqueUniforms = { // Add matrices - modelViewMatrix : { - semantic : hasCesiumRTCExtension ? 'CESIUM_RTC_MODELVIEW' : 'MODELVIEW', + u_modelViewMatrix : { + semantic : hasExtension(gltf, 'CESIUM_RTC') ? 'CESIUM_RTC_MODELVIEW' : 'MODELVIEW', type : WebGLConstants.FLOAT_MAT4 }, - projectionMatrix : { + u_projectionMatrix : { semantic : 'PROJECTION', type : WebGLConstants.FLOAT_MAT4 } }; if (hasNormals) { - techniqueParameters.normalMatrix = { + techniqueUniforms.u_normalMatrix = { semantic : 'MODELVIEWINVERSETRANSPOSE', type : WebGLConstants.FLOAT_MAT3 }; } if (hasSkinning) { - techniqueParameters.jointMatrix = { + techniqueUniforms.u_jointMatrix = { count : jointCount, semantic : 'JOINTMATRIX', type : WebGLConstants.FLOAT_MAT4 @@ -175,7 +193,7 @@ define([ } if (hasMorphTargets) { - techniqueParameters.morphWeights = { + techniqueUniforms.u_morphWeights = { count : morphTargets.length, semantic : 'MORPHWEIGHTS', type : WebGLConstants.FLOAT @@ -183,27 +201,25 @@ define([ } // Add material parameters - for (var name in parameterValues) { - if (parameterValues.hasOwnProperty(name)) { - techniqueParameters[name] = { - type : getPBRValueType(name) + for (uniformName in parameterValues) { + if (parameterValues.hasOwnProperty(uniformName)) { + techniqueUniforms[uniformName] = { + type : getPBRValueType(uniformName) }; } } - // Generate uniforms object before attributes are added - var techniqueUniforms = {}; - for (var paramName in techniqueParameters) { - if (techniqueParameters.hasOwnProperty(paramName) && paramName !== 'extras') { - var param = techniqueParameters[paramName]; - techniqueUniforms['u_' + paramName] = paramName; - var arraySize = defined(param.count) ? '[' + param.count + ']' : ''; - if (((param.type !== WebGLConstants.FLOAT_MAT3) && (param.type !== WebGLConstants.FLOAT_MAT4) && (paramName !== 'morphWeights')) || - param.useInFragment) { - fragmentShader += 'uniform ' + webGLConstantToGlslType(param.type) + ' u_' + paramName + arraySize + ';\n'; - delete param.useInFragment; + // Add uniforms to shaders + for (uniformName in techniqueUniforms) { + if (techniqueUniforms.hasOwnProperty(uniformName)) { + var uniform = techniqueUniforms[uniformName]; + var arraySize = defined(uniform.count) ? '[' + uniform.count + ']' : ''; + if (((uniform.type !== WebGLConstants.FLOAT_MAT3) && (uniform.type !== WebGLConstants.FLOAT_MAT4) && (uniformName !== 'u_morphWeights')) || + uniform.useInFragment) { + fragmentShader += 'uniform ' + webGLConstantToGlslType(uniform.type) + ' ' + uniformName + arraySize + ';\n'; + delete uniform.useInFragment; } else { - vertexShader += 'uniform ' + webGLConstantToGlslType(param.type) + ' u_' + paramName + arraySize + ';\n'; + vertexShader += 'uniform ' + webGLConstantToGlslType(uniform.type) + ' ' + uniformName + arraySize + ';\n'; } } } @@ -243,18 +259,14 @@ define([ // Add position always var techniqueAttributes = { - a_position : 'position' - }; - techniqueParameters.position = { - semantic : 'POSITION', - type : WebGLConstants.FLOAT_VEC3 + a_position : { + semantic : 'POSITION' + } }; vertexShader += 'attribute vec3 a_position;\n'; if (hasNormals) { vertexShader += 'varying vec3 v_positionEC;\n'; - if (optimizeForCesium) { - vertexShader += 'varying vec3 v_positionWC;\n'; - } + vertexShader += 'varying vec3 v_positionWC;\n'; } // Morph Target Weighting @@ -270,19 +282,17 @@ define([ var targetAttributes = morphTargets[k]; for (var targetAttribute in targetAttributes) { if (targetAttributes.hasOwnProperty(targetAttribute) && targetAttribute !== 'extras') { - var attributeLower = targetAttribute.toLowerCase() + '_' + k; - techniqueAttributes['a_' + attributeLower] = attributeLower; - techniqueParameters[attributeLower] = { - semantic : targetAttribute + '_' + k, - type : WebGLConstants.FLOAT_VEC3 + var attributeName = 'a_' + targetAttribute + '_' + k; + techniqueAttributes[attributeName] = { + semantic : targetAttribute + '_' + k }; - vertexShader += 'attribute vec3 a_' + attributeLower + ';\n'; + vertexShader += 'attribute vec3 ' + attributeName + ';\n'; if (targetAttribute === 'POSITION') { - vertexShaderMain += ' weightedPosition += u_morphWeights[' + k + '] * a_' + attributeLower + ';\n'; + vertexShaderMain += ' weightedPosition += u_morphWeights[' + k + '] * a_' + attributeName + ';\n'; } else if (targetAttribute === 'NORMAL') { - vertexShaderMain += ' weightedNormal += u_morphWeights[' + k + '] * a_' + attributeLower + ';\n'; + vertexShaderMain += ' weightedNormal += u_morphWeights[' + k + '] * a_' + attributeName + ';\n'; } else if (hasTangents && targetAttribute === 'TANGENT') { - vertexShaderMain += ' weightedTangent.xyz += u_morphWeights[' + k + '] * a_' + attributeLower + ';\n'; + vertexShaderMain += ' weightedTangent.xyz += u_morphWeights[' + k + '] * a_' + attributeName + ';\n'; } } } @@ -295,7 +305,7 @@ define([ } else { vertexShaderMain += ' vec4 position = vec4(weightedPosition, 1.0);\n'; } - if (hasNormals && optimizeForCesium) { + if (hasNormals) { vertexShaderMain += ' v_positionWC = (czm_model * position).xyz;\n'; } vertexShaderMain += ' position = u_modelViewMatrix * position;\n'; @@ -306,10 +316,8 @@ define([ // Final normal computation if (hasNormals) { - techniqueAttributes.a_normal = 'normal'; - techniqueParameters.normal = { - semantic : 'NORMAL', - type : WebGLConstants.FLOAT_VEC3 + techniqueAttributes.a_normal = { + semantic : 'NORMAL' }; vertexShader += 'attribute vec3 a_normal;\n'; vertexShader += 'varying vec3 v_normal;\n'; @@ -321,18 +329,13 @@ define([ fragmentShader += 'varying vec3 v_normal;\n'; fragmentShader += 'varying vec3 v_positionEC;\n'; - - if (optimizeForCesium) { - fragmentShader += 'varying vec3 v_positionWC;\n'; - } + fragmentShader += 'varying vec3 v_positionWC;\n'; } // Read tangents if available if (hasTangents) { - techniqueAttributes.a_tangent = 'tangent'; - techniqueParameters.tangent = { - semantic : 'TANGENT', - type : WebGLConstants.FLOAT_VEC4 + techniqueAttributes.a_tangent = { + semantic : 'TANGENT' }; vertexShader += 'attribute vec4 a_tangent;\n'; vertexShader += 'varying vec4 v_tangent;\n'; @@ -345,10 +348,8 @@ define([ // Add texture coordinates if the material uses them var v_texcoord; if (hasTexCoords) { - techniqueAttributes.a_texcoord_0 = 'texcoord_0'; - techniqueParameters.texcoord_0 = { - semantic : 'TEXCOORD_0', - type : WebGLConstants.FLOAT_VEC2 + techniqueAttributes.a_texcoord_0 = { + semantic : 'TEXCOORD_0' }; v_texcoord = 'v_texcoord_0'; @@ -361,18 +362,12 @@ define([ // Add skinning information if available if (hasSkinning) { - techniqueAttributes.a_joint = 'joint'; - var attributeType = getShaderVariable(skinningInfo.type); - var webGLConstant = glslTypeToWebGLConstant(attributeType); - - techniqueParameters.joint = { - semantic : 'JOINTS_0', - type : webGLConstant + var attributeType = ModelUtility.getShaderVariable(skinningInfo.type); + techniqueAttributes.a_joint = { + semantic : 'JOINTS_0' }; - techniqueAttributes.a_weight = 'weight'; - techniqueParameters.weight = { - semantic : 'WEIGHTS_0', - type : webGLConstant + techniqueAttributes.a_weight ={ + semantic : 'WEIGHTS_0' }; vertexShader += 'attribute ' + attributeType + ' a_joint;\n'; @@ -380,10 +375,8 @@ define([ } if (hasVertexColors) { - techniqueAttributes.a_vertexColor = 'vertexColor'; - techniqueParameters.vertexColor = { - semantic: 'COLOR_0', - type: WebGLConstants.FLOAT_VEC4 + techniqueAttributes.a_vertexColor = { + semantic: 'COLOR_0' }; vertexShader += 'attribute vec4 a_vertexColor;\n'; vertexShader += 'varying vec4 v_vertexColor;\n'; @@ -392,10 +385,8 @@ define([ } if (addBatchIdToGeneratedShaders) { - techniqueAttributes.a_batchId = 'batchId'; - techniqueParameters.batchId = { - semantic: '_BATCHID', - type: WebGLConstants.FLOAT + techniqueAttributes.a_batchId = { + semantic: '_BATCHID' }; vertexShader += 'attribute float a_batchId;\n'; } @@ -463,7 +454,7 @@ define([ // Add normal mapping to fragment shader if (hasNormals) { fragmentShader += ' vec3 ng = normalize(v_normal);\n'; - if (defined(parameterValues.normalTexture)) { + if (defined(parameterValues.u_normalTexture)) { if (hasTangents) { // Read tangents from varying fragmentShader += ' vec3 t = normalize(v_tangent.xyz);\n'; @@ -496,7 +487,7 @@ define([ } else { fragmentShader += ' vec3 n = ng;\n'; } - if (parameterValues.doubleSided) { + if (material.doubleSided) { fragmentShader += ' if (!gl_FrontFacing)\n'; fragmentShader += ' {\n'; fragmentShader += ' n = -n;\n'; @@ -505,18 +496,16 @@ define([ } // Add base color to fragment shader - if (defined(parameterValues.baseColorTexture)) { + if (defined(parameterValues.u_baseColorTexture)) { fragmentShader += ' vec4 baseColorWithAlpha = SRGBtoLINEAR4(texture2D(u_baseColorTexture, ' + v_texcoord + '));\n'; - if (defined(parameterValues.baseColorFactor)) { + if (defined(parameterValues.u_baseColorFactor)) { fragmentShader += ' baseColorWithAlpha *= u_baseColorFactor;\n'; } - } else { - if (defined(parameterValues.baseColorFactor)) { + } else if (defined(parameterValues.u_baseColorFactor)) { fragmentShader += ' vec4 baseColorWithAlpha = u_baseColorFactor;\n'; } else { fragmentShader += ' vec4 baseColorWithAlpha = vec4(1.0);\n'; } - } if (hasVertexColors) { fragmentShader += ' baseColorWithAlpha *= v_vertexColor;\n'; @@ -526,23 +515,23 @@ define([ if (hasNormals) { // Add metallic-roughness to fragment shader - if (defined(parameterValues.metallicRoughnessTexture)) { + if (defined(parameterValues.u_metallicRoughnessTexture)) { fragmentShader += ' vec3 metallicRoughness = texture2D(u_metallicRoughnessTexture, ' + v_texcoord + ').rgb;\n'; fragmentShader += ' float metalness = clamp(metallicRoughness.b, 0.0, 1.0);\n'; fragmentShader += ' float roughness = clamp(metallicRoughness.g, 0.04, 1.0);\n'; - if (defined(parameterValues.metallicFactor)) { + if (defined(parameterValues.u_metallicFactor)) { fragmentShader += ' metalness *= u_metallicFactor;\n'; } - if (defined(parameterValues.roughnessFactor)) { + if (defined(parameterValues.u_roughnessFactor)) { fragmentShader += ' roughness *= u_roughnessFactor;\n'; } } else { - if (defined(parameterValues.metallicFactor)) { + if (defined(parameterValues.u_metallicFactor)) { fragmentShader += ' float metalness = clamp(u_metallicFactor, 0.0, 1.0);\n'; } else { fragmentShader += ' float metalness = 1.0;\n'; } - if (defined(parameterValues.roughnessFactor)) { + if (defined(parameterValues.u_roughnessFactor)) { fragmentShader += ' float roughness = clamp(u_roughnessFactor, 0.04, 1.0);\n'; } else { fragmentShader += ' float roughness = 1.0;\n'; @@ -551,29 +540,20 @@ define([ fragmentShader += ' vec3 v = -normalize(v_positionEC);\n'; // Generate fragment shader's lighting block - if (optimizeForCesium) { - // The Sun is brighter than your average light source, and has a yellowish tint balanced by the Earth's ambient blue. - fragmentShader += ' vec3 lightColor = vec3(1.5, 1.4, 1.2);\n'; - fragmentShader += ' vec3 l = normalize(czm_sunDirectionEC);\n'; - } else { - fragmentShader += ' vec3 lightColor = vec3(1.0, 1.0, 1.0);\n'; - fragmentShader += ' vec3 l = vec3(0.0, 0.0, 1.0);\n'; - } + // The Sun is brighter than your average light source, and has a yellowish tint balanced by the Earth's ambient blue. + fragmentShader += ' vec3 lightColor = vec3(1.5, 1.4, 1.2);\n'; + fragmentShader += ' vec3 l = normalize(czm_sunDirectionEC);\n'; fragmentShader += ' vec3 h = normalize(v + l);\n'; - if (optimizeForCesium) { - fragmentShader += ' vec3 r = normalize(czm_inverseViewRotation * normalize(reflect(v, n)));\n'; - // Figure out if the reflection vector hits the ellipsoid - fragmentShader += ' czm_ellipsoid ellipsoid = czm_getWgs84EllipsoidEC();\n'; - fragmentShader += ' float vertexRadius = length(v_positionWC);\n'; - fragmentShader += ' float horizonDotNadir = 1.0 - min(1.0, ellipsoid.radii.x / vertexRadius);\n'; - fragmentShader += ' float reflectionDotNadir = dot(r, normalize(v_positionWC));\n'; - // Flipping the X vector is a cheap way to get the inverse of czm_temeToPseudoFixed, since that's a rotation about Z. - fragmentShader += ' r.x = -r.x;\n'; - fragmentShader += ' r = -normalize(czm_temeToPseudoFixed * r);\n'; - fragmentShader += ' r.x = -r.x;\n'; - } else { - fragmentShader += ' vec3 r = normalize(reflect(v, n));\n'; - } + fragmentShader += ' vec3 r = normalize(czm_inverseViewRotation * normalize(reflect(v, n)));\n'; + // Figure out if the reflection vector hits the ellipsoid + fragmentShader += ' czm_ellipsoid ellipsoid = czm_getWgs84EllipsoidEC();\n'; + fragmentShader += ' float vertexRadius = length(v_positionWC);\n'; + fragmentShader += ' float horizonDotNadir = 1.0 - min(1.0, ellipsoid.radii.x / vertexRadius);\n'; + fragmentShader += ' float reflectionDotNadir = dot(r, normalize(v_positionWC));\n'; + // Flipping the X vector is a cheap way to get the inverse of czm_temeToPseudoFixed, since that's a rotation about Z. + fragmentShader += ' r.x = -r.x;\n'; + fragmentShader += ' r = -normalize(czm_temeToPseudoFixed * r);\n'; + fragmentShader += ' r.x = -r.x;\n'; fragmentShader += ' float NdotL = clamp(dot(n, l), 0.001, 1.0);\n'; fragmentShader += ' float NdotV = abs(dot(n, v)) + 0.001;\n'; fragmentShader += ' float NdotH = clamp(dot(n, h), 0.0, 1.0);\n'; @@ -596,58 +576,54 @@ define([ fragmentShader += ' vec3 specularContribution = F * G * D / (4.0 * NdotL * NdotV);\n'; fragmentShader += ' vec3 color = NdotL * lightColor * (diffuseContribution + specularContribution);\n'; - if (optimizeForCesium) { - fragmentShader += ' float inverseRoughness = 1.04 - roughness;\n'; - fragmentShader += ' inverseRoughness *= inverseRoughness;\n'; - fragmentShader += ' vec3 sceneSkyBox = textureCube(czm_environmentMap, r).rgb * inverseRoughness;\n'; - - fragmentShader += ' float atmosphereHeight = 0.05;\n'; - fragmentShader += ' float blendRegionSize = 0.1 * ((1.0 - inverseRoughness) * 8.0 + 1.1 - horizonDotNadir);\n'; - fragmentShader += ' float blendRegionOffset = roughness * -1.0;\n'; - fragmentShader += ' float farAboveHorizon = clamp(horizonDotNadir - blendRegionSize * 0.5 + blendRegionOffset, 1.0e-10 - blendRegionSize, 0.99999);\n'; - fragmentShader += ' float aroundHorizon = clamp(horizonDotNadir + blendRegionSize * 0.5, 1.0e-10 - blendRegionSize, 0.99999);\n'; - fragmentShader += ' float farBelowHorizon = clamp(horizonDotNadir + blendRegionSize * 1.5, 1.0e-10 - blendRegionSize, 0.99999);\n'; - fragmentShader += ' float smoothstepHeight = smoothstep(0.0, atmosphereHeight, horizonDotNadir);\n'; - - fragmentShader += ' vec3 belowHorizonColor = mix(vec3(0.1, 0.15, 0.25), vec3(0.4, 0.7, 0.9), smoothstepHeight);\n'; - fragmentShader += ' vec3 nadirColor = belowHorizonColor * 0.5;\n'; - fragmentShader += ' vec3 aboveHorizonColor = mix(vec3(0.9, 1.0, 1.2), belowHorizonColor, roughness * 0.5);\n'; - fragmentShader += ' vec3 blueSkyColor = mix(vec3(0.18, 0.26, 0.48), aboveHorizonColor, reflectionDotNadir * inverseRoughness * 0.5 + 0.75);\n'; - fragmentShader += ' vec3 zenithColor = mix(blueSkyColor, sceneSkyBox, smoothstepHeight);\n'; - - fragmentShader += ' vec3 blueSkyDiffuseColor = vec3(0.7, 0.85, 0.9);\n'; - fragmentShader += ' float diffuseIrradianceFromEarth = (1.0 - horizonDotNadir) * (reflectionDotNadir * 0.25 + 0.75) * smoothstepHeight;\n'; - fragmentShader += ' float diffuseIrradianceFromSky = (1.0 - smoothstepHeight) * (1.0 - (reflectionDotNadir * 0.25 + 0.25));\n'; - fragmentShader += ' vec3 diffuseIrradiance = blueSkyDiffuseColor * clamp(diffuseIrradianceFromEarth + diffuseIrradianceFromSky, 0.0, 1.0);\n'; - - fragmentShader += ' float notDistantRough = (1.0 - horizonDotNadir * roughness * 0.8);\n'; - fragmentShader += ' vec3 specularIrradiance = mix(zenithColor, aboveHorizonColor, smoothstep(farAboveHorizon, aroundHorizon, reflectionDotNadir) * notDistantRough);\n'; - fragmentShader += ' specularIrradiance = mix(specularIrradiance, belowHorizonColor, smoothstep(aroundHorizon, farBelowHorizon, reflectionDotNadir) * inverseRoughness);\n'; - fragmentShader += ' specularIrradiance = mix(specularIrradiance, nadirColor, smoothstep(farBelowHorizon, 1.0, reflectionDotNadir) * inverseRoughness);\n'; - - fragmentShader += ' vec2 brdfLut = texture2D(czm_brdfLut, vec2(NdotV, 1.0 - roughness)).rg;\n'; - fragmentShader += ' vec3 IBLColor = (diffuseIrradiance * diffuseColor) + (specularIrradiance * SRGBtoLINEAR3(specularColor * brdfLut.x + brdfLut.y));\n'; - fragmentShader += ' color += IBLColor;\n'; - } + fragmentShader += ' float inverseRoughness = 1.04 - roughness;\n'; + fragmentShader += ' inverseRoughness *= inverseRoughness;\n'; + fragmentShader += ' vec3 sceneSkyBox = textureCube(czm_environmentMap, r).rgb * inverseRoughness;\n'; + + fragmentShader += ' float atmosphereHeight = 0.05;\n'; + fragmentShader += ' float blendRegionSize = 0.1 * ((1.0 - inverseRoughness) * 8.0 + 1.1 - horizonDotNadir);\n'; + fragmentShader += ' float blendRegionOffset = roughness * -1.0;\n'; + fragmentShader += ' float farAboveHorizon = clamp(horizonDotNadir - blendRegionSize * 0.5 + blendRegionOffset, 1.0e-10 - blendRegionSize, 0.99999);\n'; + fragmentShader += ' float aroundHorizon = clamp(horizonDotNadir + blendRegionSize * 0.5, 1.0e-10 - blendRegionSize, 0.99999);\n'; + fragmentShader += ' float farBelowHorizon = clamp(horizonDotNadir + blendRegionSize * 1.5, 1.0e-10 - blendRegionSize, 0.99999);\n'; + fragmentShader += ' float smoothstepHeight = smoothstep(0.0, atmosphereHeight, horizonDotNadir);\n'; + + fragmentShader += ' vec3 belowHorizonColor = mix(vec3(0.1, 0.15, 0.25), vec3(0.4, 0.7, 0.9), smoothstepHeight);\n'; + fragmentShader += ' vec3 nadirColor = belowHorizonColor * 0.5;\n'; + fragmentShader += ' vec3 aboveHorizonColor = mix(vec3(0.9, 1.0, 1.2), belowHorizonColor, roughness * 0.5);\n'; + fragmentShader += ' vec3 blueSkyColor = mix(vec3(0.18, 0.26, 0.48), aboveHorizonColor, reflectionDotNadir * inverseRoughness * 0.5 + 0.75);\n'; + fragmentShader += ' vec3 zenithColor = mix(blueSkyColor, sceneSkyBox, smoothstepHeight);\n'; + + fragmentShader += ' vec3 blueSkyDiffuseColor = vec3(0.7, 0.85, 0.9);\n'; + fragmentShader += ' float diffuseIrradianceFromEarth = (1.0 - horizonDotNadir) * (reflectionDotNadir * 0.25 + 0.75) * smoothstepHeight;\n'; + fragmentShader += ' float diffuseIrradianceFromSky = (1.0 - smoothstepHeight) * (1.0 - (reflectionDotNadir * 0.25 + 0.25));\n'; + fragmentShader += ' vec3 diffuseIrradiance = blueSkyDiffuseColor * clamp(diffuseIrradianceFromEarth + diffuseIrradianceFromSky, 0.0, 1.0);\n'; + + fragmentShader += ' float notDistantRough = (1.0 - horizonDotNadir * roughness * 0.8);\n'; + fragmentShader += ' vec3 specularIrradiance = mix(zenithColor, aboveHorizonColor, smoothstep(farAboveHorizon, aroundHorizon, reflectionDotNadir) * notDistantRough);\n'; + fragmentShader += ' specularIrradiance = mix(specularIrradiance, belowHorizonColor, smoothstep(aroundHorizon, farBelowHorizon, reflectionDotNadir) * inverseRoughness);\n'; + fragmentShader += ' specularIrradiance = mix(specularIrradiance, nadirColor, smoothstep(farBelowHorizon, 1.0, reflectionDotNadir) * inverseRoughness);\n'; + + fragmentShader += ' vec2 brdfLut = texture2D(czm_brdfLut, vec2(NdotV, 1.0 - roughness)).rg;\n'; + fragmentShader += ' vec3 IBLColor = (diffuseIrradiance * diffuseColor) + (specularIrradiance * SRGBtoLINEAR3(specularColor * brdfLut.x + brdfLut.y));\n'; + fragmentShader += ' color += IBLColor;\n'; } else { fragmentShader += ' vec3 color = baseColor;\n'; } - if (defined(parameterValues.occlusionTexture)) { + if (defined(parameterValues.u_occlusionTexture)) { fragmentShader += ' color *= texture2D(u_occlusionTexture, ' + v_texcoord + ').r;\n'; } - if (defined(parameterValues.emissiveTexture)) { + if (defined(parameterValues.u_emissiveTexture)) { fragmentShader += ' vec3 emissive = SRGBtoLINEAR3(texture2D(u_emissiveTexture, ' + v_texcoord + ').rgb);\n'; - if (defined(parameterValues.emissiveFactor)) { + if (defined(parameterValues.u_emissiveFactor)) { fragmentShader += ' emissive *= u_emissiveFactor;\n'; } fragmentShader += ' color += emissive;\n'; } - else { - if (defined(parameterValues.emissiveFactor)) { + else if (defined(parameterValues.u_emissiveFactor)) { fragmentShader += ' color += u_emissiveFactor;\n'; } - } // Final color fragmentShader += ' color = LINEARtoSRGB(color);\n'; @@ -666,46 +642,6 @@ define([ } fragmentShader += '}\n'; - var techniqueStates; - if (defined(alphaMode) && alphaMode !== 'OPAQUE') { - techniqueStates = { - enable: parameterValues.doubleSided ? [ - WebGLConstants.DEPTH_TEST, - WebGLConstants.BLEND - ]: [ - WebGLConstants.CULL_FACE, - WebGLConstants.DEPTH_TEST, - WebGLConstants.BLEND - ], - functions: { - depthMask : [false], - blendEquationSeparate: [ - WebGLConstants.FUNC_ADD, - WebGLConstants.FUNC_ADD - ], - blendFuncSeparate: [ - WebGLConstants.ONE, - WebGLConstants.ONE_MINUS_SRC_ALPHA, - WebGLConstants.ONE, - WebGLConstants.ONE_MINUS_SRC_ALPHA - ] - } - }; - } else if (parameterValues.doubleSided) { - techniqueStates = { - enable : [ - WebGLConstants.DEPTH_TEST - ] - }; - } else { - techniqueStates = { - enable : [ - WebGLConstants.CULL_FACE, - WebGLConstants.DEPTH_TEST - ] - }; - } - // Add shaders var vertexShaderId = addToArray(shaders, { type : WebGLConstants.VERTEX_SHADER, @@ -728,18 +664,14 @@ define([ }); // Add program - var programAttributes = Object.keys(techniqueAttributes); var programId = addToArray(programs, { - attributes : programAttributes, fragmentShader : fragmentShaderId, vertexShader : vertexShaderId }); var techniqueId = addToArray(techniques, { attributes : techniqueAttributes, - parameters : techniqueParameters, program : programId, - states : techniqueStates, uniforms : techniqueUniforms }); @@ -748,161 +680,26 @@ define([ function getPBRValueType(paramName) { switch (paramName) { - case 'baseColorFactor': + case 'u_baseColorFactor': return WebGLConstants.FLOAT_VEC4; - case 'metallicFactor': + case 'u_metallicFactor': return WebGLConstants.FLOAT; - case 'roughnessFactor': + case 'u_roughnessFactor': return WebGLConstants.FLOAT; - case 'baseColorTexture': + case 'u_baseColorTexture': return WebGLConstants.SAMPLER_2D; - case 'metallicRoughnessTexture': + case 'u_metallicRoughnessTexture': return WebGLConstants.SAMPLER_2D; - case 'normalTexture': + case 'u_normalTexture': return WebGLConstants.SAMPLER_2D; - case 'occlusionTexture': + case 'u_occlusionTexture': return WebGLConstants.SAMPLER_2D; - case 'emissiveTexture': + case 'u_emissiveTexture': return WebGLConstants.SAMPLER_2D; - case 'emissiveFactor': + case 'u_emissiveFactor': return WebGLConstants.FLOAT_VEC3; - case 'doubleSided': - return WebGLConstants.BOOL; } } - function getShaderVariable(type) { - if (type === 'SCALAR') { - return 'float'; - } - return type.toLowerCase(); - } - - function ensureSemanticExistenceForPrimitive(gltf, primitive) { - var accessors = gltf.accessors; - var materials = gltf.materials; - var techniques = gltf.techniques; - var programs = gltf.programs; - var shaders = gltf.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.technique]; - var program = programs[technique.program]; - var vertexShader = shaders[program.vertexShader]; - - for (var semantic in attributes) { - if (attributes.hasOwnProperty(semantic)) { - if (!defined(techniqueParameterForSemantic(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.parameters[lowerCase] = { - semantic: semantic, - type: accessor.componentType - }; - technique.attributes[attributeName] = lowerCase; - program.attributes.push(attributeName); - var pipelineExtras = vertexShader.extras._pipeline; - var shaderText = pipelineExtras.source; - shaderText = 'attribute ' + getShaderVariable(accessor.type) + ' ' + attributeName + ';\n' + shaderText; - pipelineExtras.source = shaderText; - } - } - } - } - - function ensureSemanticExistence(gltf) { - ForEach.mesh(gltf, function(mesh) { - ForEach.meshPrimitive(mesh, function(primitive) { - ensureSemanticExistenceForPrimitive(gltf, primitive); - }); - }); - } - - function splitIncompatibleMaterials(gltf) { - var accessors = gltf.accessors; - var materials = gltf.materials; - ForEach.mesh(gltf, function(mesh) { - ForEach.meshPrimitive(mesh, function(primitive) { - var materialId = primitive.material; - var material = materials[materialId]; - - 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 = material.extras._pipeline.primitive; - if (!defined(primitiveInfo)) { - material.extras._pipeline.primitive = { - 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); - clonedMaterial.extras._pipeline.primitive = { - skinning : { - skinned : isSkinned, - componentType : componentType, - type : type - }, - hasVertexColors : hasVertexColors, - hasMorphTargets : hasMorphTargets, - hasNormals : hasNormals, - hasTangents : hasTangents, - hasTexCoords : hasTexCoords - }; - // Split this off as a separate material - materialId = addToArray(materials, clonedMaterial); - primitive.material = materialId; - } - }); - }); - } - return processPbrMetallicRoughness; }); diff --git a/Source/ThirdParty/GltfPipeline/ForEach.js b/Source/ThirdParty/GltfPipeline/ForEach.js index 1894f5a896b1..dd5ce20378ad 100644 --- a/Source/ThirdParty/GltfPipeline/ForEach.js +++ b/Source/ThirdParty/GltfPipeline/ForEach.js @@ -1,99 +1,231 @@ define([ - '../../Core/defined' + './hasExtension', + '../../Core/defined', + '../../Core/isArray' ], function( - defined) { + hasExtension, + defined, + isArray) { 'use strict'; /** * Contains traversal functions for processing elements of the glTF hierarchy. + * @constructor + * + * @private */ - var ForEach = {}; + function ForEach() { + } + /** + * Fallback for glTF 1.0 + * @private + */ + ForEach.objectLegacy = function(objects, handler) { + if (defined(objects)) { + for (var objectId in objects) { + if (objects.hasOwnProperty(objectId)) { + var object = objects[objectId]; + var value = handler(object, objectId); + + if (defined(value)) { + return value; + } + } + } + } + }; + + /** + * @private + */ ForEach.object = function(arrayOfObjects, handler) { if (defined(arrayOfObjects)) { - for (var i = 0; i < arrayOfObjects.length; i++) { + var length = arrayOfObjects.length; + for (var i = 0; i < length; i++) { var object = arrayOfObjects[i]; - var returnValue = handler(object, i); - if (typeof returnValue === 'number') { - i += returnValue; - } - else if (returnValue) { - break; + var value = handler(object, i); + + if (defined(value)) { + return value; } } } }; + /** + * Supports glTF 1.0 and 2.0 + * @private + */ ForEach.topLevel = function(gltf, name, handler) { - var arrayOfObjects = gltf[name]; - ForEach.object(arrayOfObjects, handler); + var gltfProperty = gltf[name]; + if (defined(gltfProperty) && !isArray(gltfProperty)) { + return ForEach.objectLegacy(gltfProperty, handler); + } + + return ForEach.object(gltfProperty, handler); }; ForEach.accessor = function(gltf, handler) { - ForEach.topLevel(gltf, 'accessors', handler); + return ForEach.topLevel(gltf, 'accessors', handler); }; ForEach.accessorWithSemantic = function(gltf, semantic, handler) { - ForEach.mesh(gltf, function(mesh) { - ForEach.meshPrimitive(mesh, function(primitive) { - ForEach.meshPrimitiveAttribute(primitive, function(accessorId, attributeSemantic) { - if (attributeSemantic.indexOf(semantic) === 0) { - handler(accessorId, attributeSemantic, primitive); + var visited = {}; + return ForEach.mesh(gltf, function(mesh) { + return ForEach.meshPrimitive(mesh, function(primitive) { + var value = ForEach.meshPrimitiveAttribute(primitive, function(accessorId, attributeSemantic) { + if (attributeSemantic.indexOf(semantic) === 0 && !defined(visited[accessorId])) { + visited[accessorId] = true; + value = handler(accessorId); + + if (defined(value)) { + return value; + } } }); + + if (defined(value)) { + return value; + } + + return ForEach.meshPrimitiveTarget(primitive, function(target) { + return ForEach.meshPrimitiveTargetAttribute(target, function(accessorId, attributeSemantic) { + if (attributeSemantic.indexOf(semantic) === 0 && !defined(visited[accessorId])) { + visited[accessorId] = true; + value = handler(accessorId); + + if (defined(value)) { + return value; + } + } + }); + }); + }); + }); + }; + + ForEach.accessorContainingVertexAttributeData = function(gltf, handler) { + var visited = {}; + return ForEach.mesh(gltf, function(mesh) { + return ForEach.meshPrimitive(mesh, function(primitive) { + var value = ForEach.meshPrimitiveAttribute(primitive, function(accessorId) { + if (!defined(visited[accessorId])) { + visited[accessorId] = true; + value = handler(accessorId); + + if (defined(value)) { + return value; + } + } + }); + + if (defined(value)) { + return value; + } + + return ForEach.meshPrimitiveTarget(primitive, function(target) { + return ForEach.meshPrimitiveTargetAttribute(target, function(accessorId) { + if (!defined(visited[accessorId])) { + visited[accessorId] = true; + value = handler(accessorId); + + if (defined(value)) { + return value; + } + } + }); + }); + }); + }); + }; + + ForEach.accessorContainingIndexData = function(gltf, handler) { + var visited = {}; + return ForEach.mesh(gltf, function(mesh) { + return ForEach.meshPrimitive(mesh, function(primitive) { + var indices = primitive.indices; + if (defined(indices) && !defined(visited[indices])) { + visited[indices] = true; + var value = handler(indices); + + if (defined(value)) { + return value; + } + } }); }); }; ForEach.animation = function(gltf, handler) { - ForEach.topLevel(gltf, 'animations', handler); + return ForEach.topLevel(gltf, 'animations', handler); }; ForEach.animationChannel = function(animation, handler) { var channels = animation.channels; - ForEach.object(channels, handler); + return ForEach.object(channels, handler); }; ForEach.animationSampler = function(animation, handler) { var samplers = animation.samplers; - if (defined(samplers)) { - ForEach.object(samplers, handler); - } + return ForEach.object(samplers, handler); }; ForEach.buffer = function(gltf, handler) { - ForEach.topLevel(gltf, 'buffers', handler); + return ForEach.topLevel(gltf, 'buffers', handler); }; ForEach.bufferView = function(gltf, handler) { - ForEach.topLevel(gltf, 'bufferViews', handler); + return ForEach.topLevel(gltf, 'bufferViews', handler); }; ForEach.camera = function(gltf, handler) { - ForEach.topLevel(gltf, 'cameras', handler); + return ForEach.topLevel(gltf, 'cameras', handler); }; ForEach.image = function(gltf, handler) { - ForEach.topLevel(gltf, 'images', handler); + return ForEach.topLevel(gltf, 'images', handler); + }; + + ForEach.compressedImage = function(image, handler) { + if (defined(image.extras)) { + var compressedImages = image.extras.compressedImage3DTiles; + for (var type in compressedImages) { + if (compressedImages.hasOwnProperty(type)) { + var compressedImage = compressedImages[type]; + var value = handler(compressedImage, type); + + if (defined(value)) { + return value; + } + } + } + } }; ForEach.material = function(gltf, handler) { - ForEach.topLevel(gltf, 'materials', handler); + return ForEach.topLevel(gltf, 'materials', handler); }; ForEach.materialValue = function(material, handler) { var values = material.values; - if (defined(values)) { - for (var name in values) { - if (values.hasOwnProperty(name)) { - handler(values[name], name); + if (defined(material.extensions) && defined(material.extensions.KHR_techniques_webgl)) { + values = material.extensions.KHR_techniques_webgl.values; + } + + for (var name in values) { + if (values.hasOwnProperty(name)) { + var value = handler(values[name], name); + + if (defined(value)) { + return value; } } } }; ForEach.mesh = function(gltf, handler) { - ForEach.topLevel(gltf, 'meshes', handler); + return ForEach.topLevel(gltf, 'meshes', handler); }; ForEach.meshPrimitive = function(mesh, handler) { @@ -102,53 +234,80 @@ define([ var primitivesLength = primitives.length; for (var i = 0; i < primitivesLength; i++) { var primitive = primitives[i]; - handler(primitive, i); + var value = handler(primitive, i); + + if (defined(value)) { + return value; + } } } }; ForEach.meshPrimitiveAttribute = function(primitive, handler) { var attributes = primitive.attributes; - if (defined(attributes)) { - for (var semantic in attributes) { - if (attributes.hasOwnProperty(semantic)) { - handler(attributes[semantic], semantic); + for (var semantic in attributes) { + if (attributes.hasOwnProperty(semantic)) { + var value = handler(attributes[semantic], semantic); + + if (defined(value)) { + return value; } } } }; - ForEach.meshPrimitiveTargetAttribute = function(primitive, handler) { + ForEach.meshPrimitiveTarget = function(primitive, handler) { var targets = primitive.targets; if (defined(targets)) { - for (var targetId in targets) { - if (targets.hasOwnProperty(targetId)) { - var target = targets[targetId]; - for (var attributeId in target) { - if (target.hasOwnProperty(attributeId) && attributeId !== 'extras') { - handler(target[attributeId], attributeId); - } - } + var length = targets.length; + for (var i = 0; i < length; ++i) { + var value = handler(targets[i], i); + + if (defined(value)) { + return value; + } + } + } + }; + + ForEach.meshPrimitiveTargetAttribute = function(target, handler) { + for (var semantic in target) { + if (target.hasOwnProperty(semantic)) { + var accessorId = target[semantic]; + var value = handler(accessorId, semantic); + + if (defined(value)) { + return value; } } } }; ForEach.node = function(gltf, handler) { - ForEach.topLevel(gltf, 'nodes', handler); + return ForEach.topLevel(gltf, 'nodes', handler); }; ForEach.nodeInTree = function(gltf, nodeIds, handler) { var nodes = gltf.nodes; if (defined(nodes)) { - for (var i = 0; i < nodeIds.length; i++) { + var length = nodeIds.length; + for (var i = 0; i < length; i++) { var nodeId = nodeIds[i]; var node = nodes[nodeId]; if (defined(node)) { - handler(node, nodeId); + var value = handler(node, nodeId); + + if (defined(value)) { + return value; + } + var children = node.children; if (defined(children)) { - ForEach.nodeInTree(gltf, children, handler); + value = ForEach.nodeInTree(gltf, children, handler); + + if (defined(value)) { + return value; + } } } } @@ -158,38 +317,59 @@ define([ ForEach.nodeInScene = function(gltf, scene, handler) { var sceneNodeIds = scene.nodes; if (defined(sceneNodeIds)) { - ForEach.nodeInTree(gltf, sceneNodeIds, handler); + return ForEach.nodeInTree(gltf, sceneNodeIds, handler); } }; ForEach.program = function(gltf, handler) { - ForEach.topLevel(gltf, 'programs', handler); + if (hasExtension(gltf, 'KHR_techniques_webgl')) { + return ForEach.object(gltf.extensions.KHR_techniques_webgl.programs, handler); + } + + return ForEach.topLevel(gltf, 'programs', handler); }; ForEach.sampler = function(gltf, handler) { - ForEach.topLevel(gltf, 'samplers', handler); + return ForEach.topLevel(gltf, 'samplers', handler); }; ForEach.scene = function(gltf, handler) { - ForEach.topLevel(gltf, 'scenes', handler); + return ForEach.topLevel(gltf, 'scenes', handler); }; ForEach.shader = function(gltf, handler) { - ForEach.topLevel(gltf, 'shaders', handler); + if (hasExtension(gltf, 'KHR_techniques_webgl')) { + return ForEach.object(gltf.extensions.KHR_techniques_webgl.shaders, handler); + } + + return ForEach.topLevel(gltf, 'shaders', handler); }; ForEach.skin = function(gltf, handler) { - ForEach.topLevel(gltf, 'skins', handler); + return ForEach.topLevel(gltf, 'skins', handler); }; ForEach.techniqueAttribute = function(technique, handler) { var attributes = technique.attributes; - if (defined(attributes)) { - for (var semantic in attributes) { - if (attributes.hasOwnProperty(semantic)) { - if (handler(attributes[semantic], semantic)) { - break; - } + for (var attributeName in attributes) { + if (attributes.hasOwnProperty(attributeName)) { + var value = handler(attributes[attributeName], attributeName); + + if (defined(value)) { + return value; + } + } + } + }; + + ForEach.techniqueUniform = function(technique, handler) { + var uniforms = technique.uniforms; + for (var uniformName in uniforms) { + if (uniforms.hasOwnProperty(uniformName)) { + var value = handler(uniforms[uniformName], uniformName); + + if (defined(value)) { + return value; } } } @@ -197,23 +377,27 @@ define([ ForEach.techniqueParameter = function(technique, handler) { var parameters = technique.parameters; - if (defined(parameters)) { - for (var parameterName in parameters) { - if (parameters.hasOwnProperty(parameterName)) { - if (handler(parameters[parameterName], parameterName)) { - break; - } + for (var parameterName in parameters) { + if (parameters.hasOwnProperty(parameterName)) { + var value = handler(parameters[parameterName], parameterName); + + if (defined(value)) { + return value; } } } }; ForEach.technique = function(gltf, handler) { - ForEach.topLevel(gltf, 'techniques', handler); + if (hasExtension(gltf, 'KHR_techniques_webgl')) { + return ForEach.object(gltf.extensions.KHR_techniques_webgl.techniques, handler); + } + + return ForEach.topLevel(gltf, 'techniques', handler); }; ForEach.texture = function(gltf, handler) { - ForEach.topLevel(gltf, 'textures', handler); + return ForEach.topLevel(gltf, 'textures', handler); }; return ForEach; diff --git a/Source/ThirdParty/GltfPipeline/addDefaults.js b/Source/ThirdParty/GltfPipeline/addDefaults.js index 51f46acb4b54..503f3f91b7f7 100644 --- a/Source/ThirdParty/GltfPipeline/addDefaults.js +++ b/Source/ThirdParty/GltfPipeline/addDefaults.js @@ -1,522 +1,173 @@ define([ - './addToArray', './ForEach', - '../../Core/clone', + './getAccessorByteStride', '../../Core/defaultValue', '../../Core/defined', '../../Core/WebGLConstants' ], function( - addToArray, ForEach, - clone, + getAccessorByteStride, defaultValue, defined, WebGLConstants) { 'use strict'; - var gltfTemplate = { - accessors: [], - animations : [ - { - channels : [], - samplers : [ - { - interpolation : 'LINEAR' - } - ] - } - ], - asset : {}, - buffers : [ - { - byteLength: 0, - type: 'arraybuffer' - } - ], - bufferViews: [ - { - byteLength: 0 - } - ], - cameras: [], - images: [], - materials: [ - { - values: function(material) { - var extensions = defaultValue(material.extensions, {}); - var materialsCommon = extensions.KHR_materials_common; - if (!defined(materialsCommon)) { - return {}; - } - }, - extensions: function(material) { - var extensions = defaultValue(material.extensions, {}); - var materialsCommon = extensions.KHR_materials_common; - if (defined(materialsCommon)) { - var technique = materialsCommon.technique; - var defaults = { - ambient: [0.0, 0.0, 0.0, 1.0], - emission: [0.0, 0.0, 0.0, 1.0], - transparency: 1.0 - }; - if (technique !== 'CONSTANT') { - defaults.diffuse = [0.0, 0.0, 0.0, 1.0]; - if (technique !== 'LAMBERT') { - defaults.specular = [0.0, 0.0, 0.0, 1.0]; - defaults.shininess = 0.0; - } - } - return { - KHR_materials_common: { - doubleSided: false, - transparent: false, - values: defaults - } - }; - } - } - } - ], - meshes : [ - { - primitives : [ - { - attributes : {}, - mode : WebGLConstants.TRIANGLES - } - ] - } - ], - nodes : [ - { - children : [], - matrix : function(node) { - if (!defined(node.translation) && !defined(node.rotation) && !defined(node.scale)) { - return [ - 1.0, 0.0, 0.0, 0.0, - 0.0, 1.0, 0.0, 0.0, - 0.0, 0.0, 1.0, 0.0, - 0.0, 0.0, 0.0, 1.0 - ]; - } - }, - rotation : function(node) { - if (defined(node.translation) || defined(node.scale)) { - return [0.0, 0.0, 0.0, 1.0]; - } - }, - scale : function(node) { - if (defined(node.translation) || defined(node.rotation)) { - return [1.0, 1.0, 1.0]; - } - }, - translation : function(node) { - if (defined(node.rotation) || defined(node.scale)) { - return [0.0, 0.0, 0.0]; - } - } - } - ], - programs : [ - { - attributes : [] - } - ], - samplers : [ - { - magFilter: WebGLConstants.LINEAR, - minFilter : WebGLConstants.NEAREST_MIPMAP_LINEAR, - wrapS : WebGLConstants.REPEAT, - wrapT : WebGLConstants.REPEAT - } - ], - scenes : [ - { - nodes : [] - } - ], - shaders : [], - skins : [ - { - bindShapeMatrix : [ - 1.0, 0.0, 0.0, 0.0, - 0.0, 1.0, 0.0, 0.0, - 0.0, 0.0, 1.0, 0.0, - 0.0, 0.0, 0.0, 1.0 - ] - } - ], - techniques : [ - { - parameters: {}, - attributes: {}, - uniforms: {}, - states: { - enable: [] - } - } - ], - textures : [ - { - format: WebGLConstants.RGBA, - internalFormat: WebGLConstants.RGBA, - target: WebGLConstants.TEXTURE_2D, - type: WebGLConstants.UNSIGNED_BYTE - } - ], - extensionsUsed : [], - extensionsRequired : [] - }; + /** + * Adds default glTF values if they don't exist. + * + * @param {Object} gltf A javascript object containing a glTF asset. + * @returns {Object} The modified glTF. + */ + function addDefaults(gltf) { + ForEach.accessor(gltf, function(accessor) { + accessor.byteOffset = defaultValue(accessor.byteOffset, 0); + }); - function addDefaultsFromTemplate(object, template) { - for (var id in template) { - if (template.hasOwnProperty(id)) { - var templateValue = template[id]; - if (typeof templateValue === 'function') { - templateValue = templateValue(object); - } - if (defined(templateValue)) { - if (typeof templateValue === 'object') { - if (Array.isArray(templateValue)) { - var arrayValue = defaultValue(object[id], []); - if (templateValue.length > 0) { - var arrayTemplate = templateValue[0]; - if (typeof arrayTemplate === 'object') { - var arrayValueLength = arrayValue.length; - for (var i = 0; i < arrayValueLength; i++) { - addDefaultsFromTemplate(arrayValue[i], arrayTemplate); - } - } else { - arrayValue = defaultValue(object[id], templateValue); - } - } - object[id] = arrayValue; - } else { - var applyTemplate = templateValue['*']; - object[id] = defaultValue(object[id], {}); - var objectValue = object[id]; - if (defined(applyTemplate)) { - for (var subId in objectValue) { - if (objectValue.hasOwnProperty(subId) && subId !== 'extras') { - var subObject = objectValue[subId]; - addDefaultsFromTemplate(subObject, applyTemplate); - } - } - } else { - addDefaultsFromTemplate(objectValue, templateValue); - } - } - } else { - object[id] = defaultValue(object[id], templateValue); - } - } - } - } - } + ForEach.bufferView(gltf, function(bufferView) { + bufferView.byteOffset = defaultValue(bufferView.byteOffset, 0); + }); - function getAnimatedNodes(gltf) { - var nodes = {}; - ForEach.animation(gltf, function(animation) { - ForEach.animationChannel(animation, function(channel) { - var target = channel.target; - var nodeId = target.node; - var path = target.path; - // Ignore animations that target 'weights' - if (path === 'translation' || path === 'rotation' || path === 'scale') { - nodes[nodeId] = true; - } + ForEach.mesh(gltf, function(mesh) { + ForEach.meshPrimitive(mesh, function(primitive) { + primitive.mode = defaultValue(primitive.mode, WebGLConstants.TRIANGLES); }); }); - return nodes; - } - function addDefaultTransformToAnimatedNodes(gltf) { - var animatedNodes = getAnimatedNodes(gltf); - ForEach.node(gltf, function(node, id) { - if (defined(animatedNodes[id])) { - delete node.matrix; - node.translation = defaultValue(node.translation, [0.0, 0.0, 0.0]); - node.rotation = defaultValue(node.rotation, [0.0, 0.0, 0.0, 1.0]); - node.scale = defaultValue(node.scale, [1.0, 1.0, 1.0]); + ForEach.accessorContainingVertexAttributeData(gltf, function(accessorId) { + var accessor = gltf.accessors[accessorId]; + var bufferViewId = accessor.bufferView; + accessor.normalized = defaultValue(accessor.normalized, false); + if (defined(bufferViewId)) { + var bufferView = gltf.bufferViews[bufferViewId]; + bufferView.byteStride = getAccessorByteStride(gltf, accessor); + bufferView.target = WebGLConstants.ARRAY_BUFFER; } }); - } - var defaultMaterial = { - values : { - emission : [ - 0.5, 0.5, 0.5, 1.0 - ] - }, - extras : { - _pipeline: {} - } - }; - - var defaultTechnique = { - attributes : { - a_position : 'position' - }, - parameters : { - modelViewMatrix : { - semantic : 'MODELVIEW', - type : WebGLConstants.FLOAT_MAT4 - }, - projectionMatrix : { - semantic : 'PROJECTION', - type : WebGLConstants.FLOAT_MAT4 - }, - emission : { - type : WebGLConstants.FLOAT_VEC4, - value : [ - 0.5, 0.5, 0.5, 1.0 - ] - }, - position : { - semantic: 'POSITION', - type: WebGLConstants.FLOAT_VEC3 - } - }, - states : { - enable : [ - WebGLConstants.CULL_FACE, - WebGLConstants.DEPTH_TEST - ] - }, - uniforms : { - u_modelViewMatrix : 'modelViewMatrix', - u_projectionMatrix : 'projectionMatrix', - u_emission : 'emission' - } - }; - - var defaultProgram = { - attributes : [ - 'a_position' - ] - }; - - var defaultVertexShader = { - type : WebGLConstants.VERTEX_SHADER, - extras : { - _pipeline : { - extension : '.vert', - source : '' + - 'precision highp float;\n' + - '\n' + - 'uniform mat4 u_modelViewMatrix;\n' + - 'uniform mat4 u_projectionMatrix;\n' + - '\n' + - 'attribute vec3 a_position;\n' + - '\n' + - 'void main (void)\n' + - '{\n' + - ' gl_Position = u_projectionMatrix * u_modelViewMatrix * vec4(a_position, 1.0);\n' + - '}\n' + ForEach.accessorContainingIndexData(gltf, function(accessorId) { + var accessor = gltf.accessors[accessorId]; + var bufferViewId = accessor.bufferView; + if (defined(bufferViewId)) { + var bufferView = gltf.bufferViews[bufferViewId]; + bufferView.target = WebGLConstants.ELEMENT_ARRAY_BUFFER; } - } - }; - - var defaultFragmentShader = { - type : WebGLConstants.FRAGMENT_SHADER, - extras : { - _pipeline : { - extension: '.frag', - source : '' + - 'precision highp float;\n' + - '\n' + - 'uniform vec4 u_emission;\n' + - '\n' + - 'void main(void)\n' + - '{\n' + - ' gl_FragColor = u_emission;\n' + - '}\n' - } - } - }; - - function addDefaultMaterial(gltf) { - var materials = gltf.materials; - var meshes = gltf.meshes; - - var defaultMaterialId; + }); - var meshesLength = meshes.length; - for (var meshId = 0; meshId < meshesLength; meshId++) { - var mesh = meshes[meshId]; - var primitives = mesh.primitives; - var primitivesLength = primitives.length; - for (var j = 0; j < primitivesLength; j++) { - var primitive = primitives[j]; - if (!defined(primitive.material)) { - if (!defined(defaultMaterialId)) { - defaultMaterialId = addToArray(materials, clone(defaultMaterial, true)); + ForEach.material(gltf, function(material) { + var extensions = defaultValue(material.extensions, defaultValue.EMPTY_OBJECT); + var materialsCommon = extensions.KHR_materials_common; + if (defined(materialsCommon)) { + var technique = materialsCommon.technique; + var values = defined(materialsCommon.values) ? materialsCommon.values : {}; + materialsCommon.values = values; + + values.ambient = defined(values.ambient) ? values.ambient : [0.0, 0.0, 0.0, 1.0]; + values.emission = defined(values.emission) ? values.emission : [0.0, 0.0, 0.0, 1.0]; + + values.transparency = defaultValue(values.transparency, 1.0); + values.transparent = defaultValue(values.transparent, false); + values.doubleSided = defaultValue(values.doubleSided, false); + + if (technique !== 'CONSTANT') { + values.diffuse = defined(values.diffuse) ? values.diffuse : [0.0, 0.0, 0.0, 1.0]; + if (technique !== 'LAMBERT') { + values.specular = defined(values.specular) ? values.specular : [0.0, 0.0, 0.0, 1.0]; + values.shininess = defaultValue(values.shininess, 0.0); } - primitive.material = defaultMaterialId; } + return; } - } - } - function addDefaultTechnique(gltf) { - var materials = gltf.materials; - var techniques = gltf.techniques; - var programs = gltf.programs; - var shaders = gltf.shaders; + material.emissiveFactor = defaultValue(material.emissiveFactor, [0.0, 0.0, 0.0]); + material.alphaMode = defaultValue(material.alphaMode, 'OPAQUE'); + material.doubleSided = defaultValue(material.doubleSided, false); - var defaultTechniqueId; - - var materialsLength = materials.length; - for (var materialId = 0; materialId < materialsLength; materialId++) { - var material = materials[materialId]; - var techniqueId = material.technique; - var extensions = defaultValue(material.extensions, {}); - var materialsCommon = extensions.KHR_materials_common; - if (!defined(techniqueId)) { - if (!defined(defaultTechniqueId) && !defined(materialsCommon)) { - var technique = clone(defaultTechnique, true); - defaultTechniqueId = addToArray(techniques, technique); + if (material.alphaMode === 'MASK') { + material.alphaCutoff = defaultValue(material.alphaCutoff, 0.5); + } - var program = clone(defaultProgram, true); - technique.program = addToArray(programs, program); + var techniquesExtension = extensions.KHR_techniques_webgl; + if (defined(techniquesExtension)) { + ForEach.materialValue(material, function (materialValue) { + // Check if material value is a TextureInfo object + if (defined(materialValue.index)) { + addTextureDefaults(materialValue); + } + }); + } - var vertexShader = clone(defaultVertexShader, true); - program.vertexShader = addToArray(shaders, vertexShader); + addTextureDefaults(material.emissiveTexture); + addTextureDefaults(material.normalTexture); + addTextureDefaults(material.occlusionTexture); - var fragmentShader = clone(defaultFragmentShader, true); - program.fragmentShader = addToArray(shaders, fragmentShader); - } - material.technique = defaultTechniqueId; + var pbrMetallicRoughness = material.pbrMetallicRoughness; + if (defined(pbrMetallicRoughness)) { + pbrMetallicRoughness.baseColorFactor = defaultValue(pbrMetallicRoughness.baseColorFactor, [1.0, 1.0, 1.0, 1.0]); + pbrMetallicRoughness.metallicFactor = defaultValue(pbrMetallicRoughness.metallicFactor, 1.0); + pbrMetallicRoughness.roughnessFactor = defaultValue(pbrMetallicRoughness.roughnessFactor, 1.0); + addTextureDefaults(pbrMetallicRoughness.baseColorTexture); + addTextureDefaults(pbrMetallicRoughness.metallicRoughnessTexture); } - } - } - - function addDefaultByteOffsets(gltf) { - var accessors = gltf.accessors; - var accessorLength = accessors.length; - for (var i = 0; i < accessorLength; i++) { - var accessor = accessors[i]; - if (!defined(accessor.byteOffset)) { - accessor.byteOffset = 0; + var pbrSpecularGlossiness = extensions.pbrSpecularGlossiness; + if (defined(pbrSpecularGlossiness)) { + pbrSpecularGlossiness.diffuseFactor = defaultValue(pbrSpecularGlossiness.diffuseFactor, [1.0, 1.0, 1.0, 1.0]); + pbrSpecularGlossiness.specularFactor = defaultValue(pbrSpecularGlossiness.specularFactor, [1.0, 1.0, 1.0]); + pbrSpecularGlossiness.glossinessFactor = defaultValue(pbrSpecularGlossiness.glossinessFactor, 1.0); + addTextureDefaults(pbrSpecularGlossiness.specularGlossinessTexture); } - } + }); - var bufferViews = gltf.bufferViews; + ForEach.animation(gltf, function(animation) { + ForEach.animationSampler(animation, function(sampler) { + sampler.interpolation = defaultValue(sampler.interpolation, 'LINEAR'); + }); + }); - var bufferViewsLength = bufferViews.length; - for (var j = 0; j < bufferViewsLength; j++) { - var bufferView = bufferViews[j]; - if (!defined(bufferView.byteOffset)) { - bufferView.byteOffset = 0; + var animatedNodes = getAnimatedNodes(gltf); + ForEach.node(gltf, function(node, id) { + var animated = defined(animatedNodes[id]); + if (animated || defined(node.translation) || defined(node.rotation) || defined(node.scale)) { + node.translation = defaultValue(node.translation, [0.0, 0.0, 0.0]); + node.rotation = defaultValue(node.rotation, [0.0, 0.0, 0.0, 1.0]); + node.scale = defaultValue(node.scale, [1.0, 1.0, 1.0]); + } else { + node.matrix = defaultValue(node.matrix, [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0]); } - } - } + }); + + ForEach.sampler(gltf, function(sampler) { + sampler.wrapS = defaultValue(sampler.wrapS, WebGLConstants.REPEAT); + sampler.wrapT = defaultValue(sampler.wrapT, WebGLConstants.REPEAT); + }); - function selectDefaultScene(gltf) { if (defined(gltf.scenes) && !defined(gltf.scene)) { gltf.scene = 0; } - } - function optimizeForCesium(gltf) { - // Give the diffuse uniform a semantic to support color replacement in 3D Tiles - var techniques = gltf.techniques; - var techniquesLength = techniques.length; - for (var techniqueId = 0; techniqueId < techniquesLength; techniqueId++) { - var technique = techniques[techniqueId]; - var parameters = technique.parameters; - if (defined(parameters.diffuse)) { - parameters.diffuse.semantic = '_3DTILESDIFFUSE'; - } - } + return gltf; } - function inferBufferViewTargets(gltf) { - // If bufferView elements are missing targets, we can infer their type from their use - var needsTarget = {}; - var shouldTraverse = 0; - ForEach.bufferView(gltf, function(bufferView, bufferViewId) { - if (!defined(bufferView.target)) { - needsTarget[bufferViewId] = true; - shouldTraverse++; - } - }); - if (shouldTraverse > 0) { - var accessors = gltf.accessors; - var bufferViews = gltf.bufferViews; - ForEach.mesh(gltf, function (mesh) { - ForEach.meshPrimitive(mesh, function (primitive) { - var indices = primitive.indices; - if (defined(indices)) { - var accessor = accessors[indices]; - var bufferViewId = accessor.bufferView; - if (needsTarget[bufferViewId]) { - var bufferView = bufferViews[bufferViewId]; - if (defined(bufferView)) { - bufferView.target = WebGLConstants.ELEMENT_ARRAY_BUFFER; - needsTarget[bufferViewId] = false; - shouldTraverse--; - } - } - } - ForEach.meshPrimitiveAttribute(primitive, function (accessorId) { - var accessor = accessors[accessorId]; - var bufferViewId = accessor.bufferView; - if (needsTarget[bufferViewId]) { - var bufferView = bufferViews[bufferViewId]; - if (defined(bufferView)) { - bufferView.target = WebGLConstants.ARRAY_BUFFER; - needsTarget[bufferViewId] = false; - shouldTraverse--; - } - } - }); - ForEach.meshPrimitiveTargetAttribute(primitive, function (targetAttribute) { - var bufferViewId = accessors[targetAttribute].bufferView; - if (needsTarget[bufferViewId]) { - var bufferView = bufferViews[bufferViewId]; - if (defined(bufferView)) { - bufferView.target = WebGLConstants.ARRAY_BUFFER; - needsTarget[bufferViewId] = false; - shouldTraverse--; - } - } - }); - }); - if (shouldTraverse === 0) { - return true; + function getAnimatedNodes(gltf) { + var nodes = {}; + ForEach.animation(gltf, function(animation) { + ForEach.animationChannel(animation, function(channel) { + var target = channel.target; + var nodeId = target.node; + var path = target.path; + // Ignore animations that target 'weights' + if (path === 'translation' || path === 'rotation' || path === 'scale') { + nodes[nodeId] = true; } }); - } + }); + return nodes; } - /** - * Adds default glTF values if they don't exist. - * - * The glTF asset must be initialized for the pipeline. - * - * @param {Object} gltf A javascript object containing a glTF asset. - * @param {Object} [options] An object with the following properties: - * @param {Boolean} [options.optimizeForCesium] Optimize the defaults for Cesium. Uses the Cesium sun as the default light source. - * @returns {Object} The modified glTF. - * - * @see addPipelineExtras - * @see loadGltfUris - */ - function addDefaults(gltf, options) { - options = defaultValue(options, {}); - addDefaultsFromTemplate(gltf, gltfTemplate); - addDefaultTransformToAnimatedNodes(gltf); - addDefaultMaterial(gltf); - addDefaultTechnique(gltf); - addDefaultByteOffsets(gltf); - selectDefaultScene(gltf); - inferBufferViewTargets(gltf); - if (options.optimizeForCesium) { - optimizeForCesium(gltf); + function addTextureDefaults(texture) { + if (defined(texture)) { + texture.texCoord = defaultValue(texture.texCoord, 0); } - return gltf; } return addDefaults; diff --git a/Source/ThirdParty/GltfPipeline/addExtensionsRequired.js b/Source/ThirdParty/GltfPipeline/addExtensionsRequired.js index 49ec2de50fa6..2affd1d2b842 100644 --- a/Source/ThirdParty/GltfPipeline/addExtensionsRequired.js +++ b/Source/ThirdParty/GltfPipeline/addExtensionsRequired.js @@ -12,6 +12,8 @@ define([ * * @param {Object} gltf A javascript object containing a glTF asset. * @param {String} extension The extension to add. + * + * @private */ function addExtensionsRequired(gltf, extension) { var extensionsRequired = gltf.extensionsRequired; @@ -19,10 +21,11 @@ define([ extensionsRequired = []; gltf.extensionsRequired = extensionsRequired; } - if (extensionsRequired.indexOf(extension) < 0) { + if (extensionsRequired.indexOf(extension) === -1) { extensionsRequired.push(extension); } addExtensionsUsed(gltf, extension); } + return addExtensionsRequired; }); diff --git a/Source/ThirdParty/GltfPipeline/addExtensionsUsed.js b/Source/ThirdParty/GltfPipeline/addExtensionsUsed.js index 6d8bed56db03..a008069cf114 100644 --- a/Source/ThirdParty/GltfPipeline/addExtensionsUsed.js +++ b/Source/ThirdParty/GltfPipeline/addExtensionsUsed.js @@ -10,6 +10,8 @@ define([ * * @param {Object} gltf A javascript object containing a glTF asset. * @param {String} extension The extension to add. + * + * @private */ function addExtensionsUsed(gltf, extension) { var extensionsUsed = gltf.extensionsUsed; @@ -17,9 +19,10 @@ define([ extensionsUsed = []; gltf.extensionsUsed = extensionsUsed; } - if (extensionsUsed.indexOf(extension) < 0) { + if (extensionsUsed.indexOf(extension) === -1) { extensionsUsed.push(extension); } } + return addExtensionsUsed; }); diff --git a/Source/ThirdParty/GltfPipeline/addPipelineExtras.js b/Source/ThirdParty/GltfPipeline/addPipelineExtras.js index 5f5dc2b54656..4f4b3db8162f 100644 --- a/Source/ThirdParty/GltfPipeline/addPipelineExtras.js +++ b/Source/ThirdParty/GltfPipeline/addPipelineExtras.js @@ -1,68 +1,43 @@ define([ - '../../Core/defaultValue', + './ForEach', '../../Core/defined' ], function( - defaultValue, + ForEach, defined) { 'use strict'; - // Objects with these ids should not have extras added - var exceptions = { - attributes: true, - uniforms: true, - extensions: true, - values: true, - samplers: true - }; - /** * Adds extras._pipeline to each object that can have extras in the glTF asset. + * This stage runs before updateVersion and handles both glTF 1.0 and glTF 2.0 assets. * * @param {Object} gltf A javascript object containing a glTF asset. * @returns {Object} The glTF asset with the added pipeline extras. + * + * @private */ function addPipelineExtras(gltf) { - var objectStack = []; - for (var rootArrayId in gltf) { - if (gltf.hasOwnProperty(rootArrayId)) { - var rootArray = gltf[rootArrayId]; - var rootArrayLength = rootArray.length; - for (var i = 0; i < rootArrayLength; i++) { - var rootObject = rootArray[i]; - if (defined(rootObject) && typeof rootObject === 'object') { - rootObject.extras = defaultValue(rootObject.extras, {}); - rootObject.extras._pipeline = defaultValue(rootObject.extras._pipeline, {}); - objectStack.push(rootObject); - } - } - } - } - while (objectStack.length > 0) { - var object = objectStack.pop(); - for (var propertyId in object) { - if (object.hasOwnProperty(propertyId)) { - var property = object[propertyId]; - if (defined(property) && typeof property === 'object' && propertyId !== 'extras') { - objectStack.push(property); - if (!exceptions[propertyId] && !Array.isArray(property)) { - property.extras = defaultValue(property.extras, {}); - property.extras._pipeline = defaultValue(property.extras._pipeline, {}); - } - } - } - } - } - gltf.extras = defaultValue(gltf.extras, {}); - gltf.extras._pipeline = defaultValue(gltf.extras._pipeline, {}); - gltf.asset = defaultValue(gltf.asset, {}); - gltf.asset.extras = defaultValue(gltf.asset.extras, {}); - if (defined(gltf.asset.extras) && typeof(gltf.asset.extras) !== 'object') { - gltf.asset.extras = { - extras : gltf.asset.extras - }; - } - gltf.asset.extras._pipeline = defaultValue(gltf.asset.extras._pipeline, {}); + ForEach.shader(gltf, function(shader) { + addExtras(shader); + }); + ForEach.buffer(gltf, function(buffer) { + addExtras(buffer); + }); + ForEach.image(gltf, function (image) { + addExtras(image); + ForEach.compressedImage(image, function(compressedImage) { + addExtras(compressedImage); + }); + }); + + addExtras(gltf); + return gltf; } + + function addExtras(object) { + object.extras = defined(object.extras) ? object.extras : {}; + object.extras._pipeline = defined(object.extras._pipeline) ? object.extras._pipeline : {}; + } + return addPipelineExtras; }); diff --git a/Source/ThirdParty/GltfPipeline/addToArray.js b/Source/ThirdParty/GltfPipeline/addToArray.js index 8559cb54288b..78e347799ba6 100644 --- a/Source/ThirdParty/GltfPipeline/addToArray.js +++ b/Source/ThirdParty/GltfPipeline/addToArray.js @@ -1,9 +1,18 @@ define([], function() { 'use strict'; + /** + * Adds an element to an array and returns the element's index. + * + * @param {Array} array The array to add to. + * @param {Object} element The element to add. + * + * @private + */ function addToArray(array, element) { array.push(element); return array.length - 1; } + return addToArray; }); diff --git a/Source/ThirdParty/GltfPipeline/byteLengthForComponentType.js b/Source/ThirdParty/GltfPipeline/byteLengthForComponentType.js deleted file mode 100644 index 409bc740ad48..000000000000 --- a/Source/ThirdParty/GltfPipeline/byteLengthForComponentType.js +++ /dev/null @@ -1,34 +0,0 @@ -define([ - '../../Core/WebGLConstants' - ], function( - WebGLConstants) { - 'use strict'; - - /** - * Utility function for retrieving the byte length of a component type. - * As per the spec: - * 5120 (BYTE) : 1 - * 5121 (UNSIGNED_BYTE) : 1 - * 5122 (SHORT) : 2 - * 5123 (UNSIGNED_SHORT) : 2 - * 5126 (FLOAT) : 4 - * 5125 (UNSIGNED_INT) : 4 - * - * @param {Number} [componentType] - * @returns {Number} The byte length of the component type. - */ - function byteLengthForComponentType(componentType) { - switch (componentType) { - case WebGLConstants.BYTE: - case WebGLConstants.UNSIGNED_BYTE: - return 1; - case WebGLConstants.SHORT: - case WebGLConstants.UNSIGNED_SHORT: - return 2; - case WebGLConstants.FLOAT: - case WebGLConstants.UNSIGNED_INT: - return 4; - } - } - return byteLengthForComponentType; -}); diff --git a/Source/ThirdParty/GltfPipeline/findAccessorMinMax.js b/Source/ThirdParty/GltfPipeline/findAccessorMinMax.js index 3ebf53b24eb1..cb2a46810e40 100644 --- a/Source/ThirdParty/GltfPipeline/findAccessorMinMax.js +++ b/Source/ThirdParty/GltfPipeline/findAccessorMinMax.js @@ -1,11 +1,13 @@ define([ './getAccessorByteStride', + './getComponentReader', './numberOfComponentsForType', '../../Core/arrayFill', '../../Core/ComponentDatatype', '../../Core/defined' ], function( getAccessorByteStride, + getComponentReader, numberOfComponentsForType, arrayFill, ComponentDatatype, @@ -13,51 +15,60 @@ define([ 'use strict'; /** - * Finds the min and max for an accessor in gltf. - * - * The glTF asset must be initialized for the pipeline. + * Finds the min and max values of the accessor. * * @param {Object} gltf A javascript object containing a glTF asset. * @param {Object} accessor The accessor object from the glTF asset to read. * @returns {{min: Array, max: Array}} min holding the array of minimum values and max holding the array of maximum values. * - * @see addPipelineExtras - * @see loadGltfUris + * @private */ function findAccessorMinMax(gltf, accessor) { var bufferViews = gltf.bufferViews; var buffers = gltf.buffers; var bufferViewId = accessor.bufferView; var numberOfComponents = numberOfComponentsForType(accessor.type); + + // According to the spec, when bufferView is not defined, accessor must be initialized with zeros + if (!defined(accessor.bufferView)) { + return { + min: arrayFill(new Array(numberOfComponents), 0.0), + max: arrayFill(new Array(numberOfComponents), 0.0) + }; + } + var min = arrayFill(new Array(numberOfComponents), Number.POSITIVE_INFINITY); var max = arrayFill(new Array(numberOfComponents), Number.NEGATIVE_INFINITY); - if (defined(bufferViewId) && defined(bufferViews) && bufferViews.hasOwnProperty(bufferViewId)) { - var bufferView = bufferViews[bufferViewId]; - var bufferId = bufferView.buffer; - if (defined(bufferId) && defined(buffers) && buffers.hasOwnProperty(bufferId)) { - var buffer = buffers[bufferId]; - var source = buffer.extras._pipeline.source; - - var count = accessor.count; - var byteStride = getAccessorByteStride(gltf, accessor); - var byteOffset = accessor.byteOffset + bufferView.byteOffset; - var componentType = accessor.componentType; - - for (var i = 0; i < count; i++) { - var typedArray = ComponentDatatype.createArrayBufferView(componentType, source.buffer, byteOffset + source.byteOffset, numberOfComponents); - for (var j = 0; j < numberOfComponents; j++) { - var value = typedArray[j]; - min[j] = Math.min(min[j], value); - max[j] = Math.max(max[j], value); - } - byteOffset += byteStride; - } + + var bufferView = bufferViews[bufferViewId]; + var bufferId = bufferView.buffer; + var buffer = buffers[bufferId]; + var source = buffer.extras._pipeline.source; + + var count = accessor.count; + var byteStride = getAccessorByteStride(gltf, accessor); + var byteOffset = accessor.byteOffset + bufferView.byteOffset + source.byteOffset; + var componentType = accessor.componentType; + var componentTypeByteLength = ComponentDatatype.getSizeInBytes(componentType); + var dataView = new DataView(source.buffer); + var components = new Array(numberOfComponents); + var componentReader = getComponentReader(componentType); + + for (var i = 0; i < count; i++) { + componentReader(dataView, byteOffset, numberOfComponents, componentTypeByteLength, components); + for (var j = 0; j < numberOfComponents; j++) { + var value = components[j]; + min[j] = Math.min(min[j], value); + max[j] = Math.max(max[j], value); } + byteOffset += byteStride; } + return { - min : min, - max : max + min: min, + max: max }; } + return findAccessorMinMax; }); diff --git a/Source/ThirdParty/GltfPipeline/getAccessorByteStride.js b/Source/ThirdParty/GltfPipeline/getAccessorByteStride.js index c9dbfe0f9fb4..5de99d59fe34 100644 --- a/Source/ThirdParty/GltfPipeline/getAccessorByteStride.js +++ b/Source/ThirdParty/GltfPipeline/getAccessorByteStride.js @@ -1,10 +1,10 @@ define([ - './byteLengthForComponentType', './numberOfComponentsForType', + '../../Core/ComponentDatatype', '../../Core/defined' ], function( - byteLengthForComponentType, numberOfComponentsForType, + ComponentDatatype, defined) { 'use strict'; @@ -15,13 +15,19 @@ define([ * @param {Object} gltf A javascript object containing a glTF asset. * @param {Object} accessor The accessor. * @returns {Number} The byte stride of the accessor. + * + * @private */ function getAccessorByteStride(gltf, accessor) { - var bufferView = gltf.bufferViews[accessor.bufferView]; - if (defined(bufferView.byteStride) && bufferView.byteStride > 0) { - return bufferView.byteStride; + var bufferViewId = accessor.bufferView; + if (defined(bufferViewId)) { + var bufferView = gltf.bufferViews[bufferViewId]; + if (defined(bufferView.byteStride) && bufferView.byteStride > 0) { + return bufferView.byteStride; + } } - return byteLengthForComponentType(accessor.componentType) * numberOfComponentsForType(accessor.type); + return ComponentDatatype.getSizeInBytes(accessor.componentType) * numberOfComponentsForType(accessor.type); } + return getAccessorByteStride; }); diff --git a/Source/ThirdParty/GltfPipeline/getComponentReader.js b/Source/ThirdParty/GltfPipeline/getComponentReader.js new file mode 100644 index 000000000000..c6fbf048a35a --- /dev/null +++ b/Source/ThirdParty/GltfPipeline/getComponentReader.js @@ -0,0 +1,80 @@ +define([ + '../../Core/ComponentDatatype' + ], function( + ComponentDatatype) { + 'use strict'; + + /** + * Returns a function to read and convert data from a DataView into an array. + * + * @param {Number} componentType Type to convert the data to. + * @returns {ComponentReader} Function that reads and converts data. + * + * @private + */ + function getComponentReader(componentType) { + switch (componentType) { + case ComponentDatatype.BYTE: + return function (dataView, byteOffset, numberOfComponents, componentTypeByteLength, result) { + for (var i = 0; i < numberOfComponents; ++i) { + result[i] = dataView.getInt8(byteOffset + i * componentTypeByteLength); + } + }; + case ComponentDatatype.UNSIGNED_BYTE: + return function (dataView, byteOffset, numberOfComponents, componentTypeByteLength, result) { + for (var i = 0; i < numberOfComponents; ++i) { + result[i] = dataView.getUint8(byteOffset + i * componentTypeByteLength); + } + }; + case ComponentDatatype.SHORT: + return function (dataView, byteOffset, numberOfComponents, componentTypeByteLength, result) { + for (var i = 0; i < numberOfComponents; ++i) { + result[i] = dataView.getInt16(byteOffset + i * componentTypeByteLength, true); + } + }; + case ComponentDatatype.UNSIGNED_SHORT: + return function (dataView, byteOffset, numberOfComponents, componentTypeByteLength, result) { + for (var i = 0; i < numberOfComponents; ++i) { + result[i] = dataView.getUint16(byteOffset + i * componentTypeByteLength, true); + } + }; + case ComponentDatatype.INT: + return function (dataView, byteOffset, numberOfComponents, componentTypeByteLength, result) { + for (var i = 0; i < numberOfComponents; ++i) { + result[i] = dataView.getInt32(byteOffset + i * componentTypeByteLength, true); + } + }; + case ComponentDatatype.UNSIGNED_INT: + return function (dataView, byteOffset, numberOfComponents, componentTypeByteLength, result) { + for (var i = 0; i < numberOfComponents; ++i) { + result[i] = dataView.getUint32(byteOffset + i * componentTypeByteLength, true); + } + }; + case ComponentDatatype.FLOAT: + return function (dataView, byteOffset, numberOfComponents, componentTypeByteLength, result) { + for (var i = 0; i < numberOfComponents; ++i) { + result[i] = dataView.getFloat32(byteOffset + i * componentTypeByteLength, true); + } + }; + case ComponentDatatype.DOUBLE: + return function (dataView, byteOffset, numberOfComponents, componentTypeByteLength, result) { + for (var i = 0; i < numberOfComponents; ++i) { + result[i] = dataView.getFloat64(byteOffset + i * componentTypeByteLength, true); + } + }; + } + } + + /** + * A callback function that logs messages. + * @callback ComponentReader + * + * @param {DataView} dataView The data view to read from. + * @param {Number} byteOffset The byte offset applied when reading from the data view. + * @param {Number} numberOfComponents The number of components to read. + * @param {Number} componentTypeByteLength The byte length of each component. + * @param {Number} result An array storing the components that are read. + */ + + return getComponentReader; +}); diff --git a/Source/ThirdParty/GltfPipeline/getJointCountForMaterials.js b/Source/ThirdParty/GltfPipeline/getJointCountForMaterials.js deleted file mode 100644 index ba299be639e7..000000000000 --- a/Source/ThirdParty/GltfPipeline/getJointCountForMaterials.js +++ /dev/null @@ -1,44 +0,0 @@ -define([ - './ForEach', - '../../Core/defined' - ], function( - ForEach, - defined) { - 'use strict'; - - function getJointCountForMaterials(gltf) { - var meshes = gltf.meshes; - var jointCountForMaterialId = {}; - - var nodesForSkinId = {}; - ForEach.node(gltf, function(node) { - if (defined(node.skin)) { - if (!defined(nodesForSkinId[node.skin])) { - nodesForSkinId[node.skin] = []; - } - nodesForSkinId[node.skin].push(node); - } - }); - - ForEach.skin(gltf, function(skin, skinId) { - var jointCount = skin.joints.length; - var meshPrimitiveFunction = function(primitive) { - jointCountForMaterialId[primitive.material] = jointCount; - }; - var skinnedNodes = nodesForSkinId[skinId]; - var skinnedNodesLength = skinnedNodes.length; - for (var i = 0; i < skinnedNodesLength; i++) { - var skinnedNode = skinnedNodes[i]; - var meshId = skinnedNode.mesh; - if (defined(meshId)) { - var mesh = meshes[meshId]; - ForEach.meshPrimitive(mesh, meshPrimitiveFunction); - } - } - }); - - return jointCountForMaterialId; - } - - return getJointCountForMaterials; -}); diff --git a/Source/ThirdParty/GltfPipeline/glslTypeToWebGLConstant.js b/Source/ThirdParty/GltfPipeline/glslTypeToWebGLConstant.js deleted file mode 100644 index f05c65a0c871..000000000000 --- a/Source/ThirdParty/GltfPipeline/glslTypeToWebGLConstant.js +++ /dev/null @@ -1,28 +0,0 @@ -define([ - '../../Core/WebGLConstants' - ], function( - WebGLConstants) { - 'use strict'; - - function glslTypeToWebGLConstant(glslType) { - switch (glslType) { - case 'float': - return WebGLConstants.FLOAT; - case 'vec2': - return WebGLConstants.FLOAT_VEC2; - case 'vec3': - return WebGLConstants.FLOAT_VEC3; - case 'vec4': - return WebGLConstants.FLOAT_VEC4; - case 'mat2': - return WebGLConstants.FLOAT_MAT2; - case 'mat3': - return WebGLConstants.FLOAT_MAT3; - case 'mat4': - return WebGLConstants.FLOAT_MAT4; - case 'sampler2D': - return WebGLConstants.SAMPLER_2D; - } - } - return glslTypeToWebGLConstant; -}); diff --git a/Source/ThirdParty/GltfPipeline/hasExtension.js b/Source/ThirdParty/GltfPipeline/hasExtension.js new file mode 100644 index 000000000000..84308f8a7618 --- /dev/null +++ b/Source/ThirdParty/GltfPipeline/hasExtension.js @@ -0,0 +1,21 @@ +define([ + '../../Core/defined' + ], function( + defined) { + 'use strict'; + + /** + * Checks whether the glTF has the given extension. + * + * @param {Object} gltf A javascript object containing a glTF asset. + * @param {String} extension The name of the extension. + * @returns {Boolean} Whether the glTF has the given extension. + * + * @private + */ + function hasExtension(gltf, extension) { + return defined(gltf.extensionsUsed) && (gltf.extensionsUsed.indexOf(extension) >= 0); + } + + return hasExtension; +}); diff --git a/Source/ThirdParty/GltfPipeline/moveTechniqueRenderStates.js b/Source/ThirdParty/GltfPipeline/moveTechniqueRenderStates.js new file mode 100644 index 000000000000..4c2da1660bab --- /dev/null +++ b/Source/ThirdParty/GltfPipeline/moveTechniqueRenderStates.js @@ -0,0 +1,138 @@ +define([ + './addExtensionsUsed', + './ForEach', + '../../Core/defaultValue', + '../../Core/defined', + '../../Core/WebGLConstants' + ], function( + addExtensionsUsed, + ForEach, + defaultValue, + defined, + WebGLConstants) { + 'use strict'; + + var defaultBlendEquation = [ + WebGLConstants.FUNC_ADD, + WebGLConstants.FUNC_ADD + ]; + + var defaultBlendFactors = [ + WebGLConstants.ONE, + WebGLConstants.ZERO, + WebGLConstants.ONE, + WebGLConstants.ZERO + ]; + + function isStateEnabled(renderStates, state) { + var enabled = renderStates.enable; + if (!defined(enabled)) { + return false; + } + + return (enabled.indexOf(state) > -1); + } + + var supportedBlendFactors = [ + WebGLConstants.ZERO, + WebGLConstants.ONE, + WebGLConstants.SRC_COLOR, + WebGLConstants.ONE_MINUS_SRC_COLOR, + WebGLConstants.SRC_ALPHA, + WebGLConstants.ONE_MINUS_SRC_ALPHA, + WebGLConstants.DST_ALPHA, + WebGLConstants.ONE_MINUS_DST_ALPHA, + WebGLConstants.DST_COLOR, + WebGLConstants.ONE_MINUS_DST_COLOR + ]; + + // If any of the blend factors are not supported, return the default + function getSupportedBlendFactors(value, defaultValue) { + if (!defined(value)) { + return defaultValue; + } + + for (var i = 0; i < 4; i++) { + if (supportedBlendFactors.indexOf(value[i]) === -1) { + return defaultValue; + } + } + + return value; + } + + /** + * Move glTF 1.0 technique render states to glTF 2.0 materials properties and KHR_blend extension. + * + * @param {Object} gltf A javascript object containing a glTF asset. + * @returns {Object} The updated glTF asset. + * + * @private + */ + function moveTechniqueRenderStates(gltf) { + var blendingForTechnique = {}; + var materialPropertiesForTechnique = {}; + var techniquesLegacy = gltf.techniques; + if (!defined(techniquesLegacy)) { + return gltf; + } + + ForEach.technique(gltf, function (techniqueLegacy, techniqueIndex) { + var renderStates = techniqueLegacy.states; + if (defined(renderStates)) { + var materialProperties = materialPropertiesForTechnique[techniqueIndex] = {}; + + // If BLEND is enabled, the material should have alpha mode BLEND + if (isStateEnabled(renderStates, WebGLConstants.BLEND)) { + materialProperties.alphaMode = 'BLEND'; + + var blendFunctions = renderStates.functions; + if (defined(blendFunctions) && (defined(blendFunctions.blendEquationSeparate) + || defined(blendFunctions.blendFuncSeparate))) { + blendingForTechnique[techniqueIndex] = { + blendEquation: defaultValue(blendFunctions.blendEquationSeparate, defaultBlendEquation), + blendFactors: getSupportedBlendFactors(blendFunctions.blendFuncSeparate, defaultBlendFactors) + }; + } + } + + // If CULL_FACE is not enabled, the material should be doubleSided + if (!isStateEnabled(renderStates, WebGLConstants.CULL_FACE)) { + materialProperties.doubleSided = true; + } + + delete techniqueLegacy.states; + } + }); + + if (Object.keys(blendingForTechnique).length > 0) { + if (!defined(gltf.extensions)) { + gltf.extensions = {}; + } + + addExtensionsUsed(gltf, 'KHR_blend'); + } + + ForEach.material(gltf, function (material) { + if (defined(material.technique)) { + var materialProperties = materialPropertiesForTechnique[material.technique]; + ForEach.objectLegacy(materialProperties, function (value, property) { + material[property] = value; + }); + + var blending = blendingForTechnique[material.technique]; + if (defined(blending)) { + if (!defined(material.extensions)) { + material.extensions = {}; + } + + material.extensions.KHR_blend = blending; + } + } + }); + + return gltf; + } + + return moveTechniqueRenderStates; +}); diff --git a/Source/ThirdParty/GltfPipeline/moveTechniquesToExtension.js b/Source/ThirdParty/GltfPipeline/moveTechniquesToExtension.js new file mode 100644 index 000000000000..35b4ff1124dd --- /dev/null +++ b/Source/ThirdParty/GltfPipeline/moveTechniquesToExtension.js @@ -0,0 +1,128 @@ +define([ + './addExtensionsUsed', + './addExtensionsRequired', + './addToArray', + './ForEach', + '../../Core/defined' + ], function( + addExtensionsUsed, + addExtensionsRequired, + addToArray, + ForEach, + defined) { + 'use strict'; + + /** + * Move glTF 1.0 material techniques to glTF 2.0 KHR_techniques_webgl extension. + * + * @param {Object} gltf A javascript object containing a glTF asset. + * @returns {Object} The updated glTF asset. + * + * @private + */ + function moveTechniquesToExtension(gltf) { + var techniquesLegacy = gltf.techniques; + var mappedUniforms = {}; + var updatedTechniqueIndices = {}; + if (defined(techniquesLegacy)) { + var extension = { + programs: [], + shaders: [], + techniques: [] + }; + + ForEach.technique(gltf, function (techniqueLegacy, techniqueIndex) { + var technique = { + name: techniqueLegacy.name, + program: undefined, + attributes: {}, + uniforms: {} + }; + + var parameterLegacy; + ForEach.techniqueAttribute(techniqueLegacy, function (parameterName, attributeName) { + parameterLegacy = techniqueLegacy.parameters[parameterName]; + technique.attributes[attributeName] = { + semantic: parameterLegacy.semantic + }; + }); + + ForEach.techniqueUniform(techniqueLegacy, function (parameterName, uniformName) { + parameterLegacy = techniqueLegacy.parameters[parameterName]; + technique.uniforms[uniformName] = { + count: parameterLegacy.count, + node: parameterLegacy.node, + type: parameterLegacy.type, + semantic: parameterLegacy.semantic, + value: parameterLegacy.value + }; + + // Store the name of the uniform to update material values. + mappedUniforms[parameterName] = uniformName; + }); + + var programLegacy = gltf.programs[techniqueLegacy.program]; + var program = { + name: programLegacy.name, + fragmentShader: undefined, + vertexShader: undefined + }; + + var fs = gltf.shaders[programLegacy.fragmentShader]; + program.fragmentShader = addToArray(extension.shaders, fs); + + var vs = gltf.shaders[programLegacy.vertexShader]; + program.vertexShader = addToArray(extension.shaders, vs); + + technique.program = addToArray(extension.programs, program); + + // Store the index of the new technique to reference instead. + updatedTechniqueIndices[techniqueIndex] = addToArray(extension.techniques, technique); + }); + + if (extension.techniques.length > 0) { + if (!defined(gltf.extensions)) { + gltf.extensions = {}; + } + + gltf.extensions.KHR_techniques_webgl = extension; + addExtensionsUsed(gltf, 'KHR_techniques_webgl'); + addExtensionsRequired(gltf, 'KHR_techniques_webgl'); + } + } + + ForEach.material(gltf, function (material) { + if (defined(material.technique)) { + var materialExtension = { + technique: updatedTechniqueIndices[material.technique] + }; + + ForEach.objectLegacy(material.values, function (value, parameterName) { + if (!defined(materialExtension.values)) { + materialExtension.values = {}; + } + + var uniformName = mappedUniforms[parameterName]; + materialExtension.values[uniformName] = value; + }); + + if (!defined(material.extensions)) { + material.extensions = {}; + } + + material.extensions.KHR_techniques_webgl = materialExtension; + } + + delete material.technique; + delete material.values; + }); + + delete gltf.techniques; + delete gltf.programs; + delete gltf.shaders; + + return gltf; + } + + return moveTechniquesToExtension; +}); diff --git a/Source/ThirdParty/GltfPipeline/numberOfComponentsForType.js b/Source/ThirdParty/GltfPipeline/numberOfComponentsForType.js index f87c62123c3b..9329ca1b8ebb 100644 --- a/Source/ThirdParty/GltfPipeline/numberOfComponentsForType.js +++ b/Source/ThirdParty/GltfPipeline/numberOfComponentsForType.js @@ -3,17 +3,11 @@ define([], function() { /** * Utility function for retrieving the number of components in a given type. - * As per the spec: - * 'SCALAR' : 1 - * 'VEC2' : 2 - * 'VEC3' : 3 - * 'VEC4' : 4 - * 'MAT2' : 4 - * 'MAT3' : 9 - * 'MAT4' : 16 * * @param {String} type glTF type * @returns {Number} The number of components in that type. + * + * @private */ function numberOfComponentsForType(type) { switch (type) { @@ -32,5 +26,6 @@ define([], function() { return 16; } } + return numberOfComponentsForType; }); diff --git a/Source/ThirdParty/GltfPipeline/parseBinaryGltf.js b/Source/ThirdParty/GltfPipeline/parseBinaryGltf.js deleted file mode 100644 index fd2000d6c8f9..000000000000 --- a/Source/ThirdParty/GltfPipeline/parseBinaryGltf.js +++ /dev/null @@ -1,122 +0,0 @@ -define([ - './addPipelineExtras', - './removeExtensionsUsed', - './updateVersion', - '../../Core/ComponentDatatype', - '../../Core/defined', - '../../Core/DeveloperError', - '../../Core/getMagic', - '../../Core/getStringFromTypedArray', - '../../Core/WebGLConstants' - ], function( - addPipelineExtras, - removeExtensionsUsed, - updateVersion, - ComponentDatatype, - defined, - DeveloperError, - getMagic, - getStringFromTypedArray, - WebGLConstants) { - 'use strict'; - - /** - * Parses a binary glTF buffer into glTF JSON. - * - * @param {Uint8Array} data The binary glTF data to parse. - * @returns {Object} The parsed binary glTF. - */ - function parseBinaryGltf(data) { - var headerView = ComponentDatatype.createArrayBufferView(WebGLConstants.INT, data.buffer, data.byteOffset, 5); - - // Check that the magic string is present - var magic = getMagic(data); - if (magic !== 'glTF') { - throw new DeveloperError('File is not valid binary glTF'); - } - - // Check that the version is 1 or 2 - var version = headerView[1]; - if (version !== 1 && version !== 2) { - throw new DeveloperError('Binary glTF version is not 1 or 2'); - } - - var gltf; - var buffers; - var length; - // Load binary glTF version 1 - if (version === 1) { - length = headerView[2]; - var contentLength = headerView[3]; - var contentFormat = headerView[4]; - - // Check that the content format is 0, indicating that it is JSON - if (contentFormat !== 0) { - throw new DeveloperError('Binary glTF scene format is not JSON'); - } - - var jsonStart = 20; - var binaryStart = jsonStart + contentLength; - - var contentString = getStringFromTypedArray(data, jsonStart, contentLength); - gltf = JSON.parse(contentString); - - var binaryData = data.subarray(binaryStart, length); - - buffers = gltf.buffers; - if (defined(buffers) && Object.keys(buffers).length > 0) { - var binaryGltfBuffer = buffers.binary_glTF; - // In some older models, the binary glTF buffer is named KHR_binary_glTF - if (!defined(binaryGltfBuffer)) { - binaryGltfBuffer = buffers.KHR_binary_glTF; - } - if (defined(binaryGltfBuffer)) { - binaryGltfBuffer.extras = { - _pipeline: { - source: binaryData - } - }; - } - } - // Update to glTF 2.0 - updateVersion(gltf); - // Remove the KHR_binary_glTF extension - removeExtensionsUsed(gltf, 'KHR_binary_glTF'); - addPipelineExtras(gltf); - } - - // Load binary glTF version 2 - if (version === 2) { - length = headerView[2]; - var byteOffset = 12; - var binaryBuffer; - while (byteOffset < length) { - var chunkHeaderView = ComponentDatatype.createArrayBufferView(WebGLConstants.INT, data.buffer, data.byteOffset + byteOffset, 2); - var chunkLength = chunkHeaderView[0]; - var chunkType = chunkHeaderView[1]; - byteOffset += 8; - var chunkBuffer = data.subarray(byteOffset, byteOffset + chunkLength); - byteOffset += chunkLength; - // Load JSON chunk - if (chunkType === 0x4E4F534A) { - var jsonString = getStringFromTypedArray(chunkBuffer); - gltf = JSON.parse(jsonString); - addPipelineExtras(gltf); - } - // Load Binary chunk - else if (chunkType === 0x004E4942) { - binaryBuffer = chunkBuffer; - } - } - if (defined(gltf) && defined(binaryBuffer)) { - buffers = gltf.buffers; - if (defined(buffers) && buffers.length > 0) { - var buffer = buffers[0]; - buffer.extras._pipeline.source = binaryBuffer; - } - } - } - return gltf; - } - return parseBinaryGltf; -}); diff --git a/Source/ThirdParty/GltfPipeline/parseGlb.js b/Source/ThirdParty/GltfPipeline/parseGlb.js new file mode 100644 index 000000000000..07c8c979fbda --- /dev/null +++ b/Source/ThirdParty/GltfPipeline/parseGlb.js @@ -0,0 +1,126 @@ +define([ + './addPipelineExtras', + './removeExtensionsUsed', + '../../Core/defaultValue', + '../../Core/defined', + '../../Core/getMagic', + '../../Core/getStringFromTypedArray', + '../../Core/RuntimeError' + ], function( + addPipelineExtras, + removeExtensionsUsed, + defaultValue, + defined, + getMagic, + getStringFromTypedArray, + RuntimeError) { + 'use strict'; + + var sizeOfUint32 = 4; + + /** + * Convert a binary glTF to glTF. + * + * The returned glTF has pipeline extras included. The binary data is stored in gltf.buffers[0].extras._pipeline.source. + * + * @param {Buffer} glb The glb data to parse. + * @returns {Object} A javascript object containing a glTF asset with pipeline extras included. + * + * @private + */ + function parseGlb(glb) { + // Check that the magic string is present + var magic = getMagic(glb); + if (magic !== 'glTF') { + throw new RuntimeError('File is not valid binary glTF'); + } + + var header = readHeader(glb, 0, 5); + var version = header[1]; + if (version !== 1 && version !== 2) { + throw new RuntimeError('Binary glTF version is not 1 or 2'); + } + + if (version === 1) { + return parseGlbVersion1(glb, header); + } + + return parseGlbVersion2(glb, header); + } + + function readHeader(glb, byteOffset, count) { + var dataView = new DataView(glb.buffer); + var header = new Array(count); + for (var i = 0; i < count; ++i) { + header[i] = dataView.getUint32(glb.byteOffset + byteOffset + i * sizeOfUint32, true); + } + return header; + } + + function parseGlbVersion1(glb, header) { + var length = header[2]; + var contentLength = header[3]; + var contentFormat = header[4]; + + // Check that the content format is 0, indicating that it is JSON + if (contentFormat !== 0) { + throw new RuntimeError('Binary glTF scene format is not JSON'); + } + + var jsonStart = 20; + var binaryStart = jsonStart + contentLength; + + var contentString = getStringFromTypedArray(glb, jsonStart, contentLength); + var gltf = JSON.parse(contentString); + addPipelineExtras(gltf); + + var binaryBuffer = glb.subarray(binaryStart, length); + + var buffers = gltf.buffers; + if (defined(buffers) && Object.keys(buffers).length > 0) { + // In some older models, the binary glTF buffer is named KHR_binary_glTF + var binaryGltfBuffer = defaultValue(buffers.binary_glTF, buffers.KHR_binary_glTF); + if (defined(binaryGltfBuffer)) { + binaryGltfBuffer.extras._pipeline.source = binaryBuffer; + } + } + // Remove the KHR_binary_glTF extension + removeExtensionsUsed(gltf, 'KHR_binary_glTF'); + return gltf; + } + + function parseGlbVersion2(glb, header) { + var length = header[2]; + var byteOffset = 12; + var gltf; + var binaryBuffer; + while (byteOffset < length) { + var chunkHeader = readHeader(glb, byteOffset, 2); + var chunkLength = chunkHeader[0]; + var chunkType = chunkHeader[1]; + byteOffset += 8; + var chunkBuffer = glb.subarray(byteOffset, byteOffset + chunkLength); + byteOffset += chunkLength; + // Load JSON chunk + if (chunkType === 0x4E4F534A) { + var jsonString = getStringFromTypedArray(chunkBuffer); + gltf = JSON.parse(jsonString); + addPipelineExtras(gltf); + } + // Load Binary chunk + else if (chunkType === 0x004E4942) { + binaryBuffer = chunkBuffer; + } + } + if (defined(gltf) && defined(binaryBuffer)) { + var buffers = gltf.buffers; + if (defined(buffers) && buffers.length > 0) { + var buffer = buffers[0]; + buffer.extras._pipeline.source = binaryBuffer; + } + } + return gltf; + } + + return parseGlb; +}); diff --git a/Source/ThirdParty/GltfPipeline/removeExtensionsRequired.js b/Source/ThirdParty/GltfPipeline/removeExtensionsRequired.js index 54d8002887bb..c77cf1ff9e07 100644 --- a/Source/ThirdParty/GltfPipeline/removeExtensionsRequired.js +++ b/Source/ThirdParty/GltfPipeline/removeExtensionsRequired.js @@ -9,6 +9,8 @@ define([ * * @param {Object} gltf A javascript object containing a glTF asset. * @param {String} extension The extension to remove. + * + * @private */ function removeExtensionsRequired(gltf, extension) { var extensionsRequired = gltf.extensionsRequired; diff --git a/Source/ThirdParty/GltfPipeline/removeExtensionsUsed.js b/Source/ThirdParty/GltfPipeline/removeExtensionsUsed.js index f3fc28de7bca..7ded30174af7 100644 --- a/Source/ThirdParty/GltfPipeline/removeExtensionsUsed.js +++ b/Source/ThirdParty/GltfPipeline/removeExtensionsUsed.js @@ -11,6 +11,8 @@ define([ * * @param {Object} gltf A javascript object containing a glTF asset. * @param {String} extension The extension to remove. + * + * @private */ function removeExtensionsUsed(gltf, extension) { var extensionsUsed = gltf.extensionsUsed; @@ -25,5 +27,6 @@ define([ } } } + return removeExtensionsUsed; }); diff --git a/Source/ThirdParty/GltfPipeline/removePipelineExtras.js b/Source/ThirdParty/GltfPipeline/removePipelineExtras.js deleted file mode 100644 index abe075ca8a75..000000000000 --- a/Source/ThirdParty/GltfPipeline/removePipelineExtras.js +++ /dev/null @@ -1,34 +0,0 @@ -define([ - '../../Core/defined' - ], function( - defined) { - 'use strict'; - - /** - * Iterate through the objects within each glTF object and delete their pipeline extras object. - * - * @param {Object} object Root object to remove pipeline extras. - * @returns {Object} glTF with no pipeline extras. - */ - function removePipelineExtras(object) { - if (defined(object) && typeof object === 'object') { - if (defined(object.extras) && defined(object.extras._pipeline)) { - delete object.extras._pipeline; - // Also delete extras if extras._pipeline is the only extras object - if (Object.keys(object.extras).length === 0) { - delete object.extras; - } - } - - //Recursively check subproperties for extras - for (var propertyId in object) { - if (object.hasOwnProperty(propertyId)) { - removePipelineExtras(object[propertyId]); - } - } - } - - return object; - } - return removePipelineExtras; -}); diff --git a/Source/ThirdParty/GltfPipeline/removeUnusedElements.js b/Source/ThirdParty/GltfPipeline/removeUnusedElements.js new file mode 100644 index 000000000000..c906e386ef52 --- /dev/null +++ b/Source/ThirdParty/GltfPipeline/removeUnusedElements.js @@ -0,0 +1,266 @@ +define([ + './ForEach', + './hasExtension', + '../../Core/defined' + ], function( + ForEach, + hasExtension, + defined) { + 'use strict'; + + /** + * Removes unused elements from gltf. + * This function currently only works for accessors, buffers, and bufferViews. + * + * @param {Object} gltf A javascript object containing a glTF asset. + * + * @private + */ + function removeUnusedElements(gltf) { + removeUnusedElementsByType(gltf, 'accessor'); + removeUnusedElementsByType(gltf, 'bufferView'); + removeUnusedElementsByType(gltf, 'buffer'); + return gltf; + } + + var TypeToGltfElementName = { + accessor: 'accessors', + buffer: 'buffers', + bufferView: 'bufferViews' + }; + + function removeUnusedElementsByType(gltf, type) { + var name = TypeToGltfElementName[type]; + var arrayOfObjects = gltf[name]; + + if (defined(arrayOfObjects)) { + var removed = 0; + var usedIds = getListOfElementsIdsInUse[type](gltf); + var length = arrayOfObjects.length; + + for (var i = 0; i < length; ++i) { + if (!usedIds[i]) { + Remove[type](gltf, i - removed); + removed++; + } + } + } + } + + /** + * Contains functions for removing elements from a glTF hierarchy. + * Since top-level glTF elements are arrays, when something is removed, referring + * indices need to be updated. + * @constructor + * + * @private + */ + function Remove() {} + + Remove.accessor = function(gltf, accessorId) { + var accessors = gltf.accessors; + + accessors.splice(accessorId, 1); + + ForEach.mesh(gltf, function(mesh) { + ForEach.meshPrimitive(mesh, function(primitive) { + // Update accessor ids for the primitives. + ForEach.meshPrimitiveAttribute(primitive, function(attributeAccessorId, semantic) { + if (attributeAccessorId > accessorId) { + primitive.attributes[semantic]--; + } + }); + + // Update accessor ids for the targets. + ForEach.meshPrimitiveTarget(primitive, function(target) { + ForEach.meshPrimitiveTargetAttribute(target, function(attributeAccessorId, semantic) { + if (attributeAccessorId > accessorId) { + target[semantic]--; + } + }); + }); + var indices = primitive.indices; + if (defined(indices) && indices > accessorId) { + primitive.indices--; + } + }); + }); + + ForEach.skin(gltf, function(skin) { + if (defined(skin.inverseBindMatrices) && skin.inverseBindMatrices > accessorId) { + skin.inverseBindMatrices--; + } + }); + + ForEach.animation(gltf, function(animation) { + ForEach.animationSampler(animation, function(sampler) { + if (defined(sampler.input) && sampler.input > accessorId) { + sampler.input--; + } + if (defined(sampler.output) && sampler.output > accessorId) { + sampler.output--; + } + }); + }); + }; + + Remove.buffer = function(gltf, bufferId) { + var buffers = gltf.buffers; + + buffers.splice(bufferId, 1); + + ForEach.bufferView(gltf, function(bufferView) { + if (defined(bufferView.buffer) && bufferView.buffer > bufferId) { + bufferView.buffer--; + } + }); + }; + + Remove.bufferView = function(gltf, bufferViewId) { + var bufferViews = gltf.bufferViews; + + bufferViews.splice(bufferViewId, 1); + + ForEach.accessor(gltf, function(accessor) { + if (defined(accessor.bufferView) && accessor.bufferView > bufferViewId) { + accessor.bufferView--; + } + }); + + ForEach.shader(gltf, function(shader) { + if (defined(shader.bufferView) && shader.bufferView > bufferViewId) { + shader.bufferView--; + } + }); + + ForEach.image(gltf, function(image) { + if (defined(image.bufferView) && image.bufferView > bufferViewId) { + image.bufferView--; + } + ForEach.compressedImage(image, function(compressedImage) { + var compressedImageBufferView = compressedImage.bufferView; + if (defined(compressedImageBufferView) && compressedImageBufferView > bufferViewId) { + compressedImage.bufferView--; + } + }); + }); + + if (hasExtension(gltf, 'KHR_draco_mesh_compression')) { + ForEach.mesh(gltf, function (mesh) { + ForEach.meshPrimitive(mesh, function (primitive) { + if (defined(primitive.extensions) && + defined(primitive.extensions.KHR_draco_mesh_compression)) { + if (primitive.extensions.KHR_draco_mesh_compression.bufferView > bufferViewId) { + primitive.extensions.KHR_draco_mesh_compression.bufferView--; + } + } + }); + }); + } + }; + + /** + * Contains functions for getting a list of element ids in use by the glTF asset. + * @constructor + * + * @private + */ + function getListOfElementsIdsInUse() {} + + getListOfElementsIdsInUse.accessor = function(gltf) { + // Calculate accessor's that are currently in use. + var usedAccessorIds = {}; + + ForEach.mesh(gltf, function(mesh) { + ForEach.meshPrimitive(mesh, function(primitive) { + ForEach.meshPrimitiveAttribute(primitive, function(accessorId) { + usedAccessorIds[accessorId] = true; + }); + ForEach.meshPrimitiveTarget(primitive, function(target) { + ForEach.meshPrimitiveTargetAttribute(target, function(accessorId) { + usedAccessorIds[accessorId] = true; + }); + }); + var indices = primitive.indices; + if (defined(indices)) { + usedAccessorIds[indices] = true; + } + }); + }); + + ForEach.skin(gltf, function(skin) { + if (defined(skin.inverseBindMatrices)) { + usedAccessorIds[skin.inverseBindMatrices] = true; + } + }); + + ForEach.animation(gltf, function(animation) { + ForEach.animationSampler(animation, function(sampler) { + if (defined(sampler.input)) { + usedAccessorIds[sampler.input] = true; + } + if (defined(sampler.output)) { + usedAccessorIds[sampler.output] = true; + } + }); + }); + + return usedAccessorIds; + }; + + getListOfElementsIdsInUse.buffer = function(gltf) { + // Calculate buffer's that are currently in use. + var usedBufferIds = {}; + + ForEach.bufferView(gltf, function(bufferView) { + if (defined(bufferView.buffer)) { + usedBufferIds[bufferView.buffer] = true; + } + }); + + return usedBufferIds; + }; + + getListOfElementsIdsInUse.bufferView = function(gltf) { + // Calculate bufferView's that are currently in use. + var usedBufferViewIds = {}; + + ForEach.accessor(gltf, function(accessor) { + if (defined(accessor.bufferView)) { + usedBufferViewIds[accessor.bufferView] = true; + } + }); + + ForEach.shader(gltf, function(shader) { + if (defined(shader.bufferView)) { + usedBufferViewIds[shader.bufferView] = true; + } + }); + + ForEach.image(gltf, function(image) { + if (defined(image.bufferView)) { + usedBufferViewIds[image.bufferView] = true; + } + ForEach.compressedImage(image, function(compressedImage) { + if (defined(compressedImage.bufferView)) { + usedBufferViewIds[compressedImage.bufferView] = true; + } + }); + }); + + if (hasExtension(gltf, 'KHR_draco_mesh_compression')) { + ForEach.mesh(gltf, function(mesh) { + ForEach.meshPrimitive(mesh, function(primitive) { + if (defined(primitive.extensions) && + defined(primitive.extensions.KHR_draco_mesh_compression)) { + usedBufferViewIds[primitive.extensions.KHR_draco_mesh_compression.bufferView] = true; + } + }); + }); + } + + return usedBufferViewIds; + }; + + return removeUnusedElements; +}); diff --git a/Source/ThirdParty/GltfPipeline/techniqueParameterForSemantic.js b/Source/ThirdParty/GltfPipeline/techniqueParameterForSemantic.js deleted file mode 100644 index a0dc6adfe587..000000000000 --- a/Source/ThirdParty/GltfPipeline/techniqueParameterForSemantic.js +++ /dev/null @@ -1,29 +0,0 @@ -define([ - '../../Core/defined' - ], function( - defined) { - 'use strict'; - - /** - * Retrieves the technique parameter that has a matching semantic. - * - * @param {Object} technique A javascript object containing a glTF technique. - * @param {String} semantic The search string for semantics. - * @returns {String} The technique parameter with matching semantic. - * - * @private - */ - function techniqueParameterForSemantic(technique, semantic) { - var parameters = technique.parameters; - for (var parameterName in parameters) { - if (parameters.hasOwnProperty(parameterName)) { - var parameter = parameters[parameterName]; - var parameterSemantic = parameter.semantic; - if (defined(parameterSemantic) && parameterSemantic === semantic) { - return parameterName; - } - } - } - } - return techniqueParameterForSemantic; -}); diff --git a/Source/ThirdParty/GltfPipeline/updateVersion.js b/Source/ThirdParty/GltfPipeline/updateVersion.js index 637af6603081..c083be681089 100644 --- a/Source/ThirdParty/GltfPipeline/updateVersion.js +++ b/Source/ThirdParty/GltfPipeline/updateVersion.js @@ -1,37 +1,45 @@ define([ - './addExtensionsRequired', + './addExtensionsUsed', './addToArray', + './findAccessorMinMax', './ForEach', './getAccessorByteStride', './numberOfComponentsForType', + './moveTechniqueRenderStates', + './moveTechniquesToExtension', + './removeUnusedElements', '../../Core/Cartesian3', - '../../Core/Math', '../../Core/clone', '../../Core/ComponentDatatype', '../../Core/defaultValue', '../../Core/defined', + '../../Core/isArray', '../../Core/Quaternion', '../../Core/WebGLConstants' ], function( - addExtensionsRequired, + addExtensionsUsed, addToArray, + findAccessorMinMax, ForEach, getAccessorByteStride, numberOfComponentsForType, + moveTechniqueRenderStates, + moveTechniquesToExtension, + removeUnusedElements, Cartesian3, - CesiumMath, clone, ComponentDatatype, defaultValue, defined, + isArray, Quaternion, WebGLConstants) { 'use strict'; var updateFunctions = { - '0.8' : glTF08to10, - '1.0' : glTF10to20, - '2.0' : undefined + '0.8': glTF08to10, + '1.0': glTF10to20, + '2.0': undefined }; /** @@ -43,9 +51,11 @@ define([ * @param {Object} [options] Options for updating the glTF. * @param {String} [options.targetVersion] The glTF will be upgraded until it hits the specified version. * @returns {Object} The updated glTF asset. + * + * @private */ function updateVersion(gltf, options) { - options = defaultValue(options, {}); + options = defaultValue(options, defaultValue.EMPTY_OBJECT); var targetVersion = options.targetVersion; var version = gltf.version; @@ -53,14 +63,16 @@ define([ version: '1.0' }); - version = defaultValue(version, gltf.asset.version); - // invalid version + gltf.asset.version = defaultValue(gltf.asset.version, '1.0'); + version = defaultValue(version, gltf.asset.version).toString(); + + // Invalid version if (!updateFunctions.hasOwnProperty(version)) { - // try truncating trailing version numbers, could be a number as well if it is 0.8 + // Try truncating trailing version numbers, could be a number as well if it is 0.8 if (defined(version)) { - version = ('' + version).substring(0, 3); + version = version.substring(0, 3); } - // default to 1.0 if it cannot be determined + // Default to 1.0 if it cannot be determined if (!updateFunctions.hasOwnProperty(version)) { version = '1.0'; } @@ -72,7 +84,7 @@ define([ if (version === targetVersion) { break; } - updateFunction(gltf); + updateFunction(gltf, options); version = gltf.asset.version; updateFunction = updateFunctions[version]; } @@ -102,7 +114,7 @@ define([ var primitives = mesh.primitives; if (defined(primitives)) { var primitivesLength = primitives.length; - for (var i = 0; i < primitivesLength; i++) { + for (var i = 0; i < primitivesLength; ++i) { var primitive = primitives[i]; var defaultMode = defaultValue(primitive.primitive, WebGLConstants.TRIANGLES); primitive.mode = defaultValue(primitive.mode, defaultMode); @@ -215,11 +227,18 @@ define([ } var asset = gltf.asset; asset.version = '1.0'; - // profile should be an object, not a string - if (!defined(asset.profile) || (typeof asset.profile === 'string')) { + // Profile should be an object, not a string + if (typeof asset.profile === 'string') { + var split = asset.profile.split(' '); + asset.profile = { + api: split[0], + version: split[1] + }; + } else { asset.profile = {}; } - // version property should be in asset, not on the root element + + // Version property should be in asset, not on the root element if (defined(gltf.version)) { delete gltf.version; } @@ -227,13 +246,18 @@ define([ updateInstanceTechniques(gltf); // primitive.primitive should be primitive.mode setPrimitiveModes(gltf); - // node rotation should be quaternion, not axis-angle + // Node rotation should be quaternion, not axis-angle // node.instanceSkin is deprecated updateNodes(gltf); - // animations that target rotations should be quaternion, not axis-angle + // Animations that target rotations should be quaternion, not axis-angle updateAnimations(gltf); // technique.pass and techniques.passes are deprecated removeTechniquePasses(gltf); + // gltf.allExtensions -> extensionsUsed + if (defined(gltf.allExtensions)) { + gltf.extensionsUsed = gltf.allExtensions; + delete gltf.allExtensions; + } // gltf.lights -> khrMaterialsCommon.lights if (defined(gltf.lights)) { var extensions = defaultValue(gltf.extensions, {}); @@ -242,11 +266,7 @@ define([ extensions.KHR_materials_common = materialsCommon; materialsCommon.lights = gltf.lights; delete gltf.lights; - } - // gltf.allExtensions -> extensionsUsed - if (defined(gltf.allExtensions)) { - gltf.extensionsUsed = gltf.allExtensions; - gltf.allExtensions = undefined; + addExtensionsUsed(gltf, 'KHR_materials_common'); } } @@ -278,7 +298,7 @@ define([ var value = object[id]; mapping[id] = array.length; array.push(value); - if (!defined(value.name) && typeof(value) === 'object') { + if (!defined(value.name)) { value.name = id; } } @@ -291,15 +311,19 @@ define([ var globalMapping = { accessors: {}, animations: {}, - bufferViews: {}, buffers: {}, + bufferViews: {}, cameras: {}, + images: {}, materials: {}, meshes: {}, nodes: {}, programs: {}, + samplers: {}, + scenes: {}, shaders: {}, skins: {}, + textures: {}, techniques: {} }; @@ -318,18 +342,11 @@ define([ // Convert top level objects to arrays for (var topLevelId in gltf) { - if (gltf.hasOwnProperty(topLevelId) && topLevelId !== 'extras' && topLevelId !== 'asset' && topLevelId !== 'extensions') { + if (gltf.hasOwnProperty(topLevelId) && defined(globalMapping[topLevelId])) { var objectMapping = {}; var object = gltf[topLevelId]; - if (typeof(object) === 'object' && !Array.isArray(object)) { - gltf[topLevelId] = objectToArray(object, objectMapping); - globalMapping[topLevelId] = objectMapping; - if (topLevelId === 'animations') { - objectMapping = {}; - object.samplers = objectToArray(object.samplers, objectMapping); - globalMapping[topLevelId].samplers = objectMapping; - } - } + gltf[topLevelId] = objectToArray(object, objectMapping); + globalMapping[topLevelId] = objectMapping; } } @@ -384,18 +401,10 @@ define([ parameter.node = globalMapping.nodes[parameter.node]; } var value = parameter.value; - if (defined(value)) { - if (Array.isArray(value)) { - if (value.length === 1) { - var textureId = value[0]; - if (typeof textureId === 'string') { - value[0] = globalMapping.textures[textureId]; - } - } - } - else if (typeof value === 'string') { - parameter.value = [globalMapping.textures[value]]; - } + if (typeof value === 'string') { + parameter.value = { + index: globalMapping.textures[value] + }; } }); }); @@ -416,7 +425,7 @@ define([ var children = node.children; if (defined(children)) { var childrenLength = children.length; - for (i = 0; i < childrenLength; i++) { + for (i = 0; i < childrenLength; ++i) { children[i] = globalMapping.nodes[children[i]]; } } @@ -426,12 +435,9 @@ define([ var meshesLength = meshes.length; if (meshesLength > 0) { node.mesh = globalMapping.meshes[meshes[0]]; - for (i = 1; i < meshesLength; i++) { + for (i = 1; i < meshesLength; ++i) { var meshNode = { - mesh: globalMapping.meshes[meshes[i]], - extras: { - _pipeline: {} - } + mesh: globalMapping.meshes[meshes[i]] }; var meshNodeId = addToArray(gltf.nodes, meshNode); if (!defined(children)) { @@ -446,31 +452,32 @@ define([ if (defined(node.camera)) { node.camera = globalMapping.cameras[node.camera]; } + if (defined(node.skin)) { + node.skin = globalMapping.skins[node.skin]; + } if (defined(node.skeletons)) { // Assign skeletons to skins var skeletons = node.skeletons; var skeletonsLength = skeletons.length; if ((skeletonsLength > 0) && defined(node.skin)) { - var skin = gltf.skins[globalMapping.skins[node.skin]]; + var skin = gltf.skins[node.skin]; skin.skeleton = globalMapping.nodes[skeletons[0]]; } delete node.skeletons; } - if (defined(node.skin)) { - node.skin = globalMapping.skins[node.skin]; - } if (defined(node.jointName)) { - delete(node.jointName); + delete node.jointName; } }); ForEach.skin(gltf, function(skin) { if (defined(skin.inverseBindMatrices)) { skin.inverseBindMatrices = globalMapping.accessors[skin.inverseBindMatrices]; } - var joints = []; var jointNames = skin.jointNames; if (defined(jointNames)) { - for (i = 0; i < jointNames.length; i++) { + var joints = []; + var jointNamesLength = jointNames.length; + for (i = 0; i < jointNamesLength; ++i) { joints[i] = jointNameToId[jointNames[i]]; } skin.joints = joints; @@ -481,7 +488,7 @@ define([ var sceneNodes = scene.nodes; if (defined(sceneNodes)) { var sceneNodesLength = sceneNodes.length; - for (i = 0; i < sceneNodesLength; i++) { + for (i = 0; i < sceneNodesLength; ++i) { sceneNodes[i] = globalMapping.nodes[sceneNodes[i]]; } } @@ -493,36 +500,23 @@ define([ sampler.input = globalMapping.accessors[sampler.input]; sampler.output = globalMapping.accessors[sampler.output]; }); - var channels = animation.channels; - if (defined(channels)) { - var channelsLength = channels.length; - for (i = 0; i < channelsLength; i++) { - var channel = channels[i]; - channel.sampler = samplerMapping[channel.sampler]; - var target = channel.target; - if (defined(target)) { - target.node = globalMapping.nodes[target.id]; - delete target.id; - } + ForEach.animationChannel(animation, function(channel) { + channel.sampler = samplerMapping[channel.sampler]; + var target = channel.target; + if (defined(target)) { + target.node = globalMapping.nodes[target.id]; + delete target.id; } - } + }); }); ForEach.material(gltf, function(material) { if (defined(material.technique)) { material.technique = globalMapping.techniques[material.technique]; } ForEach.materialValue(material, function(value, name) { - if (Array.isArray(value)) { - if (value.length === 1) { - var textureId = value[0]; - if (typeof textureId === 'string') { - value[0] = globalMapping.textures[textureId]; - } - } - } - else if (typeof value === 'string') { + if (typeof value === 'string') { material.values[name] = { - index : globalMapping.textures[value] + index: globalMapping.textures[value] }; } }); @@ -531,15 +525,7 @@ define([ var materialsCommon = extensions.KHR_materials_common; if (defined(materialsCommon)) { ForEach.materialValue(materialsCommon, function(value, name) { - if (Array.isArray(value)) { - if (value.length === 1) { - var textureId = value[0]; - if (typeof textureId === 'string') { - value[0] = globalMapping.textures[textureId]; - } - } - } - else if (typeof value === 'string') { + if (typeof value === 'string') { materialsCommon.values[name] = { index: globalMapping.textures[value] }; @@ -561,26 +547,20 @@ define([ delete image.extensions; } } - if (defined(image.extras)) { - var compressedImages = image.extras.compressedImage3DTiles; - for (var type in compressedImages) { - if (compressedImages.hasOwnProperty(type)) { - var compressedImage = compressedImages[type]; - var compressedExtensions = compressedImage.extensions; - if (defined(compressedExtensions)) { - var compressedBinaryGltf = compressedExtensions.KHR_binary_glTF; - if (defined(compressedBinaryGltf)) { - compressedImage.bufferView = globalMapping.bufferViews[compressedBinaryGltf.bufferView]; - compressedImage.mimeType = compressedBinaryGltf.mimeType; - delete compressedExtensions.KHR_binary_glTF; - } - if (Object.keys(compressedExtensions).length === 0) { - delete compressedImage.extensions; - } - } + ForEach.compressedImage(image, function(compressedImage) { + var compressedExtensions = compressedImage.extensions; + if (defined(compressedExtensions)) { + var compressedBinaryGltf = compressedExtensions.KHR_binary_glTF; + if (defined(compressedBinaryGltf)) { + compressedImage.bufferView = globalMapping.bufferViews[compressedBinaryGltf.bufferView]; + compressedImage.mimeType = compressedBinaryGltf.mimeType; + delete compressedExtensions.KHR_binary_glTF; + } + if (Object.keys(extensions).length === 0) { + delete compressedImage.extensions; } } - } + }); }); ForEach.texture(gltf, function(texture) { if (defined(texture.sampler)) { @@ -592,22 +572,39 @@ define([ }); } - function stripProfile(gltf) { + function removeEmptyArrays(gltf) { + for (var topLevelId in gltf) { + if (gltf.hasOwnProperty(topLevelId)) { + var array = gltf[topLevelId]; + if (isArray(array) && array.length === 0) { + delete gltf[topLevelId]; + } + } + } + ForEach.node(gltf, function(node) { + if (defined(node.children) && node.children.length === 0) { + delete node.children; + } + }); + } + + function stripAsset(gltf) { var asset = gltf.asset; delete asset.profile; + delete asset.premultipliedAlpha; } var knownExtensions = { - CESIUM_RTC : true, - KHR_materials_common : true, - WEB3D_quantized_attributes : true + CESIUM_RTC: true, + KHR_materials_common: true, + WEB3D_quantized_attributes: true }; function requireKnownExtensions(gltf) { var extensionsUsed = gltf.extensionsUsed; gltf.extensionsRequired = defaultValue(gltf.extensionsRequired, []); if (defined(extensionsUsed)) { var extensionsUsedLength = extensionsUsed.length; - for (var i = 0; i < extensionsUsedLength; i++) { + for (var i = 0; i < extensionsUsedLength; ++i) { var extension = extensionsUsed[i]; if (defined(knownExtensions[extension])) { gltf.extensionsRequired.push(extension); @@ -622,6 +619,15 @@ define([ }); } + function removeTextureProperties(gltf) { + ForEach.texture(gltf, function(texture) { + delete texture.format; + delete texture.internalFormat; + delete texture.target; + delete texture.type; + }); + } + function requireAttributeSetIndex(gltf) { ForEach.mesh(gltf, function(mesh) { ForEach.meshPrimitive(mesh, function(primitive) { @@ -653,25 +659,37 @@ define([ var knownSemantics = { POSITION: true, NORMAL: true, - TEXCOORD: true, - COLOR: true, - JOINT: true, - WEIGHT: true + TANGENT: true + }; + var indexedSemantics = { + COLOR: 'COLOR', + JOINT : 'JOINTS', + JOINTS: 'JOINTS', + TEXCOORD: 'TEXCOORD', + WEIGHT: 'WEIGHTS', + WEIGHTS: 'WEIGHTS' }; function underscoreApplicationSpecificSemantics(gltf) { var mappedSemantics = {}; ForEach.mesh(gltf, function(mesh) { ForEach.meshPrimitive(mesh, function(primitive) { - /* jshint unused:vars */ + /*eslint-disable no-unused-vars*/ ForEach.meshPrimitiveAttribute(primitive, function(accessorId, semantic) { if (semantic.charAt(0) !== '_') { var setIndex = semantic.search(/_[0-9]+/g); var strippedSemantic = semantic; + var suffix = '_0'; if (setIndex >= 0) { strippedSemantic = semantic.substring(0, setIndex); + suffix = semantic.substring(setIndex); } - if (!defined(knownSemantics[strippedSemantic])) { - var newSemantic = '_' + semantic; + var newSemantic; + var indexedSemantic = indexedSemantics[strippedSemantic]; + if (defined(indexedSemantic)) { + newSemantic = indexedSemantic + suffix; + mappedSemantics[semantic] = newSemantic; + } else if (!defined(knownSemantics[strippedSemantic])) { + newSemantic = '_' + semantic; mappedSemantics[semantic] = newSemantic; } } @@ -698,47 +716,6 @@ define([ }); } - function removeScissorFromTechniques(gltf) { - ForEach.technique(gltf, function(technique) { - var techniqueStates = technique.states; - if (defined(techniqueStates)) { - var techniqueFunctions = techniqueStates.functions; - if (defined(techniqueFunctions)) { - delete techniqueFunctions.scissor; - } - var enableStates = techniqueStates.enable; - if (defined(enableStates)) { - var scissorIndex = enableStates.indexOf(WebGLConstants.SCISSOR_TEST); - if (scissorIndex >= 0) { - enableStates.splice(scissorIndex, 1); - } - } - } - }); - } - - function clampTechniqueFunctionStates(gltf) { - ForEach.technique(gltf, function(technique) { - var techniqueStates = technique.states; - if (defined(techniqueStates)) { - var functions = techniqueStates.functions; - if (defined(functions)) { - var blendColor = functions.blendColor; - if (defined(blendColor)) { - for (var i = 0; i < 4; i++) { - blendColor[i] = CesiumMath.clamp(blendColor[i], 0.0, 1.0); - } - } - var depthRange = functions.depthRange; - if (defined(depthRange)) { - depthRange[1] = CesiumMath.clamp(depthRange[1], 0.0, 1.0); - depthRange[0] = CesiumMath.clamp(depthRange[0], 0.0, depthRange[1]); - } - } - } - }); - } - function clampCameraParameters(gltf) { ForEach.camera(gltf, function(camera) { var perspective = camera.perspective; @@ -755,172 +732,140 @@ define([ }); } + function computeAccessorByteStride(gltf, accessor) { + return (defined(accessor.byteStride) && accessor.byteStride !== 0) ? accessor.byteStride : getAccessorByteStride(gltf, accessor); + } + function requireByteLength(gltf) { ForEach.buffer(gltf, function(buffer) { if (!defined(buffer.byteLength)) { buffer.byteLength = buffer.extras._pipeline.source.length; } }); - ForEach.bufferView(gltf, function(bufferView) { - if (!defined(bufferView.byteLength)) { - var bufferViewBufferId = bufferView.buffer; - var bufferViewBuffer = gltf.buffers[bufferViewBufferId]; - bufferView.byteLength = bufferViewBuffer.byteLength; + ForEach.accessor(gltf, function(accessor) { + var bufferViewId = accessor.bufferView; + if (defined(bufferViewId)) { + var bufferView = gltf.bufferViews[bufferViewId]; + var accessorByteStride = computeAccessorByteStride(gltf, accessor); + var accessorByteEnd = accessor.byteOffset + accessor.count * accessorByteStride; + bufferView.byteLength = Math.max(defaultValue(bufferView.byteLength, 0), accessorByteEnd); } }); } function moveByteStrideToBufferView(gltf) { + var i; + var j; + var bufferView; var bufferViews = gltf.bufferViews; - var bufferViewsToDelete = {}; - ForEach.accessor(gltf, function(accessor) { - var oldBufferViewId = accessor.bufferView; - if (defined(oldBufferViewId)) { - if (!defined(bufferViewsToDelete[oldBufferViewId])) { - bufferViewsToDelete[oldBufferViewId] = true; - } - var bufferView = clone(bufferViews[oldBufferViewId]); - var accessorByteStride = (defined(accessor.byteStride) && accessor.byteStride !== 0) ? accessor.byteStride : getAccessorByteStride(gltf, accessor); - if (defined(accessorByteStride)) { - bufferView.byteStride = accessorByteStride; - if (bufferView.byteStride !== 0) { - bufferView.byteLength = accessor.count * accessorByteStride; - } - bufferView.byteOffset += accessor.byteOffset; - accessor.byteOffset = 0; - delete accessor.byteStride; - } - accessor.bufferView = addToArray(bufferViews, bufferView); - } - }); - var bufferViewShiftMap = {}; - var bufferViewRemovalCount = 0; - /* jshint unused:vars */ - ForEach.bufferView(gltf, function(bufferView, bufferViewId) { - if (defined(bufferViewsToDelete[bufferViewId])) { - bufferViewRemovalCount++; - } else { - bufferViewShiftMap[bufferViewId] = bufferViewId - bufferViewRemovalCount; + var bufferViewHasVertexAttributes = {}; + ForEach.accessorContainingVertexAttributeData(gltf, function(accessorId) { + var accessor = gltf.accessors[accessorId]; + if (defined(accessor.bufferView)) { + bufferViewHasVertexAttributes[accessor.bufferView] = true; } }); - var removedCount = 0; - for (var bufferViewId in bufferViewsToDelete) { - if (defined(bufferViewId)) { - var index = parseInt(bufferViewId) - removedCount; - bufferViews.splice(index, 1); - removedCount++; - } - } - + // Map buffer views to a list of accessors + var bufferViewMap = {}; ForEach.accessor(gltf, function(accessor) { - var accessorBufferView = accessor.bufferView; - if (defined(accessorBufferView)) { - accessor.bufferView = bufferViewShiftMap[accessorBufferView]; + if (defined(accessor.bufferView)) { + bufferViewMap[accessor.bufferView] = defaultValue(bufferViewMap[accessor.bufferView], []); + bufferViewMap[accessor.bufferView].push(accessor); } }); - ForEach.shader(gltf, function(shader) { - var shaderBufferView = shader.bufferView; - if (defined(shaderBufferView)) { - shader.bufferView = bufferViewShiftMap[shaderBufferView]; - } - }); + // Split accessors with different byte strides + for (var bufferViewId in bufferViewMap) { + if (bufferViewMap.hasOwnProperty(bufferViewId)) { + bufferView = bufferViews[bufferViewId]; + var accessors = bufferViewMap[bufferViewId]; + accessors.sort(function(a, b) { + return a.byteOffset - b.byteOffset; + }); + var currentByteOffset = 0; + var currentIndex = 0; + var accessorsLength = accessors.length; + for (i = 0; i < accessorsLength; ++i) { + var accessor = accessors[i]; + var accessorByteStride = computeAccessorByteStride(gltf, accessor); + var accessorByteOffset = accessor.byteOffset; + var accessorByteLength = accessor.count * accessorByteStride; + delete accessor.byteStride; - ForEach.image(gltf, function(image) { - var imageBufferView = image.bufferView; - if (defined(imageBufferView)) { - image.bufferView = bufferViewShiftMap[imageBufferView]; - } - if (defined(image.extras)) { - var compressedImages = image.extras.compressedImage3DTiles; - for (var type in compressedImages) { - if (compressedImages.hasOwnProperty(type)) { - var compressedImage = compressedImages[type]; - var compressedImageBufferView = compressedImage.bufferView; - if (defined(compressedImageBufferView)) { - compressedImage.bufferView = bufferViewShiftMap[compressedImageBufferView]; + var nextAccessorByteStride = (i < accessorsLength - 1) ? computeAccessorByteStride(gltf, accessors[i + 1]) : undefined; + if (accessorByteStride !== nextAccessorByteStride) { + var newBufferView = clone(bufferView, true); + if (bufferViewHasVertexAttributes[bufferViewId]) { + newBufferView.byteStride = accessorByteStride; } + newBufferView.byteOffset += currentByteOffset; + newBufferView.byteLength = accessorByteOffset + accessorByteLength - currentByteOffset; + var newBufferViewId = addToArray(bufferViews, newBufferView); + for (j = currentIndex; j <= i; ++j) { + accessor = accessors[j]; + accessor.bufferView = newBufferViewId; + accessor.byteOffset = accessor.byteOffset - currentByteOffset; + } + currentByteOffset = accessorByteOffset + accessorByteLength; + currentIndex = i + 1; } } } - }); - } + } - function stripTechniqueAttributeValues(gltf) { - ForEach.technique(gltf, function(technique) { - ForEach.techniqueAttribute(technique, function(attribute) { - var parameter = technique.parameters[attribute]; - if (defined(parameter.value)) { - delete parameter.value; - } - }); - }); + // Remove unused buffer views + removeUnusedElements(gltf); } - function stripTechniqueParameterCount(gltf) { - ForEach.technique(gltf, function(technique) { - ForEach.techniqueParameter(technique, function(parameter) { - if (defined(parameter.count)) { - var semantic = parameter.semantic; - if (!defined(semantic) || (semantic !== 'JOINTMATRIX' && semantic.indexOf('_') !== 0)) { - delete parameter.count; - } - } - }); + function requirePositionAccessorMinMax(gltf) { + ForEach.accessorWithSemantic(gltf, 'POSITION', function(accessorId) { + var accessor = gltf.accessors[accessorId]; + if (!defined(accessor.min) || !defined(accessor.max)) { + var minMax = findAccessorMinMax(gltf, accessor); + accessor.min = minMax.min; + accessor.max = minMax.max; + } }); } - function addKHRTechniqueExtension(gltf) { - var techniques = gltf.techniques; - if (defined(techniques) && techniques.length > 0) { - addExtensionsRequired(gltf, 'KHR_technique_webgl'); - } - } - function glTF10to20(gltf) { - if (!defined(gltf.asset)) { - gltf.asset = {}; - } - if (!defined(gltf.asset.extras)) { - gltf.asset.extras = {}; - } - var asset = gltf.asset; - asset.version = '2.0'; - asset.extras.gltf_pipeline_upgrade_10to20 = true; + gltf.asset = defaultValue(gltf.asset, {}); + gltf.asset.version = '2.0'; // material.instanceTechnique properties should be directly on the material. instanceTechnique is a gltf 0.8 property but is seen in some 1.0 models. updateInstanceTechniques(gltf); // animation.samplers now refers directly to accessors and animation.parameters should be removed removeAnimationSamplersIndirection(gltf); - // top-level objects are now arrays referenced by index instead of id + // Top-level objects are now arrays referenced by index instead of id objectsToArrays(gltf); // asset.profile no longer exists - stripProfile(gltf); - // move known extensions from extensionsUsed to extensionsRequired + stripAsset(gltf); + // Move known extensions from extensionsUsed to extensionsRequired requireKnownExtensions(gltf); // bufferView.byteLength and buffer.byteLength are required requireByteLength(gltf); // byteStride moved from accessor to bufferView moveByteStrideToBufferView(gltf); + // accessor.min and accessor.max must be defined for accessors containing POSITION attributes + requirePositionAccessorMinMax(gltf); // buffer.type is unnecessary and should be removed removeBufferType(gltf); + // Remove format, internalFormat, target, and type + removeTextureProperties(gltf); // TEXCOORD and COLOR attributes must be written with a set index (TEXCOORD_#) requireAttributeSetIndex(gltf); // Add underscores to application-specific parameters underscoreApplicationSpecificSemantics(gltf); - // remove scissor from techniques - removeScissorFromTechniques(gltf); - // clamp technique function states to min/max - clampTechniqueFunctionStates(gltf); - // clamp camera parameters + // Clamp camera parameters clampCameraParameters(gltf); - // a technique parameter specified as an attribute cannot have a value - stripTechniqueAttributeValues(gltf); - // only techniques with a JOINTMATRIX or application specific semantic may have a defined count property - stripTechniqueParameterCount(gltf); - // add KHR_technique_webgl extension - addKHRTechniqueExtension(gltf); + // Move legacy technique render states to material properties and add KHR_blend extension blending functions + moveTechniqueRenderStates(gltf); + // Add material techniques to KHR_techniques_webgl extension, removing shaders, programs, and techniques + moveTechniquesToExtension(gltf); + // Remove empty arrays + removeEmptyArrays(gltf); } + return updateVersion; }); From 9d907df8e65e75cc85eee2b50789057006910369 Mon Sep 17 00:00:00 2001 From: ggetz Date: Mon, 16 Jul 2018 17:08:03 -0400 Subject: [PATCH 02/52] Cleanup --- Source/Scene/ClassificationModel.js | 2 +- Source/Scene/Model.js | 17 ++++++++--------- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/Source/Scene/ClassificationModel.js b/Source/Scene/ClassificationModel.js index e628df0e348e..3f2fb412a199 100644 --- a/Source/Scene/ClassificationModel.js +++ b/Source/Scene/ClassificationModel.js @@ -133,7 +133,7 @@ define([ var gltfMeshes = gltf.meshes; var gltfNode = gltfNodes.rootNode; - if (!defined(gltfNode)) { + if (!defined(gltfNode) || !defined(gltfNode.meshes)) { throw new RuntimeError('Only one node is supported for classification and it must have a mesh.'); } diff --git a/Source/Scene/Model.js b/Source/Scene/Model.js index 63bd0356e635..71982b8d930d 100644 --- a/Source/Scene/Model.js +++ b/Source/Scene/Model.js @@ -2342,9 +2342,10 @@ define([ if (!defined(material)) { return attributeLocations; } + var technique = techniques[material._technique]; if (!defined(technique)) { - return; + return attributeLocations; } var attributes = technique.attributes; @@ -2920,8 +2921,8 @@ define([ }); return { - map : uniformMap, // uniform name -> function for the renderer - values : uniformValues, // material parameter name -> ModelMaterial for modifying the parameter at runtime + map : uniformMap, + values : uniformValues, jointMatrixUniformName : jointMatrixUniformName, morphWeightsUniformName : morphWeightsUniformName }; @@ -3377,10 +3378,10 @@ define([ var program = programs[programId]; var shader = shaders[program.vertexShader].extras._pipeline.source; if (model.extensionsUsed.WEB3D_quantized_attributes || model._dequantizeInShader) { - var quantizedVS = quantizedVertexShaders[programId]; + var quantizedVS = quantizedVertexShaders[programId]; if (!defined(quantizedVS)) { - quantizedVS = modifyShaderForQuantizedAttributes(shader, programId, model); - quantizedVertexShaders[programId] = quantizedVS; + quantizedVS = modifyShaderForQuantizedAttributes(shader, programId, model); + quantizedVertexShaders[programId] = quantizedVS; } shader = quantizedVS; } @@ -4263,13 +4264,11 @@ define([ // glTF pipeline updates addPipelineExtras(this.gltf); - updateVersion(this.gltf); if (defined(this.gltf.asset) && defined(this.gltf.asset.extras) && - this.gltf.asset.extras.gltf_pipeline_upgrade_10to20) { + this.gltf.asset.extras.gltf_pipeline_upgrade_10to20) { this._forwardAxis = Axis.X; } - addDefaults(this.gltf); var options = { From e82b4b6291db5472ed9fd589b72c36f1c76c2815 Mon Sep 17 00:00:00 2001 From: Sean Lilley Date: Thu, 19 Jul 2018 18:30:21 -0400 Subject: [PATCH 03/52] Doc edits --- Source/Scene/Model.js | 8 ++++---- Source/Scene/ModelMaterial.js | 12 +++--------- Source/Scene/ModelMesh.js | 10 ++-------- Source/Scene/ModelNode.js | 10 ++-------- 4 files changed, 11 insertions(+), 29 deletions(-) diff --git a/Source/Scene/Model.js b/Source/Scene/Model.js index 71982b8d930d..28b152a59a2c 100644 --- a/Source/Scene/Model.js +++ b/Source/Scene/Model.js @@ -603,12 +603,12 @@ define([ this._runtime = { animations : undefined, rootNodes : undefined, - nodes : undefined, // Indexed with the node property's name, i.e., glTF id + nodes : undefined, // Indexed with the node's index nodesByName : undefined, // Indexed with name property in the node skinnedNodes : undefined, meshesByName : undefined, // Indexed with the name property in the mesh materialsByName : undefined, // Indexed with the name property in the material - materialsById : undefined // Indexed with the material's property name + materialsById : undefined // Indexed with the material's index }; this._uniformMaps = {}; // Not cached since it can be targeted by glTF animation @@ -1547,8 +1547,8 @@ define([ if (!defined(sourcePrograms[programId])) { sourcePrograms[programId] = clone(programs[programId]); model._loadResources.programsToCreate.enqueue({ - id: programId, - technique: techniqueId + id : programId, + technique : techniqueId }); } }); diff --git a/Source/Scene/ModelMaterial.js b/Source/Scene/ModelMaterial.js index 5726a532ef14..bebec280cfe3 100644 --- a/Source/Scene/ModelMaterial.js +++ b/Source/Scene/ModelMaterial.js @@ -34,10 +34,7 @@ define([ defineProperties(ModelMaterial.prototype, { /** - * The value of the name property of this material. This is the - * name assigned by the artist when the asset is created. This can be - * different than the name of the material property ({@link ModelMaterial#id}), - * which is internal to glTF. + * The value of the name property of this material. * * @memberof ModelMaterial.prototype * @@ -51,10 +48,7 @@ define([ }, /** - * The name of the glTF JSON property for this material. This is guaranteed - * to be unique among all materials. It may not match the material's - * name property (@link ModelMaterial#name), which is assigned by - * the artist when the asset is created. + * The index of the material. * * @memberof ModelMaterial.prototype * @@ -80,7 +74,7 @@ define([ * * @example * material.setValue('diffuse', new Cesium.Cartesian4(1.0, 0.0, 0.0, 1.0)); // vec4 - * material.setValue('shininess', 256.0); // scalar + * material.setValue('shininess', 256.0); // scalar */ ModelMaterial.prototype.setValue = function(name, value) { //>>includeStart('debug', pragmas.debug); diff --git a/Source/Scene/ModelMesh.js b/Source/Scene/ModelMesh.js index 6b1363d3b83f..0acb1c546f64 100644 --- a/Source/Scene/ModelMesh.js +++ b/Source/Scene/ModelMesh.js @@ -31,10 +31,7 @@ define([ defineProperties(ModelMesh.prototype, { /** - * The value of the name property of this mesh. This is the - * name assigned by the artist when the asset is created. This can be - * different than the name of the mesh property ({@link ModelMesh#id}), - * which is internal to glTF. + * The value of the name property of this mesh. * * @memberof ModelMesh.prototype * @@ -48,10 +45,7 @@ define([ }, /** - * The name of the glTF JSON property for this mesh. This is guaranteed - * to be unique among all meshes. It may not match the mesh's - * name property (@link ModelMesh#name), which is assigned by - * the artist when the asset is created. + * The index of the mesh. * * @memberof ModelMesh.prototype * diff --git a/Source/Scene/ModelNode.js b/Source/Scene/ModelNode.js index 619093d16196..051380ee4caf 100644 --- a/Source/Scene/ModelNode.js +++ b/Source/Scene/ModelNode.js @@ -42,10 +42,7 @@ define([ defineProperties(ModelNode.prototype, { /** - * The value of the name property of this node. This is the - * name assigned by the artist when the asset is created. This can be - * different than the name of the node property ({@link ModelNode#id}), - * which is internal to glTF. + * The value of the name property of this node. * * @memberof ModelNode.prototype * @@ -59,10 +56,7 @@ define([ }, /** - * The name of the glTF JSON property for this node. This is guaranteed - * to be unique among all nodes. It may not match the node's - * name property (@link ModelNode#name), which is assigned by - * the artist when the asset is created. + * The index of the node. * * @memberof ModelNode.prototype * From 395eb34ae79a540e00cccc9c22b8e30b5ebec4c0 Mon Sep 17 00:00:00 2001 From: Sean Lilley Date: Mon, 23 Jul 2018 17:48:08 -0400 Subject: [PATCH 04/52] Minor cleanup --- Source/Scene/Model.js | 2 +- Source/Scene/ModelUtility.js | 2 +- Source/Scene/processModelMaterialsCommon.js | 3 +-- Source/Scene/processPbrMetallicRoughness.js | 3 +-- 4 files changed, 4 insertions(+), 6 deletions(-) diff --git a/Source/Scene/Model.js b/Source/Scene/Model.js index 28b152a59a2c..ae8dbc71f255 100644 --- a/Source/Scene/Model.js +++ b/Source/Scene/Model.js @@ -2194,7 +2194,7 @@ define([ } } - function createSamplers(model, context) { + function createSamplers(model) { var loadResources = model._loadResources; if (loadResources.createSamplers) { diff --git a/Source/Scene/ModelUtility.js b/Source/Scene/ModelUtility.js index d1cdd8cb83c4..d288f7e3e329 100644 --- a/Source/Scene/ModelUtility.js +++ b/Source/Scene/ModelUtility.js @@ -391,7 +391,7 @@ define([ 'KHR_binary_glTF' : true, 'KHR_draco_mesh_compression' : true, 'KHR_materials_common' : true, - 'KHR_techniques_webgl': true, + 'KHR_techniques_webgl' : true, 'WEB3D_quantized_attributes' : true }; diff --git a/Source/Scene/processModelMaterialsCommon.js b/Source/Scene/processModelMaterialsCommon.js index c8fd54254680..7a1a5cbcfb7c 100644 --- a/Source/Scene/processModelMaterialsCommon.js +++ b/Source/Scene/processModelMaterialsCommon.js @@ -17,8 +17,7 @@ define([ addToArray, ForEach, hasExtension, - numberOfComponentsForType - ) { + numberOfComponentsForType) { 'use strict'; /** diff --git a/Source/Scene/processPbrMetallicRoughness.js b/Source/Scene/processPbrMetallicRoughness.js index 17458246ab48..8facade5626a 100644 --- a/Source/Scene/processPbrMetallicRoughness.js +++ b/Source/Scene/processPbrMetallicRoughness.js @@ -17,8 +17,7 @@ define([ addToArray, ForEach, hasExtension, - numberOfComponentsForType -) { + numberOfComponentsForType) { 'use strict'; /** From 173f4b5df5d9f4b030b925ef3400532a519c47d1 Mon Sep 17 00:00:00 2001 From: ggetz Date: Wed, 25 Jul 2018 16:26:53 -0400 Subject: [PATCH 05/52] Cleanup model with new gltf-pipeline --- Source/Scene/Model.js | 359 ++++++++++++++++-------------------------- 1 file changed, 135 insertions(+), 224 deletions(-) diff --git a/Source/Scene/Model.js b/Source/Scene/Model.js index ae8dbc71f255..0536b0288e62 100644 --- a/Source/Scene/Model.js +++ b/Source/Scene/Model.js @@ -232,8 +232,6 @@ define([ * Cesium supports glTF assets with the following extensions: *