From 1406b32e6ca44c7ba491ee4b3c90fe0285434c18 Mon Sep 17 00:00:00 2001 From: Rob Taglang Date: Fri, 28 Apr 2017 10:26:57 -0400 Subject: [PATCH 01/35] Update version -> 2.0 (#271) * Added updateVersion stage as well as some refactoring * Split out into multiple functions * Cleaned up a few failing tests * Added new upgrades to specs * Application specific parameters are prefixed with underscores * Migrated changes back from cesium * Changed 1.1 to 2.0 * Lots of 1.0->2.0 changes in pipeline stages * Tweaks from model generation * Generate default material * Add updateVersion to buildForCesium * Select default scene * A few more small changes * Add removePipelineExtras to cesium build * kmc fixes * Build global cesium include * Update * Update CHANGES.md * Added two more update functions * Update CHANGES.md * Strip version numbers when guessing if invalid * WIP Array-based Traversal * More WIP changes * Removed combineMeshes -> nodes only have a singular mesh now * Operator -> operate * combineNodes, removeUnused and dagToTree traversal changes * More WIP * Bulk WIP changes for traversal * Fixed a few more failing tests * Removed findUsedIds * WIP, switching workspaces * WIP, pretty much just AO left * Fixed a few more tests * All tests pass * Removed riggedSimpleUnoptimized * Delete generateTangentsBitangents models * Don't look for slots in array, just append * Small fixes from testing * More fixes * A few test fixes and byteStride -> bufferView * A few more test fixes * Missed a function * Removed vestigial byteStride references * Some fixes from cesium changes * Fixed cesium dependency list * Fixed some plurality issues * Add KHR_technique_webgl extensions if there are techniques --- CHANGES.md | 2 + gulpfile.js | 26 +- index.js | 2 + lib/AccessorReader.js | 10 +- lib/ForEach.js | 195 ++ lib/MergeDuplicateProperties.js | 207 +-- lib/NodeHelpers.js | 96 +- lib/Pipeline.js | 73 +- lib/PrimitiveHelpers.js | 13 +- lib/Remove.js | 269 +++ lib/RemoveUnusedProperties.js | 447 +++-- lib/addCesiumRTC.js | 2 + lib/addDefaults.js | 294 +-- lib/addExtensionsRequired.js | 26 + lib/addPipelineExtras.js | 16 +- lib/addToArray.js | 7 + lib/bakeAmbientOcclusion.js | 144 +- lib/cesiumGeometryToGltfPrimitive.js | 14 +- lib/changeAccessorComponentType.js | 30 +- lib/combineMeshes.js | 69 - lib/combineNodes.js | 127 +- lib/combinePrimitives.js | 33 +- lib/compressIntegerAccessors.js | 50 +- lib/compressTextureCoordinates.js | 169 +- lib/compressTextures.js | 82 +- lib/convertDagToTree.js | 91 +- lib/createAccessor.js | 54 +- lib/createAccessorUsageTables.js | 158 +- lib/encodeImages.js | 45 +- lib/findAccessorMinMax.js | 2 +- lib/findUsedIds.js | 27 - lib/generateModelMaterialsCommon.js | 4 +- lib/generateNormals.js | 7 +- lib/generateTangentsBitangents.js | 49 +- lib/getAccessorByteStride.js | 10 +- lib/getAccessorsForSemantic.js | 40 - lib/getBinaryGltf.js | 219 ++- lib/getStatistics.js | 89 +- lib/getUniqueId.js | 29 - lib/isTexture.js | 17 + lib/loadGltfUris.js | 216 ++- lib/mergeBuffers.js | 74 +- lib/mergeDuplicateVertices.js | 21 +- lib/octEncodeNormals.js | 176 +- lib/optimizeForVertexCache.js | 57 +- lib/parseBinaryGltf.js | 273 +-- lib/processModelMaterialsCommon.js | 346 ++-- lib/quantizeAttributes.js | 57 +- lib/removeDuplicatePrimitives.js | 71 +- lib/removeExtensionsRequired.js | 25 + lib/removeExtensionsUsed.js | 27 + lib/removePipelineExtras.js | 1 + lib/removeUnusedVertices.js | 5 +- lib/uninterleaveAndPackBuffers.js | 250 ++- lib/updateVersion.js | 626 ++++++- lib/writeBinaryGltf.js | 28 +- lib/writeGltf.js | 28 +- lib/writeSource.js | 71 +- .../ambientOcclusion/cube_over_ground.gltf | 267 ++- .../CesiumTexturedBoxTest.gltf | 157 +- .../CesiumTexturedBoxTestAddExtras.gltf | 147 +- .../CesiumTexturedBoxTestEmbedded.gltf | 153 +- .../CesiumTexturedBoxTestTransparent.gltf | 147 +- .../CesiumTexturedBoxTestUnusedTree.gltf | 182 +- .../CesiumTexturedBoxTest_Binary.gltf | 148 +- .../CesiumTexturedBoxTest_BinaryCheck.gltf | 191 +- .../CesiumTexturedBoxTest_BinaryInput.gltf | 162 +- specs/data/combineObjects/fiveBox.gltf | 194 +- .../dagToTree/DagTestSingleDuplicate.gltf | 39 +- specs/data/dagToTree/DagTestSingleNode.gltf | 16 +- .../dagToTree/DagTestSubgraphDuplicate.gltf | 62 +- specs/data/dagToTree/DagTestTree.gltf | 29 +- specs/data/dagToTree/DagTestTwoRoots.gltf | 55 +- .../data/generateNormals/box_no_normals.gltf | 86 +- specs/data/generateNormals/box_normals.gltf | 128 +- ...iumTexturedBoxTest_TangentsBitangents.gltf | 313 ---- .../riggedSimpleUnoptimized/riggedSimple.bin | Bin 10468 -> 0 bytes .../riggedSimpleUnoptimized/riggedSimple.glb | Bin 18745 -> 0 bytes .../riggedSimpleUnoptimized/riggedSimple.gltf | 620 ------- .../riggedSimple0FS.glsl | 24 - .../riggedSimple0VS.glsl | 19 - .../riggedSimple_Embedded.gltf | 588 ------ specs/lib/MergeDuplicatePropertiesSpec.js | 258 ++- specs/lib/NodeHelpersSpec.js | 69 +- specs/lib/PipelineSpec.js | 18 +- specs/lib/RemoveUnusedPropertiesSpec.js | 1626 +++++++---------- specs/lib/addDefaultsSpec.js | 362 ++-- specs/lib/addPipelineExtrasSpec.js | 84 +- specs/lib/bakeAmbientOcclusionSpec.js | 267 ++- specs/lib/changeAccessorComponentTypeSpec.js | 89 +- specs/lib/combineMeshesSpec.js | 132 -- specs/lib/combineNodesSpec.js | 370 ++-- specs/lib/combinePrimitivesSpec.js | 448 ++--- specs/lib/compressIntegerAccessorsSpec.js | 186 +- specs/lib/compressTextureCoordinatesSpec.js | 238 ++- specs/lib/compressTexturesSpec.js | 44 +- specs/lib/convertDagToTreeSpec.js | 196 +- specs/lib/encodeImagesSpec.js | 24 +- specs/lib/findAccessorMinMaxSpec.js | 3 +- specs/lib/findUsedIdsSpec.js | 39 - specs/lib/generateNormalsSpec.js | 10 +- specs/lib/generateTangentsBitangentsSpec.js | 129 +- specs/lib/getBinaryGltfSpec.js | 224 +-- specs/lib/getStatisticsSpec.js | 115 +- specs/lib/getUniqueIdSpec.js | 84 - specs/lib/loadBufferUrisSpec.js | 56 +- specs/lib/loadImageUrisSpec.js | 80 +- specs/lib/loadShaderUrisSpec.js | 65 +- specs/lib/mergeBuffersSpec.js | 97 +- specs/lib/mergeDuplicateVerticesSpec.js | 201 +- specs/lib/octEncodeNormalsSpec.js | 241 ++- specs/lib/optimizeForVertexCacheSpec.js | 2 +- specs/lib/parseBinaryGltfSpec.js | 271 ++- specs/lib/processModelMaterialsCommonSpec.js | 172 +- specs/lib/quantizeAttributesSpec.js | 140 +- specs/lib/removeDuplicatePrimitivesSpec.js | 24 +- specs/lib/removeUnusedVerticesSpec.js | 555 +++--- specs/lib/uninterleaveAndPackBuffersSpec.js | 106 +- specs/lib/updateVersionSpec.js | 248 ++- specs/lib/writeBinaryGltfSpec.js | 31 +- specs/lib/writeBuffersSpec.js | 27 +- specs/lib/writeImagesSpec.js | 31 +- specs/lib/writeShadersSpec.js | 29 +- 123 files changed, 7883 insertions(+), 8831 deletions(-) create mode 100644 lib/ForEach.js create mode 100644 lib/Remove.js create mode 100644 lib/addExtensionsRequired.js create mode 100644 lib/addToArray.js delete mode 100644 lib/combineMeshes.js delete mode 100644 lib/findUsedIds.js delete mode 100644 lib/getAccessorsForSemantic.js delete mode 100644 lib/getUniqueId.js create mode 100644 lib/isTexture.js create mode 100644 lib/removeExtensionsRequired.js create mode 100644 lib/removeExtensionsUsed.js delete mode 100644 specs/data/generateTangentsBitangents/CesiumTexturedBoxTest_TangentsBitangents.gltf delete mode 100644 specs/data/riggedSimpleUnoptimized/riggedSimple.bin delete mode 100644 specs/data/riggedSimpleUnoptimized/riggedSimple.glb delete mode 100644 specs/data/riggedSimpleUnoptimized/riggedSimple.gltf delete mode 100644 specs/data/riggedSimpleUnoptimized/riggedSimple0FS.glsl delete mode 100644 specs/data/riggedSimpleUnoptimized/riggedSimple0VS.glsl delete mode 100644 specs/data/riggedSimpleUnoptimized/riggedSimple_Embedded.gltf delete mode 100644 specs/lib/combineMeshesSpec.js delete mode 100644 specs/lib/findUsedIdsSpec.js delete mode 100644 specs/lib/getUniqueIdSpec.js diff --git a/CHANGES.md b/CHANGES.md index fb059294..897a9128 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -19,6 +19,8 @@ Change Log * Change Cesium `Geometry`'s and `VertexFormat`'s `binormal` attribute to bitangent. * Fixed a bug in `combinePrimitives` where combining primitives can overflow uint16 for the resulting indices. [#230](https://github.com/AnalyticalGraphicsInc/gltf-pipeline/issues/230) * Made `generateNormals` stage optional and added `smoothNormals` option for generating smooth normals if the model does not have normals. [#240](https://github.com/AnalyticalGraphicsInc/gltf-pipeline/pull/240) +* `updateVersion` stage for upgrades the glTF version of an asset from `1.0` to `2.0`. [#223](https://github.com/AnalyticalGraphicsInc/gltf-pipeline/pull/223) + * All pipeline stages now operate on glTF `2.0` assets. ### 0.1.0-alpha10 - 2017-01-10 * Added `tangentsBitangents` generation option diff --git a/gulpfile.js b/gulpfile.js index 536b5bcd..da431bae 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -194,13 +194,17 @@ function amdify(source, subDependencyMapping) { paths.push(requireMapping[variable]); } } - var definePathsHeader = '\'' + paths.join('\',\n \'') + '\''; - var defineVariablesHeader = variables.join(',\n '); var defineHeader = '/*global define*/\n' + - 'define([\n' + - ' ' + definePathsHeader + '\n' + - ' ], function(\n' + - ' ' + defineVariablesHeader + ') {\n '; + 'define([], function() {\n '; + if (paths.length > 0) { + var definePathsHeader = '\'' + paths.join('\',\n \'') + '\''; + var defineVariablesHeader = variables.join(',\n '); + defineHeader = '/*global define*/\n' + + 'define([\n' + + ' ' + definePathsHeader + '\n' + + ' ], function(\n' + + ' ' + defineVariablesHeader + ') {\n '; + } var defineFooter = '\n});\n'; if (defined(returnValue)) { defineFooter = '\n return ' + returnValue + ';' + defineFooter; @@ -273,17 +277,23 @@ gulp.task('build-cesium', function () { var outputDir = 'dist/cesium'; var files = [ 'addDefaults.js', + 'addExtensionsRequired.js', 'addExtensionsUsed.js', 'addPipelineExtras.js', + 'addToArray.js', 'byteLengthForComponentType.js', 'findAccessorMinMax.js', + 'ForEach.js', 'getAccessorByteStride.js', 'getStatistics.js', - 'getUniqueId.js', 'numberOfComponentsForType.js', 'parseBinaryGltf.js', 'processModelMaterialsCommon.js', - 'techniqueParameterForSemantic.js' + 'removePipelineExtras.js', + 'removeExtensionsRequired.js', + 'removeExtensionsUsed.js', + 'techniqueParameterForSemantic.js', + 'updateVersion.js' ]; var subDependencyMapping = { cesium : { diff --git a/index.js b/index.js index 7a7e9d7d..dd8e23e4 100644 --- a/index.js +++ b/index.js @@ -2,6 +2,7 @@ module.exports = { AccessorReader : require('./lib/AccessorReader'), addCesiumRTC : require('./lib/addCesiumRTC'), addDefaults : require('./lib/addDefaults'), + addExtensionsRequired : require('./lib/addExtensionsRequired'), addExtensionsUsed : require('./lib/addExtensionsUsed'), addPipelineExtras : require('./lib/addPipelineExtras'), bakeAmbientOcclusion : require('./lib/bakeAmbientOcclusion'), @@ -41,6 +42,7 @@ module.exports = { removeUnusedVertices : require('./lib/removeUnusedVertices'), triangleAxisAlignedBoundingBoxOverlap : require('./lib/triangleAxisAlignedBoundingBoxOverlap'), uninterleaveAndPackBuffers : require('./lib/uninterleaveAndPackBuffers'), + updateVersion : require('./lib/updateVersion'), writeAccessor : require('./lib/writeAccessor'), writeBinaryGltf : require('./lib/writeBinaryGltf'), writeBufferComponent : require('./lib/writeBufferComponent'), diff --git a/lib/AccessorReader.js b/lib/AccessorReader.js index 634690ec..0a1e69d9 100644 --- a/lib/AccessorReader.js +++ b/lib/AccessorReader.js @@ -1,13 +1,14 @@ 'use strict'; var Cesium = require('cesium'); -var defaultValue = Cesium.defaultValue; - var byteLengthForComponentType = require('./byteLengthForComponentType'); var getAccessorByteStride = require('./getAccessorByteStride'); var numberOfComponentsForType = require('./numberOfComponentsForType'); var readBufferComponent = require('./readBufferComponent'); var writeBufferComponent = require('./writeBufferComponent'); +var defaultValue = Cesium.defaultValue; +var defined = Cesium.defined; + module.exports = AccessorReader; /** @@ -32,8 +33,9 @@ function AccessorReader(gltf, accessor) { var buffer = buffers[bufferId]; this.accessor = accessor; + this.bufferView = bufferView; this.byteOffset = accessor.byteOffset + bufferView.byteOffset; - this.byteStride = getAccessorByteStride(accessor); + this.byteStride = getAccessorByteStride(gltf, accessor); this.componentType = accessor.componentType; this.numberOfComponents = numberOfComponentsForType(accessor.type); this.count = accessor.count; @@ -85,7 +87,7 @@ AccessorReader.prototype.write = function(data, componentType, dataOffset) { dataOffset = defaultValue(dataOffset, 0); var componentByteLength = byteLengthForComponentType(componentType); var byteStride = this.byteStride; - if (this.accessor.byteStride === 0 && componentType !== this.componentType) { + if ((!defined(this.bufferView.byteStride) || this.bufferView.byteStride === 0) && componentType !== this.componentType) { byteStride = byteLengthForComponentType(componentType) * this.numberOfComponents; } for (var i = 0; i < this.numberOfComponents; i++) { diff --git a/lib/ForEach.js b/lib/ForEach.js new file mode 100644 index 00000000..e4880ea9 --- /dev/null +++ b/lib/ForEach.js @@ -0,0 +1,195 @@ +'use strict'; +var Cesium = require('cesium'); + +var defaultValue = Cesium.defaultValue; +var defined = Cesium.defined; + +module.exports = ForEach; + + +/** + * Contains traversal functions for processing elements of the glTF hierarchy. + * @constructor + */ +function ForEach() {} + +ForEach.object = function(arrayOfObjects, handler) { + if (defined(arrayOfObjects)) { + for (var i = 0; i < arrayOfObjects.length; i++) { + var object = arrayOfObjects[i]; + var offset = defaultValue(handler(object, i), 0); + i += offset; + } + } +}; + +ForEach.topLevel = function(gltf, name, handler) { + var arrayOfObjects = gltf[name]; + ForEach.object(arrayOfObjects, handler); +}; + +ForEach.accessor = function(gltf, handler) { + 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); + } + }); + }); + }); +}; + +ForEach.animation = function(gltf, handler) { + ForEach.topLevel(gltf, 'animations', handler); +}; + +ForEach.animationSampler = function(animation, handler) { + var samplers = animation.samplers; + if (defined(samplers)) { + ForEach.object(samplers, handler); + } +}; + +ForEach.buffer = function(gltf, handler) { + ForEach.topLevel(gltf, 'buffers', handler); +}; + +ForEach.bufferView = function(gltf, handler) { + ForEach.topLevel(gltf, 'bufferViews', handler); +}; + +ForEach.camera = function(gltf, handler) { + ForEach.topLevel(gltf, 'cameras', handler); +}; + +ForEach.image = function(gltf, handler) { + ForEach.topLevel(gltf, 'images', handler); +}; + +ForEach.material = function(gltf, handler) { + 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); + } + } + } +}; + +ForEach.mesh = function(gltf, handler) { + ForEach.topLevel(gltf, 'meshes', handler); +}; + +ForEach.meshPrimitive = function(mesh, handler) { + var primitives = mesh.primitives; + if (defined(primitives)) { + var primitivesLength = primitives.length; + for (var i = 0; i < primitivesLength; i++) { + var primitive = primitives[i]; + handler(primitive, i); + } + } +}; + +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); + } + } + } +}; + +ForEach.node = function(gltf, handler) { + 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 nodeId = nodeIds[i]; + var node = nodes[nodeId]; + if (defined(node)) { + handler(node, nodeId); + var children = node.children; + if (defined(children)) { + ForEach.nodeInTree(gltf, children, handler); + } + } + } + } +}; + +ForEach.nodeInScene = function(gltf, scene, handler) { + var sceneNodeIds = scene.nodes; + if (defined(sceneNodeIds)) { + ForEach.nodeInTree(gltf, sceneNodeIds, handler); + } +}; + +ForEach.program = function(gltf, handler) { + ForEach.topLevel(gltf, 'programs', handler); +}; + +ForEach.sampler = function(gltf, handler) { + ForEach.topLevel(gltf, 'samplers', handler); +}; + +ForEach.scene = function(gltf, handler) { + ForEach.topLevel(gltf, 'scenes', handler); +}; + +ForEach.shader = function(gltf, handler) { + ForEach.topLevel(gltf, 'shaders', handler); +}; + +ForEach.skin = function(gltf, handler) { + 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; + } + } + } + } +}; + +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; + } + } + } + } +}; + +ForEach.technique = function(gltf, handler) { + ForEach.topLevel(gltf, 'techniques', handler); +}; + +ForEach.texture = function(gltf, handler) { + ForEach.topLevel(gltf, 'textures', handler); +}; \ No newline at end of file diff --git a/lib/MergeDuplicateProperties.js b/lib/MergeDuplicateProperties.js index 1d5548b9..2e7d78df 100644 --- a/lib/MergeDuplicateProperties.js +++ b/lib/MergeDuplicateProperties.js @@ -3,10 +3,11 @@ var Cesium = require('cesium'); var clone = require('clone'); var bufferEqual = require('buffer-equal'); var deepEqual = require('deep-equal'); - var byteLengthForComponentType = require('./byteLengthForComponentType'); +var ForEach = require('./ForEach'); var getAccessorByteStride = require('./getAccessorByteStride'); var numberOfComponentsForType = require('./numberOfComponentsForType'); +var RemoveUnusedProperties = require('./RemoveUnusedProperties'); var defined = Cesium.defined; @@ -48,11 +49,11 @@ MergeDuplicateProperties.mergeAll = function(gltf) { * @see loadGltfUris */ MergeDuplicateProperties.mergeAccessors = function(gltf) { - var accessors = gltf.accessors; var duplicateMapping = createDuplicateMapping(gltf); // Use the duplicate mapping to merge the accessors for (var accessorId in duplicateMapping) { if (duplicateMapping.hasOwnProperty(accessorId)) { + accessorId = parseInt(accessorId); var duplicates = duplicateMapping[accessorId]; for (var i = 0; i < duplicates.length; i++) { var duplicateId = duplicates[i]; @@ -61,53 +62,38 @@ MergeDuplicateProperties.mergeAccessors = function(gltf) { duplicates.concat(metaDuplicates); } replaceAccessorIdInstances(gltf, duplicateId, accessorId); - delete duplicateMapping[duplicateId]; - delete accessors[duplicateId]; } } } + RemoveUnusedProperties.removeAccessors(gltf); return gltf; }; function replaceAccessorIdInstances(gltf, accessorId, newAccessorId) { - var meshes = gltf.meshes; - for (var meshId in meshes) { - if (meshes.hasOwnProperty(meshId)) { - var mesh = meshes[meshId]; - var primitives = mesh.primitives; - var primitivesLength = primitives.length; - for (var i = 0; i < primitivesLength; i++) { - var primitive = primitives[i]; - var indices = primitive.indices; - if (indices === accessorId) { - primitive.indices = newAccessorId; - } - var attributes = primitive.attributes; - for (var attribute in attributes) { - if (attributes.hasOwnProperty(attribute)) { - var attributeAccessorId = attributes[attribute]; - if (attributeAccessorId === accessorId) { - attributes[attribute] = newAccessorId; - } - } - } + ForEach.mesh(gltf, function(mesh) { + ForEach.meshPrimitive(mesh, function (primitive) { + var indices = primitive.indices; + if (indices === accessorId) { + primitive.indices = newAccessorId; } - } - } + ForEach.meshPrimitiveAttribute(primitive, function (attributeAccessorId, semantic) { + if (attributeAccessorId === accessorId) { + primitive.attributes[semantic] = newAccessorId; + } + }); + }); + }); } function createDuplicateMapping(gltf) { var accessors = gltf.accessors; var bufferViews = gltf.bufferViews; var buffers = gltf.buffers; - var accessorIdArray = Object.keys(accessors); var duplicateMapping = {}; - for (var i = 0; i < accessorIdArray.length; i++) { - var iAccessorId = accessorIdArray[i]; - var iAccessor = accessors[iAccessorId]; - for (var j = i+1; j < accessorIdArray.length; j++) { - var jAccessorId = accessorIdArray[j]; - var jAccessor = accessors[jAccessorId]; + for (var i = 0; i < accessors.length; i++) { + var iAccessor = accessors[i]; + for (var j = i+1; j < accessors.length; j++) { + var jAccessor = accessors[j]; if (accessorPropertiesMatch(iAccessor, jAccessor)) { var iBufferViewId = iAccessor.bufferView; var iBufferView = bufferViews[iBufferViewId]; @@ -115,7 +101,7 @@ function createDuplicateMapping(gltf) { var iBuffer = buffers[iBufferId]; var iBufferSource = iBuffer.extras._pipeline.source; var iByteOffset = iAccessor.byteOffset + iBufferView.byteOffset; - var iByteStride = getAccessorByteStride(iAccessor); + var iByteStride = getAccessorByteStride(gltf, iAccessor); var count = iAccessor.count; var elementByteLength = byteLengthForComponentType(iAccessor.componentType) * numberOfComponentsForType(iAccessor.type); @@ -125,7 +111,7 @@ function createDuplicateMapping(gltf) { var jBuffer = buffers[jBufferId]; var jBufferSource = jBuffer.extras._pipeline.source; var jByteOffset = jAccessor.byteOffset + jBufferView.byteOffset; - var jByteStride = getAccessorByteStride(jAccessor); + var jByteStride = getAccessorByteStride(gltf, jAccessor); var accessorsMatch = true; for (var k = 0; k < count; k++) { @@ -142,12 +128,12 @@ function createDuplicateMapping(gltf) { jByteOffset += jByteStride; } if (accessorsMatch) { - var mapping = duplicateMapping[iAccessorId]; + var mapping = duplicateMapping[i]; if (!defined(mapping)) { mapping = []; - duplicateMapping[iAccessorId] = mapping; + duplicateMapping[i] = mapping; } - mapping.push(jAccessorId); + mapping.push(j); } } } @@ -174,7 +160,7 @@ MergeDuplicateProperties.mergeShaders = function(gltf) { var shaderIdMapping = {}; var uniqueShadersByType = {}; for (var i = 0; i < shaderIdsLength; i++) { - var shaderId = shaderIds[i]; + var shaderId = parseInt(shaderIds[i]); var shader = shaders[shaderId]; var type = shader.type; var uniqueShaders = uniqueShadersByType[type]; @@ -202,22 +188,18 @@ MergeDuplicateProperties.mergeShaders = function(gltf) { }; function remapShaders(gltf, shaderIdMapping) { - var programs = gltf.programs; - for (var programId in programs) { - if (programs.hasOwnProperty(programId)) { - var program = programs[programId]; - var fragmentShaderId = program.fragmentShader; - var vertexShaderId = program.vertexShader; - var mappedFragmentShaderId = shaderIdMapping[fragmentShaderId]; - var mappedVertexShaderId = shaderIdMapping[vertexShaderId]; - if (defined(mappedFragmentShaderId)) { - program.fragmentShader = mappedFragmentShaderId; - } - if (defined(mappedVertexShaderId)) { - program.vertexShader = mappedVertexShaderId; - } + ForEach.program(gltf, function(program) { + var fragmentShaderId = program.fragmentShader; + var vertexShaderId = program.vertexShader; + var mappedFragmentShaderId = shaderIdMapping[fragmentShaderId]; + var mappedVertexShaderId = shaderIdMapping[vertexShaderId]; + if (defined(mappedFragmentShaderId)) { + program.fragmentShader = mappedFragmentShaderId; } - } + if (defined(mappedVertexShaderId)) { + program.vertexShader = mappedVertexShaderId; + } + }); } function shaderEquals(shaderOne, shaderTwo) { @@ -238,28 +220,26 @@ MergeDuplicateProperties.mergePrograms = function(gltf) { var programIdMapping = {}; var uniqueProgramIds = []; var uniquePrograms = {}; - for (var programId in programs) { - if (programs.hasOwnProperty(programId)) { - var program = clone(programs[programId]); - delete program.name; - delete program.extras; - var uniqueProgramIdsLength = uniqueProgramIds.length; - var unique = true; - for (var i = 0; i < uniqueProgramIdsLength; i++) { - var uniqueProgramId = uniqueProgramIds[i]; - var uniqueProgram = programs[uniqueProgramId]; - if (deepEqual(program, uniqueProgram)) { - programIdMapping[programId] = uniqueProgramId; - unique = false; - break; - } - } - if (unique) { - uniqueProgramIds.push(programId); - uniquePrograms[programId] = program; + ForEach.program(gltf, function(program, programId) { + program = clone(program); + delete program.name; + delete program.extras; + var uniqueProgramIdsLength = uniqueProgramIds.length; + var unique = true; + for (var i = 0; i < uniqueProgramIdsLength; i++) { + var uniqueProgramId = uniqueProgramIds[i]; + var uniqueProgram = programs[uniqueProgramId]; + if (deepEqual(program, uniqueProgram)) { + programIdMapping[programId] = uniqueProgramId; + unique = false; + break; } } - } + if (unique) { + uniqueProgramIds.push(programId); + uniquePrograms[programId] = program; + } + }); remapPrograms(gltf, programIdMapping); }; @@ -288,28 +268,26 @@ MergeDuplicateProperties.mergeTechniques = function(gltf) { var techniqueIdMapping = {}; var uniqueTechniqueIds = []; var uniqueTechniques = {}; - for (var techniqueId in techniques) { - if (techniques.hasOwnProperty(techniqueId)) { - var technique = clone(techniques[techniqueId]); - delete technique.name; - delete technique.extras; - var uniqueTechniqueIdsLength = uniqueTechniqueIds.length; - var unique = true; - for (var i = 0; i < uniqueTechniqueIdsLength; i++) { - var uniqueTechniqueId = uniqueTechniqueIds[i]; - var uniqueTechnique = techniques[uniqueTechniqueId]; - if (deepEqual(technique, uniqueTechnique)) { - techniqueIdMapping[techniqueId] = uniqueTechniqueId; - unique = false; - break; - } - } - if (unique) { - uniqueTechniqueIds.push(techniqueId); - uniqueTechniques[techniqueId] = technique; + ForEach.technique(gltf, function(technique, techniqueId) { + technique = clone(technique); + delete technique.name; + delete technique.extras; + var uniqueTechniqueIdsLength = uniqueTechniqueIds.length; + var unique = true; + for (var i = 0; i < uniqueTechniqueIdsLength; i++) { + var uniqueTechniqueId = uniqueTechniqueIds[i]; + var uniqueTechnique = techniques[uniqueTechniqueId]; + if (deepEqual(technique, uniqueTechnique)) { + techniqueIdMapping[techniqueId] = uniqueTechniqueId; + unique = false; + break; } } - } + if (unique) { + uniqueTechniqueIds.push(techniqueId); + uniqueTechniques[techniqueId] = technique; + } + }); remapTechniques(gltf,techniqueIdMapping); }; @@ -334,32 +312,29 @@ function remapTechniques(gltf, techniqueIdMapping) { * @returns {Object} The glTF with merged duplicate materials. */ MergeDuplicateProperties.mergeMaterials = function(gltf) { - var materials = gltf.materials; var materialIdMapping = {}; var uniqueMaterialIds = []; var uniqueMaterials = {}; - for (var materialId in materials) { - if (materials.hasOwnProperty(materialId)) { - var material = clone(materials[materialId]); - delete material.name; - delete material.extras; - var uniqueMaterialIdsLength = uniqueMaterialIds.length; - var unique = true; - for (var i = 0; i < uniqueMaterialIdsLength; i++) { - var uniqueMaterialId = uniqueMaterialIds[i]; - var uniqueMaterial = uniqueMaterials[uniqueMaterialId]; - if (deepEqual(material, uniqueMaterial)) { - materialIdMapping[materialId] = uniqueMaterialId; - unique = false; - break; - } - } - if (unique) { - uniqueMaterialIds.push(materialId); - uniqueMaterials[materialId] = material; + ForEach.material(gltf, function(material, materialId) { + material = clone(material); + delete material.name; + delete material.extras; + var uniqueMaterialIdsLength = uniqueMaterialIds.length; + var unique = true; + for (var i = 0; i < uniqueMaterialIdsLength; i++) { + var uniqueMaterialId = uniqueMaterialIds[i]; + var uniqueMaterial = uniqueMaterials[uniqueMaterialId]; + if (deepEqual(material, uniqueMaterial)) { + materialIdMapping[materialId] = uniqueMaterialId; + unique = false; + break; } } - } + if (unique) { + uniqueMaterialIds.push(materialId); + uniqueMaterials[materialId] = material; + } + }); remapMaterials(gltf, materialIdMapping); }; diff --git a/lib/NodeHelpers.js b/lib/NodeHelpers.js index fb0bf8af..e8cff21b 100644 --- a/lib/NodeHelpers.js +++ b/lib/NodeHelpers.js @@ -1,12 +1,12 @@ 'use strict'; var Cesium = require('cesium'); + var defined = Cesium.defined; var defaultValue = Cesium.defaultValue; var Matrix4 = Cesium.Matrix4; var Cartesian3 = Cesium.Cartesian3; var Quaternion = Cesium.Quaternion; - module.exports = NodeHelpers; /** @@ -48,15 +48,15 @@ function flattenTransform(parameters, node, parent) { * @private */ NodeHelpers.computeFlatTransformScene = function(scene, nodes) { - var rootNodeIDs = scene.nodes; + var nodeIds = scene.nodes; var parameters = { matrix4Scratch: matrix4Scratch }; - for (var id in rootNodeIDs) { - if (rootNodeIDs.hasOwnProperty(id)) { - var rootNode = nodes[rootNodeIDs[id]]; - NodeHelpers.depthFirstTraversal(rootNode, nodes, flattenTransform, parameters); - } + var nodeIdsLength = nodeIds.length; + for (var i = 0; i < nodeIdsLength; i++) { + var nodeId = nodeIds[i]; + var node = nodes[nodeId]; + NodeHelpers.depthFirstTraversal(node, nodes, flattenTransform, parameters); } }; @@ -77,18 +77,18 @@ function addNodeToArray(parameters, node) { * @private */ NodeHelpers.getAllNodesInScene = function(scene, nodes, resultArray) { - var rootNodeIDs = scene.nodes; + var nodeIds = scene.nodes; if (!defined(resultArray)) { resultArray = []; } var parameters = { nodeArray: resultArray }; - for (var id in rootNodeIDs) { - if (rootNodeIDs.hasOwnProperty(id)) { - var rootNode = nodes[rootNodeIDs[id]]; - NodeHelpers.depthFirstTraversal(rootNode, nodes, addNodeToArray, parameters); - } + var nodeIdsLength = nodeIds.length; + for (var i = 0; i < nodeIdsLength; i++) { + var nodeId = nodeIds[i]; + var node = nodes[nodeId]; + NodeHelpers.depthFirstTraversal(node, nodes, addNodeToArray, parameters); } return resultArray; }; @@ -118,14 +118,13 @@ NodeHelpers.depthFirstTraversal = function(rootNode, allNodes, functionChildPare if (!defined(currentNode.children)) { continue; } - var childrenIDs = currentNode.children; - for (var id in childrenIDs) { - if (childrenIDs.hasOwnProperty(id)) { - var childID = childrenIDs[id]; - var childNode = allNodes[childID]; - functionChildParent(parameters, childNode, currentNode); - nodeStack.push(childNode); - } + var children = currentNode.children; + var childrenLength = children.length; + for (var i = 0; i < childrenLength; i++) { + var childId = children[i]; + var childNode = allNodes[childId]; + functionChildParent(parameters, childNode, currentNode); + nodeStack.push(childNode); } } }; @@ -190,16 +189,15 @@ var packedParametersScratch = { * @private */ NodeHelpers.forEachPrimitiveInScene = function(gltf, scene, primitiveFunction, parameters) { - var rootNodeNames = scene.nodes; - var allNodes = gltf.nodes; + var nodeIds = scene.nodes; + var nodes = gltf.nodes; packedParametersScratch.meshes = gltf.meshes; packedParametersScratch.parameters = parameters; packedParametersScratch.primitiveFunction = primitiveFunction; - for (var nodeID in rootNodeNames) { - if (rootNodeNames.hasOwnProperty(nodeID)) { - var rootNodeName = rootNodeNames[nodeID]; - NodeHelpers.depthFirstTraversal(allNodes[rootNodeName], allNodes, forEachPrimitiveInNode, packedParametersScratch); - } + var nodeIdsLength = nodeIds.length; + for (var i = 0; i < nodeIdsLength; i++) { + var nodeId = nodeIds[i]; + NodeHelpers.depthFirstTraversal(nodes[nodeId], nodes, forEachPrimitiveInNode, packedParametersScratch); } }; @@ -208,18 +206,17 @@ function forEachPrimitiveInNode(packedParameters, node) { var parameters = packedParameters.parameters; var primitiveFunction = packedParameters.primitiveFunction; - var meshIDs = node.meshes; - if (!defined(meshIDs)) { + var meshId = node.mesh; + if (!defined(meshId)) { return; } - var meshIdsLength = meshIDs.length; - for (var i = 0; i < meshIdsLength; i++) { - var meshID = meshIDs[i]; - var meshData = meshes[meshID]; - var primitives = meshData.primitives; - var primitiveIdsLength = primitives.length; - for (var j = 0; j < primitiveIdsLength; j++) { - primitiveFunction(primitives[j], meshID + '_' + j, parameters, node); + var mesh = meshes[meshId]; + var primitives = mesh.primitives; + if (defined(primitives)) { + var primitivesLength = primitives.length; + for (var i = 0; i < primitivesLength; i++) { + var primitive = primitives[i]; + primitiveFunction(primitive, meshId + '_' + i, parameters, node); } } } @@ -235,21 +232,18 @@ function forEachPrimitiveInNode(packedParameters, node) { NodeHelpers.mapMeshesToNodes = function(gltf) { var meshesToNodes = {}; var nodes = gltf.nodes; - for (var nodeId in nodes) { - if (nodes.hasOwnProperty(nodeId)) { + if (defined(nodes)) { + var nodesLength = nodes.length; + for (var nodeId = 0; nodeId < nodesLength; nodeId++) { var node = nodes[nodeId]; - var meshes = node.meshes; - if (defined(meshes)) { - var meshesLength = meshes.length; - for (var i = 0; i < meshesLength; i++) { - var mesh = meshes[i]; - var nodeMapping = meshesToNodes[mesh]; - if (!defined(nodeMapping)) { - nodeMapping = []; - meshesToNodes[mesh] = nodeMapping; - } - nodeMapping.push(nodeId); + var meshId = node.mesh; + if (defined(meshId)) { + var nodeMapping = meshesToNodes[meshId]; + if (!defined(nodeMapping)) { + nodeMapping = []; + meshesToNodes[meshId] = nodeMapping; } + nodeMapping.push(nodeId); } } } diff --git a/lib/Pipeline.js b/lib/Pipeline.js index ae18e517..a9229424 100644 --- a/lib/Pipeline.js +++ b/lib/Pipeline.js @@ -8,7 +8,6 @@ var RemoveUnusedProperties = require('./RemoveUnusedProperties'); var addDefaults = require('./addDefaults'); var addPipelineExtras = require('./addPipelineExtras'); var bakeAmbientOcclusion = require('./bakeAmbientOcclusion'); -var combineMeshes = require('./combineMeshes'); var combineNodes = require('./combineNodes'); var combinePrimitives = require('./combinePrimitives'); var compressIntegerAccessors = require('./compressIntegerAccessors'); @@ -29,8 +28,10 @@ var readGltf = require('./readGltf'); var removeDuplicatePrimitives = require('./removeDuplicatePrimitives'); var removeNormals = require('./removeNormals'); var removePipelineExtras = require('./removePipelineExtras'); +var removeUnusedVertices = require('./removeUnusedVertices'); var quantizeAttributes = require('./quantizeAttributes'); var updateVersion = require('./updateVersion'); +var uninterleaveAndPackBuffers = require('./uninterleaveAndPackBuffers'); var writeGltf = require('./writeGltf'); var writeBinaryGltf = require('./writeBinaryGltf'); var writeSource = require('./writeSource'); @@ -59,7 +60,6 @@ function Pipeline() {} */ Pipeline.processJSON = function(gltf, options) { options = defaultValue(options, {}); - addPipelineExtras(gltf); return loadGltfUris(gltf, options) .then(function(gltf) { return Pipeline.processJSONWithExtras(gltf, options); @@ -90,6 +90,7 @@ Pipeline.processJSONWithExtras = function(gltfWithExtras, options) { options = defaultValue(options, {}); updateVersion(gltfWithExtras, options); + addPipelineExtras(gltfWithExtras); addDefaults(gltfWithExtras, options); processModelMaterialsCommon(gltfWithExtras, options); @@ -113,13 +114,13 @@ Pipeline.processJSONWithExtras = function(gltfWithExtras, options) { } if (!shouldPreserve) { mergeDuplicateVertices(gltfWithExtras); + removeUnusedVertices(gltfWithExtras); MergeDuplicateProperties.mergeAll(gltfWithExtras); RemoveUnusedProperties.removeAll(gltfWithExtras); removeDuplicatePrimitives(gltfWithExtras); combinePrimitives(gltfWithExtras); convertDagToTree(gltfWithExtras); combineNodes(gltfWithExtras); - combineMeshes(gltfWithExtras); combinePrimitives(gltfWithExtras); MergeDuplicateProperties.mergeAll(gltfWithExtras); removeDuplicatePrimitives(gltfWithExtras); @@ -138,39 +139,36 @@ Pipeline.processJSONWithExtras = function(gltfWithExtras, options) { bakeAmbientOcclusion(gltfWithExtras, aoOptions); } - var waitForStages = [new Promise(function(resolve) {resolve();})]; if (options.encodeNormals) { - waitForStages.push(octEncodeNormals(gltfWithExtras)); + octEncodeNormals(gltfWithExtras); } if (options.compressTextureCoordinates) { - waitForStages.push(compressTextureCoordinates(gltfWithExtras)); + compressTextureCoordinates(gltfWithExtras); } - waitForStages.push(compressIntegerAccessors(gltfWithExtras, { + compressIntegerAccessors(gltfWithExtras, { semantics : ["JOINT"] - })); - return Promise.all(waitForStages) - .then(function() { - if (options.quantize) { - var quantizedOptions = { - findMinMax : true, - exclude : [ - 'JOINT', - '_OCCLUSION' - ] - }; - if (options.compressTextureCoordinates) { - quantizedOptions.exclude.push('TEXCOORD'); - } - quantizeAttributes(gltfWithExtras, quantizedOptions); - } - var textureCompressionOptions = options.textureCompressionOptions; - if (defined(textureCompressionOptions)) { - return compressTextures(gltfWithExtras, textureCompressionOptions); - } else { - return encodeImages(gltfWithExtras); - } - }) - .then(function() { + }); + if (options.quantize) { + var quantizedOptions = { + findMinMax : true, + exclude : [ + 'JOINT', + '_OCCLUSION' + ] + }; + if (options.compressTextureCoordinates) { + quantizedOptions.exclude.push('TEXCOORD'); + } + quantizeAttributes(gltfWithExtras, quantizedOptions); + } + var textureCompressionOptions = options.textureCompressionOptions; + var promise; + if (defined(textureCompressionOptions)) { + promise = compressTextures(gltfWithExtras, textureCompressionOptions); + } else { + promise = encodeImages(gltfWithExtras); + } + return promise.then(function() { var kmcOptions = options.kmcOptions; if (defined(kmcOptions)) { generateModelMaterialsCommon(gltfWithExtras, options.kmcOptions); @@ -182,6 +180,7 @@ Pipeline.processJSONWithExtras = function(gltfWithExtras, options) { console.log(getStatistics(gltfWithExtras).toString() + '\n'); } + uninterleaveAndPackBuffers(gltfWithExtras); return gltfWithExtras; }); }; @@ -270,17 +269,7 @@ function writeSources(gltf) { writeSource(gltf.images, 'images', undefined, embed, embedImage), writeSource(gltf.shaders, 'shaders', undefined, embed, embedImage) ]; - // Write sources for compressed textures - var images = gltf.images; - for (var imageId in images) { - if (images.hasOwnProperty(imageId)) { - var image = images[imageId]; - if (defined(image.extras) && defined(image.extras.compressedImage3DTiles)) { - var compressedImages = image.extras.compressedImage3DTiles; - writeSourcePromises.push(writeSource(compressedImages, 'images', undefined, embed, embedImage)); - } - } - } + return Promise.all(writeSourcePromises) .then(function() { return gltf; diff --git a/lib/PrimitiveHelpers.js b/lib/PrimitiveHelpers.js index 0a5218d0..ff8b300b 100644 --- a/lib/PrimitiveHelpers.js +++ b/lib/PrimitiveHelpers.js @@ -2,6 +2,7 @@ var Cesium = require('cesium'); var deepEqual = require('deep-equal'); var AccessorReader = require('./AccessorReader'); +var ForEach = require('./ForEach'); var getPrimitiveAttributeSemantics = require('./getPrimitiveAttributeSemantics'); var readAccessor = require('./readAccessor'); @@ -240,13 +241,11 @@ function getPrimitiveConflicts(primitives, primitive) { */ function getAllPrimitives(gltf) { var primitives = []; - var meshes = gltf.meshes; - for (var meshId in meshes) { - if (meshes.hasOwnProperty(meshId)) { - var mesh = meshes[meshId]; - primitives = primitives.concat(mesh.primitives); - } - } + ForEach.mesh(gltf, function(mesh) { + ForEach.meshPrimitive(mesh, function(primitive) { + primitives.push(primitive); + }); + }); return primitives; } diff --git a/lib/Remove.js b/lib/Remove.js new file mode 100644 index 00000000..ef888055 --- /dev/null +++ b/lib/Remove.js @@ -0,0 +1,269 @@ +'use strict'; +var Cesium = require('cesium'); +var ForEach = require('./ForEach'); +var isTexture = require('./isTexture'); + +var defined = Cesium.defined; + +module.exports = Remove; + +/** + * 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 + */ +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) { + ForEach.meshPrimitiveAttribute(primitive, function(attributeAccessorId, semantic) { + if (attributeAccessorId > accessorId) { + primitive.attributes[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--; + } + }); +}; + +Remove.camera = function(gltf, cameraId) { + var cameras = gltf.cameras; + + cameras.splice(cameraId, 1); + + ForEach.node(gltf, function(node) { + if (defined(node.camera) && node.camera > cameraId) { + node.camera--; + } + }); +}; + +Remove.image = function(gltf, imageId) { + var images = gltf.images; + + images.splice(imageId, 1); + + ForEach.texture(gltf, function(texture) { + if (defined(texture.source) && texture.source > imageId) { + texture.source--; + } + }); +}; + +Remove.material = function(gltf, materialId) { + var materials = gltf.materials; + + materials.splice(materialId, 1); + + ForEach.mesh(gltf, function(mesh) { + ForEach.meshPrimitive(mesh, function(primitive) { + if (defined(primitive.material) && primitive.material > materialId) { + primitive.material--; + } + }); + }); +}; + +Remove.mesh = function(gltf, meshId) { + var meshes = gltf.meshes; + + meshes.splice(meshId, 1); + + ForEach.node(gltf, function(node) { + if (defined(node.mesh) && node.mesh > meshId) { + node.mesh--; + } + }); +}; + +Remove.node = function(gltf, nodeId) { + var nodes = gltf.nodes; + + nodes.splice(nodeId, 1); + + ForEach.node(gltf, function(node) { + var children = node.children; + if (defined(children)) { + var childrenLength = children.length; + for (var i = 0; i < childrenLength; i++) { + var childId = children[i]; + if (childId > nodeId) { + children[i]--; + } + } + } + var skeletons = node.skeletons; + if (defined(skeletons)) { + var skeletonsLength = skeletons.length; + for (var j = 0; j < skeletonsLength; j++) { + var skeletonId = skeletons[j]; + if (skeletonId > nodeId) { + skeletons[j]--; + } + } + } + }); + + ForEach.technique(gltf, function(technique) { + ForEach.techniqueParameter(technique, function(value) { + if (defined(value.node) && value.node > nodeId) { + value.node--; + } + }); + }); + + ForEach.scene(gltf, function(scene) { + var sceneNodeIds = scene.nodes; + if (defined(sceneNodeIds)) { + var sceneNodeIdsLength = sceneNodeIds.length; + for (var k = 0; k < sceneNodeIdsLength; k++) { + var sceneNodeId = sceneNodeIds[k]; + if (sceneNodeId > nodeId) { + sceneNodeIds[k]--; + } + } + } + }); +}; + +Remove.program = function(gltf, programId) { + var programs = gltf.programs; + + programs.splice(programId, 1); + + ForEach.technique(gltf, function(technique) { + if (defined(technique.program) && technique.program > programId) { + technique.program--; + } + }); +}; + +Remove.sampler = function(gltf, samplerId) { + var samplers = gltf.samplers; + + samplers.splice(samplerId, 1); + + ForEach.texture(gltf, function(texture) { + if (defined(texture.sampler) && texture.sampler > samplerId) { + texture.sampler--; + } + }); +}; + +Remove.shader = function(gltf, shaderId) { + var shaders = gltf.shaders; + + shaders.splice(shaderId, 1); + + ForEach.program(gltf, function(program) { + if (defined(program.vertexShader) && program.vertexShader > shaderId) { + program.vertexShader--; + } + if (defined(program.fragmentShader) && program.fragmentShader > shaderId) { + program.fragmentShader--; + } + }); +}; + +Remove.skin = function(gltf, skinId) { + var skins = gltf.skins; + + skins.splice(skinId, 1); + + ForEach.node(gltf, function(node) { + if (defined(node.skin) && node.skin > skinId) { + node.skin--; + } + }); +}; + +Remove.technique = function(gltf, techniqueId) { + var techniques = gltf.techniques; + + techniques.splice(techniqueId, 1); + + ForEach.material(gltf, function(material) { + if (defined(material.technique) && material.technique > techniqueId) { + material.technique--; + } + }); +}; + +Remove.texture = function(gltf, textureId) { + var textures = gltf.textures; + + textures.splice(textureId, 1); + + ForEach.material(gltf, function(material) { + ForEach.materialValue(material, function(value, name) { + if (isTexture(name, value)) { + if (value[0] > textureId) { + value[0]--; + } + } + }); + }); + + ForEach.technique(gltf, function(technique) { + ForEach.techniqueParameter(technique, function(parameter, name) { + var value = parameter.value; + if (defined(value)) { + if (isTexture(name, value)) { + if (value[0] > textureId) { + value[0]--; + } + } + } + }); + }); +}; \ No newline at end of file diff --git a/lib/RemoveUnusedProperties.js b/lib/RemoveUnusedProperties.js index 8748a7e6..3d039c7a 100644 --- a/lib/RemoveUnusedProperties.js +++ b/lib/RemoveUnusedProperties.js @@ -1,7 +1,8 @@ 'use strict'; var Cesium = require('cesium'); -var findUsedIds = require('./findUsedIds'); -var removeObject = require('./removeObject'); +var ForEach = require('./ForEach'); +var isTexture = require('./isTexture'); +var Remove = require('./Remove'); var defined = Cesium.defined; @@ -38,6 +39,18 @@ RemoveUnusedProperties.removeAll = function(gltf) { RemoveUnusedProperties.removePrimitiveAttributes(gltf); }; +function removeUnusedElements(gltf, type, usedIds) { + var removed = 0; + /* jshint unused:vars */ + ForEach[type](gltf, function(object, id) { + if (!usedIds[id + removed]) { + Remove[type](gltf, id); + removed++; + return -1; + } + }); +} + /** * Remove all unused nodes in the glTF asset * @@ -46,41 +59,30 @@ RemoveUnusedProperties.removeAll = function(gltf) { */ RemoveUnusedProperties.removeNodes = function(gltf) { var usedNodeIds = {}; - var scenes = gltf.scenes; - var nodes = gltf.nodes; - - // Build hash of used nodes by traversing through node trees starting at scenes - if (defined(scenes)) { - for (var sceneId in scenes) { - if (scenes.hasOwnProperty(sceneId)) { - var roots = scenes[sceneId].nodes; - if (defined(roots)) { - var nodeStack = []; - var rootsLength = roots.length; - for (var i = 0; i < rootsLength; i++) { - var root = roots[i]; - nodeStack.push(root); - } - - while (nodeStack.length > 0) { - var node = nodeStack.pop(); - usedNodeIds[node] = true; - var children = nodes[node].children; - if (defined(children)) { - var childrenLength = children.length; - for (var j = 0; j < childrenLength; j++) { - var child = children[j]; - nodeStack.push(child); - } - } - } + ForEach.scene(gltf, function(scene) { + ForEach.nodeInScene(gltf, scene, function(node, nodeId) { + usedNodeIds[nodeId] = true; + var skeletons = node.skeletons; + if (defined(skeletons)) { + var skeletonsLength = skeletons.length; + for (var i = 0; i < skeletonsLength; i++) { + usedNodeIds[skeletons[i]] = true; } } - } - } + }); + }); + + ForEach.technique(gltf, function(technique) { + ForEach.techniqueParameter(technique, function(value) { + if (defined(value.node)) { + usedNodeIds[value.node] = true; + } + }); + }); - return removeObject(gltf, 'nodes', usedNodeIds); + removeUnusedElements(gltf, 'node', usedNodeIds); + return gltf; }; /** @@ -90,8 +92,17 @@ RemoveUnusedProperties.removeNodes = function(gltf) { * @returns {Object} The glTF asset with removed unused skins. */ RemoveUnusedProperties.removeSkins = function(gltf) { - var usedSkinIds = findUsedIds(gltf, 'nodes', 'skin'); - return removeObject(gltf, 'skins', usedSkinIds); + var usedSkinIds = {}; + + ForEach.node(gltf, function(node) { + var nodeSkinId = node.skin; + if (defined(nodeSkinId)) { + usedSkinIds[nodeSkinId] = true; + } + }); + + removeUnusedElements(gltf, 'skin', usedSkinIds); + return gltf; }; /** @@ -101,8 +112,17 @@ RemoveUnusedProperties.removeSkins = function(gltf) { * @returns {Object} The glTF asset with removed unused cameras. */ RemoveUnusedProperties.removeCameras = function(gltf) { - var usedCameraIds = findUsedIds(gltf, 'nodes', 'camera'); - return removeObject(gltf, 'cameras', usedCameraIds); + var usedCameraIds = {}; + + ForEach.node(gltf, function(node) { + var cameraId = node.camera; + if (defined(cameraId)) { + usedCameraIds[cameraId] = true; + } + }); + + removeUnusedElements(gltf, 'camera', usedCameraIds); + return gltf; }; /** @@ -113,33 +133,16 @@ RemoveUnusedProperties.removeCameras = function(gltf) { */ RemoveUnusedProperties.removeMeshes = function(gltf) { var usedMeshIds = {}; - var meshes = gltf.meshes; - var nodes = gltf.nodes; - - // Build hash of used meshes by iterating through nodes - if (defined(nodes)) { - for (var nodeId in nodes) { - if (nodes.hasOwnProperty(nodeId)) { - if (defined(nodes[nodeId].meshes)) { - var nodeMeshes = nodes[nodeId].meshes; - var length = nodeMeshes.length; - for (var i = 0; i < length; i++) { - var id = nodeMeshes[i]; - var mesh = meshes[id]; - if (!defined(mesh.primitives) || mesh.primitives.length === 0) { - // This is an empty mesh, remove it - nodeMeshes.splice(i, 1); - i--; - length--; - } else { - usedMeshIds[id] = true; - } - } - } - } + + ForEach.node(gltf, function(node) { + var meshId = node.mesh; + if (defined(meshId)) { + usedMeshIds[meshId] = true; } - } - return removeObject(gltf, 'meshes', usedMeshIds); + }); + + removeUnusedElements(gltf, 'mesh', usedMeshIds); + return gltf; }; /** @@ -150,60 +153,38 @@ RemoveUnusedProperties.removeMeshes = function(gltf) { */ RemoveUnusedProperties.removeAccessors = function(gltf) { var usedAccessorIds = {}; - var meshes = gltf.meshes; - var skins = gltf.skins; - var animations = gltf.animations; - - // Build hash of used accessors by iterating through meshes, skins, and animations - if (defined(meshes)) { - for (var meshId in meshes) { - if (meshes.hasOwnProperty(meshId)) { - var primitives = meshes[meshId].primitives; - if (defined(primitives)) { - var length = primitives.length; - for (var i = 0; i < length; i++) { - var attributes = primitives[i].attributes; - if (defined(attributes)) { - for (var attributeId in attributes) { - if (attributes.hasOwnProperty(attributeId)) { - var primitiveAccessorId = attributes[attributeId]; - usedAccessorIds[primitiveAccessorId] = true; - } - } - } - var indicesId = primitives[i].indices; - if (defined(indicesId)) { - usedAccessorIds[indicesId] = true; - } - } - } + + ForEach.mesh(gltf, function(mesh) { + ForEach.meshPrimitive(mesh, function(primitive) { + ForEach.meshPrimitiveAttribute(primitive, function(accessorId) { + usedAccessorIds[accessorId] = true; + }); + var indices = primitive.indices; + if (defined(indices)) { + usedAccessorIds[indices] = true; } - } - } - if (defined(skins)) { - for (var skinId in skins) { - if (skins.hasOwnProperty(skinId)) { - var skinAccessorId = skins[skinId].inverseBindMatrices; - usedAccessorIds[skinAccessorId] = 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(animations)) { - for (var animationId in animations) { - if (animations.hasOwnProperty(animationId)) { - var parameters = animations[animationId].parameters; - if (defined(parameters)) { - for (var parameterId in parameters) { - if (parameters.hasOwnProperty(parameterId)) { - var animationAccessorId = parameters[parameterId]; - usedAccessorIds[animationAccessorId] = true; - } - } - } + if (defined(sampler.output)) { + usedAccessorIds[sampler.output] = true; } - } - } - return removeObject(gltf, 'accessors', usedAccessorIds); + }); + }); + + removeUnusedElements(gltf, 'accessor', usedAccessorIds); + return gltf; }; /** @@ -214,24 +195,17 @@ RemoveUnusedProperties.removeAccessors = function(gltf) { */ RemoveUnusedProperties.removeMaterials = function(gltf) { var usedMaterialIds = {}; - var meshes = gltf.meshes; - - // Build hash of used materials by iterating through meshes - if (defined(meshes)) { - for (var meshId in meshes) { - if (meshes.hasOwnProperty(meshId)) { - if (defined(meshes[meshId].primitives)) { - var primitives = meshes[meshId].primitives; - var length = primitives.length; - for (var i = 0; i < length; i++) { - var id = primitives[i].material; - usedMaterialIds[id] = true; - } - } + + ForEach.mesh(gltf, function(mesh) { + ForEach.meshPrimitive(mesh, function(primitive) { + if (defined(primitive.material)) { + usedMaterialIds[primitive.material] = true; } - } - } - return removeObject(gltf, 'materials', usedMaterialIds); + }); + }); + + removeUnusedElements(gltf, 'material', usedMaterialIds); + return gltf; }; /** @@ -241,8 +215,16 @@ RemoveUnusedProperties.removeMaterials = function(gltf) { * @returns {Object} The glTF asset with removed unused buffers views. */ RemoveUnusedProperties.removeBufferViews = function(gltf) { - var usedBufferViewIds = findUsedIds(gltf, 'accessors', 'bufferView'); - return removeObject(gltf, 'bufferViews', usedBufferViewIds); + var usedBufferViewIds = {}; + + ForEach.accessor(gltf, function(accessor) { + if (defined(accessor.bufferView)) { + usedBufferViewIds[accessor.bufferView] = true; + } + }); + + removeUnusedElements(gltf, 'bufferView', usedBufferViewIds); + return gltf; }; /** @@ -252,8 +234,16 @@ RemoveUnusedProperties.removeBufferViews = function(gltf) { * @returns {Object} The glTF asset with removed unused techniques */ RemoveUnusedProperties.removeTechniques = function(gltf) { - var usedTechniqueIds = findUsedIds(gltf, 'materials', 'technique'); - return removeObject(gltf, 'techniques', usedTechniqueIds); + var usedTechniqueIds = {}; + + ForEach.material(gltf, function(material) { + if (defined(material.technique)) { + usedTechniqueIds[material.technique] = true; + } + }); + + removeUnusedElements(gltf, 'technique', usedTechniqueIds); + return gltf; }; /** @@ -264,48 +254,28 @@ RemoveUnusedProperties.removeTechniques = function(gltf) { */ RemoveUnusedProperties.removeTextures = function(gltf) { var usedTextureIds = {}; - var materials = gltf.materials; - var techniques = gltf.techniques; - // Build hash of used textures by iterating through materials and techniques - if (defined(materials)) { - for (var materialId in materials) { - if (materials.hasOwnProperty(materialId)) { - if (defined(materials[materialId].values)) { - var values = materials[materialId].values; - for (var valueId in values) { - if (values.hasOwnProperty(valueId)) { - if (typeof values[valueId] === 'string') { - var materialTextureId = values[valueId]; - usedTextureIds[materialTextureId] = true; - } - } - } - } + ForEach.material(gltf, function(material) { + ForEach.materialValue(material, function(value, name) { + if (isTexture(name, value)) { + usedTextureIds[value[0]] = true; } - } - } - if (defined(techniques)) { - for (var techniqueId in techniques) { - if (techniques.hasOwnProperty(techniqueId)) { - if (defined(techniques[techniqueId].parameters)) { - var parameters = techniques[techniqueId].parameters; - for (var parameterId in parameters) { - if (parameters.hasOwnProperty(parameterId)) { - if (defined(parameters[parameterId].value)) { - var value = parameters[parameterId].value; - if (typeof value === 'string') { - var techniqueTextureId = value; - usedTextureIds[techniqueTextureId] = true; - } - } - } - } + }); + }); + + ForEach.technique(gltf, function(technique) { + ForEach.techniqueParameter(technique, function(parameter, name) { + var value = parameter.value; + if (defined(value)) { + if (isTexture(name, value)) { + usedTextureIds[value[0]] = true; } } - } - } - return removeObject(gltf, 'textures', usedTextureIds); + }); + }); + + removeUnusedElements(gltf, 'texture', usedTextureIds); + return gltf; }; /** @@ -315,8 +285,16 @@ RemoveUnusedProperties.removeTextures = function(gltf) { * @returns {Object} The glTF asset with removed unused buffers. */ RemoveUnusedProperties.removeBuffers = function(gltf) { - var usedBufferIds = findUsedIds(gltf, 'bufferViews', 'buffer'); - return removeObject(gltf, 'buffers', usedBufferIds); + var usedBufferIds = {}; + + ForEach.bufferView(gltf, function(bufferView) { + if (defined(bufferView.buffer)) { + usedBufferIds[bufferView.buffer] = true; + } + }); + + removeUnusedElements(gltf, 'buffer', usedBufferIds); + return gltf; }; /** @@ -326,8 +304,16 @@ RemoveUnusedProperties.removeBuffers = function(gltf) { * @returns {Object} The glTF asset with removed unused programs. */ RemoveUnusedProperties.removePrograms = function(gltf) { - var usedProgramIds = findUsedIds(gltf, 'techniques', 'program'); - return removeObject(gltf, 'programs', usedProgramIds); + var usedProgramIds = {}; + + ForEach.technique(gltf, function(technique) { + if (defined(technique.program)) { + usedProgramIds[technique.program] = true; + } + }); + + removeUnusedElements(gltf, 'program', usedProgramIds); + return gltf; }; /** @@ -337,8 +323,15 @@ RemoveUnusedProperties.removePrograms = function(gltf) { * @returns {Object} The glTF asset with removed unused images. */ RemoveUnusedProperties.removeImages = function(gltf) { - var usedImageIds = findUsedIds(gltf, 'textures', 'source'); - return removeObject(gltf, 'images', usedImageIds); + var usedImageIds = {}; + + ForEach.texture(gltf, function(texture) { + if (defined(texture.source)) { + usedImageIds[texture.source] = true; + } + }); + + removeUnusedElements(gltf, 'image', usedImageIds); }; /** @@ -348,8 +341,16 @@ RemoveUnusedProperties.removeImages = function(gltf) { * @returns {Object} The glTF asset with removed unused samplers. */ RemoveUnusedProperties.removeSamplers = function(gltf) { - var usedSamplerIds = findUsedIds(gltf, 'textures', 'sampler'); - return removeObject(gltf, 'samplers', usedSamplerIds); + var usedSamplerIds = {}; + + ForEach.texture(gltf, function(texture) { + if (defined(texture.sampler)) { + usedSamplerIds[texture.sampler] = true; + } + }); + + removeUnusedElements(gltf, 'sampler', usedSamplerIds); + return gltf; }; /** @@ -360,20 +361,18 @@ RemoveUnusedProperties.removeSamplers = function(gltf) { */ RemoveUnusedProperties.removeShaders = function(gltf) { var usedShaderIds = {}; - var programs = gltf.programs; - - // Build hash of used shaders by iterating through programs - if (defined(programs)) { - for (var programId in programs) { - if (programs.hasOwnProperty(programId)) { - var fragId = programs[programId].fragmentShader; - var vertId = programs[programId].vertexShader; - usedShaderIds[fragId] = true; - usedShaderIds[vertId] = true; - } + + ForEach.program(gltf, function(program) { + if (defined(program.vertexShader)) { + usedShaderIds[program.vertexShader] = true; + } + if (defined(program.fragmentShader)) { + usedShaderIds[program.fragmentShader] = true; } - } - return removeObject(gltf, 'shaders', usedShaderIds); + }); + + removeUnusedElements(gltf, 'shader', usedShaderIds); + return gltf; }; /** @@ -383,46 +382,42 @@ RemoveUnusedProperties.removeShaders = function(gltf) { * @returns {Object} The glTF asset with removed unused primitive attributes. */ RemoveUnusedProperties.removePrimitiveAttributes = function(gltf) { - var meshes = gltf.meshes; var materials = gltf.materials; var techniques = gltf.techniques; - for (var meshId in meshes) { - if (meshes.hasOwnProperty(meshId)) { - var mesh = meshes[meshId]; - var primitives = mesh.primitives; - var primitivesLength = primitives.length; - for (var i = 0; i < primitivesLength; i++) { - var primitive = primitives[i]; + + ForEach.mesh(gltf, function(mesh) { + ForEach.meshPrimitive(mesh, function(primitive) { + var usedAttributes = {}; + var hasAttributes = false; + /* jshint unused:vars */ + ForEach.meshPrimitiveAttribute(primitive, function(accessorId, semantic) { + usedAttributes[semantic] = false; + hasAttributes = true; + }); + if (hasAttributes) { var materialId = primitive.material; - var material = materials[materialId]; - var techniqueId = material.technique; - var technique = techniques[techniqueId]; - var techniqueParameters = technique.parameters; - var attributes = primitive.attributes; - var usedAttributes = {}; - for (var attributeSemantic in attributes) { - if (attributes.hasOwnProperty(attributeSemantic)) { - usedAttributes[attributeSemantic] = false; - } - } - for (var techniqueParameter in techniqueParameters) { - if (techniqueParameters.hasOwnProperty(techniqueParameter)) { - var parameterProperties = techniqueParameters[techniqueParameter]; - var parameterSemantic = parameterProperties.semantic; - if (defined(parameterSemantic)) { - usedAttributes[parameterSemantic] = true; - } + if (defined(materialId)) { + var material = materials[materialId]; + var techniqueId = material.technique; + if (defined(techniqueId)) { + var technique = techniques[techniqueId]; + ForEach.techniqueParameter(technique, function (parameter) { + if (defined(parameter.semantic)) { + usedAttributes[parameter.semantic] = true; + } + }); } } - for (var attribute in usedAttributes) { - if (usedAttributes.hasOwnProperty(attribute)) { - if (!usedAttributes[attribute]) { - delete attributes[attribute]; + for (var semantic in usedAttributes) { + if (usedAttributes.hasOwnProperty(semantic)) { + if (!usedAttributes[semantic]) { + delete primitive.attributes[semantic]; } } } } - } - } + }); + }); + return gltf; }; \ No newline at end of file diff --git a/lib/addCesiumRTC.js b/lib/addCesiumRTC.js index e9dbf7fa..b9d196b4 100644 --- a/lib/addCesiumRTC.js +++ b/lib/addCesiumRTC.js @@ -6,6 +6,7 @@ var Ellipsoid = Cesium.Ellipsoid; var defaultValue = Cesium.defaultValue; var defined = Cesium.defined; +var addExtensionsRequired = require('./addExtensionsRequired'); var addExtensionsUsed = require('./addExtensionsUsed'); module.exports = addCesiumRTC; @@ -44,6 +45,7 @@ function addCesiumRTC(gltf, options) { extensions.CESIUM_RTC = { center : positionArray }; + addExtensionsRequired(gltf, 'CEISUM_RTC'); addExtensionsUsed(gltf, 'CESIUM_RTC'); var techniques = gltf.techniques; for (var techniqueId in techniques) { diff --git a/lib/addDefaults.js b/lib/addDefaults.js index bc246a73..d3a5aa67 100644 --- a/lib/addDefaults.js +++ b/lib/addDefaults.js @@ -1,6 +1,6 @@ 'use strict'; var Cesium = require('cesium'); -var getUniqueId = require('./getUniqueId'); +var addToArray = require('./addToArray'); var clone = Cesium.clone; var defaultValue = Cesium.defaultValue; @@ -10,44 +10,33 @@ var WebGLConstants = Cesium.WebGLConstants; module.exports = addDefaults; var gltfTemplate = { - accessors : { - '*' : { - byteStride : 0 - } - }, - animations : { - '*' : { + accessors: [], + animations : [ + { channels : [], - parameters : {}, - samplers : { - '*' : { + samplers : [ + { interpolation : 'LINEAR' } - } - } - }, - asset : { - premultipliedAlpha : false, - profile : { - api : 'WebGL', - version : '1.0.3' + ] } - }, - buffers : { - '*': { + ], + asset : {}, + buffers : [ + { byteLength: 0, type: 'arraybuffer' } - }, - bufferViews: { - '*': { + ], + bufferViews: [ + { byteLength: 0 } - }, - cameras: {}, - images: {}, - materials: { - '*': { + ], + cameras: [], + images: [], + materials: [ + { values: function(material) { var extensions = defaultValue(material.extensions, {}); var materialsCommon = extensions.KHR_materials_common; @@ -62,29 +51,29 @@ var gltfTemplate = { var technique = materialsCommon.technique; var defaults = { ambient: [0.0, 0.0, 0.0, 1.0], - doubleSided: false, emission: [0.0, 0.0, 0.0, 1.0], - transparency: 1.0, - transparent: false + 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; + defaults.shininess = [0.0]; } } return { KHR_materials_common: { + doubleSided: false, + transparent: false, values: defaults } }; } } } - }, - meshes : { - '*' : { + ], + meshes : [ + { primitives : [ { attributes : {}, @@ -92,9 +81,9 @@ var gltfTemplate = { } ] } - }, - nodes : { - '*' : { + ], + nodes : [ + { children : [], matrix : function(node) { if (!defined(node.translation) && !defined(node.rotation) && !defined(node.scale)) { @@ -122,28 +111,28 @@ var gltfTemplate = { } } } - }, - programs : { - '*' : { + ], + programs : [ + { attributes : [] } - }, - samplers : { - '*' : { + ], + samplers : [ + { magFilter: WebGLConstants.LINEAR, minFilter : WebGLConstants.NEAREST_MIPMAP_LINEAR, wrapS : WebGLConstants.REPEAT, wrapT : WebGLConstants.REPEAT } - }, - scenes : { - '*' : { + ], + scenes : [ + { nodes : [] } - }, - shaders : {}, - skins : { - '*' : { + ], + shaders : [], + skins : [ + { bindShapeMatrix : [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, @@ -151,28 +140,27 @@ var gltfTemplate = { 0.0, 0.0, 0.0, 1.0 ] } - }, - techniques : { - '*' : { + ], + techniques : [ + { parameters: {}, attributes: {}, uniforms: {}, states: { - '*': { - enable: [] - } + enable: [] } } - }, - textures : { - '*' : { + ], + textures : [ + { format: WebGLConstants.RGBA, internalFormat: WebGLConstants.RGBA, target: WebGLConstants.TEXTURE_2D, type: WebGLConstants.UNSIGNED_BYTE } - }, - extensionsUsed : [] + ], + extensionsUsed : [], + extensionsRequired : [] }; function addDefaultsFromTemplate(object, template) { @@ -221,6 +209,14 @@ function addDefaultsFromTemplate(object, template) { } } +var defaultMaterial = { + values : { + emission : [ + 0.5, 0.5, 0.5, 1.0 + ] + } +}; + var defaultTechnique = { attributes : { a_position : 'position' @@ -268,6 +264,7 @@ var defaultVertexShader = { type : WebGLConstants.VERTEX_SHADER, extras : { _pipeline : { + extension : '.vert', source : '' + 'precision highp float;\n' + '\n' + @@ -288,7 +285,7 @@ var defaultFragmentShader = { type : WebGLConstants.FRAGMENT_SHADER, extras : { _pipeline : { - extension : '.vert', + extension: '.frag', source : '' + 'precision highp float;\n' + '\n' + @@ -302,6 +299,29 @@ var defaultFragmentShader = { } }; +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)); + } + primitive.material = defaultMaterialId; + } + } + } +} + function addDefaultTechnique(gltf) { var materials = gltf.materials; var techniques = gltf.techniques; @@ -309,41 +329,30 @@ function addDefaultTechnique(gltf) { var shaders = gltf.shaders; var defaultTechniqueId; - var defaultProgramId; - var defaultVertexShaderId; - var defaultFragmentShaderId; - - for (var materialId in materials) { - if (materials.hasOwnProperty(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)) { - defaultTechniqueId = getUniqueId(gltf, 'defaultTechnique'); - defaultProgramId = getUniqueId(gltf, 'defaultProgram'); - defaultVertexShaderId = getUniqueId(gltf, 'defaultVertexShader'); - defaultFragmentShaderId = getUniqueId(gltf, 'defaultFragmentShader'); - var technique = clone(defaultTechnique, true); - techniques[defaultTechniqueId] = technique; - technique.program = defaultProgramId; + 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); - var program = clone(defaultProgram, true); - programs[defaultProgramId] = program; - program.vertexShader = defaultVertexShaderId; - program.fragmentShader = defaultFragmentShaderId; + var program = clone(defaultProgram, true); + technique.program = addToArray(programs, program); - var vertexShader = clone(defaultVertexShader, true); - shaders[defaultVertexShaderId] = vertexShader; + var vertexShader = clone(defaultVertexShader, true); + program.vertexShader = addToArray(shaders, vertexShader); - var fragmentShader = clone(defaultFragmentShader, true); - shaders[defaultFragmentShaderId] = fragmentShader; - } - material.technique = defaultTechniqueId; + var fragmentShader = clone(defaultFragmentShader, true); + program.fragmentShader = addToArray(shaders, fragmentShader); } + material.technique = defaultTechniqueId; } + } } @@ -351,45 +360,57 @@ function enableDiffuseTransparency(gltf) { var materials = gltf.materials; var techniques = gltf.techniques; - for (var materialId in materials) { - if (materials.hasOwnProperty(materialId)) { - var material = materials[materialId]; - if (defined(material.values) && defined(material.values.diffuse)) { - // Check if the diffuse texture/color is transparent - var diffuse = material.values.diffuse; - var diffuseTransparent = false; - if (typeof diffuse === 'string') { - diffuseTransparent = gltf.images[gltf.textures[diffuse].source].extras._pipeline.transparent; - } else { - diffuseTransparent = diffuse[3] < 1.0; - } + var materialsLength = materials.length; + for (var materialId = 0; materialId < materialsLength; materialId++) { + var material = materials[materialId]; + if (defined(material.values) && defined(material.values.diffuse)) { + // Check if the diffuse texture/color is transparent + var diffuse = material.values.diffuse; + var diffuseTransparent = false; + if (diffuse.length === 1) { + diffuseTransparent = gltf.images[gltf.textures[diffuse[0]].source].extras._pipeline.transparent; + } else { + diffuseTransparent = diffuse[3] < 1.0; + } - var technique = techniques[material.technique]; - var blendingEnabled = technique.states.enable.indexOf(WebGLConstants.BLEND) > -1; + var technique = techniques[material.technique]; + var blendingEnabled = technique.states.enable.indexOf(WebGLConstants.BLEND) > -1; - // Override the technique's states if blending isn't already enabled - if (diffuseTransparent && !blendingEnabled) { - technique.states = { - enable: [ - WebGLConstants.DEPTH_TEST, - WebGLConstants.BLEND + // Override the technique's states if blending isn't already enabled + if (diffuseTransparent && !blendingEnabled) { + technique.states = { + enable: [ + WebGLConstants.DEPTH_TEST, + WebGLConstants.BLEND + ], + depthMask: false, + functions: { + blendEquationSeparate: [ + WebGLConstants.FUNC_ADD, + WebGLConstants.FUNC_ADD ], - depthMask: false, - functions: { - blendEquationSeparate: [ - WebGLConstants.FUNC_ADD, - WebGLConstants.FUNC_ADD - ], - blendFuncSeparate: [ - WebGLConstants.ONE, - WebGLConstants.ONE_MINUS_SRC_ALPHA, - WebGLConstants.ONE, - WebGLConstants.ONE_MINUS_SRC_ALPHA - ] - } - }; - } + blendFuncSeparate: [ + WebGLConstants.ONE, + WebGLConstants.ONE_MINUS_SRC_ALPHA, + WebGLConstants.ONE, + WebGLConstants.ONE_MINUS_SRC_ALPHA + ] + } + }; } + + } + } +} + +function selectDefaultScene(gltf) { + var scenes = gltf.scenes; + + if (!defined(gltf.scene)) { + var scenesLength = scenes.length; + for (var sceneId = 0; sceneId < scenesLength; sceneId++) { + gltf.scene = sceneId; + break; } } } @@ -397,13 +418,12 @@ function enableDiffuseTransparency(gltf) { function optimizeForCesium(gltf) { // Give the diffuse uniform a semantic to support color replacement in 3D Tiles var techniques = gltf.techniques; - for (var techniqueId in techniques) { - if (techniques.hasOwnProperty(techniqueId)) { - var technique = techniques[techniqueId]; - var parameters = technique.parameters; - if (defined(parameters.diffuse)) { - parameters.diffuse.semantic = '_3DTILESDIFFUSE'; - } + 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'; } } } @@ -424,8 +444,10 @@ function optimizeForCesium(gltf) { function addDefaults(gltf, options) { options = defaultValue(options, {}); addDefaultsFromTemplate(gltf, gltfTemplate); + addDefaultMaterial(gltf); addDefaultTechnique(gltf); enableDiffuseTransparency(gltf); + selectDefaultScene(gltf); if (options.optimizeForCesium) { optimizeForCesium(gltf); } diff --git a/lib/addExtensionsRequired.js b/lib/addExtensionsRequired.js new file mode 100644 index 00000000..5b70c1bb --- /dev/null +++ b/lib/addExtensionsRequired.js @@ -0,0 +1,26 @@ +'use strict'; +var Cesium = require('cesium'); +var addExtensionsUsed = require('./addExtensionsUsed'); + +var defined = Cesium.defined; + +module.exports = addExtensionsRequired; + +/** + * Adds an extension to gltf.extensionsRequired if it does not already exist. + * Initializes extensionsRequired if it is not defined. + * + * @param {Object} gltf A javascript object containing a glTF asset. + * @param {String} extension The extension to add. + */ +function addExtensionsRequired(gltf, extension) { + var extensionsRequired = gltf.extensionsRequired; + if (!defined(extensionsRequired)) { + extensionsRequired = []; + gltf.extensionsRequired = extensionsRequired; + } + if (extensionsRequired.indexOf(extension) < 0) { + extensionsRequired.push(extension); + } + addExtensionsUsed(gltf, extension); +} \ No newline at end of file diff --git a/lib/addPipelineExtras.js b/lib/addPipelineExtras.js index 764e51dc..bde4ad5e 100644 --- a/lib/addPipelineExtras.js +++ b/lib/addPipelineExtras.js @@ -23,10 +23,18 @@ var exceptions = { */ function addPipelineExtras(gltf) { var objectStack = []; - for (var rootObjectId in gltf) { - if (gltf.hasOwnProperty(rootObjectId)) { - var rootObject = gltf[rootObjectId]; - objectStack.push(rootObject); + 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) { diff --git a/lib/addToArray.js b/lib/addToArray.js new file mode 100644 index 00000000..63311e35 --- /dev/null +++ b/lib/addToArray.js @@ -0,0 +1,7 @@ +'use strict'; +module.exports = addToArray; + +function addToArray(array, element) { + array.push(element); + return array.length - 1; +} \ No newline at end of file diff --git a/lib/bakeAmbientOcclusion.js b/lib/bakeAmbientOcclusion.js index 232f7ca2..5ab3466c 100644 --- a/lib/bakeAmbientOcclusion.js +++ b/lib/bakeAmbientOcclusion.js @@ -1,11 +1,18 @@ 'use strict'; var Cesium = require('cesium'); -var clone = require('clone'); +var Jimp = require('jimp'); +var addToArray = require('./addToArray'); +var isTexture = require('./isTexture'); +var GeometryMath = require('./GeometryMath'); +var NodeHelpers = require('./NodeHelpers'); +var readAccessor = require('./readAccessor'); +var StaticUniformGrid = require('./StaticUniformGrid'); var baryCentricCoordinates = Cesium.barycentricCoordinates; var Cartesian2 = Cesium.Cartesian2; var Cartesian3 = Cesium.Cartesian3; var CesiumMath = Cesium.Math; +var clone = Cesium.clone; var defaultValue = Cesium.defaultValue; var defined = Cesium.defined; var DeveloperError = Cesium.DeveloperError; @@ -17,13 +24,6 @@ var ShaderSource = Cesium.ShaderSource; var WebGLConstants = Cesium.WebGLConstants; var IntersectionTests = Cesium.IntersectionTests; -var GeometryMath = require('./GeometryMath'); -var getUniqueId = require('./getUniqueId'); -var Jimp = require('jimp'); -var NodeHelpers = require('./NodeHelpers'); -var readAccessor = require('./readAccessor'); -var StaticUniformGrid = require('./StaticUniformGrid'); - var scratchRay = new Ray(); var barycentricCoordinateScratch = new Cartesian3(); var worldPositionScratch = new Cartesian3(); @@ -183,8 +183,7 @@ function cloneJsonAsNeeded(id, cloneIds, items) { var cloneID = cloneIds[id]; if (defined(cloneID)) { if (cloneID === '') { // No clone exists yet. Make one! - cloneID = id + "_noAO"; - items[cloneID] = clone(items[id]); + cloneID = addToArray(items, clone(items[id])); cloneIds[id] = cloneID; } return cloneID; @@ -323,9 +322,7 @@ function addVertexData(gltf, options) { var allAOData = parameters.allAOData; var allAODataLength = allAOData.length; - var aoBufferId = getUniqueId(gltf, 'aoBuffer'); - - gltf.buffers[aoBufferId] = { + var aoBuffer = { type: 'arraybuffer', extras: { _pipeline: { @@ -334,16 +331,16 @@ function addVertexData(gltf, options) { } } }; + var aoBufferId = addToArray(gltf.buffers, aoBuffer); // add buffer view - var aoBufferViewId = getUniqueId(gltf, 'aoBufferView'); - - gltf.bufferViews[aoBufferViewId] = { + var aoBufferView = { buffer: aoBufferId, byteOffset: 0, byteLength: allAODataLength * 4, target: WebGLConstants.ARRAY_BUFFER }; + var aoBufferViewId = addToArray(gltf.bufferViews, aoBufferView); // add accessor for each primitive var primitiveCount = primitiveOrder.length; @@ -351,15 +348,14 @@ function addVertexData(gltf, options) { for (var i = 0; i < primitiveCount; i++) { var primitive = primitiveOrder[i]; var primitiveVertexCount = parameters.primitiveVertexCounts[i]; - var name = 'accessor_' + parameters.primitiveNames[i] + '_AO'; - primitive.attributes._OCCLUSION = name; - gltf.accessors[name] = { + var aoAccessor = { bufferView: aoBufferViewId, byteOffset: byteOffset, componentType: WebGLConstants.FLOAT, count: primitiveVertexCount, type: 'SCALAR' }; + primitive.attributes._OCCLUSION = addToArray(gltf.accessors, aoAccessor); byteOffset += primitiveVertexCount * 4; } } @@ -573,16 +569,15 @@ function bakeToTexture(gltf, options) { var exampleTextureID; var exampleImageID; - for (var materialID in materials) { - if (materials.hasOwnProperty(materialID)) { - var material = materials[materialID]; - if (defined(material.values) && defined(material.values.diffuse)) { - if (typeof material.values.diffuse === 'string') { - exampleMaterialID = materialID; - exampleTextureID = material.values.diffuse; - exampleImageID = textures[exampleTextureID].source; - break; - } + var materialsLength = materials.length; + for (var materialId = 0; materialId < materialsLength; materialId++) { + var material = materials[materialId]; + if (defined(material.values) && defined(material.values.diffuse)) { + if (isTexture('diffuse', material.values.diffuse)) { + exampleMaterialID = materialId; + exampleTextureID = material.values.diffuse; + exampleImageID = textures[exampleTextureID].source; + break; } } } @@ -665,10 +660,6 @@ function postProcessAO(options) { } function cloneAndSetupMaterialTextureImage(options) { - var newMaterialID = options.newMaterialID; - var newTextureID = options.newTextureID; - var newImageID = options.newImageID; - var materials = options.materials; var textures = options.textures; var images = options.images; @@ -677,24 +668,24 @@ function cloneAndSetupMaterialTextureImage(options) { var newTexture; var newMaterial; - if (defined(newImageID)) { + if (defined(options.oldImageID)) { var oldImage = images[options.oldImageID]; if (!defined(oldImage.extras._pipeline.jimpImage)) { throw new DeveloperError('gltf pipeline image processing does not currently support the ' + oldImage.extras._pipeline.extension + ' format.'); } newImage = clone(oldImage); newImage.extras._pipeline.jimpImage = oldImage.extras._pipeline.jimpImage.clone(); - images[newImageID] = newImage; + options.newImageID = addToArray(images, newImage); } - if (defined(newTextureID)) { + if (defined(options.oldTextureID)) { var oldTexture = textures[options.oldTextureID]; newTexture = clone(oldTexture); - newTexture.source = newImageID; - textures[newTextureID] = newTexture; - if (defined(newMaterialID)) { + newTexture.source = options.newImageID; + options.newTextureID = addToArray(textures, newTexture); + if (defined(options.oldMaterialID)) { newMaterial = clone(materials[options.oldMaterialID]); - newMaterial.texture = newTextureID; - materials[newMaterialID] = newMaterial; + newMaterial.texture = options.newTextureID; + options.newMaterialID = addToArray(materials, newMaterial); } } } @@ -702,8 +693,8 @@ function cloneAndSetupMaterialTextureImage(options) { // Check and modify the given material to ensure every primitive gets a unique material, texture, and image function ensureImageUniqueness(gltf, options) { var primitive = options.primitive; - var meshPrimitiveID = options.meshPrimitiveID; var state = options.state; + var parameters; var materialsSeen = state.materialsSeen; var texturesSeen = state.texturesSeen; @@ -713,11 +704,6 @@ function ensureImageUniqueness(gltf, options) { var allTextures = gltf.textures; var allImages = gltf.images; - // Generate some new IDs - var newMaterialID = meshPrimitiveID + '_AO_material'; - var newTextureID = meshPrimitiveID + '_AO_texture'; - var newImageID = meshPrimitiveID + '_AO_image'; - // Grab the existing material var materialID = primitive.material; var material = allMaterials[materialID]; @@ -728,18 +714,19 @@ function ensureImageUniqueness(gltf, options) { // - clone the example material // - clone the example texture // - clone the example image. resize to resolution and set to diffuse color, if any - if (!defined(diffuse) || typeof diffuse !== 'string') { - cloneAndSetupMaterialTextureImage({ - newMaterialID : newMaterialID, - newTextureID : newTextureID, - newImageID : newImageID, + if (!defined(diffuse) || diffuse.length > 1) { + parameters = { + newMaterialID : undefined, + newTextureID : undefined, + newImageID : undefined, oldMaterialID : state.exampleMaterialID, oldTextureID : state.exampleTextureID, oldImageID : state.exampleImageID, materials : allMaterials, textures : allTextures, images : allImages - }); + }; + cloneAndSetupMaterialTextureImage(parameters); var color = defaultValue(diffuse, [1.0, 1.0, 1.0, 1.0]); // For jimp @@ -748,7 +735,7 @@ function ensureImageUniqueness(gltf, options) { color[2] *= 255; color[3] *= 255; - var newJimpImage = allImages[newImageID].extras._pipeline.jimpImage; + var newJimpImage = allImages[parameters.newImageID].extras._pipeline.jimpImage; var resolution = state.resolution; newJimpImage.resize(resolution, resolution); @@ -758,61 +745,64 @@ function ensureImageUniqueness(gltf, options) { newJimpImage.setPixelColor(x, y, hexColor); } } - primitive.material = newMaterialID; - return allImages[newImageID]; + primitive.material = parameters.newMaterialID; + return allImages[parameters.newImageID]; } - var textureID = diffuse; + var textureID = diffuse[0]; var imageID = allTextures[textureID].source; if (materialsSeen.hasOwnProperty(materialID)) { // Check if the material is unique. If not, clone material, texture, and image - cloneAndSetupMaterialTextureImage({ - newMaterialID : newMaterialID, - newTextureID : newTextureID, - newImageID : newImageID, + parameters = { + newMaterialID : undefined, + newTextureID : undefined, + newImageID : undefined, oldMaterialID : materialID, oldTextureID : textureID, oldImageID : imageID, materials : allMaterials, textures : allTextures, images : allImages - }); - primitive.material = newMaterialID; + }; + cloneAndSetupMaterialTextureImage(parameters); + primitive.material = options.newMaterialID; } else if(texturesSeen.hasOwnProperty(textureID)) { // Check if the texture is unique. If not clone the texture and the image. - cloneAndSetupMaterialTextureImage({ - newTextureID : newTextureID, - newImageID : newImageID, - oldMaterialID : materialID, + parameters = { + newTextureID : undefined, + newImageID : undefined, + oldMaterialID : undefined, oldTextureID : textureID, oldImageID : imageID, materials : allMaterials, textures : allTextures, images : allImages - }); - values.diffuse = newTextureID; + }; + cloneAndSetupMaterialTextureImage(parameters); + values.diffuse = parameters.newTextureID; } else if(imagesSeen.hasOwnProperty(imageID)) { // Check if the image is unique. if not, clone the image. var texture = allTextures[textureID]; - cloneAndSetupMaterialTextureImage({ - newImageID : newImageID, - oldMaterialID : materialID, - oldTextureID : textureID, + parameters = { + newImageID : undefined, + oldMaterialID : undefined, + oldTextureID : undefined, oldImageID : imageID, materials : allMaterials, textures : allTextures, images : allImages - }); - texture.source = newImageID; + }; + cloneAndSetupMaterialTextureImage(parameters); + texture.source = parameters.newImageID; } else { // If nothing was cloned, mark this material, texture, and image as seen materialsSeen[materialID] = true; texturesSeen[textureID] = true; imagesSeen[imageID] = true; - newImageID = imageID; + return allImages[imageID]; } - return allImages[newImageID]; + return allImages[parameters.newImageID]; } ////////// loading ////////// diff --git a/lib/cesiumGeometryToGltfPrimitive.js b/lib/cesiumGeometryToGltfPrimitive.js index f12fa723..a6fd9510 100644 --- a/lib/cesiumGeometryToGltfPrimitive.js +++ b/lib/cesiumGeometryToGltfPrimitive.js @@ -4,8 +4,6 @@ var Cesium = require('cesium'); var createAccessor = require('./createAccessor'); var findAccessorMinMax = require('./findAccessorMinMax'); var getPrimitiveAttributeSemantics = require('./getPrimitiveAttributeSemantics'); -var mergeBuffers = require('./mergeBuffers'); -var uninterleaveAndPackBuffers = require('./uninterleaveAndPackBuffers'); var writeAccessor = require('./writeAccessor'); var DeveloperError = Cesium.DeveloperError; @@ -27,16 +25,8 @@ function getFirstAttributeSemantic(gltf, primitive, semantic, packedLength) { throw new DeveloperError('Unsupported attribute semantic: ' + semantic); } if (semantics.length <= 0) { - - var id; - - // all attributes but texcoords may occur only once - if (semantic !== 'TEXCOORD') { - id = 'accessor_' + semantic.toLowerCase(); - } - primitive.attributes[semantic] = createAccessor(gltf, packedLength, type, - WebGLConstants.FLOAT, WebGLConstants.ARRAY_BUFFER, id); + WebGLConstants.FLOAT, WebGLConstants.ARRAY_BUFFER); return semantic; } return semantics[0]; @@ -96,6 +86,4 @@ function cesiumGeometryToGltfPrimitive(gltf, primitive, geometry) { var indicesId = primitive.indices; var indicesAccessor = gltf.accessors[indicesId]; writeAccessor(gltf, indicesAccessor, geometry.indices); - mergeBuffers(gltf); - uninterleaveAndPackBuffers(gltf); } diff --git a/lib/changeAccessorComponentType.js b/lib/changeAccessorComponentType.js index 0e1997d5..2e8afc10 100644 --- a/lib/changeAccessorComponentType.js +++ b/lib/changeAccessorComponentType.js @@ -1,9 +1,8 @@ 'use strict'; var Cesium = require('cesium'); - var AccessorReader = require('./AccessorReader'); +var addToArray = require('./addToArray'); var byteLengthForComponentType = require('./byteLengthForComponentType'); -var getUniqueId = require('./getUniqueId'); var numberOfComponentsForType = require('./numberOfComponentsForType'); var writeBufferComponent = require('./writeBufferComponent'); @@ -60,21 +59,8 @@ function changeAccessorComponentType(gltf, accessor, newComponentType) { accessor.componentType = newComponentType; if (defined(writeBuffer)) { - var newBufferViewId = getUniqueId(gltf, 'bufferView'); - var newBufferId = getUniqueId(gltf, 'buffer'); - accessor.bufferView = newBufferViewId; accessor.byteOffset = 0; - accessor.byteStride = 0; - bufferViews[newBufferViewId] = { - buffer: newBufferId, - byteLength: writeBuffer.length, - byteOffset: 0, - target: bufferView.target, - extras: { - _pipeline: {} - } - }; - buffers[newBufferId] = { + var newBufferId = addToArray(buffers, { byteLength: writeBuffer.length, type: buffer.type, extras: { @@ -82,7 +68,17 @@ function changeAccessorComponentType(gltf, accessor, newComponentType) { source: writeBuffer } } - }; + }); + var newBufferViewId = addToArray(bufferViews, { + buffer: newBufferId, + byteLength: writeBuffer.length, + byteOffset: 0, + target: bufferView.target, + extras: { + _pipeline: {} + } + }); + accessor.bufferView = newBufferViewId; } } return gltf; diff --git a/lib/combineMeshes.js b/lib/combineMeshes.js deleted file mode 100644 index 5878f821..00000000 --- a/lib/combineMeshes.js +++ /dev/null @@ -1,69 +0,0 @@ -'use strict'; -var Cesium = require('cesium'); - -var defined = Cesium.defined; - -module.exports = combineMeshes; - -/** - * Combines meshes in a node. - * Should be run before the {@link combinePrimitives} stage to merge all primitives for a node into one mesh. - * - * The glTF asset must be initialized for the pipeline. - * - * @param {Object} gltf A javascript object containing a glTF asset. - * @returns {Object} The glTF asset with combined meshes. - * - * @see addPipelineExtras - * @see loadGltfUris - * @see combinePrimitives - */ -function combineMeshes(gltf) { - var nodes = gltf.nodes; - var meshes = gltf.meshes; - - if (defined(nodes)) { - for (var nodeId in nodes) { - if (nodes.hasOwnProperty(nodeId)) { - var node = nodes[nodeId]; - var nodeMeshes = node.meshes; - - if (defined(nodeMeshes) && nodeMeshes.length > 1) { - //Find the next available id for the combined mesh. - var idCount = 0; - var newMeshId = nodeId + '_mesh_' + idCount; - var objectKeys = Object.keys(meshes); - while (objectKeys.indexOf(newMeshId) !== -1) { - idCount++; - newMeshId = newMeshId.slice(0, -1) + idCount; - } - - //Combine all the primitives from the meshes into one array. - var primitiveList = []; - for (var i = 0; i < nodeMeshes.length; i++) { - var primitives = meshes[nodeMeshes[i]].primitives; - if (defined(primitives)) { - for (var j = 0; j < primitives.length; j++) { - primitiveList.push(primitives[j]); - } - } - } - - //Create a new mesh with all the primitives and the node id. - var newMesh = { - "name": nodeId + '_mesh', - "primitives": primitiveList, - "extras": { - "_pipeline": {} - } - }; - - node.meshes = [newMeshId]; - meshes[newMeshId] = newMesh; - } - } - } - } - - return gltf; -} \ No newline at end of file diff --git a/lib/combineNodes.js b/lib/combineNodes.js index c6b128f0..cc87eab5 100644 --- a/lib/combineNodes.js +++ b/lib/combineNodes.js @@ -1,26 +1,24 @@ 'use strict'; var Cesium = require('cesium'); -var jp = require('jsonpath'); +var addToArray = require('./addToArray'); var NodeHelpers = require('./NodeHelpers'); var PrimitiveHelpers = require('./PrimitiveHelpers'); var RemoveUnusedProperties = require('./RemoveUnusedProperties'); -var getUniqueId = require('./getUniqueId'); var Matrix4 = Cesium.Matrix4; var defined = Cesium.defined; +var removeMeshes = RemoveUnusedProperties.removeMeshes; var removeNodes = RemoveUnusedProperties.removeNodes; module.exports = combineNodes; -var rootNodePrefix = 'rootNode'; var scratchTransform = new Matrix4(); /** * Combines nodes where possible. - * Primitives in meshes on child nodes are transformed by their node's transform and passed up the node chain + * Primitives on a child node mesh are transformed by their node's transform and passed up the node chain * if the primitive does not share data with primitives on another node. Meshes used by multiple nodes * cannot be collapsed. Camera nodes and nodes targeted as joints or skeletons will be preserved. - * Should be run before the combineMeshes stage so that all combinable meshes are contained by one node. * * The glTF asset must be initialized for the pipeline. * @@ -29,20 +27,21 @@ var scratchTransform = new Matrix4(); * * @see addPipelineExtras * @see loadGltfUris - * @see combineMeshes */ function combineNodes(gltf) { var nodes = gltf.nodes; + var scenes = gltf.scenes; + var exclude = {}; getAnimationTargets(gltf, exclude); getTechniqueTargets(gltf, exclude); - jp.apply(gltf, '$.scenes[*]', function(scene) { + var scenesLength = scenes.length; + for (var sceneId = 0; sceneId < scenesLength; sceneId++) { + var scene = scenes[sceneId]; var sceneNodes = scene.nodes; if (defined(sceneNodes)) { - var rootNodeId = getUniqueId(gltf, rootNodePrefix); var rootNode = { children : sceneNodes, - meshes : [], matrix : [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, @@ -53,34 +52,55 @@ function combineNodes(gltf) { _pipeline : {} } }; - nodes[rootNodeId] = rootNode; + var rootNodeId = addToArray(nodes, rootNode); mergeChildrenIntoNode(gltf, rootNodeId, NodeHelpers.mapMeshesToNodes(gltf), mapMeshesToMeshes(gltf), exclude); removeVestigialNodes(gltf, rootNodeId, exclude); - if (rootNode.children.length > 0 && rootNode.meshes.length === 0) { + if (rootNode.children.length > 0 && !defined(rootNode.mesh)) { scene.nodes = rootNode.children; } else { scene.nodes = [rootNodeId]; } } - return scene; - }); + } removeNodes(gltf); + removeMeshes(gltf); return gltf; } function getAnimationTargets(gltf, targets) { - jp.apply(gltf, '$.animations[*].channels[*].target.id', function(nodeId) { - targets[nodeId] = true; - return nodeId; - }); + var animations = gltf.animations; + if (defined(animations)) { + var animationsLength = animations.length; + for (var animationId = 0; animationId < animationsLength; animationId++) { + var animation = animations[animationId]; + var channels = animation.channels; + var channelsLength = channels.length; + for (var channelId = 0; channelId < channelsLength; channelId++) { + var channel = channels[channelId]; + targets[channel.target.node] = true; + } + } + } return targets; } function getTechniqueTargets(gltf, targets) { - jp.apply(gltf, '$.techniques[*].parameters[?(@.node)]', function(techniqueParameters) { - targets[techniqueParameters.node] = true; - return techniqueParameters; - }); + var techniques = gltf.techniques; + if (defined(techniques)) { + var techniquesLength = techniques.length; + for (var techniqueId = 0; techniqueId < techniquesLength; techniqueId++) { + var technique = techniques[techniqueId]; + var parameters = technique.parameters; + for (var parameterName in parameters) { + if (parameters.hasOwnProperty(parameterName)) { + var parameter = parameters[parameterName]; + if (defined(parameter.node)) { + targets[parameter.node] = true; + } + } + } + } + } return targets; } @@ -101,27 +121,37 @@ function mergeChildrenIntoNode(gltf, nodeId, meshesToNodes, meshesToMeshes, excl if (!isFixedNode(gltf, childNodeId, exclude)) { preserve = false; NodeHelpers.getLocalMatrix4(childNode, transform); - var meshIds = childNode.meshes; - if (defined(meshIds)) { - childNode.meshes = []; - while(meshIds.length > 0) { - var meshId = meshIds.pop(); - if (meshesToNodes[meshId].length === 1 && meshesToMeshes[meshId].length === 0) { - var mesh = meshes[meshId]; - if (!Matrix4.equals(transform, Matrix4.IDENTITY)) { - PrimitiveHelpers.transformPrimitives(gltf, mesh.primitives, transform); - } - if (!defined(node.meshes)) { - node.meshes = []; - } - if (node.meshes.indexOf(meshId) < 0) { - node.meshes.push(meshId); - } - } else { - childNode.meshes.push(meshId); - preserve = true; + var meshId = childNode.mesh; + if (defined(meshId)) { + var mesh = meshes[meshId]; + var primitives = mesh.primitives; + if (meshesToNodes[meshId].length === 1 && meshesToMeshes[meshId].length === 0) { + if (!Matrix4.equals(transform, Matrix4.IDENTITY)) { + PrimitiveHelpers.transformPrimitives(gltf, primitives, transform); + } + var nodeMeshId = node.mesh; + var nodeMesh = meshes[nodeMeshId]; + if (!defined(nodeMesh)) { + nodeMesh = { + primitives: [], + extras: { + _pipeline: {} + } + }; + nodeMeshId = addToArray(meshes, nodeMesh); + meshesToNodes[nodeMeshId] = [nodeId]; + meshesToMeshes[nodeMeshId] = []; + node.mesh = nodeMeshId; + } + while (primitives.length > 0) { + var primitive = primitives.pop(); + nodeMesh.primitives.push(primitive); } } + else { + preserve = true; + } + } } if (defined(childNodeChildren)) { @@ -176,7 +206,7 @@ function transformNodes(gltf, nodeIds, transform) { delete node.scale; var packedTransform = []; Matrix4.pack(nodeTransform, packedTransform); - node.matrix= packedTransform; + node.matrix = packedTransform; } } @@ -192,7 +222,7 @@ function isFixedNode(gltf, nodeId, exclude) { if (defined(node.jointName)) { return true; } - if (defined(node.skeletons) && node.skeletons.length > 0) { + if (defined(node.skeleton)) { return true; } return defined(node.skin); @@ -204,7 +234,7 @@ function canMergeToParent(gltf, nodeId, exclude) { if (isFixedNode(gltf, nodeId, exclude)) { return false; } - if (defined(node.meshes) && node.meshes.length > 0) { + if (defined(node.mesh)) { return false; } NodeHelpers.getLocalMatrix4(node, scratchTransform); @@ -226,18 +256,15 @@ function mapMeshesToMeshes(gltf) { var meshesToMeshes = {}; var meshes = gltf.meshes; if (defined(meshes)) { - var meshIds = Object.keys(meshes); - while (meshIds.length > 0) { - var meshId = meshIds.pop(); + var meshesLength = meshes.length; + for (var meshId = 0; meshId < meshesLength; meshId++) { + var mesh = meshes[meshId]; var meshConflicts = meshesToMeshes[meshId]; if (!defined(meshConflicts)) { meshConflicts = []; meshesToMeshes[meshId] = meshConflicts; } - var mesh = meshes[meshId]; - var meshIdsLength = meshIds.length; - for (var i = 0; i < meshIdsLength; i++) { - var compareMeshId = meshIds[i]; + for (var compareMeshId = meshId + 1; compareMeshId < meshesLength; compareMeshId++) { var compareMesh = meshes[compareMeshId]; var compareMeshConflicts = meshesToMeshes[compareMeshId]; if (!defined(compareMeshConflicts)) { diff --git a/lib/combinePrimitives.js b/lib/combinePrimitives.js index 0962793a..c30431a1 100644 --- a/lib/combinePrimitives.js +++ b/lib/combinePrimitives.js @@ -1,6 +1,7 @@ 'use strict'; var Cesium = require('cesium'); var deepEqual = require('deep-equal'); +var ForEach = require('./ForEach'); var PrimitiveHelpers = require('./PrimitiveHelpers'); var createAccessor = require('./createAccessor'); var readAccessor = require('./readAccessor'); @@ -26,29 +27,25 @@ module.exports = combinePrimitives; */ function combinePrimitives(gltf) { var allPrimitives = PrimitiveHelpers.getAllPrimitives(gltf); - var meshes = gltf.meshes; - for (var meshId in meshes) { - if (meshes.hasOwnProperty(meshId)) { - var mesh = meshes[meshId]; - var primitivesByMaterialMode = PrimitiveHelpers.getPrimitivesByMaterialMode(mesh.primitives); - mesh.primitives = []; - for (var materialId in primitivesByMaterialMode) { - if (primitivesByMaterialMode.hasOwnProperty(materialId)) { - var primitivesByMode = primitivesByMaterialMode[materialId]; - for (var mode in primitivesByMode) { - if (primitivesByMode.hasOwnProperty(mode)) { - var primitives = primitivesByMode[mode]; - primitives = combinePrimitivesInGroup(gltf, allPrimitives, primitives, materialId, parseInt(mode), false); - var primitivesLength = primitives.length; - for (var i = 0; i < primitivesLength; i++) { - mesh.primitives.push(primitives[i]); - } + ForEach.mesh(gltf, function(mesh) { + var primitivesByMaterialMode = PrimitiveHelpers.getPrimitivesByMaterialMode(mesh.primitives); + mesh.primitives = []; + for (var materialId in primitivesByMaterialMode) { + if (primitivesByMaterialMode.hasOwnProperty(materialId)) { + var primitivesByMode = primitivesByMaterialMode[materialId]; + for (var mode in primitivesByMode) { + if (primitivesByMode.hasOwnProperty(mode)) { + var primitives = primitivesByMode[mode]; + primitives = combinePrimitivesInGroup(gltf, allPrimitives, primitives, materialId, parseInt(mode), false); + var primitivesLength = primitives.length; + for (var i = 0; i < primitivesLength; i++) { + mesh.primitives.push(primitives[i]); } } } } } - } + }); } function combinePrimitivesInGroup(gltf, allPrimitives, primitives, materialId, mode, uint32Enabled) { diff --git a/lib/compressIntegerAccessors.js b/lib/compressIntegerAccessors.js index fdbed8f3..98e521ac 100644 --- a/lib/compressIntegerAccessors.js +++ b/lib/compressIntegerAccessors.js @@ -1,17 +1,14 @@ 'use strict'; var Cesium = require('cesium'); -var Promise = require('bluebird'); +var AccessorReader = require('./AccessorReader'); +var changeAccessorComponentType = require('./changeAccessorComponentType'); +var findAccessorMinMax = require('./findAccessorMinMax'); +var ForEach = require('./ForEach'); var WebGLConstants = Cesium.WebGLConstants; var defined = Cesium.defined; var defaultValue = Cesium.defaultValue; -var AccessorReader = require('./AccessorReader'); -var changeAccessorComponentType = require('./changeAccessorComponentType'); -var findAccessorMinMax = require('./findAccessorMinMax'); -var getAccessorsForSemantic = require('./getAccessorsForSemantic'); -var uninterLeaveAndPackBuffers = require('./uninterleaveAndPackBuffers'); - module.exports = compressIntegerAccessors; var signedComponentTypes = [ @@ -50,7 +47,7 @@ var unsignedComponentTypes = [ * @param {Object} gltf A javascript object containing a glTF asset. * @param {Object} [options] Options defining custom behavior. * @param {Array} [options.semantics] An array of semantics to compress. - * @returns {Promise} A promise that resolves to the glTF asset with compressed integer accessors. + * @returns {Object} The glTF asset with compressed integer accessors. * * @see addPipelineExtras * @see loadGltfUris @@ -59,32 +56,27 @@ function compressIntegerAccessors(gltf, options) { options = defaultValue(options, {}); var semantics = defaultValue(options.semantics, []); var semanticsLength = semantics.length; - var promises = []; + + var handler = function(accessorId) { + var accessors = gltf.accessors; + var accessor = accessors[accessorId]; + var accessorReader = new AccessorReader(gltf, accessor); + var bufferView = accessorReader.bufferView; + if (bufferView.target === WebGLConstants.ARRAY_BUFFER) { + var newComponentType = canCompressAccessor(gltf, accessorReader); + if (defined(newComponentType)) { + changeAccessorComponentType(gltf, accessor, newComponentType); + } + } + }; + for (var i = 0; i < semanticsLength; i++) { var semantic = semantics[i]; - promises.push(getAccessorsForSemantic(gltf, semantic, compressIntegerAccessor)); + ForEach.accessorWithSemantic(gltf, semantic, handler); } - return Promise.all(promises).then(function() { - uninterLeaveAndPackBuffers(gltf); - return gltf; - }); + return gltf; } -function compressIntegerAccessor(gltf, primitive, accessorId, matchedSemantic) { - /* These callback parameters are unused */ - void(primitive, matchedSemantic); - - var accessors = gltf.accessors; - var accessor = accessors[accessorId]; - var accessorReader = new AccessorReader(gltf, accessor); - var bufferView = accessorReader.bufferView; - if (bufferView.target === WebGLConstants.ARRAY_BUFFER) { - var newComponentType = canCompressAccessor(gltf, accessorReader); - if (defined(newComponentType)) { - changeAccessorComponentType(gltf, accessor, newComponentType); - } - } -} function canCompressAccessor(gltf, accessorReader) { // Can't compress something smaller than a byte diff --git a/lib/compressTextureCoordinates.js b/lib/compressTextureCoordinates.js index 83342061..a8c3cc33 100644 --- a/lib/compressTextureCoordinates.js +++ b/lib/compressTextureCoordinates.js @@ -1,6 +1,12 @@ 'use strict'; var Cesium = require('cesium'); -var Promise = require('bluebird'); +var byteLengthForComponentType = require('./byteLengthForComponentType'); +var findAccessorMinMax = require('./findAccessorMinMax'); +var ForEach = require('./ForEach'); +var getAccessorByteStride = require('./getAccessorByteStride'); +var numberOfComponentsForType = require('./numberOfComponentsForType'); +var readBufferComponent = require('./readBufferComponent'); +var writeBufferComponent = require('./writeBufferComponent'); var AttributeCompression = Cesium.AttributeCompression; var Cartesian2 = Cesium.Cartesian2; @@ -9,15 +15,6 @@ var ShaderSource = Cesium.ShaderSource; var WebGLConstants = Cesium.WebGLConstants; var defined = Cesium.defined; -var byteLengthForComponentType = require('./byteLengthForComponentType'); -var findAccessorMinMax = require('./findAccessorMinMax'); -var getAccessorByteStride = require('./getAccessorByteStride'); -var getAccessorsForSemantic = require('./getAccessorsForSemantic'); -var numberOfComponentsForType = require('./numberOfComponentsForType'); -var readBufferComponent = require('./readBufferComponent'); -var uninterleaveAndPackBuffers = require('./uninterleaveAndPackBuffers'); -var writeBufferComponent = require('./writeBufferComponent'); - module.exports = compressTextureCoordinates; /** @@ -27,75 +24,72 @@ module.exports = compressTextureCoordinates; * The glTF asset must be initialized for the pipeline. * * @param {Object} gltf A javascript object containing a glTF asset. - * @returns {Promise} A promise that resolves to the glTF asset with compressed texture coordinates. + * @returns {Object} The glTF asset with compressed texture coordinates. * * @see addPipelineExtras * @see loadGltfUris */ function compressTextureCoordinates(gltf) { - return new Promise(function(resolve) { - var accessors = gltf.accessors; - var bufferViews = gltf.bufferViews; - var buffers = gltf.buffers; - var materials = gltf.materials; - var techniques = gltf.techniques; - var patchedTechniques = {}; - var patchedPrograms = {}; - var patchedShaders = {}; + var accessors = gltf.accessors; + var bufferViews = gltf.bufferViews; + var buffers = gltf.buffers; + var materials = gltf.materials; + var techniques = gltf.techniques; + var patchedTechniques = {}; + var patchedPrograms = {}; + var patchedShaders = {}; - getAccessorsForSemantic(gltf, 'TEXCOORD', function(gltf, primitive, accessorId) { - var accessor = accessors[accessorId]; - if (canCompress(accessor, primitive)) { - // Compress texture coordinates to a single float - var bufferViewId = accessor.bufferView; - var bufferView = bufferViews[bufferViewId]; - var bufferId = bufferView.buffer; - var buffer = buffers[bufferId]; - var source = buffer.extras._pipeline.source; - var byteStride = getAccessorByteStride(accessor); - var byteOffset = accessor.byteOffset + bufferView.byteOffset; - var componentType = accessor.componentType; - var newComponentType = WebGLConstants.FLOAT; - var componentByteLength = byteLengthForComponentType(componentType); - var numElements = accessor.count; - var numComponents = numberOfComponentsForType(accessor.type); - for (var j = 0; j < numElements; j++) { - var elementArray = []; - for (var k = 0; k < numComponents; k++) { - var element = readBufferComponent(source, componentType, byteOffset + componentByteLength * k); - elementArray.push(element); - } - var texCoord = Cartesian2.fromArray(elementArray); - var compressed = AttributeCompression.compressTextureCoordinates(texCoord); - writeBufferComponent(source, newComponentType, compressed, byteOffset); - byteOffset += byteStride; - } - accessor.byteStride = byteStride; - accessor.componentType = newComponentType; - accessor.type = 'SCALAR'; - var minMax = findAccessorMinMax(gltf, accessor); - accessor.min = minMax.min; - accessor.max = minMax.max; - var materialId = primitive.material; - var material = materials[materialId]; - var techniqueId = material.technique; - var attributeVariableName = patchedTechniques[techniqueId]; - if (!defined(patchedTechniques[techniqueId])) { - attributeVariableName = patchTechnique(gltf, techniqueId); - patchedTechniques[techniqueId] = attributeVariableName; - } - var technique = techniques[techniqueId]; - var programId = technique.program; - if (!defined(patchedPrograms[programId])) { - patchProgram(gltf, programId, attributeVariableName, patchedShaders); - patchedPrograms[programId] = true; + /* jshint unused:vars */ + ForEach.accessorWithSemantic(gltf, 'TEXCOORD', function(accessorId, semantic, primitive) { + var accessor = accessors[accessorId]; + if (canCompress(accessor, primitive)) { + // Compress texture coordinates to a single float + var bufferViewId = accessor.bufferView; + var bufferView = bufferViews[bufferViewId]; + var bufferId = bufferView.buffer; + var buffer = buffers[bufferId]; + var source = buffer.extras._pipeline.source; + var byteStride = getAccessorByteStride(gltf, accessor); + var byteOffset = accessor.byteOffset + bufferView.byteOffset; + var componentType = accessor.componentType; + var newComponentType = WebGLConstants.FLOAT; + var componentByteLength = byteLengthForComponentType(componentType); + var numElements = accessor.count; + var numComponents = numberOfComponentsForType(accessor.type); + for (var j = 0; j < numElements; j++) { + var elementArray = []; + for (var k = 0; k < numComponents; k++) { + var element = readBufferComponent(source, componentType, byteOffset + componentByteLength * k); + elementArray.push(element); } + var texCoord = Cartesian2.fromArray(elementArray); + var compressed = AttributeCompression.compressTextureCoordinates(texCoord); + writeBufferComponent(source, newComponentType, compressed, byteOffset); + byteOffset += byteStride; } - }).then(function() { - uninterleaveAndPackBuffers(gltf); - resolve(gltf); - }); + bufferView.byteStride = byteStride; + accessor.componentType = newComponentType; + accessor.type = 'SCALAR'; + var minMax = findAccessorMinMax(gltf, accessor); + accessor.min = minMax.min; + accessor.max = minMax.max; + var materialId = primitive.material; + var material = materials[materialId]; + var techniqueId = material.technique; + var attributeVariableName = patchedTechniques[techniqueId]; + if (!defined(patchedTechniques[techniqueId])) { + attributeVariableName = patchTechnique(gltf, techniqueId); + patchedTechniques[techniqueId] = attributeVariableName; + } + var technique = techniques[techniqueId]; + var programId = technique.program; + if (!defined(patchedPrograms[programId])) { + patchProgram(gltf, programId, attributeVariableName, patchedShaders); + patchedPrograms[programId] = true; + } + } }); + return gltf; } function canCompress(accessor) { @@ -107,34 +101,29 @@ function canCompress(accessor) { function patchTechnique(gltf, techniqueId) { var techniques = gltf.techniques; var technique = techniques[techniqueId]; - var attributes = technique.attributes; - var parameters = technique.parameters; var texCoordParameterName; - for (var parameterName in parameters) { - if (parameters.hasOwnProperty(parameterName)) { - var parameter = parameters[parameterName]; - var semantic = parameter.semantic; - if (defined(semantic)) { - if (semantic.indexOf('TEXCOORD') === 0) { - texCoordParameterName = parameterName; - parameter.type = WebGLConstants.FLOAT; - break; - } + ForEach.techniqueParameter(technique, function(parameter, parameterName) { + var semantic = parameter.semantic; + if (defined(semantic)) { + if (semantic.indexOf('TEXCOORD') === 0) { + texCoordParameterName = parameterName; + parameter.type = WebGLConstants.FLOAT; + return true; } } - } + }); + var texcoordVariableName; if (!defined(texCoordParameterName)) { throw new DeveloperError('TEXCOORD semantic in technique' + techniqueId + ' doesn\'t have a defined parameter'); } else { - for (var attributeVariableName in attributes) { - if (attributes.hasOwnProperty(attributeVariableName)) { - var attributeParameterName = attributes[attributeVariableName]; - if (attributeParameterName === texCoordParameterName) { - return attributeVariableName; - } + ForEach.techniqueAttribute(technique, function(attributeParameterName, attributeVariableName) { + if (attributeParameterName === texCoordParameterName) { + texcoordVariableName = attributeVariableName; + return true; } - } + }); } + return texcoordVariableName; } function patchProgram(gltf, programId, texCoordVariableName, patchedShaders) { diff --git a/lib/compressTextures.js b/lib/compressTextures.js index 66a5335d..eac054b4 100644 --- a/lib/compressTextures.js +++ b/lib/compressTextures.js @@ -45,55 +45,53 @@ function compressTextures(gltf, options) { var promises = []; var images = gltf.images; - for (var imageId in images) { - if (images.hasOwnProperty(imageId)) { - var image = images[imageId]; - var pipelineExtras = image.extras._pipeline; - var compressedImages = {}; - var length = optionsArray.length; - for (var i = 0; i < length; ++i) { - var compressionOptions = optionsArray[i]; - var compressedType = compressionOptions.format; - if (compressedType.indexOf('crunch') >= 0) { - // crunch-dxt1, crunch-dxt5 require the s3tc extension and a crunch decoder - compressedType = 'crunch'; - } else if (compressedType.indexOf('dxt') >= 0) { - // dxt1, dxt3, dxt5 all require the s3tc extension - compressedType = 's3tc'; - } - var compressedImage = { - uri : undefined, - extras : { - _pipeline : { - source : undefined, - extension : undefined, - name : imageId + '-' + compressedType - } - } - }; - compressedImages[compressedType] = compressedImage; - promises.push(compressTexture(gltf, imageId, compressionOptions) - .then(replaceImage(compressedImage))); + var imagesLength = images.length; + for (var imageId = 0; imageId < imagesLength; imageId++) { + var image = images[imageId]; + var pipelineExtras = image.extras._pipeline; + var compressedImages = []; + var length = optionsArray.length; + for (var i = 0; i < length; ++i) { + var compressionOptions = optionsArray[i]; + var compressedType = compressionOptions.format; + if (compressedType.indexOf('crunch') >= 0) { + // crunch-dxt1, crunch-dxt5 require the s3tc extension and a crunch decoder + compressedType = 'crunch'; + } else if (compressedType.indexOf('dxt') >= 0) { + // dxt1, dxt3, dxt5 all require the s3tc extension + compressedType = 's3tc'; } + var compressedImage = { + uri : undefined, + extras : { + _pipeline : { + source : undefined, + extension : undefined, + name : imageId + '-' + compressedType + } + } + }; + compressedImages.push(compressedImage); + promises.push(compressTexture(gltf, imageId, compressionOptions) + .then(replaceImage(compressedImage))); + } - image.extras.compressedImage3DTiles = compressedImages; + image.extras.compressedImage3DTiles = compressedImages; - // Set the default image to a 1x1 white png - image.uri = defaultImageUri; - pipelineExtras.source = Buffer.from(defaultImageUri.slice(22), 'base64'); - pipelineExtras.transparent = false; - pipelineExtras.extension = '.png'; - } + // Set the default image to a 1x1 white png + image.uri = defaultImageUri; + pipelineExtras.source = Buffer.from(defaultImageUri.slice(22), 'base64'); + pipelineExtras.transparent = false; + pipelineExtras.extension = '.png'; } // Edit samplers to disallow mip-mapping var samplers = gltf.samplers; - for (var samplerId in samplers) { - if (samplers.hasOwnProperty(samplerId)) { - var sampler = samplers[samplerId]; - if (sampler.minFilter !== WebGLConstants.NEAREST && sampler.minFilter !== WebGLConstants.LINEAR) { - sampler.minFilter = WebGLConstants.LINEAR; - } + var samplersLength = samplers.length; + for (var samplerId = 0; samplerId < samplersLength; samplerId++) { + var sampler = samplers[samplerId]; + if (sampler.minFilter !== WebGLConstants.NEAREST && sampler.minFilter !== WebGLConstants.LINEAR) { + sampler.minFilter = WebGLConstants.LINEAR; } } diff --git a/lib/convertDagToTree.js b/lib/convertDagToTree.js index 2a21dcfb..49d3b626 100644 --- a/lib/convertDagToTree.js +++ b/lib/convertDagToTree.js @@ -1,6 +1,8 @@ 'use strict'; var Cesium = require('cesium'); -var clone = require('clone'); +var addToArray = require('./addToArray'); + +var clone = Cesium.clone; var defined = Cesium.defined; module.exports = convertDagToTree; @@ -21,48 +23,46 @@ module.exports = convertDagToTree; function convertDagToTree(gltf) { var scenes = gltf.scenes; var nodes = gltf.nodes; + var nodesLength = nodes.length; if (defined(scenes) && defined(nodes)) { - for (var sceneId in scenes) { - if (scenes.hasOwnProperty(sceneId)) { - var roots = scenes[sceneId].nodes; - if (defined(roots)) { - //For each scene, reinitialize all nodes to unvisited - for (var nodeId in nodes) { - if (nodes.hasOwnProperty(nodeId)) { - nodes[nodeId].extras._pipeline.visited = false; - nodes[nodeId].extras._pipeline.copy = 0; - } - } + var scenesLength = scenes.length; + for (var sceneId = 0; sceneId < scenesLength; sceneId++) { + var roots = scenes[sceneId].nodes; + if (defined(roots)) { + //For each scene, reinitialize all nodes to unvisited + for (var nodeId = 0; nodeId < nodesLength; nodeId++) { + nodes[nodeId].extras._pipeline.visited = false; + } - //Perform a breadth-first search from each root, searching for previously visited nodes - var nodeStack = []; - var rootsLength = roots.length; - for (var i = 0; i < rootsLength; i++) { - var root = roots[i]; - nodeStack.push(root); - nodes[root].extras._pipeline.visited = true; - while (nodeStack.length > 0) { - var currentNode = nodes[nodeStack.shift()]; - var children = currentNode.children; - if (defined(children)) { - for (var j = 0; j < children.length; j++) { - var childId = children[j]; - var child = nodes[childId]; - //If child has already been visited, duplicate and search the subgraph - if (child.extras._pipeline.visited) { - nodeStack.push(duplicateSubgraph(nodes, currentNode, j, childId)); - } - else { - child.extras._pipeline.visited = true; - nodeStack.push(childId); - } + //Perform a breadth-first search from each root, searching for previously visited nodes + var nodeStack = []; + var rootsLength = roots.length; + for (var i = 0; i < rootsLength; i++) { + var root = roots[i]; + nodeStack.push(root); + nodes[root].extras._pipeline.visited = true; + while (nodeStack.length > 0) { + var currentNode = nodes[nodeStack.shift()]; + var children = currentNode.children; + if (defined(children)) { + for (var j = 0; j < children.length; j++) { + var childId = children[j]; + var child = nodes[childId]; + //If child has already been visited, duplicate and search the subgraph + if (child.extras._pipeline.visited) { + nodeStack.push(duplicateSubgraph(nodes, currentNode, j, childId)); + } + else { + child.extras._pipeline.visited = true; + nodeStack.push(childId); } } } } } } + } } @@ -105,24 +105,7 @@ function duplicateSubgraph(nodes, parent, rootIndex, root) { //Duplicate node and return the id of the new node function duplicateNode(nodes, nodeId) { var node = nodes[nodeId]; - var copyId = node.extras._pipeline.copy + 1; - var newId = nodeId; - - //Appends the copy suffix if duplicating the original node - if (copyId === 1) { - newId += '_1'; - } - - //Increments the copy suffix until the new node has a unique id - var nodeKeys = Object.keys(nodes); - while (nodeKeys.indexOf(newId) !== -1) { - copyId++; - newId = newId.slice(0, -1) + copyId; - } - - var newNode = clone(node); - nodes[newId] = newNode; - newNode.extras._pipeline.visited = false; - newNode.extras._pipeline.copy = copyId; - return newId; + var nodeClone = clone(node, true); + nodeClone.extras._pipeline.visited = false; + return addToArray(nodes, nodeClone); } \ No newline at end of file diff --git a/lib/createAccessor.js b/lib/createAccessor.js index f2187335..b7d74f28 100644 --- a/lib/createAccessor.js +++ b/lib/createAccessor.js @@ -1,9 +1,8 @@ 'use strict'; var Cesium = require('cesium'); - +var addToArray = require('./addToArray'); var byteLengthForComponentType = require('./byteLengthForComponentType'); var findAccessorMinMax = require('./findAccessorMinMax'); -var getUniqueId = require('./getUniqueId'); var numberOfComponentsForType = require('./numberOfComponentsForType'); var writeBufferComponent = require('./writeBufferComponent'); @@ -20,11 +19,10 @@ module.exports = createAccessor; * @param {String} type glTF type (e.g. 'scalar', 'vec3') * @param {Number} componentType glTF component type (e.g. 5126 (float)) * @param {Number} target glTF bufferView target (e.g. 34962 (ARRAY_BUFFER), 34963 (ELEMENT_ARRAY_BUFFER) - * @param {String} [id] The id to use when assigning the accessor to the glTF asset. If undefined, a unique id is generated. * * @returns {String} The accessor's id. */ -function createAccessor(gltf, dataOrLength, type, componentType, target, id) { +function createAccessor(gltf, dataOrLength, type, componentType, target) { var numberOfComponents = numberOfComponentsForType(type); var data; var dataLength; @@ -38,29 +36,24 @@ function createAccessor(gltf, dataOrLength, type, componentType, target, id) { throw new DeveloperError('Length of data written must be a multiple of the number of accessor components.'); } var componentByteLength = byteLengthForComponentType(componentType); - if (!defined(id)) { - id = getUniqueId(gltf, 'accessor'); - } - var bufferViewId = getUniqueId(gltf, 'bufferView'); - var bufferId = getUniqueId(gltf, 'buffer'); var bufferData = new Buffer(dataLength * componentByteLength); if (defined(data)) { for (var i = 0; i < data.length; i++) { writeBufferComponent(bufferData, componentType, data[i], i * componentByteLength); } } - var accessor = { - bufferView : bufferViewId, - byteOffset : 0, - byteStride : 0, - componentType : componentType, - count : dataLength / numberOfComponents, + + var buffer = { + type : "arraybuffer", + byteLength : bufferData.length, extras : { - _pipeline : {} - }, - type : type + _pipeline : { + extension : '.bin', + source : bufferData + } + } }; - gltf.accessors[id] = accessor; + var bufferId = addToArray(gltf.buffers, buffer); var bufferView = { buffer : bufferId, @@ -71,22 +64,23 @@ function createAccessor(gltf, dataOrLength, type, componentType, target, id) { }, target : target }; - gltf.bufferViews[bufferViewId] = bufferView; + var bufferViewId = addToArray(gltf.bufferViews, bufferView); - var buffer = { - type : "arraybuffer", - byteLength : bufferData.length, + var accessor = { + bufferView : bufferViewId, + byteOffset : 0, + byteStride : 0, + componentType : componentType, + count : dataLength / numberOfComponents, extras : { - _pipeline : { - extension : '.bin', - source : bufferData - } - } + _pipeline : {} + }, + type : type }; - gltf.buffers[bufferId] = buffer; + var accessorId = addToArray(gltf.accessors, accessor); var minMax = findAccessorMinMax(gltf, accessor); accessor.min = minMax.min; accessor.max = minMax.max; - return id; + return accessorId; } \ No newline at end of file diff --git a/lib/createAccessorUsageTables.js b/lib/createAccessorUsageTables.js index 5b10164c..c3301b97 100644 --- a/lib/createAccessorUsageTables.js +++ b/lib/createAccessorUsageTables.js @@ -1,6 +1,7 @@ 'use strict'; var Cesium = require('cesium'); var defined = Cesium.defined; +var ForEach = require('./ForEach'); var getAccessorByteStride = require('./getAccessorByteStride'); var readBufferComponent = require('./readBufferComponent'); @@ -55,7 +56,7 @@ function markUsageForIndexAccessor(gltf, accessor, usage) { var buffer = buffers[bufferId]; var source = buffer.extras._pipeline.source; var byteOffset = accessor.byteOffset + bufferView.byteOffset; - var byteStride = getAccessorByteStride(accessor); + var byteStride = getAccessorByteStride(gltf, accessor); for (var i = 0; i < accessor.count; i++) { var index = readBufferComponent(source, accessor.componentType, byteOffset + i * byteStride); if (index > usage.length) { @@ -71,7 +72,6 @@ function markUsageForIndexAccessor(gltf, accessor, usage) { */ function createAccessorUsageTables(gltf) { var accessors = gltf.accessors; - var meshes = gltf.meshes; var tables = []; var accessorTableMapping = {}; var attribute; @@ -79,86 +79,80 @@ function createAccessorUsageTables(gltf) { var table; var tableIndex; var i; - for (var meshId in meshes) { - if (meshes.hasOwnProperty(meshId)) { - var mesh = meshes[meshId]; - var primitives = mesh.primitives; - var primitivesLength = primitives.length; - for (i = 0; i < primitivesLength ; i++) { - var primitive = primitives[i]; - var attributes = primitive.attributes; - var indexAccessorId = primitive.indices; - if (defined(indexAccessorId)) { - var indexAccessor = accessors[indexAccessorId]; - tableIndex = accessorTableMapping[indexAccessorId]; - if (!defined(tableIndex)) { - // There is no mapping for this index accessor, check if there is an existing mapping for any of the attributes - var mappedTableIndex; - var mappedTableIndices = {}; - for (attribute in attributes) { - if (attributes.hasOwnProperty(attribute)) { - attributeAccessorId = attributes[attribute]; - if (defined(accessorTableMapping[attributeAccessorId])) { - // There is already a mapping for one of the attributes, join that one - mappedTableIndices[accessorTableMapping[attributeAccessorId]] = true; - } - } - } - var mappedTableIndexArray = Object.keys(mappedTableIndices); - var mappedTableIndexArrayLength = mappedTableIndexArray.length; - if (mappedTableIndexArrayLength > 0) { - mappedTableIndex = parseInt(mappedTableIndexArray[0]); - for (var j = 1; j < mappedTableIndexArrayLength; j++) { - // Multiple attributes mapped to different tables, merge them - var indexB = mappedTableIndexArray[j]; - mergeUsageTables(tables, accessorTableMapping, mappedTableIndex, indexB); - } - } - if (!defined(mappedTableIndex)) { - // There are no existing linkages to other accessors, make a new table entry - table = { - indexAccessors : {}, - attributeAccessors : {}, - usage : [] - }; - tables.push(table); - mappedTableIndex = tables.length - 1; - } else { - // Join an existing mapping - table = tables[mappedTableIndex]; - } - table.usage = markUsageForIndexAccessor(gltf, indexAccessor, table.usage); - table.indexAccessors[indexAccessorId] = true; - for (attribute in attributes) { - if (attributes.hasOwnProperty(attribute)) { - attributeAccessorId = attributes[attribute]; - table.attributeAccessors[attributeAccessorId] = true; - accessorTableMapping[attributeAccessorId] = mappedTableIndex; - } - } - accessorTableMapping[indexAccessorId] = mappedTableIndex; - mappedTableIndex = undefined; - } else { - // This index accessor has already been done - table = tables[tableIndex]; - for (attribute in attributes) { - if (attributes.hasOwnProperty(attribute)) { - attributeAccessorId = attributes[attribute]; - // Make sure the attribute accessors haven't been assigned somewhere else - var attributeTableIndex = accessorTableMapping[attributeAccessorId]; - if (defined(attributeTableIndex) && attributeTableIndex !== tableIndex) { - // Merge them into this one if they have been - mergeUsageTables(tables, accessorTableMapping, tableIndex, attributeTableIndex); - } - table.attributeAccessors[attributeAccessorId] = true; - accessorTableMapping[attributeAccessorId] = tableIndex; - } - } - } - } - } - } - } + ForEach.mesh(gltf, function(mesh) { + ForEach.meshPrimitive(mesh, function(primitive) { + var attributes = primitive.attributes; + var indexAccessorId = primitive.indices; + if (defined(indexAccessorId)) { + var indexAccessor = accessors[indexAccessorId]; + tableIndex = accessorTableMapping[indexAccessorId]; + if (!defined(tableIndex)) { + // There is no mapping for this index accessor, check if there is an existing mapping for any of the attributes + var mappedTableIndex; + var mappedTableIndices = {}; + for (attribute in attributes) { + if (attributes.hasOwnProperty(attribute)) { + attributeAccessorId = attributes[attribute]; + if (defined(accessorTableMapping[attributeAccessorId])) { + // There is already a mapping for one of the attributes, join that one + mappedTableIndices[accessorTableMapping[attributeAccessorId]] = true; + } + } + } + var mappedTableIndexArray = Object.keys(mappedTableIndices); + var mappedTableIndexArrayLength = mappedTableIndexArray.length; + if (mappedTableIndexArrayLength > 0) { + mappedTableIndex = parseInt(mappedTableIndexArray[0]); + for (var j = 1; j < mappedTableIndexArrayLength; j++) { + // Multiple attributes mapped to different tables, merge them + var indexB = mappedTableIndexArray[j]; + mergeUsageTables(tables, accessorTableMapping, mappedTableIndex, indexB); + } + } + if (!defined(mappedTableIndex)) { + // There are no existing linkages to other accessors, make a new table entry + table = { + indexAccessors : {}, + attributeAccessors : {}, + usage : [] + }; + tables.push(table); + mappedTableIndex = tables.length - 1; + } else { + // Join an existing mapping + table = tables[mappedTableIndex]; + } + table.usage = markUsageForIndexAccessor(gltf, indexAccessor, table.usage); + table.indexAccessors[indexAccessorId] = true; + for (attribute in attributes) { + if (attributes.hasOwnProperty(attribute)) { + attributeAccessorId = attributes[attribute]; + table.attributeAccessors[attributeAccessorId] = true; + accessorTableMapping[attributeAccessorId] = mappedTableIndex; + } + } + accessorTableMapping[indexAccessorId] = mappedTableIndex; + mappedTableIndex = undefined; + } else { + // This index accessor has already been done + table = tables[tableIndex]; + for (attribute in attributes) { + if (attributes.hasOwnProperty(attribute)) { + attributeAccessorId = attributes[attribute]; + // Make sure the attribute accessors haven't been assigned somewhere else + var attributeTableIndex = accessorTableMapping[attributeAccessorId]; + if (defined(attributeTableIndex) && attributeTableIndex !== tableIndex) { + // Merge them into this one if they have been + mergeUsageTables(tables, accessorTableMapping, tableIndex, attributeTableIndex); + } + table.attributeAccessors[attributeAccessorId] = true; + accessorTableMapping[attributeAccessorId] = tableIndex; + } + } + } + } + }) ; + }); var finalTables = []; var tablesLength = tables.length; for (i = 0; i < tablesLength; i++) { diff --git a/lib/encodeImages.js b/lib/encodeImages.js index 9c0ab329..f39aa9bc 100644 --- a/lib/encodeImages.js +++ b/lib/encodeImages.js @@ -1,6 +1,7 @@ 'use strict'; var Jimp = require('jimp'); var Promise = require('bluebird'); +var ForEach = require('./ForEach'); Jimp.prototype.getBufferAsync = Promise.promisify(Jimp.prototype.getBuffer); @@ -18,33 +19,29 @@ module.exports = encodeImages; * @see loadGltfUris */ function encodeImages(gltf) { - var images = gltf.images; var promises = []; - for (var imageId in images) { - if (images.hasOwnProperty(imageId)) { - var image = images[imageId]; - var pipelineExtras = image.extras._pipeline; - if (pipelineExtras.imageChanged) { - // re-encode the jimp image here to a buffer that can be put in source - var mime; - switch (pipelineExtras.extension) { - case '.png': - mime = Jimp.MIME_PNG; - break; - case '.jpeg': - mime = Jimp.MIME_JPEG; - break; - case '.jpg': - mime = Jimp.MIME_JPEG; - break; - case '.bmp': - mime = Jimp.MIME_BMP; - break; - } - promises.push(loadImageSource(pipelineExtras, mime)); + ForEach.image(gltf, function(image) { + var pipelineExtras = image.extras._pipeline; + if (pipelineExtras.imageChanged) { + // re-encode the jimp image here to a buffer that can be put in source + var mime; + switch (pipelineExtras.extension) { + case '.png': + mime = Jimp.MIME_PNG; + break; + case '.jpeg': + mime = Jimp.MIME_JPEG; + break; + case '.jpg': + mime = Jimp.MIME_JPEG; + break; + case '.bmp': + mime = Jimp.MIME_BMP; + break; } + promises.push(loadImageSource(pipelineExtras, mime)); } - } + }); return Promise.all(promises) .then(function() { return gltf; diff --git a/lib/findAccessorMinMax.js b/lib/findAccessorMinMax.js index 1da6e2db..e13a12d2 100644 --- a/lib/findAccessorMinMax.js +++ b/lib/findAccessorMinMax.js @@ -36,7 +36,7 @@ function findAccessorMinMax(gltf, accessor) { var source = buffer.extras._pipeline.source; var count = accessor.count; - var byteStride = getAccessorByteStride(accessor); + var byteStride = getAccessorByteStride(gltf, accessor); var byteOffset = accessor.byteOffset + bufferView.byteOffset; var componentType = accessor.componentType; diff --git a/lib/findUsedIds.js b/lib/findUsedIds.js deleted file mode 100644 index e842b363..00000000 --- a/lib/findUsedIds.js +++ /dev/null @@ -1,27 +0,0 @@ -'use strict'; -var Cesium = require('cesium'); -var defined = Cesium.defined; - -module.exports = findUsedIds; - -/** - * @private - */ -function findUsedIds(gltf, name, idName) { - var usedIds = {}; - var objects = gltf[name]; - - // Build hash of used ids by iterating through objects - if (defined(objects)) { - for (var objectId in objects) { - if (objects.hasOwnProperty(objectId)) { - var id = (objects[objectId])[idName]; - if (defined(id)) { - usedIds[id] = true; - } - } - } - } - - return usedIds; -} \ No newline at end of file diff --git a/lib/generateModelMaterialsCommon.js b/lib/generateModelMaterialsCommon.js index cb2f091e..51cd0b39 100644 --- a/lib/generateModelMaterialsCommon.js +++ b/lib/generateModelMaterialsCommon.js @@ -1,6 +1,6 @@ 'use strict'; var Cesium = require('cesium'); -var addExtensionsUsed = require('./addExtensionsUsed'); +var addExtensionsRequired = require('./addExtensionsRequired'); var defaultValue = Cesium.defaultValue; var defined = Cesium.defined; @@ -24,7 +24,7 @@ function generateModelMaterialsCommon(gltf, kmcOptions) { kmcOptions = defaultValue(kmcOptions, {}); kmcOptions.doubleSided = defaultValue(kmcOptions.doubleSided, false); kmcOptions.technique = defaultValue(kmcOptions.technique, 'PHONG'); - addExtensionsUsed(gltf, 'KHR_materials_common'); + addExtensionsRequired(gltf, 'KHR_materials_common'); var materialsCommon; var materials = gltf.materials; var nodes = gltf.nodes; diff --git a/lib/generateNormals.js b/lib/generateNormals.js index 0cb79079..3217aab0 100644 --- a/lib/generateNormals.js +++ b/lib/generateNormals.js @@ -10,11 +10,11 @@ var defined = Cesium.defined; var RemoveUnusedProperties = require('./RemoveUnusedProperties'); var addExtensionsUsed = require('./addExtensionsUsed'); +var addToArray = require('./addToArray'); var cesiumGeometryToGltfPrimitive = require('./cesiumGeometryToGltfPrimitive'); var createAccessor = require('./createAccessor'); var gltfPrimitiveToCesiumGeometry = require('./gltfPrimitiveToCesiumGeometry'); var getPrimitiveAttributeSemantics = require('./getPrimitiveAttributeSemantics'); -var getUniqueId = require('./getUniqueId'); var mergeBuffers = require('./mergeBuffers'); var processModelMaterialsCommon = require('./processModelMaterialsCommon'); var packArray = require('./packArray'); @@ -191,7 +191,6 @@ function generateMaterial(gltf, primitive, generatedMaterials) { } if (!defined(normalParameter)) { addExtensionsUsed(gltf, 'KHR_materials_common'); - generatedMaterialId = getUniqueId(gltf, materialId + '-common'); var values = clone(material.values); values.doubleSided = true; @@ -204,7 +203,7 @@ function generateMaterial(gltf, primitive, generatedMaterials) { values.transparent = true; } - materials[generatedMaterialId] = { + var generatedMaterial = { extensions : { KHR_materials_common : { technique : 'BLINN', @@ -215,6 +214,8 @@ function generateMaterial(gltf, primitive, generatedMaterials) { } } }; + + generatedMaterialId = addToArray(materials, generatedMaterial); primitive.material = generatedMaterialId; generatedMaterials[materialId] = generatedMaterialId; } diff --git a/lib/generateTangentsBitangents.js b/lib/generateTangentsBitangents.js index 3d6bd385..675cb878 100644 --- a/lib/generateTangentsBitangents.js +++ b/lib/generateTangentsBitangents.js @@ -1,20 +1,19 @@ 'use strict'; var Cesium = require('cesium'); +var ForEach = require('./ForEach'); var gltfPrimitiveToCesiumGeometry = require('./gltfPrimitiveToCesiumGeometry'); var cesiumGeometryToGltfPrimitive = require('./cesiumGeometryToGltfPrimitive'); -var PrimitiveHelpers = require('./PrimitiveHelpers'); var defined = Cesium.defined; var WebGLConstants = Cesium.WebGLConstants; var GeometryPipeline = Cesium.GeometryPipeline; -var getAllPrimitives = PrimitiveHelpers.getAllPrimitives; module.exports = generateTangentsBitangents; /** * Generates tangents and bitangents for primitives if they do not exist. * - * The glTF asset must be initialized for the pipeline. It mus already have normals. + * The glTF asset must be initialized for the pipeline. It must already have normals. * * @param {Object} gltf A javascript object containing a glTF asset. * @returns {Object} The glTF asset with generated tangents and bitangents. @@ -23,27 +22,27 @@ module.exports = generateTangentsBitangents; * @see loadGltfUris */ function generateTangentsBitangents(gltf) { - var primitives = getAllPrimitives(gltf); - var primitivesLength = primitives.length; - for (var i = 0; i < primitivesLength; i++) { - var primitive = primitives[i]; - var positionAccessorId = primitive.attributes.POSITION; - var normalAccessorId = primitive.attributes.NORMAL; - var texcoordAccessorId = primitive.attributes.TEXCOORD_0; - var bitangentAccessorId = primitive.attributes.BITANGENT; - var tangentAccessorId = primitive.attributes.TANGENT; - var indicesAccessorId = primitive.indices; + ForEach.mesh(gltf, function(mesh) { + ForEach.meshPrimitive(mesh, function(primitive) { + var positionAccessorId = primitive.attributes.POSITION; + var normalAccessorId = primitive.attributes.NORMAL; + var texcoordAccessorId = primitive.attributes.TEXCOORD_0; + var bitangentAccessorId = primitive.attributes.BITANGENT; + var tangentAccessorId = primitive.attributes.TANGENT; + var indicesAccessorId = primitive.indices; - if (primitive.mode === WebGLConstants.TRIANGLES && defined(indicesAccessorId) && - defined(positionAccessorId) && - defined(normalAccessorId) && - defined(texcoordAccessorId) && - !defined(bitangentAccessorId) && - !defined(tangentAccessorId) ) { - var geometry = gltfPrimitiveToCesiumGeometry(gltf, primitive); - GeometryPipeline.computeTangentAndBitangent(geometry); - cesiumGeometryToGltfPrimitive(gltf, primitive, geometry); - } - } + if (primitive.mode === WebGLConstants.TRIANGLES && + defined(indicesAccessorId) && + defined(positionAccessorId) && + defined(normalAccessorId) && + defined(texcoordAccessorId) && + !defined(bitangentAccessorId) && + !defined(tangentAccessorId)) { + var geometry = gltfPrimitiveToCesiumGeometry(gltf, primitive); + GeometryPipeline.computeTangentAndBitangent(geometry); + cesiumGeometryToGltfPrimitive(gltf, primitive, geometry); + } + }); + }); return gltf; -} +} \ No newline at end of file diff --git a/lib/getAccessorByteStride.js b/lib/getAccessorByteStride.js index 68003eef..f691e5d3 100644 --- a/lib/getAccessorByteStride.js +++ b/lib/getAccessorByteStride.js @@ -1,7 +1,10 @@ 'use strict'; +var Cesium = require('cesium'); var byteLengthForComponentType = require('./byteLengthForComponentType'); var numberOfComponentsForType = require('./numberOfComponentsForType'); +var defined = Cesium.defined; + module.exports = getAccessorByteStride; /** @@ -11,9 +14,10 @@ module.exports = getAccessorByteStride; * @param {Object} accessor The accessor. * @returns {Number} The byte stride of the accessor. */ -function getAccessorByteStride(accessor) { - if (accessor.byteStride > 0) { - return accessor.byteStride; +function getAccessorByteStride(gltf, accessor) { + var bufferView = gltf.bufferViews[accessor.bufferView]; + if (defined(bufferView.byteStride) && bufferView.byteStride > 0) { + return bufferView.byteStride; } return byteLengthForComponentType(accessor.componentType) * numberOfComponentsForType(accessor.type); } \ No newline at end of file diff --git a/lib/getAccessorsForSemantic.js b/lib/getAccessorsForSemantic.js deleted file mode 100644 index faf390b2..00000000 --- a/lib/getAccessorsForSemantic.js +++ /dev/null @@ -1,40 +0,0 @@ -'use strict'; -var Promise = require('bluebird'); - -module.exports = getAccessorsForSemantic; - -/** - * Iterates over the provided glTF meshes and calls the callback when a primitive is - * found that uses a particular semantic. - * - * @param {Object} gltf The glTF hierarchy - * @param {String} semantic Matches against the beginning of the semantic string for the primitives' attributes - * @param {Function} callback This gets called when a match is found with the arguments (gltf, primitive, accessorId, matchedSemantic) - * - * @returns {Promise} A promise that resolves when all primitives have been searched. - * @private - */ -function getAccessorsForSemantic(gltf, semantic, callback) { - return new Promise(function(resolve) { - var meshes = gltf.meshes; - for (var meshId in meshes) { - if (meshes.hasOwnProperty(meshId)) { - var mesh = meshes[meshId]; - var primitives = mesh.primitives; - var primitivesLength = primitives.length; - for (var i = 0; i < primitivesLength; i++) { - var primitive = primitives[i]; - var primitiveAttributes = primitive.attributes; - for (var attributeSemantic in primitiveAttributes) { - if (primitiveAttributes.hasOwnProperty(attributeSemantic)) { - if (attributeSemantic.indexOf(semantic) === 0) { - callback(gltf, primitive, primitiveAttributes[attributeSemantic], attributeSemantic); - } - } - } - } - } - } - resolve(); - }); -} \ No newline at end of file diff --git a/lib/getBinaryGltf.js b/lib/getBinaryGltf.js index 5f248961..449cc94b 100644 --- a/lib/getBinaryGltf.js +++ b/lib/getBinaryGltf.js @@ -1,66 +1,39 @@ 'use strict'; var Cesium = require('cesium'); var mime = require('mime'); -var sizeOf = require('image-size'); +var addToArray = require('./addToArray'); +var ForEach = require('./ForEach'); +var mergeBuffers = require('./mergeBuffers'); +var removePipelineExtras = require('./removePipelineExtras'); var defaultValue = Cesium.defaultValue; var defined = Cesium.defined; -var addExtensionsUsed = require('./addExtensionsUsed'); -var mergeBuffers = require('./mergeBuffers'); -var removePipelineExtras = require('./removePipelineExtras'); +// .crn (Crunch) is not a supported mime type, so add it +mime.define({'image/crn': ['crn']}); module.exports = getBinaryGltf; -// Update object with KHR_binary_glTF properties and add to body and bufferViews -function updateBinaryObject(gltf, objects, name, pipelineExtras, state) { - var bufferViews = gltf.bufferViews; - if (defined(objects)) { - for (var objectId in objects) { - if (objects.hasOwnProperty(objectId)) { - var object = objects[objectId]; - - // Update object with binary format - object.uri = 'data:,'; - object.extensions = defaultValue(object.extensions, {}); - object.extensions.KHR_binary_glTF = defaultValue(object.extensions.KHR_binary_glTF, {}); - var KHR_binary_glTF = object.extensions.KHR_binary_glTF; - - // Create a bufferView based on the byte length and current offset - var bufferViewKeys = Object.keys(bufferViews); - while (bufferViewKeys.indexOf('binary_bufferView' + state.currentBinaryView) !== -1) { - state.currentBinaryView++; - } - - var objectSource = Buffer.from(object.extras._pipeline.source); - var bufferViewId = 'binary_bufferView' + state.currentBinaryView; - KHR_binary_glTF.bufferView = bufferViewId; //Create bufferview - bufferViews[bufferViewId] = { - buffer : 'binary_glTF', - byteLength : objectSource.length, - byteOffset : state.offset - }; - state.offset += objectSource.length; - - // Append the object source to the binary body - pipelineExtras.source = Buffer.concat([pipelineExtras.source, objectSource]); - - // Add additional properties for images - if (name === 'images') { - // .crn (Crunch) is not a supported mime type, so add it - mime.define({'image/crn' : ['crn']}); - var mimeType = mime.lookup(object.extras._pipeline.extension); - KHR_binary_glTF.mimeType = mimeType; - - if (mimeType !== 'image/ktx' && mimeType !== 'image/crn') { - var dimensions = sizeOf(object.extras._pipeline.source); - KHR_binary_glTF.width = dimensions.width; - KHR_binary_glTF.height = dimensions.height; - } - } - } +function updateBinaryObject(gltf, objects, hasMimeType) { + hasMimeType = defaultValue(hasMimeType, false); + var buffer = gltf.buffers[0]; + var bufferPipelineExtras = buffer.extras._pipeline; + ForEach.object(objects, function(object) { + var pipelineExtras = object.extras._pipeline; + var source = pipelineExtras.source; + var bufferView = { + buffer: 0, + byteLength: source.length, + byteOffset: buffer.byteLength + }; + if (hasMimeType) { + object.mimeType = mime.lookup(pipelineExtras.extension); } - } + buffer.byteLength += source.length; + bufferPipelineExtras.source = Buffer.concat([bufferPipelineExtras.source, source]); + var bufferViewId = addToArray(gltf.bufferViews, bufferView); + object.bufferView = bufferViewId; + }); } /** @@ -69,82 +42,96 @@ function updateBinaryObject(gltf, objects, name, pipelineExtras, state) { * The glTF asset must be initialized for the pipeline. * * @param {Object} gltf A javascript object containing a glTF asset. - * @param {Boolean} embed Embed shaders into the binary. - * @param {Boolean} embedImage Embed images into the binary - * @returns {{glb: Buffer, header: Buffer, scene: Buffer, body: Buffer}} glb holds the whole buffer, each piece is also available via the returned object. + * @param {Object} options Options specifying custom behavior. + * @param {Boolean} options.embed Embed shaders into the binary. + * @param {Boolean} options.embedImage Embed images into the binary + * @returns {Buffer} A buffer containing the binary glTF blob * * @see addPipelineExtras * @see loadGltfUris */ -function getBinaryGltf(gltf, embed, embedImage) { - addExtensionsUsed(gltf, 'KHR_binary_glTF'); +function getBinaryGltf(gltf, options) { + options = defaultValue(options, {}); + options.embed = defaultValue(options.embed, true); + options.embedImage = defaultValue(options.embedImage, true); // Create the special binary buffer from the existing buffers - gltf.bufferViews = defaultValue(gltf.bufferViews, {}); - gltf.buffers = defaultValue(gltf.buffers, {}); - mergeBuffers(gltf, 'binary_glTF'); - + gltf.bufferViews = defaultValue(gltf.bufferViews, []); + gltf.buffers = defaultValue(gltf.buffers, []); + mergeBuffers(gltf); var buffers = gltf.buffers; - var currentOffset = buffers.binary_glTF.byteLength; - var pipelineExtras = buffers.binary_glTF.extras._pipeline; - var state = { - offset: currentOffset, - currentBinaryView: 0 - }; - - if (embed) { - updateBinaryObject(gltf, gltf.shaders, 'shaders', pipelineExtras, state); - } - if (embedImage) { - updateBinaryObject(gltf, gltf.images, 'images', pipelineExtras, state); - } - - // Update binary with compressed textures - if (embedImage) { - var images = gltf.images; - for (var imageId in images) { - if (images.hasOwnProperty(imageId)) { - var image = images[imageId]; - if (defined(image.extras) && defined(image.extras.compressedImage3DTiles)) { - var compressedImages = image.extras.compressedImage3DTiles; - updateBinaryObject(gltf, compressedImages, 'images', pipelineExtras, state); + var buffer; + if (buffers.length > 0) { + buffer = buffers[0]; + } else { + buffer = { + byteLength: 0, + extras: { + _pipeline: { + source: new Buffer([]), + extension: '.bin' } } - } + }; + buffers.push(buffer); } - var body = buffers.binary_glTF.extras._pipeline.source; - buffers.binary_glTF.byteLength = state.offset; + if (options.embed) { + updateBinaryObject(gltf, gltf.shaders); + } + if (options.embedImage) { + updateBinaryObject(gltf, gltf.images, true); + ForEach.image(function(gltf, image) { + if (defined(image.extras) && defined(image.extras.compressedImage3DTiles)) { + var compressedImages = image.extras.compressedImage3DTiles; + updateBinaryObject(gltf, compressedImages, true); + } + }); + } + var binaryBuffer = buffer.extras._pipeline.source; + if (binaryBuffer.length === 0) { + delete gltf.buffers; + } // Remove extras objects before writing removePipelineExtras(gltf); - // Create padded binary scene buffer and calculate total length - var sceneString = JSON.stringify(gltf); - var sceneBuffer = Buffer.from(sceneString); - var sceneLength = sceneBuffer.length; - var paddingLength = 4 - (sceneLength % 4); // pad out to 4 bytes as per glb specification - sceneLength += paddingLength; - var paddingBuffer = Buffer.alloc(paddingLength, ' '); - var scene = Buffer.concat([sceneBuffer, paddingBuffer]); - - var bodyOffset = 20 + sceneLength; - var glbLength = bodyOffset + body.length; - - // Write binary glTF header (magic, version, length, sceneLength, sceneFormat) - var header = Buffer.alloc(20); - header.write('glTF', 0); - header.writeUInt32LE(1, 4); - header.writeUInt32LE(glbLength, 8); - header.writeUInt32LE(sceneLength, 12); - header.writeUInt32LE(0, 16); - - // Create overall buffer - var glb = Buffer.concat([header, scene, body], glbLength); - - return { - glb : glb, - header : header, - scene : scene, - body : body - }; + // Create padded binary scene string + var jsonString = JSON.stringify(gltf); + while (jsonString.length % 4 !== 0) { + jsonString += ' '; + } + var jsonBuffer = Buffer.from(jsonString); + + // Allocate buffer (Global header) + (JSON chunk header) + (JSON chunk) + (Binary chunk header) + (Binary chunk) + var glbLength = 12 + 8 + jsonBuffer.length + 8 + binaryBuffer.length; + var glb = new Buffer(glbLength); + + // Write binary glTF header (magic, version, length) + var byteOffset = 0; + glb.writeUInt32LE(0x46546C67, byteOffset); + byteOffset += 4; + glb.writeUInt32LE(2, byteOffset); + byteOffset += 4; + glb.writeUInt32LE(glbLength, byteOffset); + byteOffset += 4; + + // Write JSON Chunk header (length, type) + glb.writeUInt32LE(jsonBuffer.length, byteOffset); + byteOffset += 4; + glb.writeUInt32LE(0x4E4F534A, byteOffset); // JSON + byteOffset += 4; + + // Write JSON Chunk + jsonBuffer.copy(glb, byteOffset); + byteOffset += jsonBuffer.length; + + // Write Binary Chunk header (length, type) + glb.writeUInt32LE(binaryBuffer.length, byteOffset); + byteOffset += 4; + glb.writeUInt32LE(0x004E4942, byteOffset); // BIN + byteOffset += 4; + + // Write Binary Chunk + binaryBuffer.copy(glb, byteOffset); + return glb; } \ No newline at end of file diff --git a/lib/getStatistics.js b/lib/getStatistics.js index f25a5153..bb68c1a7 100644 --- a/lib/getStatistics.js +++ b/lib/getStatistics.js @@ -1,8 +1,8 @@ 'use strict'; var Cesium = require('cesium'); +var ForEach = require('./ForEach'); var defined = Cesium.defined; -var defaultValue = Cesium.defaultValue; var DeveloperError = Cesium.DeveloperError; module.exports = getStatistics; @@ -43,8 +43,7 @@ function Statistics() { * @returns {String} A string describing the statistics for the glTF asset. */ Statistics.prototype.toString = function() { - var output = - 'Total size of all buffers: ' + this.buffersSizeInBytes + ' bytes' + + return 'Total size of all buffers: ' + this.buffersSizeInBytes + ' bytes' + '\nImages: ' + this.numberOfImages + '\nDraw calls: ' + this.numberOfDrawCalls + '\nRendered primitives (e.g., triangles): ' + this.numberOfRenderedPrimitives + @@ -53,8 +52,6 @@ Statistics.prototype.toString = function() { '\nMaterials: ' + this.numberOfMaterials + '\nAnimations: ' + this.numberOfAnimations + '\nExternal requests (not data uris): ' + this.numberOfExternalRequests; - - return output; }; function isDataUri(uri) { @@ -69,38 +66,30 @@ function isDataUri(uri) { function getAllPrimitives(gltf) { var primitives = []; - var meshes = gltf.meshes; - for (var meshId in meshes) { - if (meshes.hasOwnProperty(meshId)) { - var mesh = meshes[meshId]; - primitives = primitives.concat(mesh.primitives); - } - } + ForEach.mesh(gltf, function(mesh) { + ForEach.meshPrimitive(mesh, function(primitive) { + primitives.push(primitive); + }); + }); return primitives; } -function getBuffersSize(buffers) { +function getBuffersSize(gltf) { var size = 0; - for (var id in buffers) { - if (buffers.hasOwnProperty(id)) { - size += buffers[id].byteLength; - } - } + ForEach.buffer(gltf, function(buffer) { + size += buffer.byteLength; + }); return size; } function getNumberOfExternalProperties(property) { - var id; - var uri; var count = 0; - for (id in property) { - if (property.hasOwnProperty(id)) { - uri = property[id].uri; - if (defined(uri) && !isDataUri(uri)) { - ++count; - } + ForEach.object(property, function(object) { + var uri = object.uri; + if (defined(uri) && !isDataUri(uri)) { + count++; } - } + }); return count; } @@ -114,10 +103,6 @@ function getNumberOfExternalRequests(gltf) { return count; } -function getNumberOfProperties(object) { - return Object.keys(object).length; -} - function getNumberOfRenderedPrimitives(gltf, primitives) { var numberOfRenderedPrimitives = 0; @@ -157,35 +142,19 @@ function getDrawCallStatisticsForNode(gltf, nodeId) { var numberOfDrawCalls = 0; var numberOfRenderedPrimitives = 0; - var nodes = gltf.nodes; var meshes = gltf.meshes; - var nodeStack = []; - - var n = nodes[nodeId]; - nodeStack.push(n); - - while (nodeStack.length > 0) { - n = nodeStack.pop(); - - var nodeMeshes = defaultValue(n.meshes, defined(n.instanceSkin) ? n.instanceSkin.meshes : undefined); - if (defined(nodeMeshes)) { - var meshesLength = nodeMeshes.length; - for (var j = 0; j < meshesLength; ++j) { - var primitives = meshes[nodeMeshes[j]].primitives; - + ForEach.nodeInTree(gltf, [nodeId], function(node) { + var meshId = node.mesh; + var mesh = meshes[meshId]; + if (defined(mesh)) { + var primitives = mesh.primitives; + if (defined(primitives)) { numberOfDrawCalls += primitives.length; numberOfRenderedPrimitives += getNumberOfRenderedPrimitives(gltf, primitives); } } - - var children = n.children; - var childrenLength = children.length; - for (var k = 0; k < childrenLength; ++k) { - var child = nodes[children[k]]; - nodeStack.push(child); - } - } + }); return { numberOfDrawCalls : numberOfDrawCalls, @@ -235,15 +204,15 @@ function getStatistics(gltf, nodeId) { var drawStats = getDrawCallStatistics(gltf); - statistics.buffersSizeInBytes = getBuffersSize(gltf.buffers); - statistics.numberOfImages = getNumberOfProperties(gltf.images); + statistics.buffersSizeInBytes = getBuffersSize(gltf); + statistics.numberOfImages = gltf.images.length; statistics.numberOfExternalRequests = getNumberOfExternalRequests(gltf); statistics.numberOfDrawCalls = drawStats.numberOfDrawCalls; statistics.numberOfRenderedPrimitives = drawStats.numberOfRenderedPrimitives; - statistics.numberOfNodes = getNumberOfProperties(gltf.nodes); - statistics.numberOfMeshes = getNumberOfProperties(gltf.meshes); - statistics.numberOfMaterials = getNumberOfProperties(gltf.materials); - statistics.numberOfAnimations = getNumberOfProperties(gltf.animations); + statistics.numberOfNodes = gltf.nodes.length; + statistics.numberOfMeshes = gltf.meshes.length; + statistics.numberOfMaterials = gltf.materials.length; + statistics.numberOfAnimations = gltf.animations.length; return statistics; } diff --git a/lib/getUniqueId.js b/lib/getUniqueId.js deleted file mode 100644 index 3ff93adf..00000000 --- a/lib/getUniqueId.js +++ /dev/null @@ -1,29 +0,0 @@ -'use strict'; -var Cesium = require('cesium'); -var defined = Cesium.defined; - -module.exports = getUniqueId; - -/** - * Given a prefix for a new ID, checks the glTF asset for matching prefixes in top-level objects with IDs and returns a unique ID. - * - * @param {Object} gltf A javascript object containing a glTF asset. - * @param {String} prefix The string to try to use as the id. - * @returns {String} A unique id beginning with prefix. - */ -function getUniqueId(gltf, prefix) { - var id = prefix; - var appendIndex = 0; - for (var topLevelGroupId in gltf) { - if (gltf.hasOwnProperty(topLevelGroupId)) { - var topLevelGroup = gltf[topLevelGroupId]; - var match = topLevelGroup[id]; - while (defined(match)) { - id = prefix + '_' + appendIndex; - match = topLevelGroup[id]; - appendIndex++; - } - } - } - return id; -} \ No newline at end of file diff --git a/lib/isTexture.js b/lib/isTexture.js new file mode 100644 index 00000000..064e4a08 --- /dev/null +++ b/lib/isTexture.js @@ -0,0 +1,17 @@ +'use strict'; +var Cesium = require('cesium'); + +var defined = Cesium.defined; + +module.exports = isTexture; + +var textureNames = { + ambient: true, + diffuse: true, + emission: true, + specular: true +}; + +function isTexture(name, value) { + return value.length === 1 && defined(textureNames[name]); +} \ No newline at end of file diff --git a/lib/loadGltfUris.js b/lib/loadGltfUris.js index f6447336..b4cb9ca0 100644 --- a/lib/loadGltfUris.js +++ b/lib/loadGltfUris.js @@ -5,13 +5,13 @@ var Promise = require('bluebird'); var dataUriToBuffer = require('data-uri-to-buffer'); var fs = require('fs'); var path = require('path'); +var ForEach = require('./ForEach'); +var isDataUri = require('./isDataUri'); var defined = Cesium.defined; var defaultValue = Cesium.defaultValue; var DeveloperError = Cesium.DeveloperError; -var isDataUri = require('./isDataUri'); - var fsReadFile = Promise.promisify(fs.readFile); module.exports = loadGltfUris; @@ -19,98 +19,164 @@ module.exports = loadGltfUris; /** * Load uris in the glTF into buffers. * The buffer data is placed into extras._pipeline.source for the corresponding object. - * glTF must be initialized for the pipeline. * * @param {Object} gltf A javascript object containing a glTF asset. - * @param {Object} options Options for loading uris. - * @param {String} options.basePath The path to look in when loading external files. + * @param {Object} [options] Options for loading uris. + * @param {String} [options.basePath] The path to look in when loading external files. * @returns {Promise} A promise that resolves to the glTF asset when all uris are loaded. - * - * @see addPipelineExtras */ function loadGltfUris(gltf, options) { options = defaultValue(options, {}); - var basePath = options.basePath; - var loadURIs = [ - loadURI(gltf.buffers, 'buffers', basePath), - loadURI(gltf.images, 'images', basePath), - loadURI(gltf.shaders, 'shaders', basePath) - ]; - - // Read sources for compressed textures + var basePath = defaultValue(options.basePath, ''); + // Buffers need to be loaded first because images and shader may resolve to bufferViews + var buffers = gltf.buffers; + // glTF 1.0 compatibility + if (defined(buffers) && !Array.isArray(buffers)) { + buffers = Object.keys(buffers).map(function(key) { + return buffers[key]; + }); + } var images = gltf.images; - for (var imageId in images) { - if (images.hasOwnProperty(imageId)) { - var image = images[imageId]; - if (defined(image.extras) && defined(image.extras.compressedImage3DTiles)) { - var compressedImages = image.extras.compressedImage3DTiles; - loadURIs.push(loadURI(compressedImages, 'images', basePath)); - } - } + if (defined(images) && !Array.isArray(images)){ + images = Object.keys(images).map(function(key) { + return images[key]; + }); } - - return Promise.all(loadURIs) + var shaders = gltf.shaders; + if (defined(shaders) && !Array.isArray(shaders)) { + shaders = Object.keys(shaders).map(function(key) { + return shaders[key]; + }); + } + return loadURIs(gltf, buffers, 'buffers', basePath) .then(function() { - gltf.extras._pipeline.jimpScratch = new Jimp(1, 1); - return gltf; + var loadPromises = [ + loadURIs(gltf, images, 'images', basePath), + loadURIs(gltf, shaders, 'shaders', basePath) + ]; + + // Read sources for compressed textures + ForEach.image(function (image) { + if (defined(image.extras) && defined(image.extras.compressedImage3DTiles)) { + var compressedImages = image.extras.compressedImage3DTiles; + loadPromises.push(loadURIs(gltf, compressedImages, 'images', basePath)); + } + }); + + return Promise.all(loadPromises) + .then(function () { + gltf.extras = defaultValue(gltf.extras, {}); + gltf.extras._pipeline = defaultValue(gltf.extras._pipeline, { + deleteExtras: true + }); + gltf.extras._pipeline.jimpScratch = new Jimp(1, 1); + return gltf; + }); }); } -function loadURI(objects, name, basePath) { - //Iterate through each object and get a promise to load its uri - var promises = []; +function loadURIs(gltf, objects, name, basePath) { if (defined(objects)) { - for (var id in objects) { - if (objects.hasOwnProperty(id)) { - var object = objects[id]; - object.extras = defaultValue(object.extras, {}); - object.extras._pipeline = defaultValue(object.extras._pipeline, {}); - if (defined(object.extras._pipeline.source) && !defined(object.uri)) { - object.uri = 'data:,'; - } - var uri = object.uri; - //Load the uri into the extras object based on the uri type - if (isDataUri(uri)) { - if (!defined(object.extras._pipeline.source)) { - var buffer = dataUriToBuffer(uri); - if (name === 'shaders') { - object.extras._pipeline.source = buffer.toString(); - } else { - object.extras._pipeline.source = buffer; - } - } - if (!defined(object.extras._pipeline.extension)) { - switch (name) { - case 'buffers': - object.extras._pipeline.extension = '.bin'; - break; - case 'images': - object.extras._pipeline.extension = getImageDataUriFormat(uri); - break; - case 'shaders': - object.extras._pipeline.extension = '.glsl'; - break; - } - } - if (name === 'images') { - promises.push(generateJimpImage(object)); - } - } else { - var uriPath = uri; - if (!path.isAbsolute(uriPath)) { - if (!defined(basePath)) { - throw new DeveloperError('glTF model references external files but no basePath is supplied'); - } - uriPath = path.join(basePath, uriPath); - } - promises.push(readFromFile(object, name, uriPath)); - } + return Promise.each(objects, function (object) { + return loadURI(gltf, object, name, basePath); + }); + } + return Promise.resolve(); +} + +function loadURI(gltf, object, name, basePath) { + var promises = []; + object.extras = defaultValue(object.extras, {}); + object.extras._pipeline = defaultValue(object.extras._pipeline, {}); + if (defined(object.extras._pipeline.source) && !defined(object.uri)) { + object.uri = 'data:,'; + } + var uri = object.uri; + //Load the uri into the extras object based on the uri type + var bufferViews = gltf.bufferViews; + var buffers = gltf.buffers; + if (defined(object.bufferView)) { + var bufferView = bufferViews[object.bufferView]; + var bufferId = bufferView.buffer; + var buffer = buffers[bufferId]; + var source = buffer.extras._pipeline.source; + object.extras._pipeline.source = source.slice(bufferView.byteOffset, bufferView.byteOffset + bufferView.byteLength); + if (!defined(object.extras._pipeline.extension)) { + if (name === 'images') { + object.extras._pipeline.extension = getBinaryImageFormat(object.extras._pipeline.source.slice(0, 2)); + } + } + } else if (isDataUri(uri)) { + if (!defined(object.extras._pipeline.source)) { + var dataBuffer = dataUriToBuffer(uri); + if (name === 'shaders') { + object.extras._pipeline.source = dataBuffer.toString(); + } else { + object.extras._pipeline.source = dataBuffer; + } + } + if (!defined(object.extras._pipeline.extension)) { + switch (name) { + case 'buffers': + object.extras._pipeline.extension = '.bin'; + break; + case 'images': + object.extras._pipeline.extension = getImageDataUriFormat(uri); + break; + case 'shaders': + object.extras._pipeline.extension = '.glsl'; + break; + } + } + if (name === 'images') { + promises.push(generateJimpImage(object)); + } + } else { + var uriPath = uri; + if (!path.isAbsolute(uriPath)) { + if (!defined(basePath)) { + throw new DeveloperError('glTF model references external files but no basePath is supplied'); } + uriPath = path.join(basePath, uriPath); } + promises.push(readFromFile(object, name, uriPath)); } return Promise.all(promises); } +function bufferEqual(first, second) { + for (var i = 0; i < first.length && i < second.length; i++) { + if (first[i] !== second[i]) { + return false; + } + } + return true; +} + +function getBinaryImageFormat(header) { + if (bufferEqual(header, new Uint8Array([66, 77]))) { //.bmp: 42 4D + return '.bmp'; + } + else if (bufferEqual(header, new Uint8Array([71, 73]))) { //.gif: 47 49 + return '.gif'; + } + else if (bufferEqual(header, new Uint8Array([255, 216]))) { //.jpg: ff d8 + return '.jpg'; + } + else if (bufferEqual(header, new Uint8Array([137, 80]))) { //.png: 89 50 + return '.png'; + } + else if (bufferEqual(header, new Uint8Array([171, 75]))) { //.ktx ab 4b + return '.ktx'; + } + else if (bufferEqual(header, new Uint8Array([72, 120]))) { //.crn 48 78 + return '.crn'; + } + else { + throw new DeveloperError('Binary image does not have valid header'); + } +} + /** * Return the extension of the data uri. * diff --git a/lib/mergeBuffers.js b/lib/mergeBuffers.js index 913278e7..4ffa0947 100644 --- a/lib/mergeBuffers.js +++ b/lib/mergeBuffers.js @@ -1,6 +1,6 @@ 'use strict'; var Cesium = require('cesium'); -var getUniqueId = require('./getUniqueId'); +var ForEach = require('./ForEach'); var defined = Cesium.defined; @@ -18,71 +18,53 @@ module.exports = mergeBuffers; * @see addPipelineExtras * @see loadGltfUris */ -function mergeBuffers(gltf, bufferId) { +function mergeBuffers(gltf) { var buffers = gltf.buffers; var bufferViews = gltf.bufferViews; var bufferViewsForBuffers = getBufferViewsForBuffers(gltf); - if (defined(buffers)) { + if (defined(buffers) && buffers.length > 0) { var buffersToMerge = []; var lengthSoFar = 0; - for (var gltfBufferId in buffers) { - if (buffers.hasOwnProperty(gltfBufferId)) { - //Add the buffer to the merged source - var buffer = buffers[gltfBufferId]; - if (!defined(bufferId)) { - bufferId = gltfBufferId; + ForEach.buffer(gltf, function(buffer, bufferId) { + var bufferViewIds = bufferViewsForBuffers[bufferId]; + for (var bufferViewId in bufferViewIds) { + if (bufferViewIds.hasOwnProperty(bufferViewId)) { + var bufferView = bufferViews[bufferViewId]; + bufferView.byteOffset += lengthSoFar; + bufferView.buffer = 0; } - var bufferViewIds = bufferViewsForBuffers[gltfBufferId]; - for (var bufferViewId in bufferViewIds) { - if (bufferViewIds.hasOwnProperty(bufferViewId)) { - var bufferView = bufferViews[bufferViewId]; - bufferView.byteOffset += lengthSoFar; - bufferView.buffer = bufferId; - } - } - buffersToMerge.push(buffer.extras._pipeline.source); - lengthSoFar += buffer.extras._pipeline.source.length; } - } + buffersToMerge.push(buffer.extras._pipeline.source); + lengthSoFar += buffer.extras._pipeline.source.length; + }); var source = Buffer.concat(buffersToMerge, lengthSoFar); - if (!defined(bufferId)) { - bufferId = getUniqueId(gltf, 'buffer'); - } - //Replace existing buffer with new merged buffer - gltf.buffers = {}; - gltf.buffers[bufferId] = { - "type": "arraybuffer", - "byteLength": source.length, - "uri": "data:,", - "extras": { - "_pipeline": { - "source": source, - "extension": ".bin" + gltf.buffers = [{ + byteLength: source.length, + extras: { + _pipeline: { + source: source, + extension: '.bin' } } - }; + }]; } return gltf; } function getBufferViewsForBuffers(gltf) { var bufferViewsForBuffers = {}; - var bufferViews = gltf.bufferViews; - for (var bufferViewId in bufferViews) { - if (bufferViews.hasOwnProperty(bufferViewId)) { - var bufferView = bufferViews[bufferViewId]; - var bufferId = bufferView.buffer; - var bufferViewsForBuffer = bufferViewsForBuffers[bufferId]; - if (!defined(bufferViewsForBuffer)) { - bufferViewsForBuffer = {}; - bufferViewsForBuffers[bufferId] = bufferViewsForBuffer; - } - bufferViewsForBuffer[bufferViewId] = true; + ForEach.bufferView(gltf, function(bufferView, bufferViewId) { + var bufferId = bufferView.buffer; + var bufferViewsForBuffer = bufferViewsForBuffers[bufferId]; + if (!defined(bufferViewsForBuffer)) { + bufferViewsForBuffer = {}; + bufferViewsForBuffers[bufferId] = bufferViewsForBuffer; } - } + bufferViewsForBuffer[bufferViewId] = true; + }); return bufferViewsForBuffers; } \ No newline at end of file diff --git a/lib/mergeDuplicateVertices.js b/lib/mergeDuplicateVertices.js index d86cc65c..96e971de 100644 --- a/lib/mergeDuplicateVertices.js +++ b/lib/mergeDuplicateVertices.js @@ -1,13 +1,13 @@ 'use strict'; var Cesium = require('cesium'); -var defined = Cesium.defined; - var byteLengthForComponentType = require('./byteLengthForComponentType'); +var ForEach = require('./ForEach'); var getAccessorByteStride = require('./getAccessorByteStride'); var numberOfComponentsForType = require('./numberOfComponentsForType'); var readBufferComponent = require('./readBufferComponent'); var writeBufferComponent = require('./writeBufferComponent'); -var removeUnusedVertices = require('./removeUnusedVertices'); + +var defined = Cesium.defined; module.exports = mergeDuplicateVertices; @@ -22,7 +22,6 @@ module.exports = mergeDuplicateVertices; * * @see addPipelineExtras * @see loadGltfUris - * @see removeUnusedVertices */ function mergeDuplicateVertices(gltf) { var meshes = gltf.meshes; @@ -35,7 +34,6 @@ function mergeDuplicateVertices(gltf) { } } mergeDuplicateVerticesFromMapping(gltf, indexAccessors); - removeUnusedVertices(gltf); return gltf; } @@ -51,7 +49,7 @@ function mergeDuplicateVerticesFromMapping(gltf, indexAccessors) { var bufferId = bufferView.buffer; var buffer = buffers[bufferId]; var source = buffer.extras._pipeline.source; - var byteStride = getAccessorByteStride(accessor); + var byteStride = getAccessorByteStride(gltf, accessor); var byteOffset = accessor.byteOffset + bufferView.byteOffset; var numIndices = accessor.count; var duplicateMapping = indexAccessors[indexAccessorId]; @@ -70,10 +68,7 @@ function findDuplicateVerticesInMesh(gltf, mesh, indexAccessors) { var accessors = gltf.accessors; var buffers = gltf.buffers; var bufferViews = gltf.bufferViews; - var primitives = mesh.primitives; - var primitivesLength = primitives.length; - for (var n = 0; n < primitivesLength; n++) { - var primitive = primitives[n]; + ForEach.meshPrimitive(mesh, function(primitive) { var indexAccessorId = primitive.indices; var attribute; if (defined(indexAccessorId)) { @@ -98,7 +93,7 @@ function findDuplicateVerticesInMesh(gltf, mesh, indexAccessors) { attributeBufferInfo[attribute] = { buffer: attributeBufferId, byteOffset: attributeBufferView.byteOffset + attributeAccessor.byteOffset, - byteStride: getAccessorByteStride(attributeAccessor), + byteStride: getAccessorByteStride(gltf, attributeAccessor), componentType: attributeAccessor.componentType, elementByteLength: byteLengthForComponentType(attributeAccessor.componentType) * numberOfComponentsForType(attributeAccessor.type), source: attributeBuffer.extras._pipeline.source @@ -109,7 +104,7 @@ function findDuplicateVerticesInMesh(gltf, mesh, indexAccessors) { var indexBufferView = bufferViews[indexBufferViewId]; var indexBufferId = indexBufferView.buffer; var indexBuffer = buffers[indexBufferId]; - var indexByteStride = getAccessorByteStride(indexAccessor); + var indexByteStride = getAccessorByteStride(gltf, indexAccessor); var indexComponentType = indexAccessor.componentType; var indexSource = indexBuffer.extras._pipeline.source; var indexByteOffset = indexAccessor.byteOffset + indexBufferView.byteOffset; @@ -150,6 +145,6 @@ function findDuplicateVerticesInMesh(gltf, mesh, indexAccessors) { } } } - } + }); } diff --git a/lib/octEncodeNormals.js b/lib/octEncodeNormals.js index 15eb6e68..57ba391d 100644 --- a/lib/octEncodeNormals.js +++ b/lib/octEncodeNormals.js @@ -1,5 +1,13 @@ 'use strict'; var Cesium = require('cesium'); +var byteLengthForComponentType = require('./byteLengthForComponentType'); +var findAccessorMinMax = require('./findAccessorMinMax'); +var ForEach = require('./ForEach'); +var getAccessorByteStride = require('./getAccessorByteStride'); +var numberOfComponentsForType = require('./numberOfComponentsForType'); +var readBufferComponent = require('./readBufferComponent'); +var writeBufferComponent = require('./writeBufferComponent'); + var AttributeCompression = Cesium.AttributeCompression; var Cartesian2 = Cesium.Cartesian2; var Cartesian3 = Cesium.Cartesian3; @@ -7,16 +15,6 @@ var DeveloperError = Cesium.DeveloperError; var ShaderSource = Cesium.ShaderSource; var WebGLConstants = Cesium.WebGLConstants; var defined = Cesium.defined; -var Promise = require('bluebird'); - -var byteLengthForComponentType = require('./byteLengthForComponentType'); -var findAccessorMinMax = require('./findAccessorMinMax'); -var getAccessorByteStride = require('./getAccessorByteStride'); -var getAccessorsForSemantic = require('./getAccessorsForSemantic'); -var numberOfComponentsForType = require('./numberOfComponentsForType'); -var readBufferComponent = require('./readBufferComponent'); -var writeBufferComponent = require('./writeBufferComponent'); -var uninterleaveAndPackBuffers = require('./uninterleaveAndPackBuffers'); module.exports = octEncodeNormals; @@ -27,79 +25,76 @@ module.exports = octEncodeNormals; * The glTF asset must be initialized for the pipeline. * * @param {Object} gltf A glTF hierarchy. - * @returns {Promise} A promise that resolves to the glTF asset with oct-encoded normals when the operation completes. + * @returns {Object} The glTF asset with oct-encoded normals when the operation completes. * * @see addPipelineExtras * @see loadGltfUris */ function octEncodeNormals(gltf) { - return new Promise(function(resolve) { - var accessors = gltf.accessors; - var bufferViews = gltf.bufferViews; - var buffers = gltf.buffers; - var materials = gltf.materials; - var techniques = gltf.techniques; - var patchedTechniques = {}; - var patchedPrograms = {}; - var patchedShaders = {}; + var accessors = gltf.accessors; + var bufferViews = gltf.bufferViews; + var buffers = gltf.buffers; + var materials = gltf.materials; + var techniques = gltf.techniques; + var patchedTechniques = {}; + var patchedPrograms = {}; + var patchedShaders = {}; - getAccessorsForSemantic(gltf, 'NORMAL', function(gltf, primitive, accessorId) { - var accessor = accessors[accessorId]; - if (canOctEncode(accessor, primitive)) { - // Oct-encode normals to 2-bytes - var bufferViewId = accessor.bufferView; - var bufferView = bufferViews[bufferViewId]; - var bufferId = bufferView.buffer; - var buffer = buffers[bufferId]; - var source = buffer.extras._pipeline.source; - var byteStride = getAccessorByteStride(accessor); - var byteOffset = accessor.byteOffset + bufferView.byteOffset; - var componentType = accessor.componentType; - var newComponentType = WebGLConstants.UNSIGNED_BYTE; - var componentByteLength = byteLengthForComponentType(componentType); - var newComponentByteLength = byteLengthForComponentType(newComponentType); - var numElements = accessor.count; - var numComponents = numberOfComponentsForType(accessor.type); - for (var j = 0; j < numElements; j++) { - var elementArray = []; - for (var k = 0; k < numComponents; k++) { - var element = readBufferComponent(source, componentType, byteOffset + componentByteLength * k); - elementArray.push(element); - } - var normalVector = Cartesian3.fromArray(elementArray); - Cartesian3.normalize(normalVector, normalVector); - var octEncodedVector = new Cartesian2(); - AttributeCompression.octEncode(normalVector, octEncodedVector); - writeBufferComponent(source, newComponentType, octEncodedVector.x, byteOffset); - writeBufferComponent(source, newComponentType, octEncodedVector.y, byteOffset + newComponentByteLength); - byteOffset += byteStride; - } - accessor.byteStride = byteStride; - accessor.componentType = newComponentType; - accessor.type = 'VEC2'; - var minMax = findAccessorMinMax(gltf, accessor); - accessor.min = minMax.min; - accessor.max = minMax.max; - var materialId = primitive.material; - var material = materials[materialId]; - var techniqueId = material.technique; - var attributeVariableName = patchedTechniques[techniqueId]; - if (!defined(patchedTechniques[techniqueId])) { - attributeVariableName = patchTechnique(gltf, techniqueId); - patchedTechniques[techniqueId] = attributeVariableName; - } - var technique = techniques[techniqueId]; - var programId = technique.program; - if (!defined(patchedPrograms[programId])) { - patchProgram(gltf, programId, attributeVariableName, patchedShaders); - patchedPrograms[programId] = true; + /* jshint unused:vars */ + ForEach.accessorWithSemantic(gltf, 'NORMAL', function(accessorId, semantic, primitive) { + var accessor = accessors[accessorId]; + if (canOctEncode(accessor, primitive)) { + // Oct-encode normals to 2-bytes + var bufferViewId = accessor.bufferView; + var bufferView = bufferViews[bufferViewId]; + var bufferId = bufferView.buffer; + var buffer = buffers[bufferId]; + var source = buffer.extras._pipeline.source; + var byteStride = getAccessorByteStride(gltf, accessor); + var byteOffset = accessor.byteOffset + bufferView.byteOffset; + var componentType = accessor.componentType; + var newComponentType = WebGLConstants.UNSIGNED_BYTE; + var componentByteLength = byteLengthForComponentType(componentType); + var newComponentByteLength = byteLengthForComponentType(newComponentType); + var numElements = accessor.count; + var numComponents = numberOfComponentsForType(accessor.type); + for (var j = 0; j < numElements; j++) { + var elementArray = []; + for (var k = 0; k < numComponents; k++) { + var element = readBufferComponent(source, componentType, byteOffset + componentByteLength * k); + elementArray.push(element); } + var normalVector = Cartesian3.fromArray(elementArray); + Cartesian3.normalize(normalVector, normalVector); + var octEncodedVector = new Cartesian2(); + AttributeCompression.octEncode(normalVector, octEncodedVector); + writeBufferComponent(source, newComponentType, octEncodedVector.x, byteOffset); + writeBufferComponent(source, newComponentType, octEncodedVector.y, byteOffset + newComponentByteLength); + byteOffset += byteStride; } - }).then(function() { - uninterleaveAndPackBuffers(gltf); - resolve(gltf); - }); + bufferView.byteStride = byteStride; + accessor.componentType = newComponentType; + accessor.type = 'VEC2'; + var minMax = findAccessorMinMax(gltf, accessor); + accessor.min = minMax.min; + accessor.max = minMax.max; + var materialId = primitive.material; + var material = materials[materialId]; + var techniqueId = material.technique; + var attributeVariableName = patchedTechniques[techniqueId]; + if (!defined(patchedTechniques[techniqueId])) { + attributeVariableName = patchTechnique(gltf, techniqueId); + patchedTechniques[techniqueId] = attributeVariableName; + } + var technique = techniques[techniqueId]; + var programId = technique.program; + if (!defined(patchedPrograms[programId])) { + patchProgram(gltf, programId, attributeVariableName, patchedShaders); + patchedPrograms[programId] = true; + } + } }); + return gltf; } function canOctEncode(accessor) { @@ -109,32 +104,27 @@ function canOctEncode(accessor) { function patchTechnique(gltf, techniqueId) { var techniques = gltf.techniques; var technique = techniques[techniqueId]; - var attributes = technique.attributes; - var parameters = technique.parameters; var normalParameterName; - for (var parameterName in parameters) { - if (parameters.hasOwnProperty(parameterName)) { - var parameter = parameters[parameterName]; - var semantic = parameter.semantic; - if (semantic === 'NORMAL') { - normalParameterName = parameterName; - parameter.type = WebGLConstants.INT_VEC2; - break; - } + ForEach.techniqueParameter(technique, function(parameter, parameterName) { + var semantic = parameter.semantic; + if (semantic === 'NORMAL') { + normalParameterName = parameterName; + parameter.type = WebGLConstants.INT_VEC2; + return true; } - } + }); + var normalVariableName; if (!defined(normalParameterName)) { throw new DeveloperError('NORMAL semantic in technique' + techniqueId + ' doesn\'t have a defined parameter'); } else { - for (var attributeVariableName in attributes) { - if (attributes.hasOwnProperty(attributeVariableName)) { - var attributeParameterName = attributes[attributeVariableName]; - if (attributeParameterName === normalParameterName) { - return attributeVariableName; - } + ForEach.techniqueAttribute(technique, function(attributeParameterName, attributeVariableName) { + if (attributeParameterName === normalParameterName) { + normalVariableName = attributeVariableName; + return true; } - } + }); } + return normalVariableName; } function patchProgram(gltf, programId, normalVariableName, patchedShaders) { diff --git a/lib/optimizeForVertexCache.js b/lib/optimizeForVertexCache.js index 87a29b00..6c7094ca 100644 --- a/lib/optimizeForVertexCache.js +++ b/lib/optimizeForVertexCache.js @@ -1,5 +1,6 @@ 'use strict'; var Cesium = require('cesium'); +var ForEach = require('./ForEach'); var gltfPrimitiveToCesiumGeometry = require('./gltfPrimitiveToCesiumGeometry'); var cesiumGeometryToGltfPrimitive = require('./cesiumGeometryToGltfPrimitive'); var createAccessorUsageTables = require('./createAccessorUsageTables'); @@ -12,28 +13,19 @@ module.exports = optimizeForVertexCache; // Helper method to map accessor collections from the usageTable to an independent primitive (if there is one) function createIndicesToAttributeDictionary(gltf) { var dictionary = {}; - var meshes = gltf.meshes; - for (var meshId in meshes) { - if (meshes.hasOwnProperty(meshId)) { - var mesh = meshes[meshId]; - var primitives = mesh.primitives; - var primitivesLength = primitives.length; - for (var i = 0; i < primitivesLength; i++) { - var primitive = primitives[i]; - var indicesId = primitive.indices; - - var primitivesOfIndicesId; - if (!dictionary[indicesId]) { - primitivesOfIndicesId = []; - } else { - primitivesOfIndicesId = dictionary[indicesId]; - } - primitivesOfIndicesId.push(primitive); - - dictionary[indicesId] = primitivesOfIndicesId; + ForEach.mesh(gltf, function(mesh) { + ForEach.meshPrimitive(mesh, function(primitive) { + var indicesId = primitive.indices; + var primitivesOfIndicesId; + if (!dictionary[indicesId]) { + primitivesOfIndicesId = []; + } else { + primitivesOfIndicesId = dictionary[indicesId]; } - } - } + primitivesOfIndicesId.push(primitive); + dictionary[indicesId] = primitivesOfIndicesId; + }); + }); return dictionary; } @@ -80,22 +72,15 @@ function optimizeForVertexCache(gltf, cacheSize) { // perform post vertex cache optimization var primitive; var geometry; - var meshes = gltf.meshes; - for (var meshId in meshes) { - if (meshes.hasOwnProperty(meshId)) { - var mesh = meshes[meshId]; - var primitives = mesh.primitives; - var primitivesLength = primitives.length; - for (var i = 0; i < primitivesLength; i++) { - primitive = primitives[i]; - if (defined(primitive.indices)) { - geometry = gltfPrimitiveToCesiumGeometry(gltf, primitive); - GeometryPipeline.reorderForPostVertexCache(geometry, cacheSize); - cesiumGeometryToGltfPrimitive(gltf, primitive, geometry); - } + ForEach.mesh(gltf, function(mesh) { + ForEach.meshPrimitive(mesh, function(primitive) { + if (defined(primitive.indices)) { + geometry = gltfPrimitiveToCesiumGeometry(gltf, primitive); + GeometryPipeline.reorderForPostVertexCache(geometry, cacheSize); + cesiumGeometryToGltfPrimitive(gltf, primitive, geometry); } - } - } + }); + }); // perform pre vertex cache optimization on each independent primitive var usageTables = createAccessorUsageTables(gltf); var dictionary = createIndicesToAttributeDictionary(gltf); diff --git a/lib/parseBinaryGltf.js b/lib/parseBinaryGltf.js index 6ea8e7c6..89e84af1 100644 --- a/lib/parseBinaryGltf.js +++ b/lib/parseBinaryGltf.js @@ -1,12 +1,12 @@ 'use strict'; var Cesium = require('cesium'); - var addPipelineExtras = require('./addPipelineExtras'); +var removeExtensionsUsed = require('./removeExtensionsUsed'); +var updateVersion = require('./updateVersion'); var ComponentDatatype = Cesium.ComponentDatatype; var defined = Cesium.defined; var DeveloperError = Cesium.DeveloperError; -var defaultValue = Cesium.defaultValue; var getMagic = Cesium.getMagic; var getStringFromTypedArray = Cesium.getStringFromTypedArray; var WebGLConstants = Cesium.WebGLConstants; @@ -20,226 +20,89 @@ module.exports = parseBinaryGltf; * @returns {Object} The parsed binary glTF. */ function parseBinaryGltf(data) { - var bufferViewId; + var headerView = ComponentDatatype.createArrayBufferView(WebGLConstants.INT, data.buffer, data.byteOffset, 5); // Check that the magic string is present - if (getMagic(data) !== 'glTF') { + var magic = getMagic(data); + if (magic !== 'glTF') { throw new DeveloperError('File is not valid binary glTF'); } - var uint32View = ComponentDatatype.createArrayBufferView(WebGLConstants.INT, data.buffer, data.byteOffset, 5); - - // Check that the version is 1 - if (uint32View[1] !== 1) { - throw new DeveloperError('Binary glTF version is not 1'); - } - - // Get the length of the glTF scene - var sceneLength = uint32View[3]; - - // Check that the scene format is 0, indicating that it is JSON - if (uint32View[4]) { - throw new DeveloperError('Binary glTF scene format is not JSON'); + // 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'); } - // Parse gltf scene - var scene = getStringFromTypedArray(data.slice(20, 20 + sceneLength)); - var gltf = JSON.parse(scene); - addPipelineExtras(gltf); - - // Extract binary body - var body = data.slice(20 + sceneLength); + 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]; - // Find bufferViews used by accessors - var usedBufferViews = getUsedBufferViews(gltf); - - // Add image and shader sources, and delete their bufferView if not referenced by an accessor - loadSourceFromBody(gltf, gltf.images, 'images', body, usedBufferViews); - loadSourceFromBody(gltf, gltf.shaders, 'shaders', body, usedBufferViews); - - // Read sources for compressed textures - var images = gltf.images; - for (var imageId in images) { - if (images.hasOwnProperty(imageId)) { - var image = images[imageId]; - if (defined(image.extras) && defined(image.extras.compressedImage3DTiles)) { - var compressedImages = image.extras.compressedImage3DTiles; - loadSourceFromBody(gltf, compressedImages, 'images', body, usedBufferViews); - } + // 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'); } - } - - // Create a new buffer for each bufferView, and delete the original body buffer - var buffers = gltf.buffers; - var bufferViews = gltf.bufferViews; - // The extension 'KHR_binary_glTF' uses a special buffer entitled just 'binary_glTF'. - // The 'KHR_binary_glTF' check is for backwards compatibility for the Cesium model converter - // circa Cesium 1.15-1.20 when the converter incorrectly used the buffer name 'KHR_binary_glTF'. - if (defined(buffers) && (defined(buffers.binary_glTF) || defined(buffers.KHR_binary_glTF))) { - if (defined(bufferViews)) { - //Add id to each bufferView object - for (bufferViewId in bufferViews) { - if (bufferViews.hasOwnProperty(bufferViewId)) { - var bufferView = bufferViews[bufferViewId]; - bufferView.extras._pipeline.id = bufferViewId; - } - } - - //Create bufferView array and get bufferViews referencing binary_glTF - var sortedBufferViews = []; - for (bufferViewId in bufferViews) { - if (bufferViews.hasOwnProperty(bufferViewId)) { - sortedBufferViews.push(bufferViews[bufferViewId]); - } + var contentString = getStringFromTypedArray(data.slice(20, 20 + contentLength)); + gltf = JSON.parse(contentString); + + var binaryData = data.slice(20 + contentLength, 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; } - sortedBufferViews = sortedBufferViews.filter(function(bufferView) { - return bufferView.buffer === 'binary_glTF' || bufferView.buffer === 'KHR_binary_glTF'; - }); - //Sort bufferViews by increasing byteOffset - sortedBufferViews.sort(function(a, b) { - return a.byteOffset - b.byteOffset; - }); - - //Create a new buffer for each set of overlapping bufferViews - for (var i = 0; i < sortedBufferViews.length; i++) { - var currentView = sortedBufferViews[i]; - var viewStart = currentView.byteOffset; - var viewLength = defaultValue(currentView.byteLength, 0); - var viewEnd = viewStart + viewLength; - currentView.byteOffset = 0; - currentView.byteLength = viewLength; - - var bufferName = currentView.extras._pipeline.id + '_buffer'; - var bufferKeys = Object.keys(buffers); - while (bufferKeys.indexOf(bufferName) !== -1) { - bufferName += '_'; - } - currentView.buffer = bufferName; - - for (var j = i + 1; j < sortedBufferViews.length; i = j, j++) { - var nextView = sortedBufferViews[j]; - var nextViewStart = nextView.byteOffset; - var nextViewLength = defaultValue(nextView.byteLength, 0); - var nextViewEnd = nextViewStart + nextViewLength; - //Merge view ranges if they overlap - if (nextViewStart < viewEnd) { - nextView.byteOffset = nextViewStart - viewStart; - nextView.byteLength = nextViewLength; - nextView.buffer = bufferName; - if (nextViewEnd > viewEnd) { - viewEnd = nextViewEnd; - } - } - else { - break; - } - } - - buffers[bufferName] = { - "byteLength" : viewEnd - viewStart, - "uri" : "data:,", - "extras" : { - "_pipeline" : { - "source" : body.slice(viewStart, viewEnd) - } + if (defined(binaryGltfBuffer)) { + binaryGltfBuffer.extras = { + _pipeline: { + source: binaryData } }; } } - delete gltf.buffers.binary_glTF; - } - // Remove the KHR_binary_glTF extension - gltf.extensionsUsed = gltf.extensionsUsed.filter(function(extension) { - return extension !== 'KHR_binary_glTF'; - }); - if (Object.keys(gltf.extensionsUsed).length === 0) { - delete gltf.extensionsUsed; - } - - return gltf; -} - -// Load the source from the binary body to the corresponding objects -function loadSourceFromBody(gltf, objects, name, body, usedBufferViews) { - if (defined(objects)) { - for (var objectId in objects) { - if (objects.hasOwnProperty(objectId)) { - var object = objects[objectId]; - var objectExtensions = object.extensions; - if (defined(objectExtensions) && defined(objectExtensions.KHR_binary_glTF)) { - var viewId = objectExtensions.KHR_binary_glTF.bufferView; - var bufferView = gltf.bufferViews[viewId]; - var source = body.slice(bufferView.byteOffset, bufferView.byteOffset + bufferView.byteLength); - object.extras._pipeline.source = source; - - if (name === 'shaders') { - object.extras._pipeline.extension = '.glsl'; - object.extras._pipeline.source = getStringFromTypedArray(source); - } - else if (name === 'images') { - object.extras._pipeline.extension = getBinaryImageFormat(source.slice(0, 2)); - } - delete object.extensions.KHR_binary_glTF; - if (Object.keys(object.extensions).length === 0) { - delete object.extensions; - } - - //Delete the original referenced bufferView if not used anywhere else - if (!defined(usedBufferViews[viewId])) { - delete gltf.bufferViews[viewId]; - } - } + // 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.slice(byteOffset, byteOffset + chunkLength); + byteOffset += chunkLength; + // Load JSON chunk + if (chunkType === 0x4E4F534A) { + var jsonString = chunkBuffer.toString(); + gltf = JSON.parse(jsonString); + addPipelineExtras(gltf); } - } - } -} - -//Get the set bufferViews used by accessors -function getUsedBufferViews(gltf) { - var usedBufferViews = {}; - var accessors = gltf.accessors; - - if (defined(accessors)) { - for (var accessorId in accessors) { - if (accessors.hasOwnProperty(accessorId)) { - usedBufferViews[accessors[accessorId].bufferView] = true; + // Load Binary chunk + else if (chunkType === 0x004E4942) { + binaryBuffer = chunkBuffer; } } - } - - return usedBufferViews; -} - -function bufferEqual(first, second) { - for (var i = 0; i < first.length && i < second.length; i++) { - if (first[i] !== second[i]) { - return false; + if (defined(gltf) && defined(binaryBuffer)) { + buffers = gltf.buffers; + if (defined(buffers) && buffers.length > 0) { + var buffer = buffers[0]; + buffer.extras._pipeline.source = binaryBuffer; + } } } - return true; -} - -//Get binary image file format from first two bytes -function getBinaryImageFormat(header) { - if (bufferEqual(header, new Uint8Array([66, 77]))) { //.bmp: 42 4D - return '.bmp'; - } - else if (bufferEqual(header, new Uint8Array([71, 73]))) { //.gif: 47 49 - return '.gif'; - } - else if (bufferEqual(header, new Uint8Array([255, 216]))) { //.jpg: ff d8 - return '.jpg'; - } - else if (bufferEqual(header, new Uint8Array([137, 80]))) { //.png: 89 50 - return '.png'; - } - else if (bufferEqual(header, new Uint8Array([171, 75]))) { //.ktx ab 4b - return '.ktx'; - } - else if (bufferEqual(header, new Uint8Array([72, 120]))) { //.crn 48 78 - return '.crn'; - } - else { - throw new DeveloperError('Binary image does not have valid header'); - } + return gltf; } \ No newline at end of file diff --git a/lib/processModelMaterialsCommon.js b/lib/processModelMaterialsCommon.js index 58141cee..39cae316 100644 --- a/lib/processModelMaterialsCommon.js +++ b/lib/processModelMaterialsCommon.js @@ -1,6 +1,7 @@ 'use strict'; var Cesium = require('cesium'); -var getUniqueId = require('./getUniqueId'); +var addToArray = require('./addToArray'); +var ForEach = require('./ForEach'); var numberOfComponentsForType = require('./numberOfComponentsForType'); var techniqueParameterForSemantic = require('./techniqueParameterForSemantic'); @@ -9,7 +10,7 @@ var defined = Cesium.defined; var defaultValue = Cesium.defaultValue; var WebGLConstants = Cesium.WebGLConstants; -module.exports = modelMaterialsCommon; +module.exports = processModelMaterialsCommon; function webGLConstantToGlslType(webGLValue) { switch (webGLValue) { @@ -167,21 +168,6 @@ function generateLightParameters(gltf) { return result; } -function getNextId(dictionary, baseName, startingCount) { - var count = defaultValue(startingCount, 0); - var nextId; - do { - nextId = baseName + (count++).toString(); - } while (defined(dictionary[nextId])); - - return nextId; -} - -var techniqueCount = 0; -var vertexShaderCount = 0; -var fragmentShaderCount = 0; -var programCount = 0; - function generateTechnique(gltf, khrMaterialsCommon, lightParameters, optimizeForCesium) { var techniques = gltf.techniques; var shaders = gltf.shaders; @@ -193,6 +179,7 @@ function generateTechnique(gltf, khrMaterialsCommon, lightParameters, optimizeFo } var parameterValues = khrMaterialsCommon.values; var jointCount = defaultValue(khrMaterialsCommon.jointCount, 0); + var hasSkinning = jointCount > 0; var skinningInfo = {}; if (hasSkinning) { @@ -202,12 +189,6 @@ function generateTechnique(gltf, khrMaterialsCommon, lightParameters, optimizeFo var vertexShader = 'precision highp float;\n'; var fragmentShader = 'precision highp float;\n'; - // Generate IDs for our new objects - var techniqueId = getNextId(techniques, 'technique', techniqueCount); - var vertexShaderId = getNextId(shaders, 'vertexShader', vertexShaderCount); - var fragmentShaderId = getNextId(shaders, 'fragmentShader', fragmentShaderCount); - var programId = getNextId(programs, 'program', programCount); - var hasNormals = (lightingModel !== 'CONSTANT'); // Add techniques @@ -614,25 +595,19 @@ function generateTechnique(gltf, khrMaterialsCommon, lightParameters, optimizeFo ] }; } - techniques[techniqueId] = { - attributes: techniqueAttributes, - parameters: techniqueParameters, - program: programId, - states: techniqueStates, - uniforms: techniqueUniforms - }; // Add shaders - shaders[vertexShaderId] = { + var vertexShaderId = addToArray(shaders, { type: WebGLConstants.VERTEX_SHADER, - extras: { - _pipeline: { - source: vertexShader, - extension: '.glsl' + extras: { + _pipeline: { + source: vertexShader, + extension: '.glsl' } } - }; - shaders[fragmentShaderId] = { + }); + + var fragmentShaderId = addToArray(shaders, { type: WebGLConstants.FRAGMENT_SHADER, extras: { _pipeline: { @@ -640,15 +615,23 @@ function generateTechnique(gltf, khrMaterialsCommon, lightParameters, optimizeFo extension: '.glsl' } } - }; + }); // Add program var programAttributes = Object.keys(techniqueAttributes); - programs[programId] = { + var programId = addToArray(programs, { attributes: programAttributes, fragmentShader: fragmentShaderId, vertexShader: vertexShaderId - }; + }); + + var techniqueId = addToArray(techniques, { + attributes: techniqueAttributes, + parameters: techniqueParameters, + program: programId, + states: techniqueStates, + uniforms: techniqueUniforms + }); return techniqueId; } @@ -666,13 +649,13 @@ function getKHRMaterialsCommonValueType(paramName, paramValue) { switch (paramName) { case 'ambient': - return (value instanceof String || typeof value === 'string') ? WebGLConstants.SAMPLER_2D : WebGLConstants.FLOAT_VEC4; + return value.length === 1 ? WebGLConstants.SAMPLER_2D : WebGLConstants.FLOAT_VEC4; case 'diffuse': - return (value instanceof String || typeof value === 'string') ? WebGLConstants.SAMPLER_2D : WebGLConstants.FLOAT_VEC4; + return value.length === 1 ? WebGLConstants.SAMPLER_2D : WebGLConstants.FLOAT_VEC4; case 'emission': - return (value instanceof String || typeof value === 'string') ? WebGLConstants.SAMPLER_2D : WebGLConstants.FLOAT_VEC4; + return value.length === 1 ? WebGLConstants.SAMPLER_2D : WebGLConstants.FLOAT_VEC4; case 'specular': - return (value instanceof String || typeof value === 'string') ? WebGLConstants.SAMPLER_2D : WebGLConstants.FLOAT_VEC4; + return value.length === 1 ? WebGLConstants.SAMPLER_2D : WebGLConstants.FLOAT_VEC4; case 'shininess': return WebGLConstants.FLOAT; case 'transparency': @@ -732,56 +715,55 @@ function lightDefaults(gltf) { } var lights = khrMaterialsCommon.lights; - for (var name in lights) { - if (lights.hasOwnProperty(name)) { - var light = lights[name]; - if (light.type === 'ambient') { - if (!defined(light.ambient)) { - light.ambient = {}; - } - var ambientLight = light.ambient; - - if (!defined(ambientLight.color)) { - ambientLight.color = [1.0, 1.0, 1.0]; - } - } else if (light.type === 'directional') { - if (!defined(light.directional)) { - light.directional = {}; - } - var directionalLight = light.directional; + var lightsLength = lights.length; + for (var lightId = 0; lightId < lightsLength; lightId++) { + var light = lights[lightId]; + if (light.type === 'ambient') { + if (!defined(light.ambient)) { + light.ambient = {}; + } + var ambientLight = light.ambient; - if (!defined(directionalLight.color)) { - directionalLight.color = [1.0, 1.0, 1.0]; - } - } else if (light.type === 'point') { - if (!defined(light.point)) { - light.point = {}; - } - var pointLight = light.point; + if (!defined(ambientLight.color)) { + ambientLight.color = [1.0, 1.0, 1.0]; + } + } else if (light.type === 'directional') { + if (!defined(light.directional)) { + light.directional = {}; + } + var directionalLight = light.directional; - if (!defined(pointLight.color)) { - pointLight.color = [1.0, 1.0, 1.0]; - } + if (!defined(directionalLight.color)) { + directionalLight.color = [1.0, 1.0, 1.0]; + } + } else if (light.type === 'point') { + if (!defined(light.point)) { + light.point = {}; + } + var pointLight = light.point; - pointLight.constantAttenuation = defaultValue(pointLight.constantAttenuation, 1.0); - pointLight.linearAttenuation = defaultValue(pointLight.linearAttenuation, 0.0); - pointLight.quadraticAttenuation = defaultValue(pointLight.quadraticAttenuation, 0.0); - } else if (light.type === 'spot') { - if (!defined(light.spot)) { - light.spot = {}; - } - var spotLight = light.spot; + if (!defined(pointLight.color)) { + pointLight.color = [1.0, 1.0, 1.0]; + } - if (!defined(spotLight.color)) { - spotLight.color = [1.0, 1.0, 1.0]; - } + pointLight.constantAttenuation = defaultValue(pointLight.constantAttenuation, 1.0); + pointLight.linearAttenuation = defaultValue(pointLight.linearAttenuation, 0.0); + pointLight.quadraticAttenuation = defaultValue(pointLight.quadraticAttenuation, 0.0); + } else if (light.type === 'spot') { + if (!defined(light.spot)) { + light.spot = {}; + } + var spotLight = light.spot; - spotLight.constantAttenuation = defaultValue(spotLight.constantAttenuation, 1.0); - spotLight.fallOffAngle = defaultValue(spotLight.fallOffAngle, 3.14159265); - spotLight.fallOffExponent = defaultValue(spotLight.fallOffExponent, 0.0); - spotLight.linearAttenuation = defaultValue(spotLight.linearAttenuation, 0.0); - spotLight.quadraticAttenuation = defaultValue(spotLight.quadraticAttenuation, 0.0); + if (!defined(spotLight.color)) { + spotLight.color = [1.0, 1.0, 1.0]; } + + spotLight.constantAttenuation = defaultValue(spotLight.constantAttenuation, 1.0); + spotLight.fallOffAngle = defaultValue(spotLight.fallOffAngle, 3.14159265); + spotLight.fallOffExponent = defaultValue(spotLight.fallOffExponent, 0.0); + spotLight.linearAttenuation = defaultValue(spotLight.linearAttenuation, 0.0); + spotLight.quadraticAttenuation = defaultValue(spotLight.quadraticAttenuation, 0.0); } } } @@ -812,6 +794,9 @@ function ensureSemanticExistenceForPrimitive(gltf, primitive) { 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, @@ -829,77 +814,62 @@ function ensureSemanticExistenceForPrimitive(gltf, primitive) { } function ensureSemanticExistence(gltf) { - var meshes = gltf.meshes; - for (var meshId in meshes) { - if (meshes.hasOwnProperty(meshId)) { - var mesh = meshes[meshId]; - var primitives = mesh.primitives; - var primitivesLength = primitives.length; - for (var i = 0; i < primitivesLength; i++) { - ensureSemanticExistenceForPrimitive(gltf, primitives[i]); - } - } - } + ForEach.mesh(gltf, function(mesh) { + ForEach.meshPrimitive(mesh, function(primitive) { + ensureSemanticExistenceForPrimitive(gltf, primitive); + }); + }); } function splitIncompatibleSkins(gltf) { var accessors = gltf.accessors; var materials = gltf.materials; - var meshes = gltf.meshes; - for (var meshId in meshes) { - if (meshes.hasOwnProperty(meshId)) { - var mesh = meshes[meshId]; - var primitives = mesh.primitives; - var primitivesLength = primitives.length; - for (var j = 0; j < primitivesLength; j++) { - var primitive = primitives[j]; - - 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 skinningInfo = khrMaterialsCommon.extras._pipeline.skinning; - if (!defined(skinningInfo)) { - khrMaterialsCommon.extras._pipeline.skinning = { - skinned: isSkinned, - componentType: componentType, - type: type - }; - } else if ((skinningInfo.skinned !== isSkinned) || (skinningInfo.type !== type)) { - // This primitive uses the same material as another one that either isn't skinned or uses a different type to store joints and weights - materialId = getUniqueId(gltf, materialId); - primitive.material = materialId; - // Split this off as a separate material - var clonedMaterial = clone(material, true); - clonedMaterial.extensions.KHR_materials_common.extras._pipeline.skinning = { - skinned: isSkinned, - componentType: componentType, - type: type - }; - materials[materialId] = clonedMaterial; - } - } - } - } - } + 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 skinningInfo = khrMaterialsCommon.extras._pipeline.skinning; + if (!defined(skinningInfo)) { + khrMaterialsCommon.extras._pipeline.skinning = { + skinned: isSkinned, + componentType: componentType, + type: type + }; + } else if ((skinningInfo.skinned !== isSkinned) || (skinningInfo.type !== type)) { + // This primitive uses the same material as another one that either isn't skinned or uses a different type to store joints and weights + var clonedMaterial = clone(material, true); + clonedMaterial.extensions.KHR_materials_common.extras._pipeline.skinning = { + skinned: isSkinned, + componentType: componentType, + type: type + }; + // Split this off as a separate material + materialId = addToArray(materials, clonedMaterial); + primitive.material = materialId; + } + } + }); + }); } /** * @private */ -function modelMaterialsCommon(gltf, options) { +function processModelMaterialsCommon(gltf, options) { options = defaultValue(options, {}); if (!defined(gltf)) { @@ -907,28 +877,31 @@ function modelMaterialsCommon(gltf, options) { } var hasExtension = false; + var extensionsRequired = gltf.extensionsRequired; var extensionsUsed = gltf.extensionsUsed; if (defined(extensionsUsed)) { - var extensionsUsedCount = extensionsUsed.length; - for (var i = 0; i < extensionsUsedCount; ++i) { - if (extensionsUsed[i] === 'KHR_materials_common') { - hasExtension = true; - extensionsUsed.splice(i, 1); - break; + 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.asset.premultipliedAlpha = true; if (!defined(gltf.programs)) { - gltf.programs = {}; + gltf.programs = []; } if (!defined(gltf.shaders)) { - gltf.shaders = {}; + gltf.shaders = []; } if (!defined(gltf.techniques)) { - gltf.techniques = {}; + gltf.techniques = []; } lightDefaults(gltf); @@ -938,46 +911,35 @@ function modelMaterialsCommon(gltf, options) { splitIncompatibleSkins(gltf); var techniques = {}; - var materials = gltf.materials; - for (var materialId in materials) { - if (materials.hasOwnProperty(materialId)) { - var material = materials[materialId]; - 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.optimizeForCesium); - techniques[techniqueKey] = technique; - } + 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.optimizeForCesium); + techniques[techniqueKey] = technique; + } - // 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) && (valueName !== 'transparent') && (valueName !== 'doubleSided')) { - var value = values[valueName]; - - // Backwards compatibility for COLLADA2GLTF v1.0-draft when it encoding - // materials using KHR_materials_common with explicit type/value members - if (defined(value.value)) { - material.values[valueName] = value.value; - } else { - material.values[valueName] = value; - } - } + // 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; } + } - material.technique = technique; + material.technique = technique; - delete material.extensions.KHR_materials_common; - if (Object.keys(material.extensions).length === 0) { - delete material.extensions; - } + delete material.extensions.KHR_materials_common; + if (Object.keys(material.extensions).length === 0) { + delete material.extensions; } } - } + }); if (defined(gltf.extensions)) { delete gltf.extensions.KHR_materials_common; diff --git a/lib/quantizeAttributes.js b/lib/quantizeAttributes.js index a3967f4a..29189c8e 100644 --- a/lib/quantizeAttributes.js +++ b/lib/quantizeAttributes.js @@ -1,15 +1,14 @@ 'use strict'; var Cesium = require('cesium'); -var WebGLConstants = Cesium.WebGLConstants; -var defaultValue = Cesium.defaultValue; -var defined = Cesium.defined; - var AccessorReader = require('./AccessorReader'); - -var addExtensionsUsed = require('./addExtensionsUsed'); +var addExtensionsRequired = require('./addExtensionsRequired'); var findAccessorMinMax = require('./findAccessorMinMax'); +var ForEach = require('./ForEach'); var numberOfComponentsForType = require('./numberOfComponentsForType'); -var uninterleaveAndPackBuffers = require('./uninterleaveAndPackBuffers'); + +var WebGLConstants = Cesium.WebGLConstants; +var defaultValue = Cesium.defaultValue; +var defined = Cesium.defined; module.exports = quantizeAttributes; @@ -142,10 +141,8 @@ function quantizeAttributes(gltf, options) { } } if (isQuantized) { - // Repack the buffers - uninterleaveAndPackBuffers(gltf); // Finalize - addExtensionsUsed(gltf, 'WEB3D_quantized_attributes'); + addExtensionsRequired(gltf, 'WEB3D_quantized_attributes'); } } @@ -194,38 +191,24 @@ function createDecodeMatrix5(min, max, range) { function getAllQuantizableAttributes(gltf, validSemantics, excludeSemantics) { var accessors = gltf.accessors; - var meshes = gltf.meshes; var visitedAccessors = {}; var accessorAttributes = {}; - for (var meshId in meshes) { - if (meshes.hasOwnProperty(meshId)) { - var mesh = meshes[meshId]; - var primitives = mesh.primitives; - if (defined(primitives)) { - for (var i = 0; i < primitives.length; i++) { - var primitive = primitives[i]; - var attributes = primitive.attributes; - if (defined(attributes)) { - for (var attribute in attributes) { - if (attributes.hasOwnProperty(attribute)) { - if ((!defined(validSemantics) && !defined(excludeSemantics)) || - isSemanticValid(attribute, validSemantics, excludeSemantics)) { - var accessorId = attributes[attribute]; - if (!defined(visitedAccessors[accessorId])) { - var accessor = accessors[accessorId]; - if (accessorIsQuantizable(accessor)) { - accessorAttributes[accessorId] = attribute; - } - visitedAccessors[accessorId] = true; - } - } - } + ForEach.mesh(gltf, function(mesh) { + ForEach.meshPrimitive(mesh, function(primitive) { + ForEach.meshPrimitiveAttribute(primitive, function(accessorId, semantic) { + if ((!defined(validSemantics) && !defined(excludeSemantics)) || + isSemanticValid(semantic, validSemantics, excludeSemantics)) { + if (!defined(visitedAccessors[accessorId])) { + var accessor = accessors[accessorId]; + if (accessorIsQuantizable(accessor)) { + accessorAttributes[accessorId] = semantic; } + visitedAccessors[accessorId] = true; } } - } - } - } + }); + }); + }); return accessorAttributes; } diff --git a/lib/removeDuplicatePrimitives.js b/lib/removeDuplicatePrimitives.js index 17b0ce8f..685c5f9d 100644 --- a/lib/removeDuplicatePrimitives.js +++ b/lib/removeDuplicatePrimitives.js @@ -1,11 +1,10 @@ 'use strict'; var Cesium = require('cesium'); - -var defined = Cesium.defined; - +var addToArray = require('./addToArray'); var NodeHelpers = require('./NodeHelpers'); var PrimitiveHelpers = require('./PrimitiveHelpers'); -var getUniqueId = require('./getUniqueId'); + +var defined = Cesium.defined; module.exports = removeDuplicatePrimitives; @@ -22,30 +21,29 @@ function removeDuplicatePrimitives(gltf) { var primitivesCount = []; var primitivesToMeshes = []; var meshIndex; - for (var meshId in meshes) { - if (meshes.hasOwnProperty(meshId)) { - var mesh = meshes[meshId]; - var primitives = mesh.primitives; - var primitivesLength = primitives.length; - for (var i = 0; i < primitivesLength; i++) { - var primitive = primitives[i]; - var index = findObject(seenPrimitives, primitive, PrimitiveHelpers.primitiveEquals); - if (index < 0) { + 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 i = 0; i < primitivesLength; i++) { + var primitive = primitives[i]; + var index = findObject(seenPrimitives, primitive, PrimitiveHelpers.primitiveEquals); + if (index < 0) { + meshIndex = {}; + meshIndex[meshId] = {}; + meshIndex[meshId][i] = true; + primitivesToMeshes.push(meshIndex); + primitivesCount.push(1); + seenPrimitives.push(primitive); + } else { + meshIndex = primitivesToMeshes[index][meshId]; + if (!defined(meshIndex)) { meshIndex = {}; - meshIndex[meshId] = {}; - meshIndex[meshId][i] = true; - primitivesToMeshes.push(meshIndex); - primitivesCount.push(1); - seenPrimitives.push(primitive); - } else { - meshIndex = primitivesToMeshes[index][meshId]; - if (!defined(meshIndex)) { - meshIndex = {}; - primitivesToMeshes[index][meshId] = meshIndex; - } - meshIndex[i] = true; - primitivesCount[index]++; + primitivesToMeshes[index][meshId] = meshIndex; } + meshIndex[i] = true; + primitivesCount[index]++; } } } @@ -54,7 +52,6 @@ function removeDuplicatePrimitives(gltf) { return gltf; } -var splitMeshPrefix = 'mesh-split'; function removeDuplicatesFromTraversal(gltf, seenPrimitives, primitivesCount, primitivesToMeshes) { var meshes = gltf.meshes; var nodes = gltf.nodes; @@ -73,12 +70,12 @@ function removeDuplicatesFromTraversal(gltf, seenPrimitives, primitivesCount, pr indices = Object.keys(meshInstances[meshId]); removePrimitivesFromMesh(gltf, meshId, indices, 1); } else { - var splitMeshId = getUniqueId(gltf, splitMeshPrefix); - meshes[splitMeshId] = { + var splitMesh = { primitives : [ primitive ] }; + var splitMeshId = addToArray(meshes, splitMesh); for (var j = 0; j < meshIdsLength; j++) { meshId = meshIds[j]; indices = Object.keys(meshInstances[meshId]); @@ -89,7 +86,18 @@ function removeDuplicatesFromTraversal(gltf, seenPrimitives, primitivesCount, pr for (var k = 0; k < nodeIdsLength; k++) { var nodeId = nodeIds[k]; var node = nodes[nodeId]; - node.meshes.push(splitMeshId); + if (!defined(node.mesh)) { + node.mesh = splitMeshId; + } else { + var meshNode = { + mesh: splitMeshId, + extras: { + _pipeline: {} + } + }; + var meshNodeId = addToArray(nodes, meshNode); + node.children.push(meshNodeId); + } } } } @@ -110,7 +118,8 @@ function removePrimitivesFromMesh(gltf, meshId, indices, startIndex) { function finalizeRemoval(gltf) { var meshes = gltf.meshes; var removeMeshes = []; - for (var meshId in meshes) { + var meshesLength = meshes.length; + for (var meshId = 0; meshId < meshesLength; meshId++) { if (meshes.hasOwnProperty(meshId)) { var mesh = meshes[meshId]; var primitives = mesh.primitives; diff --git a/lib/removeExtensionsRequired.js b/lib/removeExtensionsRequired.js new file mode 100644 index 00000000..5e706c74 --- /dev/null +++ b/lib/removeExtensionsRequired.js @@ -0,0 +1,25 @@ +'use strict'; +var Cesium = require('cesium'); + +var defined = Cesium.defined; + +module.exports = removeExtensionsRequired; + +/** + * Removes an extension from gltf.extensionsRequired if it is present. + * + * @param {Object} gltf A javascript object containing a glTF asset. + * @param {String} extension The extension to remove. + */ +function removeExtensionsRequired(gltf, extension) { + var extensionsRequired = gltf.extensionsRequired; + if (defined(extensionsRequired)) { + var index = extensionsRequired.indexOf(extension); + if (index >= 0) { + extensionsRequired.splice(index, 1); + } + if (extensionsRequired.length === 0) { + delete gltf.extensionsRequired; + } + } +} diff --git a/lib/removeExtensionsUsed.js b/lib/removeExtensionsUsed.js new file mode 100644 index 00000000..f0f68c7b --- /dev/null +++ b/lib/removeExtensionsUsed.js @@ -0,0 +1,27 @@ +'use strict'; +var Cesium = require('cesium'); +var removeExtensionsRequired = require('./removeExtensionsRequired'); + +var defined = Cesium.defined; + +module.exports = removeExtensionsUsed; + +/** + * Removes an extension from gltf.extensionsUsed and gltf.extensionsRequired if it is present. + * + * @param {Object} gltf A javascript object containing a glTF asset. + * @param {String} extension The extension to remove. + */ +function removeExtensionsUsed(gltf, extension) { + var extensionsUsed = gltf.extensionsUsed; + if (defined(extensionsUsed)) { + var index = extensionsUsed.indexOf(extension); + if (index >= 0) { + extensionsUsed.splice(index, 1); + } + removeExtensionsRequired(gltf, extension); + if (extensionsUsed.length === 0) { + delete gltf.extensionsUsed; + } + } +} \ No newline at end of file diff --git a/lib/removePipelineExtras.js b/lib/removePipelineExtras.js index 07fe7f3c..0cdda98d 100644 --- a/lib/removePipelineExtras.js +++ b/lib/removePipelineExtras.js @@ -4,6 +4,7 @@ var Cesium = require('cesium'); var defined = Cesium.defined; module.exports = removePipelineExtras; + /** * Iterate through the objects within each glTF object and delete their pipeline extras object. * diff --git a/lib/removeUnusedVertices.js b/lib/removeUnusedVertices.js index 9082f442..22cd1cf8 100644 --- a/lib/removeUnusedVertices.js +++ b/lib/removeUnusedVertices.js @@ -9,7 +9,6 @@ var byteLengthForComponentType = require('./byteLengthForComponentType'); var createAccessorUsageTables = require('./createAccessorUsageTables'); var getAccessorByteStride = require('./getAccessorByteStride'); var numberOfComponentsForType = require('./numberOfComponentsForType'); -var uninterleaveAndPackBuffers = require('./uninterleaveAndPackBuffers'); module.exports = removeUnusedVertices; @@ -23,12 +22,10 @@ module.exports = removeUnusedVertices; * * @see addPipelineExtras * @see loadGltfUris - * @see uninterleaveAndPackBuffers */ function removeUnusedVertices(gltf) { if (defined(gltf.accessors) && defined(gltf.buffers) && defined(gltf.bufferViews) && defined(gltf.meshes)) { removeUnusedVerticesFromAccessors(gltf); - uninterleaveAndPackBuffers(gltf); } return gltf; } @@ -99,7 +96,7 @@ function accessorWriteFromTo(gltf, accessor, fromIndex, toIndex) { var source = buffer.extras._pipeline.source; var byteOffset = bufferView.byteOffset + accessor.byteOffset; - var byteStride = getAccessorByteStride(accessor); + var byteStride = getAccessorByteStride(gltf, accessor); var componentByteLength = byteLengthForComponentType(accessor.componentType); var numberOfComponents = numberOfComponentsForType(accessor.type); diff --git a/lib/uninterleaveAndPackBuffers.js b/lib/uninterleaveAndPackBuffers.js index 8bc8c962..53bf67df 100644 --- a/lib/uninterleaveAndPackBuffers.js +++ b/lib/uninterleaveAndPackBuffers.js @@ -1,13 +1,13 @@ 'use strict'; var Cesium = require('cesium'); - -var WebGLConstants = Cesium.WebGLConstants; -var defined = Cesium.defined; -var defaultValue = Cesium.defaultValue; - +var AccessorReader = require('./AccessorReader'); var byteLengthForComponentType = require('./byteLengthForComponentType'); -var getAccessorByteStride = require('./getAccessorByteStride'); +var ForEach = require('./ForEach'); var numberOfComponentsForType = require('./numberOfComponentsForType'); +var Remove = require('./Remove'); +var writeBufferComponent = require('./writeBufferComponent'); + +var WebGLConstants = Cesium.WebGLConstants; module.exports = uninterleaveAndPackBuffers; @@ -24,148 +24,122 @@ module.exports = uninterleaveAndPackBuffers; * @see loadGltfUris */ function uninterleaveAndPackBuffers(gltf) { - var accessors = gltf.accessors; - var buffers = gltf.buffers; - var packBufferViews = {length : 0}; - for (var bufferId in buffers) { - if (buffers.hasOwnProperty(bufferId)) { - packGltfBuffer(gltf, bufferId, packBufferViews); - } - } - delete packBufferViews.length; - gltf.bufferViews = packBufferViews; + var arrayBufferDataOffset = 0; + var arrayBufferDataLength = 0; + var elementArrayBufferDataOffset = 0; + var elementArrayBufferDataLength = 0; + var otherDataOffset = 0; + var otherDataLength = 0; - // Change the accessor bufferViews to point to the new bufferViews - for (var accessorId in accessors) { - if (accessors.hasOwnProperty(accessorId)) { - var accessor = accessors[accessorId]; - accessor.bufferView = accessor.extras._pipeline.bufferView; + // compute the total size for each arraybuffer type + ForEach.accessor(gltf, function (accessor) { + var bufferView = gltf.bufferViews[accessor.bufferView]; + var accessorLength = byteLengthForComponentType(accessor.componentType) * numberOfComponentsForType(accessor.type) * accessor.count; + switch (bufferView.target) { + case WebGLConstants.ARRAY_BUFFER: + arrayBufferDataLength += accessorLength; + break; + case WebGLConstants.ELEMENT_ARRAY_BUFFER: + elementArrayBufferDataLength += accessorLength; + break; + default: + otherDataLength += accessorLength; + break; } - } - return gltf; -} + }); -function packGltfBuffer(gltf, bufferId, packBufferViews) { - var buffers = gltf.buffers; - var buffer = buffers[bufferId]; - var source = buffer.extras._pipeline.source; - var packBuffer = new Uint8Array(source.length); - var accessors = getAccessorsByTargetAndByteLength(gltf, bufferId); - var offset = 0; + // allocate buffer data + var bufferData = new Buffer(arrayBufferDataLength + elementArrayBufferDataLength + otherDataLength); + var arrayBufferData = bufferData.slice(0, arrayBufferDataLength); + var elementArrayBufferData = bufferData.slice(arrayBufferDataLength, arrayBufferDataLength + elementArrayBufferDataLength); + var otherData = bufferData.slice(arrayBufferDataLength + elementArrayBufferDataLength); - var targets = [WebGLConstants.ARRAY_BUFFER, 0, WebGLConstants.ELEMENT_ARRAY_BUFFER]; - for (var i = 0; i < targets.length; i++) { - var target = targets[i]; - var accessorsByByteLength = accessors[target]; - if (defined(accessorsByByteLength)) { - offset = packAccessorsForTarget(gltf, bufferId, target, accessorsByByteLength, source, packBuffer, packBufferViews, offset); - } - } - packBuffer = new Buffer(new Uint8Array(packBuffer.buffer, 0, offset)); - buffer.extras._pipeline.source = packBuffer; - buffer.byteLength = packBuffer.length; -} + // read data from accessors into the new buffers + ForEach.accessor(gltf, function (accessor) { + var reader = new AccessorReader(gltf, accessor); + var components = []; + var bufferView = gltf.bufferViews[accessor.bufferView]; + var componentByteLength = byteLengthForComponentType(accessor.componentType); + var bytesWritten = 0; -function packAccessorsForTarget(gltf, bufferId, target, accessorsByByteLength, sourceBuffer, packBuffer, packBufferViews, offset) { - var bufferViewId = 'bufferView_' + packBufferViews.length; - var originalOffset = offset; - var byteLengths = [4, 2, 1]; - var packOffset = offset; - for (var i = 0; i < byteLengths.length; i++) { - var byteLength = byteLengths[i]; - var accessorIds = accessorsByByteLength[byteLength]; - if (defined(accessorIds) && accessorIds.length > 0) { - // Byte-boundary align the offset if it isn't already - packOffset += packOffset % byteLength; - packOffset = packAccessors(gltf, accessorIds, sourceBuffer, packBuffer, bufferViewId, originalOffset, packOffset); + while (!reader.pastEnd()) { + reader.read(components); + var componentsLength = components.length; + for (var i = 0; i < componentsLength; i++) { + switch (bufferView.target) { + case WebGLConstants.ARRAY_BUFFER: + writeBufferComponent(arrayBufferData, accessor.componentType, components[i], arrayBufferDataOffset); + arrayBufferDataOffset += componentByteLength; + break; + case WebGLConstants.ELEMENT_ARRAY_BUFFER: + writeBufferComponent(elementArrayBufferData, accessor.componentType, components[i], elementArrayBufferDataOffset); + elementArrayBufferDataOffset += componentByteLength; + break; + default: + writeBufferComponent(otherData, accessor.componentType, components[i], otherDataOffset); + otherDataOffset += componentByteLength; + break; + } + bytesWritten += componentByteLength; + } + reader.next(); } - } - var packBufferView = { - buffer : bufferId, - byteLength : packOffset - originalOffset, - byteOffset : originalOffset, - extras : { - _pipeline : {} + // assign bufferViews and offsets since we're done reading + switch (bufferView.target) { + case WebGLConstants.ARRAY_BUFFER: + accessor.bufferView = 0; + accessor.byteOffset = arrayBufferDataOffset - bytesWritten; + break; + case WebGLConstants.ELEMENT_ARRAY_BUFFER: + accessor.bufferView = 1; + accessor.byteOffset = elementArrayBufferDataOffset - bytesWritten; + break; + default: + accessor.bufferView = 2; + accessor.byteOffset = otherDataOffset - bytesWritten; + break; } - }; - if (target > 0) { - packBufferView.target = target; - } - packBufferViews[bufferViewId] = packBufferView; - packBufferViews.length++; - return packOffset; -} - -function getPipelineExtras(object) { - var extras = object.extras; - if (!defined(extras)) { - extras = {}; - object.extras = extras; - } - var pipeline = extras._pipeline; - if (!defined(pipeline)) { - pipeline = {}; - extras._pipeline = pipeline; - } - return pipeline; -} + }); -function packAccessors(gltf, accessorsToPack, sourceBuffer, packBuffer, bufferViewId, originalOffset, packOffset) { - var accessors = gltf.accessors; - var bufferViews = gltf.bufferViews; - var length = accessorsToPack.length; - var bytesWritten = 0; - for (var i = 0; i < length; i++) { - var accessorId = accessorsToPack[i]; - var accessor = accessors[accessorId]; - var bufferView = bufferViews[accessor.bufferView]; - var byteStride = getAccessorByteStride(accessor); - var byteOffset = accessor.byteOffset + bufferView.byteOffset; - var numberOfComponents = numberOfComponentsForType(accessor.type); - var componentByteLength = byteLengthForComponentType(accessor.componentType); - var byteLength = numberOfComponents * componentByteLength; - var offset = byteOffset; - var count = accessor.count; - accessor.byteStride = 0; - // Store as temp for now, finalize later - var extras = getPipelineExtras(accessor); - extras.bufferView = bufferViewId; - accessor.byteOffset = packOffset - originalOffset + bytesWritten; - for (var num = 0; num < count; num++) { - for (var j = 0; j < byteLength; j++) { - packBuffer[packOffset + bytesWritten] = sourceBuffer[offset + j]; - bytesWritten++; + var buffers = [{ + byteLength: bufferData.length, + extras: { + _pipeline: { + source: bufferData, + extension: '.bin' } - offset += byteStride; } - } - return packOffset + bytesWritten; -} + }]; -function getAccessorsByTargetAndByteLength(gltf, bufferId) { - var accessors = gltf.accessors; - var bufferViews = gltf.bufferViews; - var accessorsByTargetAndByteLength = {}; - for (var accessorId in accessors) { - if (accessors.hasOwnProperty(accessorId)) { - var accessor = accessors[accessorId]; - var bufferView = bufferViews[accessor.bufferView]; - if (bufferView.buffer === bufferId) { - var target = defaultValue(bufferView.target, 0); - var accessorsByByteLength = accessorsByTargetAndByteLength[target]; - if (!defined(accessorsByByteLength)) { - accessorsByByteLength = {}; - accessorsByTargetAndByteLength[target] = accessorsByByteLength; - } - var byteLength = byteLengthForComponentType(accessor.componentType); - var accessorIds = accessorsByByteLength[byteLength]; - if (!defined(accessorIds)) { - accessorIds = []; - accessorsByByteLength[byteLength] = accessorIds; - } - accessorIds.push(accessorId); - } - } + var bufferViews = [{ + buffer: 0, + byteLength: arrayBufferDataLength, + byteOffset: 0, + byteStride: 0 + }, { + buffer: 0, + byteLength: elementArrayBufferDataLength, + byteOffset: arrayBufferDataLength + }, { + buffer: 0, + byteLength: otherDataLength, + byteOffset: arrayBufferDataLength + elementArrayBufferDataLength, + byteStride: 0 + }]; + + gltf.buffers = buffers; + gltf.bufferViews = bufferViews; + + var removed = 0; + if (arrayBufferDataLength === 0) { + Remove.bufferView(gltf, 0); + removed++; + } + if (elementArrayBufferDataLength === 0) { + Remove.bufferView(gltf, 1 - removed); + removed++; + } + if (otherDataLength === 0) { + Remove.bufferView(gltf, 2 - removed); } - return accessorsByTargetAndByteLength; } \ No newline at end of file diff --git a/lib/updateVersion.js b/lib/updateVersion.js index fc21e241..91eae7d9 100644 --- a/lib/updateVersion.js +++ b/lib/updateVersion.js @@ -1,20 +1,28 @@ 'use strict'; var Cesium = require('cesium'); +var addExtensionsRequired = require('./addExtensionsRequired'); +var addToArray = require('./addToArray'); +var ForEach = require('./ForEach'); +var findAccessorMinMax = require('./findAccessorMinMax'); var Cartesian3 = Cesium.Cartesian3; +var CesiumMath = Cesium.Math; var Quaternion = Cesium.Quaternion; var WebGLConstants = Cesium.WebGLConstants; +var clone = Cesium.clone; var defaultValue = Cesium.defaultValue; var defined = Cesium.defined; module.exports = updateVersion; var updateFunctions = { - '0.8': glTF08to10 + '0.8' : glTF08to10, + '1.0' : glTF10to20, + '2.0' : undefined }; /** - * Update the glTF version to the latest version (1.0), or targetVersion if specified. + * Update the glTF version to the latest version (2.0), or targetVersion if specified. * Applies changes made to the glTF spec between revisions so that the core library * only has to handle the latest version. * @@ -27,13 +35,27 @@ function updateVersion(gltf, options) { options = defaultValue(options, {}); var targetVersion = options.targetVersion; var version = gltf.version; + gltf.asset = defaultValue(gltf.asset, { version: '1.0' }); + version = defaultValue(version, gltf.asset.version); + // invalid version + if (!updateFunctions.hasOwnProperty(version)) { + // try truncating trailing version numbers, could be a number as well if it is 0.8 + if (defined(version)) { + version = ('' + version).substring(0, 3); + } + // default to 1.0 if it cannot be determined + if (!updateFunctions.hasOwnProperty(version)) { + version = '1.0'; + } + } + var updateFunction = updateFunctions[version]; + while (defined(updateFunction)) { - version = gltf.asset.version; if (version === targetVersion) { break; } @@ -160,6 +182,602 @@ function glTF08to10(gltf) { // gltf.allExtensions -> extensionsUsed if (defined(gltf.allExtensions)) { gltf.extensionsUsed = gltf.allExtensions; - delete gltf.allExtensions; + gltf.allExtensions = undefined; + } +} + +function removeAnimationSamplersIndirection(gltf) { + var animations = gltf.animations; + for (var animationId in animations) { + if (animations.hasOwnProperty(animationId)) { + var animation = animations[animationId]; + var parameters = animation.parameters; + if (defined(parameters)) { + var samplers = animation.samplers; + for (var samplerId in samplers) { + if (samplers.hasOwnProperty(samplerId)) { + var sampler = samplers[samplerId]; + sampler.input = parameters[sampler.input]; + sampler.output = parameters[sampler.output]; + } + } + delete animation.parameters; + } + } + } +} + + +function objectToArray(object, mapping) { + var array = []; + for (var id in object) { + if (object.hasOwnProperty(id)) { + var value = object[id]; + mapping[id] = array.length; + array.push(value); + if (!defined(value.name)) { + value.name = id; + } + } + } + return array; +} + +function objectsToArrays(gltf) { + var i; + var globalMapping = { + accessors: {}, + animations: {}, + bufferViews: {}, + buffers: {}, + cameras: {}, + materials: {}, + meshes: {}, + nodes: {}, + programs: {}, + shaders: {}, + skins: {}, + techniques: {} + }; + // Convert top level objects to arrays + for (var topLevelId in gltf) { + if (gltf.hasOwnProperty(topLevelId) && topLevelId !== 'extras' && topLevelId !== 'asset') { + 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; + } + } + } + } + // Fix references + if (defined(gltf.scene)) { + gltf.scene = globalMapping.scenes[gltf.scene]; } + ForEach.bufferView(gltf, function(bufferView) { + if (defined(bufferView.buffer)) { + bufferView.buffer = globalMapping.buffers[bufferView.buffer]; + } + }); + ForEach.accessor(gltf, function(accessor) { + if (defined(accessor.bufferView)) { + accessor.bufferView = globalMapping.bufferViews[accessor.bufferView]; + } + }); + ForEach.shader(gltf, function(shader) { + var extensions = shader.extensions; + if (defined(extensions)) { + var binaryGltf = extensions.KHR_binary_glTF; + if (defined(binaryGltf)) { + shader.bufferView = globalMapping.bufferViews[binaryGltf.bufferView]; + delete extensions.KHR_binary_glTF; + } + if (Object.keys(extensions).length === 0) { + delete shader.extensions; + } + } + }); + ForEach.program(gltf, function(program) { + if (defined(program.vertexShader)) { + program.vertexShader = globalMapping.shaders[program.vertexShader]; + } + if (defined(program.fragmentShader)) { + program.fragmentShader = globalMapping.shaders[program.fragmentShader]; + } + }); + ForEach.technique(gltf, function(technique) { + if (defined(technique.program)) { + technique.program = globalMapping.programs[technique.program]; + } + ForEach.techniqueParameter(technique, function(parameter) { + if (defined(parameter.node)) { + 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]]; + } + } + }); + }); + ForEach.mesh(gltf, function(mesh) { + ForEach.meshPrimitive(mesh, function(primitive) { + if (defined(primitive.indices)) { + primitive.indices = globalMapping.accessors[primitive.indices]; + } + ForEach.meshPrimitiveAttribute(primitive, function(accessorId, semantic) { + primitive.attributes[semantic] = globalMapping.accessors[accessorId]; + }); + if (defined(primitive.material)) { + primitive.material = globalMapping.materials[primitive.material]; + } + }); + }); + ForEach.skin(gltf, function(skin) { + if (defined(skin.inverseBindMatrices)) { + skin.inverseBindMatrices = globalMapping.accessors[skin.inverseBindMatrices]; + } + }); + ForEach.node(gltf, function(node) { + var children = node.children; + if (defined(children)) { + var childrenLength = children.length; + for (i = 0; i < childrenLength; i++) { + children[i] = globalMapping.nodes[children[i]]; + } + } + if (defined(node.meshes)) { + // Split out meshes on nodes + var meshes = node.meshes; + var meshesLength = meshes.length; + if (meshesLength > 0) { + node.mesh = globalMapping.meshes[meshes[0]]; + for (i = 1; i < meshesLength; i++) { + var meshNode = { + mesh: globalMapping.meshes[meshes[i]], + extras: { + _pipeline: {} + } + }; + var meshNodeId = addToArray(gltf.nodes, meshNode); + if (!defined(children)) { + children = []; + node.children = children; + } + children.push(meshNodeId); + } + } + delete node.meshes; + } + if (defined(node.camera)) { + node.camera = globalMapping.cameras[node.camera]; + } + if (defined(node.skeletons)) { + // Split out skeletons on nodes + var skeletons = node.skeletons; + var skeletonsLength = skeletons.length; + if (skeletonsLength > 0) { + node.skeleton = globalMapping.nodes[skeletons[0]]; + for (i = 1; i < skeletonsLength; i++) { + var skeletonNode = { + skeleton: globalMapping.nodes[skeletons[i]] + }; + var skeletonNodeId = addToArray(gltf.nodes, skeletonNode); + if (!defined(children)) { + children = []; + node.children = children; + } + children.push(skeletonNodeId); + } + } + delete node.skeletons; + } + if (defined(node.skin)) { + node.skin = globalMapping.skins[node.skin]; + } + }); + ForEach.scene(gltf, function(scene) { + var sceneNodes = scene.nodes; + if (defined(sceneNodes)) { + var sceneNodesLength = sceneNodes.length; + for (i = 0; i < sceneNodesLength; i++) { + sceneNodes[i] = globalMapping.nodes[sceneNodes[i]]; + } + } + }); + ForEach.animation(gltf, function(animation) { + var samplerMapping = {}; + animation.samplers = objectToArray(animation.samplers, samplerMapping); + ForEach.animationSampler(animation, function(sampler) { + 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]; + } + } + } + }); + 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') { + material.values[name] = [globalMapping.textures[value]]; + } + }); + var extensions = material.extensions; + if (defined(extensions)) { + 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') { + materialsCommon.values[name] = [globalMapping.textures[value]]; + } + }); + } + } + }); + ForEach.image(gltf, function(image) { + var extensions = image.extensions; + if (defined(extensions)) { + var binaryGltf = extensions.KHR_binary_glTF; + if (defined(binaryGltf)) { + image.bufferView = globalMapping.bufferViews[binaryGltf.bufferView]; + image.mimeType = binaryGltf.mimeType; + delete extensions.KHR_binary_glTF; + } + if (Object.keys(extensions).length === 0) { + delete image.extensions; + } + } + }); + ForEach.texture(gltf, function(texture) { + if (defined(texture.sampler)) { + texture.sampler = globalMapping.samplers[texture.sampler]; + } + if (defined(texture.source)) { + texture.source = globalMapping.images[texture.source]; + } + }); +} + +function stripProfile(gltf) { + var asset = gltf.asset; + delete asset.profile; +} + +var knownExtensions = { + 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++) { + var extension = extensionsUsed[i]; + if (defined(knownExtensions[extension])) { + gltf.extensionsRequired.push(extension); + } + } + } +} + +function removeBufferType(gltf) { + ForEach.buffer(gltf, function(buffer) { + delete buffer.type; + + }); +} + +function makeMaterialValuesArrays(gltf) { + ForEach.material(gltf, function(material) { + ForEach.materialValue(material, function(value, name) { + if (!Array.isArray(value)) { + material.values[name] = [value]; + } + }) ; + }); +} + +function requireAttributeSetIndex(gltf) { + ForEach.mesh(gltf, function(mesh) { + ForEach.meshPrimitive(mesh, function(primitive) { + ForEach.meshPrimitiveAttribute(primitive, function(accessorId, semantic) { + if (semantic === 'TEXCOORD') { + primitive.attributes.TEXCOORD_0 = accessorId; + } else if (semantic === 'COLOR') { + primitive.attributes.COLOR_0 = accessorId; + } + }); + delete primitive.attributes.TEXCOORD; + delete primitive.attributes.COLOR; + }); + }); + ForEach.technique(gltf, function(technique) { + ForEach.techniqueParameter(technique, function(parameter) { + var semantic = parameter.semantic; + if (defined(semantic)) { + if (semantic === 'TEXCOORD') { + parameter.semantic = 'TEXCOORD_0'; + } else if (semantic === 'COLOR') { + parameter.semantic = 'COLOR_0'; + } + } + }); + }); +} + +var knownSemantics = { + POSITION: true, + NORMAL: true, + TEXCOORD: true, + COLOR: true, + JOINT: true, + WEIGHT: true +}; +function underscoreApplicationSpecificSemantics(gltf) { + var mappedSemantics = {}; + ForEach.mesh(gltf, function(mesh) { + ForEach.meshPrimitive(mesh, function(primitive) { + /* jshint unused:vars */ + ForEach.meshPrimitiveAttribute(primitive, function(accessorId, semantic) { + if (semantic.charAt(0) !== '_') { + var setIndex = semantic.search(/_[0-9]+/g); + var strippedSemantic = semantic; + if (setIndex >= 0) { + strippedSemantic = semantic.substring(0, setIndex); + } + if (!defined(knownSemantics[strippedSemantic])) { + var newSemantic = '_' + semantic; + mappedSemantics[semantic] = newSemantic; + } + } + }); + for(var semantic in mappedSemantics) { + if (mappedSemantics.hasOwnProperty(semantic)) { + var mappedSemantic = mappedSemantics[semantic]; + var accessorId = primitive.attributes[semantic]; + delete primitive.attributes[semantic]; + primitive.attributes[mappedSemantic] = accessorId; + } + } + }); + }); + ForEach.technique(gltf, function(technique) { + ForEach.techniqueParameter(technique, function(parameter) { + var mappedSemantic = mappedSemantics[parameter.semantic]; + if (defined(mappedSemantic)) { + parameter.semantic = mappedSemantic; + } + }); + }); +} + +function makeTechniqueValuesArrays(gltf) { + ForEach.technique(gltf, function(technique) { + ForEach.techniqueParameter(technique, function(parameter) { + var value = parameter.value; + if (defined(value) && !Array.isArray(value)) { + parameter.value = [value]; + } + }); + }); +} + +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) { + var i; + 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 (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; + if (defined(perspective)) { + var aspectRatio = perspective.aspectRatio; + if (defined(aspectRatio) && aspectRatio === 0.0) { + delete perspective.aspectRatio; + } + var yfov = perspective.yfov; + if (defined(yfov) && yfov === 0.0) { + perspective.yfov = 1.0; + } + } + }); +} + +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; + } + }); +} + +function moveByteStrideToBufferView(gltf) { + ForEach.accessor(gltf, function(accessor) { + if (defined(accessor.byteStride)) { + var byteStride = accessor.byteStride; + if (byteStride !== 0) { + var bufferView = gltf.bufferViews[accessor.bufferView]; + if (defined(bufferView.byteStride) && bufferView.byteStride !== byteStride) { + // another accessor uses this with a different byte stride + bufferView = clone(bufferView); + accessor.bufferView = addToArray(gltf.bufferViews, bufferView); + } + bufferView.byteStride = byteStride; + } + delete accessor.byteStride; + } + }); +} + +function requireAccessorMinMax(gltf) { + ForEach.accessor(gltf, function(accessor) { + if (!defined(accessor.min) || !defined(accessor.max)) { + var minMax = findAccessorMinMax(gltf, accessor); + accessor.min = minMax.min; + accessor.max = minMax.max; + } + }); +} + +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; + } + }); + }); +} + +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 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 = {}; + } + var asset = gltf.asset; + asset.version = '2.0'; + // 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 + objectsToArrays(gltf); + // asset.profile no longer exists + stripProfile(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 + requireAccessorMinMax(gltf); + // buffer.type is unnecessary and should be removed + removeBufferType(gltf); + // TEXCOORD and COLOR attributes must be written with a set index (TEXCOORD_#) + requireAttributeSetIndex(gltf); + // Add underscores to application-specific parameters + underscoreApplicationSpecificSemantics(gltf); + // material.values should be arrays + makeMaterialValuesArrays(gltf); + // technique.parameters.value should be arrays + makeTechniqueValuesArrays(gltf); + // remove scissor from techniques + removeScissorFromTechniques(gltf); + // clamp technique function states to min/max + clampTechniqueFunctionStates(gltf); + // 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); } diff --git a/lib/writeBinaryGltf.js b/lib/writeBinaryGltf.js index 4dc28373..8c84aebc 100644 --- a/lib/writeBinaryGltf.js +++ b/lib/writeBinaryGltf.js @@ -3,13 +3,13 @@ var Cesium = require('cesium'); var fsExtra = require('fs-extra'); var path = require('path'); var Promise = require('bluebird'); +var ForEach = require('./ForEach'); +var getBinaryGltf = require('./getBinaryGltf'); +var writeSource = require('./writeSource'); var defined = Cesium.defined; var DeveloperError = Cesium.DeveloperError; -var getBinaryGltf = require('./getBinaryGltf'); -var writeSource = require('./writeSource'); - fsExtra.outputFileAsync = Promise.promisify(fsExtra.outputFile); module.exports = writeBinaryGltf; @@ -32,8 +32,6 @@ module.exports = writeBinaryGltf; */ function writeBinaryGltf(gltf, options) { var outputPath = options.outputPath; - var embed = options.embed; - var embedImage = options.embedImage; var createDirectory = options.createDirectory; if (!defined(outputPath)) { throw new DeveloperError('Output path is undefined.'); @@ -51,25 +49,21 @@ function writeBinaryGltf(gltf, options) { var basePath = path.dirname(outputPath); var writeSources = [ - writeSource(gltf.images, 'images', basePath, embed, embedImage), - writeSource(gltf.shaders, 'shaders', basePath, embed, embedImage) + writeSource(gltf.images, 'images', basePath, options), + writeSource(gltf.shaders, 'shaders', basePath, options) ]; // Write sources for compressed textures - var images = gltf.images; - for (var imageId in images) { - if (images.hasOwnProperty(imageId)) { - var image = images[imageId]; - if (defined(image.extras) && defined(image.extras.compressedImage3DTiles)) { - var compressedImages = image.extras.compressedImage3DTiles; - writeSources.push(writeSource(compressedImages, 'images', basePath, embed, embedImage)); - } + ForEach.image(gltf, function(image) { + if (defined(image.extras) && defined(image.extras.compressedImage3DTiles)) { + var compressedImages = image.extras.compressedImage3DTiles; + writeSources.push(writeSource(compressedImages, 'images', basePath, options)); } - } + }); return Promise.all(writeSources) .then(function() { - var glbData = getBinaryGltf(gltf, embed, embedImage); + var glbData = getBinaryGltf(gltf, options); var glb = glbData.glb; return fsExtra.outputFileAsync(outputPath, glb); }); diff --git a/lib/writeGltf.js b/lib/writeGltf.js index 013d1e91..fd3e9e83 100755 --- a/lib/writeGltf.js +++ b/lib/writeGltf.js @@ -3,13 +3,13 @@ var Cesium = require('cesium'); var fsExtra = require('fs-extra'); var path = require('path'); var Promise = require('bluebird'); +var ForEach = require('./ForEach'); +var removePipelineExtras = require('./removePipelineExtras'); +var writeSource = require('./writeSource'); var defined = Cesium.defined; var DeveloperError = Cesium.DeveloperError; -var removePipelineExtras = require('./removePipelineExtras'); -var writeSource = require('./writeSource'); - fsExtra.outputJsonAsync = Promise.promisify(fsExtra.outputJson); module.exports = writeGltf; @@ -32,8 +32,6 @@ module.exports = writeGltf; */ function writeGltf(gltf, options) { var outputPath = options.outputPath; - var embed = options.embed; - var embedImage = options.embedImage; var createDirectory = options.createDirectory; if (!defined(outputPath)) { @@ -52,22 +50,18 @@ function writeGltf(gltf, options) { var basePath = path.dirname(outputPath); var writeSources = [ - writeSource(gltf.buffers, 'buffers', basePath, embed, embedImage), - writeSource(gltf.images, 'images', basePath, embed, embedImage), - writeSource(gltf.shaders, 'shaders', basePath, embed, embedImage) + writeSource(gltf.buffers, 'buffers', basePath, options), + writeSource(gltf.images, 'images', basePath, options), + writeSource(gltf.shaders, 'shaders', basePath, options) ]; // Write sources for compressed textures - var images = gltf.images; - for (var imageId in images) { - if (images.hasOwnProperty(imageId)) { - var image = images[imageId]; - if (defined(image.extras) && defined(image.extras.compressedImage3DTiles)) { - var compressedImages = image.extras.compressedImage3DTiles; - writeSources.push(writeSource(compressedImages, 'images', basePath, embed, embedImage)); - } + ForEach.image(gltf, function(image) { + if (defined(image.extras) && defined(image.extras.compressedImage3DTiles)) { + var compressedImages = image.extras.compressedImage3DTiles; + writeSources.push(writeSource(compressedImages, 'images', basePath, options)); } - } + }); return Promise.all(writeSources) .then(function() { diff --git a/lib/writeSource.js b/lib/writeSource.js index 9050d0d7..a1654b04 100644 --- a/lib/writeSource.js +++ b/lib/writeSource.js @@ -4,44 +4,71 @@ var fsExtra = require('fs-extra'); var mime = require('mime'); var path = require('path'); var Promise = require('bluebird'); +var ForEach = require('./ForEach'); +var isDataUri = require('./isDataUri'); var defaultValue = Cesium.defaultValue; var defined = Cesium.defined; var fsOutputFile = Promise.promisify(fsExtra.outputFile); +// .crn (Crunch) is not a supported mime type, so add it +mime.define({'image/crn': ['crn']}); + module.exports = writeSource; /** * @private */ -function writeSource(objects, name, basePath, embed, embedImage) { +function writeSource(arrayOfObjects, name, basePath, options) { + var embed = defaultValue(options.embed, true); + var embedImage = defaultValue(options.embedImage, true); var promises = []; - for (var id in objects) { - if (objects.hasOwnProperty(id)) { - var object = objects[id]; - if (defined(object.extras._pipeline.source)) { - var pipelineExtras = object.extras._pipeline; - var source = pipelineExtras.source; - var extension = pipelineExtras.extension; + ForEach.object(arrayOfObjects, function(object, i) { + if (defined(object.extras._pipeline.source)) { + var pipelineExtras = object.extras._pipeline; + var source = pipelineExtras.source; + var extension = pipelineExtras.extension; - if (embed && (embedImage || name !== 'images') || !defined(basePath)) { - if (name === 'shaders') { - object.uri = 'data:text/plain;base64,' + new Buffer(source).toString('base64'); - } else { - // .crn (Crunch) is not a supported mime type, so add it - mime.define({'image/crn' : ['crn']}); - object.uri = 'data:' + mime.lookup(extension) + ';base64,' + source.toString('base64'); - } + // Write sources for compressed textures + if (name === 'images') { + var image = object; + if (defined(image.extras) && defined(image.extras.compressedImage3DTiles)) { + var compressedImages = image.extras.compressedImage3DTiles; + promises.push(writeSource(compressedImages, 'images', undefined, embed, embedImage)); + } + } + + if (embed && (embedImage || name !== 'images') || !defined(basePath)) { + if (name === 'shaders') { + object.uri = 'data:text/plain;base64,' + new Buffer(source).toString('base64'); } else { - // For compressed textures use the name stored in the extras rather than the id - var fileName = defaultValue(pipelineExtras.name, id) + extension; - object.uri = fileName; - var outputPath = path.join(basePath, fileName); - promises.push(fsOutputFile(outputPath, source)); + var mimeType = object.mimeType; + if (!defined(mimeType)) { + mimeType = mime.lookup(extension); + } + object.uri = 'data:' + mimeType + ';base64,' + source.toString('base64'); + } + } else { + var fileName = i + extension; + // Use the name if we have one + if (defined(object.name)) { + fileName = object.name + extension; + } + var uri = object.uri; + if (defined(uri) && !isDataUri(uri)) { + // Use the original filename if it was external + fileName = uri; + } + // For compressed textures use the name stored in the extras rather than the id + if (defined(pipelineExtras.name)) { + fileName = pipelineExtras.name + extension; } + object.uri = fileName; + var outputPath = path.join(basePath, fileName); + promises.push(fsOutputFile(outputPath, source)); } } - } + }); return Promise.all(promises); } diff --git a/specs/data/ambientOcclusion/cube_over_ground.gltf b/specs/data/ambientOcclusion/cube_over_ground.gltf index a59f7742..7ee96cc9 100644 --- a/specs/data/ambientOcclusion/cube_over_ground.gltf +++ b/specs/data/ambientOcclusion/cube_over_ground.gltf @@ -1,15 +1,15 @@ { - "accessors": { - "accessor_21": { - "bufferView": "bufferView_56", + "accessors": [ + { + "bufferView": 0, "byteOffset": 0, "byteStride": 0, "componentType": 5123, "count": 36, "type": "SCALAR" }, - "accessor_23": { - "bufferView": "bufferView_57", + { + "bufferView": 1, "byteOffset": 0, "byteStride": 12, "componentType": 5126, @@ -26,8 +26,8 @@ ], "type": "VEC3" }, - "accessor_25": { - "bufferView": "bufferView_57", + { + "bufferView": 1, "byteOffset": 432, "byteStride": 12, "componentType": 5126, @@ -44,8 +44,8 @@ ], "type": "VEC3" }, - "accessor_27": { - "bufferView": "bufferView_57", + { + "bufferView": 1, "byteOffset": 864, "byteStride": 8, "componentType": 5126, @@ -60,16 +60,16 @@ ], "type": "VEC2" }, - "accessor_48": { - "bufferView": "bufferView_56", + { + "bufferView": 0, "byteOffset": 72, "byteStride": 0, "componentType": 5123, "count": 36, "type": "SCALAR" }, - "accessor_50": { - "bufferView": "bufferView_57", + { + "bufferView": 1, "byteOffset": 1152, "byteStride": 12, "componentType": 5126, @@ -86,8 +86,8 @@ ], "type": "VEC3" }, - "accessor_52": { - "bufferView": "bufferView_57", + { + "bufferView": 1, "byteOffset": 1584, "byteStride": 12, "componentType": 5126, @@ -104,8 +104,8 @@ ], "type": "VEC3" }, - "accessor_54": { - "bufferView": "bufferView_57", + { + "bufferView": 1, "byteOffset": 2016, "byteStride": 8, "componentType": 5126, @@ -120,55 +120,54 @@ ], "type": "VEC2" } - }, - "animations": {}, + ], + "animations": [], "asset": { - "generator": "collada2gltf@", "premultipliedAlpha": true, "profile": { "api": "WebGL", - "version": "1.0.2" + "version": "1.0" }, - "version": "1.0" + "version": "2.0" }, - "bufferViews": { - "bufferView_56": { - "buffer": "cube_over_ground", + "bufferViews": [ + { + "buffer": 0, "byteLength": 144, "byteOffset": 0, "target": 34963 }, - "bufferView_57": { - "buffer": "cube_over_ground", + { + "buffer": 0, "byteLength": 2304, "byteOffset": 144, "target": 34962 } - }, - "buffers": { - "cube_over_ground": { + ], + "buffers": [ + { "byteLength": 2448, "type": "arraybuffer", "uri": "data:application/octet-stream;base64,AAABAAIAAwAEAAUABgAHAAgACQAKAAsADAANAA4ADwAQABEAEgATABQAFQAWABcAGAAZABoAGwAcAB0AHgAfACAAIQAiACMAAAABAAIAAwAEAAUABgAHAAgACQAKAAsADAANAA4ADwAQABEAEgATABQAFQAWABcAGAAZABoAGwAcAB0AHgAfACAAIQAiACMAAACAPwAAgD8AAIC/AACAvwAAgL8AAIC/AACAvwAAgD8AAIC/AACAvwAAgD8AAIA/7/9/PwAAgL8AAIA/AACAPwAAgD8AAIA/AACAPwAAgD8AAIA/AACAPwAAgL8AAIC/AACAPwAAgD8AAIC/7/9/PwAAgL8AAIA/AACAvwAAgL8AAIC/AACAPwAAgL8AAIC/AACAvwAAgL8AAIC/AACAvwAAgD8AAIA/AACAvwAAgD8AAIC/AACAPwAAgD8AAIC/AACAvwAAgD8AAIA/AACAPwAAgD8AAIA/AACAPwAAgD8AAIC/AACAPwAAgL8AAIC/AACAvwAAgL8AAIC/AACAvwAAgD8AAIA/AACAvwAAgL8AAIA/7/9/PwAAgL8AAIA/AACAPwAAgD8AAIA/7/9/PwAAgL8AAIA/AACAPwAAgL8AAIC/7/9/PwAAgL8AAIA/AACAvwAAgL8AAIA/AACAvwAAgL8AAIC/AACAvwAAgL8AAIC/AACAvwAAgL8AAIA/AACAvwAAgD8AAIA/AACAPwAAgD8AAIC/AACAvwAAgD8AAIC/AACAvwAAgD8AAIA/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AACAPwAAAAAPAIC0AACAPwAAAAAPAIC0AACAPwAAAAAPAIC0AAAAAAAAgL/6//+0AAAAAAAAgL/6//+0AAAAAAAAgL/6//+0AACAvw8AgDQbACC0AACAvw8AgDQbACC0AACAvw8AgDQbACC0AwCQNAAAgD8PAIA0AwCQNAAAgD8PAIA0AwCQNAAAgD8PAIA0AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AACAP/j/H7Xt/680AACAP/j/H7Xt/680AACAP/j/H7Xt/680+v//tAAAgL8AAAAA+v//tAAAgL8AAAAA+v//tAAAgL8AAAAAAACAvw8AgDTX//+zAACAvw8AgDTX//+zAACAvw8AgDTX//+z7v9fNAAAgD8AAAAA7v9fNAAAgD8AAAAA7v9fNAAAgD8AAAAAAAAAAKCqqj6fqqo+AAAAAAAAAAAAAAAAn6qqPqCqqj4AAAAAoKoqP5+qqj6wqio/n6qqPrCqKj+wqio/AACAP7CqKj+wqio/AAAAAP7/fz+fqqo+sKoqPwAAAACwqio/AACAP7CqKj+wqio/AACAPwAAgD8AAIA/sKoqP7CqKj+fqqo+oKqqPp+qqj6wqio/AAAAAKCqqj6fqqo+oKqqPp+qqj4AAAAAn6qqPqCqqj4AAAAAoKqqPgAAAACgqio/n6qqPrCqKj+fqqo+AACAP7CqKj8AAIA/AAAAAP7/fz+fqqo+AACAP5+qqj6wqio/AACAP7CqKj+wqio/sKoqP7CqKj8AAIA/sKoqP7CqKj+wqio/oKqqPp+qqj6gqqo+AACAvwAAgD8AAIA/AACAvwAAgL8AAIC/AACAvwAAgL8AAIA/AACAPwAAgD8AAIA/AACAvwAAgD8AAIC/AACAvwAAgD8AAIA/AACAPwAAgL8AAIA/AACAPwAAgD8AAIC/AACAPwAAgD8AAIA/AACAvwAAgL8AAIA/AACAPwAAgL8AAIC/AACAPwAAgL8AAIA/AACAvwAAgD8AAIC/AACAPwAAgL8AAIC/AACAvwAAgL8AAIC/AACAPwAAgD8AAIA/AACAvwAAgL8AAIA/AACAPwAAgL8AAIA/AACAvwAAgD8AAIA/AACAvwAAgD8AAIC/AACAvwAAgL8AAIC/AACAPwAAgD8AAIA/AACAPwAAgD8AAIC/AACAvwAAgD8AAIC/AACAPwAAgL8AAIA/AACAPwAAgL8AAIC/AACAPwAAgD8AAIC/AACAvwAAgL8AAIA/AACAvwAAgL8AAIC/AACAPwAAgL8AAIC/AACAvwAAgD8AAIC/AACAPwAAgD8AAIC/AACAPwAAgL8AAIC/AACAPwAAgD8AAIA/AACAvwAAgD8AAIA/AACAvwAAgL8AAIA/AACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/n6qqPgAAgD+wqio/sKoqP5+qqj6wqio/AAAAALCqKj+fqqo+oKqqPgAAAACgqqo+AAAAAAAAgD+fqqo+sKoqP4+qCjSwqio/sKoqP7CqKj+fqqo+oKqqPp+qqj6wqio/AACAP7CqKj+wqio/AACAPwAAgD8AAIA/n6qqPqCqqj4AAAAAAAAAAAAAAACgqqo+n6qqPgAAgD+wqio/AACAP7CqKj+wqio/AAAAALCqKj+fqqo+sKoqP5+qqj6gqqo+AAAAAAAAgD+fqqo+AACAP5+qqj6wqio/sKoqP7CqKj+wqio/oKqqPp+qqj6gqqo+AACAP7CqKj+wqio/sKoqP7CqKj8AAIA/n6qqPqCqqj6fqqo+AAAAAAAAAAAAAAAA" } - }, - "images": { - "Untitled": { + ], + "images": [ + { "name": "Untitled", "uri": "data:image/png;base64,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" }, - "Untitled_001": { + { "name": "Untitled_001", "uri": "data:image/png;base64,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" } - }, - "materials": { - "Material-effect": { + ], + "materials": [ + { "name": "Material-effect", - "technique": "technique0", + "technique": 0, "values": { - "diffuse": "texture_Untitled", - "shininess": 256, + "diffuse": [0], + "shininess": [256], "specular": [ 0.2, 0.2, @@ -177,12 +176,12 @@ ] } }, - "Material_001-effect": { + { "name": "Material_001", - "technique": "technique0", + "technique": 0, "values": { - "diffuse": "texture_Untitled_001", - "shininess": 256, + "diffuse": [1], + "shininess": [256], "specular": [ 0.2, 0.2, @@ -191,12 +190,12 @@ ] } }, - "useless-material": { + { "name": "useless", - "technique": "technique0", + "technique": 0, "values": { - "diffuse": "texture_Untitled_001", - "shininess": 256, + "diffuse": [1], + "shininess": [256], "specular": [ 0.2, 0.2, @@ -205,86 +204,86 @@ ] } } - }, - "meshes": { - "Cube_mesh": { + ], + "meshes": [ + { "name": "Cube", "primitives": [ { "attributes": { - "NORMAL": "accessor_25", - "POSITION": "accessor_23", - "TEXCOORD_0": "accessor_27" + "NORMAL": 2, + "POSITION": 1, + "TEXCOORD_0": 3 }, - "indices": "accessor_21", - "material": "Material-effect", + "indices": 0, + "material": 0, "mode": 4 } ] }, - "Cube_001_mesh": { + { "name": "Cube.001", "primitives": [ { "attributes": { - "NORMAL": "accessor_52", - "POSITION": "accessor_50", - "TEXCOORD_0": "accessor_54" + "NORMAL": 6, + "POSITION": 5, + "TEXCOORD_0": 7 }, - "indices": "accessor_48", - "material": "Material_001-effect", + "indices": 4, + "material": 1, "mode": 4 } ] }, - "useless_mesh": { + { "name": "Cube.001", "primitives": [ { "attributes": { - "NORMAL": "accessor_52", - "POSITION": "accessor_50", - "TEXCOORD_0": "accessor_54" + "NORMAL": 6, + "POSITION": 5, + "TEXCOORD_0": 7 }, - "indices": "accessor_48", - "material": "Material_001-effect", + "indices": 4, + "material": 1, "mode": 4 }, { "attributes": { - "NORMAL": "accessor_52", - "POSITION": "accessor_50", - "TEXCOORD_0": "accessor_54" + "NORMAL": 6, + "POSITION": 5, + "TEXCOORD_0": 7 }, - "indices": "accessor_48", - "material": "Material_001-effect", + "indices": 4, + "material": 1, "mode": 4 }, { "attributes": { - "NORMAL": "accessor_52", - "POSITION": "accessor_50", - "TEXCOORD_0": "accessor_54" + "NORMAL": 6, + "POSITION": 5, + "TEXCOORD_0": 7 }, - "indices": "accessor_48", - "material": "useless-material", + "indices": 4, + "material": 2, "mode": 4 }, { "attributes": { - "NORMAL": "accessor_52", - "POSITION": "accessor_50", - "TEXCOORD_0": "accessor_54" + "NORMAL": 6, + "POSITION": 5, + "TEXCOORD_0": 7 }, - "indices": "accessor_48", - "material": "useless-material", + "indices": 4, + "material": 2, "mode": 4 } ] } - }, - "nodes": { - "Cube": { + ], + "nodes": [ + { "children": [], "matrix": [ 1, @@ -304,12 +303,10 @@ 0, 1 ], - "meshes": [ - "Cube_mesh" - ], + "mesh": 0, "name": "Cube" }, - "Cube_001": { + { "children": [], "matrix": [ 2, @@ -329,15 +326,13 @@ -1.3000000715255737, 1 ], - "meshes": [ - "Cube_001_mesh" - ], + "mesh": 1, "name": "Cube_001" }, - "node_2": { + { "children": [ - "Cube", - "Cube_001" + 0, + 1 ], "matrix": [ 1, @@ -359,7 +354,7 @@ ], "name": "Y_UP_Transform" }, - "useless_node": { + { "children": [], "matrix": [ 1, @@ -379,59 +374,55 @@ 0, 1 ], - "meshes": [ - "useless_mesh" - ], + "mesh": 2, "name": "useless Cube" } - }, - "programs": { - "program_0": { + ], + "programs": [ + { "attributes": [ "a_normal", "a_position", "a_texcoord0" ], - "fragmentShader": "cube_over_ground0FS", - "vertexShader": "cube_over_ground0VS" + "fragmentShader": 0, + "vertexShader": 1 } - }, - "samplers": { - "sampler_0": { + ], + "samplers": [ + { "magFilter": 9729, "minFilter": 9987, "wrapS": 10497, "wrapT": 10497 } - }, - "scene": "defaultScene", - "scenes": { - "defaultScene": { + ], + "scene": 0, + "scenes": [ + { "nodes": [ - "node_2" - ], - "node": [] + 2 + ] }, - "uselessScene": { + { "nodes": [ - "useless_node" - ], - "node": [] + 3 + ] } - }, - "shaders": { - "cube_over_ground0FS": { + ], + "shaders": [ + { "type": 35632, "uri": "data:text/plain;base64,cHJlY2lzaW9uIGhpZ2hwIGZsb2F0Ow0KdmFyeWluZyB2ZWMzIHZfbm9ybWFsOw0KdmFyeWluZyB2ZWMyIHZfdGV4Y29vcmQwOw0KdW5pZm9ybSBzYW1wbGVyMkQgdV9kaWZmdXNlOw0KdW5pZm9ybSB2ZWM0IHVfc3BlY3VsYXI7DQp1bmlmb3JtIGZsb2F0IHVfc2hpbmluZXNzOw0Kdm9pZCBtYWluKHZvaWQpIHsNCnZlYzMgbm9ybWFsID0gbm9ybWFsaXplKHZfbm9ybWFsKTsNCnZlYzQgY29sb3IgPSB2ZWM0KDAuLCAwLiwgMC4sIDAuKTsNCnZlYzQgZGlmZnVzZSA9IHZlYzQoMC4sIDAuLCAwLiwgMS4pOw0KdmVjNCBzcGVjdWxhcjsNCmRpZmZ1c2UgPSB0ZXh0dXJlMkQodV9kaWZmdXNlLCB2X3RleGNvb3JkMCk7DQpzcGVjdWxhciA9IHVfc3BlY3VsYXI7DQpkaWZmdXNlLnh5eiAqPSBtYXgoZG90KG5vcm1hbCx2ZWMzKDAuLDAuLDEuKSksIDAuKTsNCmNvbG9yLnh5eiArPSBkaWZmdXNlLnh5ejsNCmNvbG9yID0gdmVjNChjb2xvci5yZ2IgKiBkaWZmdXNlLmEsIGRpZmZ1c2UuYSk7DQpnbF9GcmFnQ29sb3IgPSBjb2xvcjsNCn0NCg==" }, - "cube_over_ground0VS": { + { "type": 35633, "uri": "data:text/plain;base64,cHJlY2lzaW9uIGhpZ2hwIGZsb2F0Ow0KYXR0cmlidXRlIHZlYzMgYV9wb3NpdGlvbjsNCmF0dHJpYnV0ZSB2ZWMzIGFfbm9ybWFsOw0KdmFyeWluZyB2ZWMzIHZfbm9ybWFsOw0KdW5pZm9ybSBtYXQzIHVfbm9ybWFsTWF0cml4Ow0KdW5pZm9ybSBtYXQ0IHVfbW9kZWxWaWV3TWF0cml4Ow0KdW5pZm9ybSBtYXQ0IHVfcHJvamVjdGlvbk1hdHJpeDsNCmF0dHJpYnV0ZSB2ZWMyIGFfdGV4Y29vcmQwOw0KdmFyeWluZyB2ZWMyIHZfdGV4Y29vcmQwOw0Kdm9pZCBtYWluKHZvaWQpIHsNCnZlYzQgcG9zID0gdV9tb2RlbFZpZXdNYXRyaXggKiB2ZWM0KGFfcG9zaXRpb24sMS4wKTsNCnZfbm9ybWFsID0gdV9ub3JtYWxNYXRyaXggKiBhX25vcm1hbDsNCnZfdGV4Y29vcmQwID0gYV90ZXhjb29yZDA7DQpnbF9Qb3NpdGlvbiA9IHVfcHJvamVjdGlvbk1hdHJpeCAqIHBvczsNCn0NCg==" } - }, - "skins": {}, - "techniques": { - "technique0": { + ], + "skins": [], + "techniques": [ + { "attributes": { "a_normal": "normal", "a_position": "position", @@ -472,7 +463,7 @@ "type": 35664 } }, - "program": "program_0", + "program": 0, "states": { "enable": [ 2929, @@ -489,27 +480,27 @@ "u_specular": "specular" } } - }, - "textures": { - "texture_Untitled": { + ], + "textures": [ + { "format": 6408, "internalFormat": 6408, - "sampler": "sampler_0", - "source": "Untitled", + "sampler": 0, + "source": 0, "target": 3553, "type": 5121 }, - "texture_Untitled_001": { + { "format": 6408, "internalFormat": 6408, - "sampler": "sampler_0", - "source": "Untitled_001", + "sampler": 0, + "source": 1, "target": 3553, "type": 5121 } - }, + ], "extensionsUsed": [], - "cameras": {}, + "cameras": [], "extensions": { "KHR_materials_common": { "lights": {} diff --git a/specs/data/boxTexturedUnoptimized/CesiumTexturedBoxTest.gltf b/specs/data/boxTexturedUnoptimized/CesiumTexturedBoxTest.gltf index 9073acdf..400bdefa 100644 --- a/specs/data/boxTexturedUnoptimized/CesiumTexturedBoxTest.gltf +++ b/specs/data/boxTexturedUnoptimized/CesiumTexturedBoxTest.gltf @@ -1,15 +1,15 @@ { - "accessors": { - "accessor_21": { - "bufferView": "bufferView_29", + "accessors": [ + { + "bufferView": 0, "byteOffset": 0, "byteStride": 0, "componentType": 5123, "count": 36, "type": "SCALAR" }, - "accessor_23": { - "bufferView": "bufferView_30", + { + "bufferView": 1, "byteOffset": 0, "byteStride": 12, "componentType": 5126, @@ -26,8 +26,8 @@ ], "type": "VEC3" }, - "accessor_25": { - "bufferView": "bufferView_30", + { + "bufferView": 1, "byteOffset": 288, "byteStride": 12, "componentType": 5126, @@ -44,8 +44,8 @@ ], "type": "VEC3" }, - "accessor_27": { - "bufferView": "bufferView_30", + { + "bufferView": 1, "byteOffset": 576, "byteStride": 8, "componentType": 5126, @@ -60,51 +60,44 @@ ], "type": "VEC2" } - }, - "animations": {}, + ], + "animations": [], "asset": { - "generator": "collada2gltf@ceec062e3d5793f2f249f53cbd843aee382ad40b", - "premultipliedAlpha": true, - "profile": { - "api": "WebGL", - "version": "1.0.2" - }, - "version": 1 + "version": "2.0" }, - "bufferViews": { - "bufferView_29": { - "buffer": "CesiumTexturedBoxTest", + "bufferViews": [ + { + "buffer": 0, "byteLength": 72, "byteOffset": 0, "target": 34963 }, - "bufferView_30": { - "buffer": "CesiumTexturedBoxTest", + { + "buffer": 0, "byteLength": 768, "byteOffset": 72, "target": 34962 } - }, - "buffers": { - "CesiumTexturedBoxTest": { + ], + "buffers": [ + { "byteLength": 840, - "type": "arraybuffer", "uri": "CesiumTexturedBoxTest.bin" } - }, - "images": { - "Image0001": { + ], + "images": [ + { "name": "Image0001", "uri": "Cesium_Logo_Flat.png" } - }, - "materials": { - "Effect-Texture": { + ], + "materials": [ + { "name": "Texture", - "technique": "technique0", + "technique": 0, "values": { - "diffuse": "texture_Image0001", - "shininess": 256, + "diffuse": [0], + "shininess": [256], "specular": [ 0.2, 0.2, @@ -113,26 +106,26 @@ ] } } - }, - "meshes": { - "Geometry-mesh002": { + ], + "meshes": [ + { "name": "Mesh", "primitives": [ { "attributes": { - "NORMAL": "accessor_25", - "POSITION": "accessor_23", - "TEXCOORD_0": "accessor_27" + "NORMAL": 2, + "POSITION": 1, + "TEXCOORD_0": 3 }, - "indices": "accessor_21", - "material": "Effect-Texture", + "indices": 0, + "material": 0, "mode": 4 } ] } - }, - "nodes": { - "Geometry-mesh002Node": { + ], + "nodes": [ + { "children": [], "matrix": [ 1, @@ -152,14 +145,12 @@ 0, 1 ], - "meshes": [ - "Geometry-mesh002" - ], + "mesh": 0, "name": "Mesh" }, - "groupLocator030Node": { + { "children": [ - "txtrLocator026Node" + 3 ], "matrix": [ 1, @@ -181,10 +172,10 @@ ], "name": "Texture_Group" }, - "node_3": { + { "children": [ - "Geometry-mesh002Node", - "groupLocator030Node" + 0, + 1 ], "matrix": [ 1, @@ -206,7 +197,7 @@ ], "name": "Y_UP_Transform" }, - "txtrLocator026Node": { + { "children": [], "matrix": [ 1, @@ -228,47 +219,47 @@ ], "name": "Cesium_Logo_Flat__Image___Texture_" } - }, - "programs": { - "program_0": { + ], + "programs": [ + { "attributes": [ "a_normal", "a_position", "a_texcoord0" ], - "fragmentShader": "CesiumTexturedBoxTest0FS", - "vertexShader": "CesiumTexturedBoxTest0VS" + "fragmentShader": 0, + "vertexShader": 1 } - }, - "samplers": { - "sampler_0": { + ], + "samplers": [ + { "magFilter": 9729, "minFilter": 9987, "wrapS": 10497, "wrapT": 10497 } - }, - "scene": "defaultScene", - "scenes": { - "defaultScene": { + ], + "scene": 0, + "scenes": [ + { "nodes": [ - "node_3" + 2 ] } - }, - "shaders": { - "CesiumTexturedBoxTest0FS": { + ], + "shaders": [ + { "type": 35632, "uri": "CesiumTexturedBoxTest0FS.glsl" }, - "CesiumTexturedBoxTest0VS": { + { "type": 35633, "uri": "CesiumTexturedBoxTest0VS.glsl" } - }, - "skins": {}, - "techniques": { - "technique0": { + ], + "skins": [], + "techniques": [ + { "attributes": { "a_normal": "normal", "a_position": "position", @@ -325,15 +316,15 @@ "u_specular": "specular" } } - }, - "textures": { - "texture_Image0001": { + ], + "textures": [ + { "format": 6408, "internalFormat": 6408, - "sampler": "sampler_0", - "source": "Image0001", + "sampler": 0, + "source": 0, "target": 3553, "type": 5121 } - } + ] } \ No newline at end of file diff --git a/specs/data/boxTexturedUnoptimized/CesiumTexturedBoxTestAddExtras.gltf b/specs/data/boxTexturedUnoptimized/CesiumTexturedBoxTestAddExtras.gltf index 113d39d9..67df8fcf 100644 --- a/specs/data/boxTexturedUnoptimized/CesiumTexturedBoxTestAddExtras.gltf +++ b/specs/data/boxTexturedUnoptimized/CesiumTexturedBoxTestAddExtras.gltf @@ -1,59 +1,58 @@ { - "accessors": { - "accessor_21": { - "bufferView": "bufferView_29", + "accessors": [ + { + "bufferView": 0, "byteOffset": 0, "componentType": 5123, "count": 36, "type": "SCALAR" } - }, - "animations": { - "animation_0": { + ], + "animations": [ + { "channels": [ { - "sampler": "animation_0_scale_sampler", + "sampler": 0, "target": { - "id": "Bone", + "id": 0, "path": "scale" } } ], - "samplers": { - "sampler": { + "samplers": [ + { "input": "TIME", "interpolation": "LINEAR", "output": "rotation" } - } + ] } - }, + ], "asset": { - "generator": "collada2gltf@ceec062e3d5793f2f249f53cbd843aee382ad40b", "premultipliedAlpha": true, "profile": { "api": "WebGL", - "version": "1.0.2" + "version": "1.0" }, - "version": 1 + "version": "2.0" }, - "bufferViews": { - "bufferView_29": { - "buffer": "CesiumTexturedBoxTest", + "bufferViews": [ + { + "buffer": 0, "byteLength": 72, "byteOffset": 0, "target": 34963 } - }, - "buffers": { - "CesiumTexturedBoxTest": { + ], + "buffers": [ + { "byteLength": 840, "type": "arraybuffer", "uri": "CesiumTexturedBoxTest.bin" } - }, - "cameras": { - "camera_0": { + ], + "cameras": [ + { "orthographic": { "xmag": 1.0, "ymag": 1.0, @@ -68,35 +67,35 @@ }, "type": "perspective" } - }, - "images": { - "Image0001": { + ], + "images": [ + { "uri": "Cesium_Logo_Flat.png" } - }, - "materials": { - "EffectTexture": { + ], + "materials": [ + { "name": "Texture", - "technique": "technique0", + "technique": 0, "values": { - "diffuse": "texture_Image0001", - "shininess": 256 + "diffuse": [0], + "shininess": [256] }, "extras": {} } - }, - "meshes": { - "mesh002": { + ], + "meshes": [ + { "name": "Mesh", "primitives": [ { "attributes": { - "NORMAL": "accessor_25", - "POSITION": "accessor_23", - "TEXCOORD_0": "accessor_27" + "NORMAL": 2, + "POSITION": 1, + "TEXCOORD_0": 3 }, - "indices": "accessor_21", - "material": "Effect-Texture", + "indices": 0, + "material": 0, "mode": 4, "extras": {} } @@ -105,59 +104,59 @@ "_pipeline": {} } } - }, - "nodes": { - "mesh002Node": { + ], + "nodes": [ + { "children": [], "meshes": [ - "Geometry-mesh002" + 0 ], "name": "Mesh", "extras": {} } - }, - "programs": { - "program_0": { + ], + "programs": [ + { "attributes": [ "a_normal", "a_position", "a_texcoord0" ], - "fragmentShader": "CesiumTexturedBoxTest0FS", - "vertexShader": "CesiumTexturedBoxTest0VS", + "fragmentShader": 0, + "vertexShader": 1, "extras": {} } - }, - "samplers": { - "sampler_0": { + ], + "samplers": [ + { "magFilter": 9729, "minFilter": 9987, "wrapS": 10497, "wrapT": 10497, "extras": {} } - }, - "scene": "defaultScene", - "scenes": { - "defaultScene": { + ], + "scene": 0, + "scenes": [ + { "nodes": [ - "node_3" + 0 ], "extras": {} } - }, - "shaders": { - "CesiumTexturedBoxTest0FS": { + ], + "shaders": [ + { "type": 35632, "uri": "CesiumTexturedBoxTest0FS.glsl", "extras": { "misc": {} } } - }, - "skins": { - "Armature_Cylinder_skin": { - "inverseBindMatrices": "IBM_Armature_Cylinder-skin", + ], + "skins": [ + { + "inverseBindMatrices": 0, "jointNames": [ "Bone", "Bone_001" @@ -167,9 +166,9 @@ "misc": {} } } - }, - "techniques": { - "technique0": { + ], + "techniques": [ + { "parameters": { "diffuse": { "type": 35678, @@ -198,18 +197,18 @@ "misc": {} } } - }, - "textures": { - "texture_Image0001": { + ], + "textures": [ + { "format": 6408, "internalFormat": 6408, - "sampler": "sampler_0", - "source": "Image0001", + "sampler": 0, + "source": 1, "target": 3553, "type": 5121, "extras": { "misc": {} } } - } + ] } \ No newline at end of file diff --git a/specs/data/boxTexturedUnoptimized/CesiumTexturedBoxTestEmbedded.gltf b/specs/data/boxTexturedUnoptimized/CesiumTexturedBoxTestEmbedded.gltf index 3e05ca2f..d6deea60 100644 --- a/specs/data/boxTexturedUnoptimized/CesiumTexturedBoxTestEmbedded.gltf +++ b/specs/data/boxTexturedUnoptimized/CesiumTexturedBoxTestEmbedded.gltf @@ -1,15 +1,15 @@ { - "accessors": { - "accessor_21": { - "bufferView": "bufferView_29", + "accessors": [ + { + "bufferView": 0, "byteOffset": 0, "byteStride": 0, "componentType": 5123, "count": 36, "type": "SCALAR" }, - "accessor_23": { - "bufferView": "bufferView_30", + { + "bufferView": 1, "byteOffset": 0, "byteStride": 12, "componentType": 5126, @@ -26,8 +26,8 @@ ], "type": "VEC3" }, - "accessor_25": { - "bufferView": "bufferView_30", + { + "bufferView": 1, "byteOffset": 288, "byteStride": 12, "componentType": 5126, @@ -44,8 +44,8 @@ ], "type": "VEC3" }, - "accessor_27": { - "bufferView": "bufferView_30", + { + "bufferView": 1, "byteOffset": 576, "byteStride": 8, "componentType": 5126, @@ -60,51 +60,50 @@ ], "type": "VEC2" } - }, - "animations": {}, + ], + "animations": [], "asset": { - "generator": "collada2gltf@ceec062e3d5793f2f249f53cbd843aee382ad40b", "premultipliedAlpha": true, "profile": { "api": "WebGL", - "version": "1.0.2" + "version": "1.0" }, - "version": 1 + "version": "2.0" }, - "bufferViews": { - "bufferView_29": { - "buffer": "CesiumTexturedBoxTest", + "bufferViews": [ + { + "buffer": 0, "byteLength": 72, "byteOffset": 0, "target": 34963 }, - "bufferView_30": { - "buffer": "CesiumTexturedBoxTest", + { + "buffer": 0, "byteLength": 768, "byteOffset": 72, "target": 34962 } - }, - "buffers": { - "CesiumTexturedBoxTest": { + ], + "buffers": [ + { "byteLength": 840, "type": "arraybuffer", "uri": "data:application/octet-stream;base64,AAABAAIAAwACAAEABAAFAAYABwAGAAUACAAJAAoACwAKAAkADAANAA4ADwAOAA0AEAARABIAEwASABEAFAAVABYAFwAWABUAAAAAvwAAAL8AAAA/AAAAPwAAAL8AAAA/AAAAvwAAAD8AAAA/AAAAPwAAAD8AAAA/AAAAPwAAAD8AAAA/AAAAPwAAAL8AAAA/AAAAPwAAAD8AAAC/AAAAPwAAAL8AAAC/AAAAvwAAAD8AAAA/AAAAPwAAAD8AAAA/AAAAvwAAAD8AAAC/AAAAPwAAAD8AAAC/AAAAPwAAAL8AAAA/AAAAvwAAAL8AAAA/AAAAPwAAAL8AAAC/AAAAvwAAAL8AAAC/AAAAvwAAAL8AAAA/AAAAvwAAAD8AAAA/AAAAvwAAAL8AAAC/AAAAvwAAAD8AAAC/AAAAvwAAAL8AAAC/AAAAvwAAAD8AAAC/AAAAPwAAAL8AAAC/AAAAPwAAAD8AAAC/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AADAQAAAAAAAAKBAAAAAAAAAwED+/38/AACgQP7/fz8AAIBAAAAAAAAAoEAAAAAAAACAQAAAgD8AAKBAAACAPwAAAEAAAAAAAACAPwAAAAAAAABAAACAPwAAgD8AAIA/AABAQAAAAAAAAIBAAAAAAAAAQEAAAIA/AACAQAAAgD8AAEBAAAAAAAAAAEAAAAAAAABAQAAAgD8AAABAAACAPwAAAAAAAAAAAAAAAP7/fz8AAIA/AAAAAAAAgD/+/38/" } - }, - "images": { - "Image0001": { + ], + "images": [ + { "name": "Image0001", "uri": "data:image/png;base64,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" } - }, - "materials": { - "Effect-Texture": { + ], + "materials": [ + { "name": "Texture", - "technique": "technique0", + "technique": 0, "values": { - "diffuse": "texture_Image0001", - "shininess": 256, + "diffuse": [0], + "shininess": [256], "specular": [ 0.2, 0.2, @@ -113,26 +112,26 @@ ] } } - }, - "meshes": { - "Geometry-mesh002": { + ], + "meshes": [ + { "name": "Mesh", "primitives": [ { "attributes": { - "NORMAL": "accessor_25", - "POSITION": "accessor_23", - "TEXCOORD_0": "accessor_27" + "NORMAL": 2, + "POSITION": 1, + "TEXCOORD_0": 3 }, - "indices": "accessor_21", - "material": "Effect-Texture", + "indices": 0, + "material": 0, "mode": 4 } ] } - }, - "nodes": { - "Geometry-mesh002Node": { + ], + "nodes": [ + { "children": [], "matrix": [ 1, @@ -152,14 +151,12 @@ 0, 1 ], - "meshes": [ - "Geometry-mesh002" - ], + "mesh": 0, "name": "Mesh" }, - "groupLocator030Node": { + { "children": [ - "txtrLocator026Node" + 3 ], "matrix": [ 1, @@ -181,10 +178,10 @@ ], "name": "Texture_Group" }, - "node_3": { + { "children": [ - "Geometry-mesh002Node", - "groupLocator030Node" + 0, + 1 ], "matrix": [ 1, @@ -206,7 +203,7 @@ ], "name": "Y_UP_Transform" }, - "txtrLocator026Node": { + { "children": [], "matrix": [ 1, @@ -228,47 +225,47 @@ ], "name": "Cesium_Logo_Flat__Image___Texture_" } - }, - "programs": { - "program_0": { + ], + "programs": [ + { "attributes": [ "a_normal", "a_position", "a_texcoord0" ], - "fragmentShader": "CesiumTexturedBoxTest0FS", - "vertexShader": "CesiumTexturedBoxTest0VS" + "fragmentShader": 0, + "vertexShader": 1 } - }, - "samplers": { - "sampler_0": { + ], + "samplers": [ + { "magFilter": 9729, "minFilter": 9987, "wrapS": 10497, "wrapT": 10497 } - }, - "scene": "defaultScene", - "scenes": { - "defaultScene": { + ], + "scene": 0, + "scenes": [ + { "nodes": [ - "node_3" + 2 ] } - }, - "shaders": { - "CesiumTexturedBoxTest0FS": { + ], + "shaders": [ + { "type": 35632, "uri": "data:text/plain;base64,cHJlY2lzaW9uIGhpZ2hwIGZsb2F0Ow0KdmFyeWluZyB2ZWMzIHZfbm9ybWFsOw0KdmFyeWluZyB2ZWMyIHZfdGV4Y29vcmQwOw0KdW5pZm9ybSBzYW1wbGVyMkQgdV9kaWZmdXNlOw0KdW5pZm9ybSB2ZWM0IHVfc3BlY3VsYXI7DQp1bmlmb3JtIGZsb2F0IHVfc2hpbmluZXNzOw0Kdm9pZCBtYWluKHZvaWQpIHsNCnZlYzMgbm9ybWFsID0gbm9ybWFsaXplKHZfbm9ybWFsKTsNCnZlYzQgY29sb3IgPSB2ZWM0KDAuLCAwLiwgMC4sIDAuKTsNCnZlYzQgZGlmZnVzZSA9IHZlYzQoMC4sIDAuLCAwLiwgMS4pOw0KdmVjNCBzcGVjdWxhcjsNCmRpZmZ1c2UgPSB0ZXh0dXJlMkQodV9kaWZmdXNlLCB2X3RleGNvb3JkMCk7DQpzcGVjdWxhciA9IHVfc3BlY3VsYXI7DQpkaWZmdXNlLnh5eiAqPSBtYXgoZG90KG5vcm1hbCx2ZWMzKDAuLDAuLDEuKSksIDAuKTsNCmNvbG9yLnh5eiArPSBkaWZmdXNlLnh5ejsNCmNvbG9yID0gdmVjNChjb2xvci5yZ2IgKiBkaWZmdXNlLmEsIGRpZmZ1c2UuYSk7DQpnbF9GcmFnQ29sb3IgPSBjb2xvcjsNCn0NCg==" }, - "CesiumTexturedBoxTest0VS": { + { "type": 35633, "uri": "data:text/plain;base64,cHJlY2lzaW9uIGhpZ2hwIGZsb2F0Ow0KYXR0cmlidXRlIHZlYzMgYV9wb3NpdGlvbjsNCmF0dHJpYnV0ZSB2ZWMzIGFfbm9ybWFsOw0KdmFyeWluZyB2ZWMzIHZfbm9ybWFsOw0KdW5pZm9ybSBtYXQzIHVfbm9ybWFsTWF0cml4Ow0KdW5pZm9ybSBtYXQ0IHVfbW9kZWxWaWV3TWF0cml4Ow0KdW5pZm9ybSBtYXQ0IHVfcHJvamVjdGlvbk1hdHJpeDsNCmF0dHJpYnV0ZSB2ZWMyIGFfdGV4Y29vcmQwOw0KdmFyeWluZyB2ZWMyIHZfdGV4Y29vcmQwOw0Kdm9pZCBtYWluKHZvaWQpIHsNCnZlYzQgcG9zID0gdV9tb2RlbFZpZXdNYXRyaXggKiB2ZWM0KGFfcG9zaXRpb24sMS4wKTsNCnZfbm9ybWFsID0gdV9ub3JtYWxNYXRyaXggKiBhX25vcm1hbDsNCnZfdGV4Y29vcmQwID0gYV90ZXhjb29yZDA7DQpnbF9Qb3NpdGlvbiA9IHVfcHJvamVjdGlvbk1hdHJpeCAqIHBvczsNCn0NCg==" } - }, - "skins": {}, - "techniques": { - "technique0": { + ], + "skins": [], + "techniques": [ + { "attributes": { "a_normal": "normal", "a_position": "position", @@ -325,15 +322,15 @@ "u_specular": "specular" } } - }, - "textures": { - "texture_Image0001": { + ], + "textures": [ + { "format": 6408, "internalFormat": 6408, - "sampler": "sampler_0", - "source": "Image0001", + "sampler": 0, + "source": 0, "target": 3553, "type": 5121 } - } + ] } \ No newline at end of file diff --git a/specs/data/boxTexturedUnoptimized/CesiumTexturedBoxTestTransparent.gltf b/specs/data/boxTexturedUnoptimized/CesiumTexturedBoxTestTransparent.gltf index 9efe2718..a819dae0 100644 --- a/specs/data/boxTexturedUnoptimized/CesiumTexturedBoxTestTransparent.gltf +++ b/specs/data/boxTexturedUnoptimized/CesiumTexturedBoxTestTransparent.gltf @@ -1,15 +1,15 @@ { - "accessors": { - "accessor_21": { - "bufferView": "bufferView_29", + "accessors": [ + { + "bufferView": 0, "byteOffset": 0, "byteStride": 0, "componentType": 5123, "count": 36, "type": "SCALAR" }, - "accessor_23": { - "bufferView": "bufferView_30", + { + "bufferView": 1, "byteOffset": 0, "byteStride": 12, "componentType": 5126, @@ -26,8 +26,8 @@ ], "type": "VEC3" }, - "accessor_25": { - "bufferView": "bufferView_30", + { + "bufferView": 1, "byteOffset": 288, "byteStride": 12, "componentType": 5126, @@ -44,8 +44,8 @@ ], "type": "VEC3" }, - "accessor_27": { - "bufferView": "bufferView_30", + { + "bufferView": 1, "byteOffset": 576, "byteStride": 8, "componentType": 5126, @@ -60,51 +60,50 @@ ], "type": "VEC2" } - }, - "animations": {}, + ], + "animations": [], "asset": { - "generator": "collada2gltf@ceec062e3d5793f2f249f53cbd843aee382ad40b", "premultipliedAlpha": true, "profile": { "api": "WebGL", - "version": "1.0.2" + "version": "1.0" }, - "version": 1 + "version": "2.0" }, - "bufferViews": { - "bufferView_29": { - "buffer": "CesiumTexturedBoxTest", + "bufferViews": [ + { + "buffer": 0, "byteLength": 72, "byteOffset": 0, "target": 34963 }, - "bufferView_30": { - "buffer": "CesiumTexturedBoxTest", + { + "buffer": 0, "byteLength": 768, "byteOffset": 72, "target": 34962 } - }, - "buffers": { - "CesiumTexturedBoxTest": { + ], + "buffers": [ + { "byteLength": 840, "type": "arraybuffer", "uri": "CesiumTexturedBoxTest.bin" } - }, - "images": { - "Image0001": { + ], + "images": [ + { "name": "Image0001", "uri": "Cesium_Logo_Flat_Transparent.png" } - }, - "materials": { - "Effect-Texture": { + ], + "materials": [ + { "name": "Texture", - "technique": "technique0", + "technique": 0, "values": { - "diffuse": "texture_Image0001", - "shininess": 256, + "diffuse": [0], + "shininess": [256], "specular": [ 0.2, 0.2, @@ -113,26 +112,26 @@ ] } } - }, - "meshes": { - "Geometry-mesh002": { + ], + "meshes": [ + { "name": "Mesh", "primitives": [ { "attributes": { - "NORMAL": "accessor_25", - "POSITION": "accessor_23", - "TEXCOORD_0": "accessor_27" + "NORMAL": 2, + "POSITION": 1, + "TEXCOORD_0": 3 }, - "indices": "accessor_21", - "material": "Effect-Texture", + "indices": 0, + "material": 0, "mode": 4 } ] } - }, - "nodes": { - "Geometry-mesh002Node": { + ], + "nodes": [ + { "children": [], "matrix": [ 1, @@ -152,12 +151,10 @@ 0, 1 ], - "meshes": [ - "Geometry-mesh002" - ], + "mesh": 0, "name": "Mesh" }, - "groupLocator030Node": { + { "children": [ "txtrLocator026Node" ], @@ -181,7 +178,7 @@ ], "name": "Texture_Group" }, - "node_3": { + { "children": [ "Geometry-mesh002Node", "groupLocator030Node" @@ -206,7 +203,7 @@ ], "name": "Y_UP_Transform" }, - "txtrLocator026Node": { + { "children": [], "matrix": [ 1, @@ -228,47 +225,47 @@ ], "name": "Cesium_Logo_Flat__Image___Texture_" } - }, - "programs": { - "program_0": { + ], + "programs": [ + { "attributes": [ "a_normal", "a_position", "a_texcoord0" ], - "fragmentShader": "CesiumTexturedBoxTest0FS", - "vertexShader": "CesiumTexturedBoxTest0VS" + "fragmentShader": 0, + "vertexShader": 1 } - }, - "samplers": { - "sampler_0": { + ], + "samplers": [ + { "magFilter": 9729, "minFilter": 9987, "wrapS": 10497, "wrapT": 10497 } - }, - "scene": "defaultScene", - "scenes": { - "defaultScene": { + ], + "scene": 0, + "scenes": [ + { "nodes": [ - "node_3" + 2 ] } - }, - "shaders": { - "CesiumTexturedBoxTest0FS": { + ], + "shaders": [ + { "type": 35632, "uri": "CesiumTexturedBoxTest0FS.glsl" }, - "CesiumTexturedBoxTest0VS": { + { "type": 35633, "uri": "CesiumTexturedBoxTest0VS.glsl" } - }, - "skins": {}, - "techniques": { - "technique0": { + ], + "skins": [], + "techniques": [ + { "attributes": { "a_normal": "normal", "a_position": "position", @@ -325,15 +322,15 @@ "u_specular": "specular" } } - }, - "textures": { - "texture_Image0001": { + ], + "textures": [ + { "format": 6408, "internalFormat": 6408, - "sampler": "sampler_0", - "source": "Image0001", + "sampler": 0, + "source": 0, "target": 3553, "type": 5121 } - } + ] } \ No newline at end of file diff --git a/specs/data/boxTexturedUnoptimized/CesiumTexturedBoxTestUnusedTree.gltf b/specs/data/boxTexturedUnoptimized/CesiumTexturedBoxTestUnusedTree.gltf index 584ba528..8dcd9c7e 100644 --- a/specs/data/boxTexturedUnoptimized/CesiumTexturedBoxTestUnusedTree.gltf +++ b/specs/data/boxTexturedUnoptimized/CesiumTexturedBoxTestUnusedTree.gltf @@ -1,141 +1,143 @@ { - "accessors": { - "accessor_23": { - "bufferView": "bufferView_30", + "accessors": [ + { + "bufferView": 0, "byteOffset": 0, "componentType": 5126, "count": 24, - "type": "VEC3" + "type": "VEC3", + "name": "accessor_23" }, - "animAccessor_0": { - "bufferView": "bufferView_30", + { + "bufferView": 0, "byteOffset": 128, "componentType": 5126, "count": 3, - "type": "SCALAR" + "type": "SCALAR", + "name": "animAccessor_0" }, - "IBM_Armature_Cylinder-skin": { - "bufferView": "bufferView_30", + { + "bufferView": 0, "byteOffset": 0, "componentType": 5126, "count": 2, - "type": "MAT4" + "type": "MAT4", + "name": "IBM_Armature_Cylinder-skin" } - }, - "animations": { - "animation_0": { - "parameters": { - } + ], + "animations": [ + { } - }, - "bufferViews": { - "bufferView_30": { - "buffer": "CesiumTexturedBoxTest", + ], + "bufferViews": [ + { + "buffer": 0, "byteOffset": 72 } - }, - "buffers": { - "CesiumTexturedBoxTest": { + ], + "buffers": [ + { "uri": "CesiumTexturedBoxTest.bin" } - }, - "cameras": { - "camera_0": { + ], + "cameras": [ + { "type": "perspective" } - }, - "images": { - "Image0001": { + ], + "images": [ + { "uri": "Cesium_Logo_Flat.png" } - }, - "materials": { - "Effect-Texture": { - "technique": "technique0", + ], + "materials": [ + { + "technique": 0, "values": { - "diffuse": "texture_Image0001" + "diffuse": [0] } } - }, - "meshes": { - "Geometry-mesh002": { + ], + "meshes": [ + { "primitives": [ { "attributes": { - "POSITION": "accessor_23" + "POSITION": 0 }, - "material": "Effect-Texture" + "material": 0 } ] } - }, - "nodes": { - "Geometry-mesh002Node": { - "meshes": [ - "Geometry-mesh002" - ] + ], + "nodes": [ + { + "mesh": 0, + "name": "Geometry-mesh002Node" }, - "groupLocator030Node": { + { "children": [ - "txtrLocator026Node" - ] + 3 + ], + "name": "groupLocator030Node" }, - "node_3": { - "camera": "camera_0", + { + "camera": 0, "children": [ - "Geometry-mesh002Node", - "groupLocator030Node" - ] + 0, + 1 + ], + "name": "node_3" }, - "txtrLocator026Node": { - "skin": "Armature_Cylinder-skin" - } - }, - "programs": { - "program_0": { - "fragmentShader": "CesiumTexturedBoxTest0FS", - "vertexShader": "CesiumTexturedBoxTest0VS" - } - }, - "samplers": { - "sampler_0": { - } - }, - "scene": "defaultScene", - "scenes": { - "defaultScene": { - "nodes": [ - ] - } - }, - "shaders": { - "CesiumTexturedBoxTest0FS": { + { + "skin": 0, + "name": "txtrLocator026Node" + } + ], + "programs": [ + { + "fragmentShader": 0, + "vertexShader": 1 + } + ], + "samplers": [ + { + } + ], + "scene": 0, + "scenes": [ + { + "nodes": [] + } + ], + "shaders": [ + { "type": 35632, "uri": "CesiumTexturedBoxTest0FS.glsl" }, - "CesiumTexturedBoxTest0VS": { + { "type": 35633, "uri": "CesiumTexturedBoxTest0VS.glsl" } - }, - "skins": { - "Armature_Cylinder-skin": { - "inverseBindMatrices": "IBM_Armature_Cylinder-skin", + ], + "skins": [ + { + "inverseBindMatrices": 2, "jointNames": [ "Bone", "Bone_001" ] } - }, - "techniques": { - "technique0": { - "program": "program_0" + ], + "techniques": [ + { + "program": 0 } - }, - "textures": { - "texture_Image0001": { - "sampler": "sampler_0", - "source": "Image0001" + ], + "textures": [ + { + "sampler": 0, + "source": 0 } - } + ] } \ No newline at end of file diff --git a/specs/data/boxTexturedUnoptimized/CesiumTexturedBoxTest_Binary.gltf b/specs/data/boxTexturedUnoptimized/CesiumTexturedBoxTest_Binary.gltf index e3b182f8..3e802e46 100644 --- a/specs/data/boxTexturedUnoptimized/CesiumTexturedBoxTest_Binary.gltf +++ b/specs/data/boxTexturedUnoptimized/CesiumTexturedBoxTest_Binary.gltf @@ -1,15 +1,15 @@ { - "accessors": { - "accessor_21": { - "bufferView": "bufferView_29", + "accessors": [ + { + "bufferView": 0, "byteOffset": 0, "byteStride": 0, "componentType": 5123, "count": 36, "type": "SCALAR" }, - "accessor_23": { - "bufferView": "bufferView_30", + { + "bufferView": 1, "byteOffset": 0, "byteStride": 12, "componentType": 5126, @@ -26,8 +26,8 @@ ], "type": "VEC3" }, - "accessor_25": { - "bufferView": "bufferView_30", + { + "bufferView": 1, "byteOffset": 288, "byteStride": 12, "componentType": 5126, @@ -44,8 +44,8 @@ ], "type": "VEC3" }, - "accessor_27": { - "bufferView": "bufferView_30", + { + "bufferView": 1, "byteOffset": 576, "byteStride": 8, "componentType": 5126, @@ -60,8 +60,8 @@ ], "type": "VEC2" } - }, - "animations": {}, + ], + "animations": [], "asset": { "generator": "collada2gltf@ceec062e3d5793f2f249f53cbd843aee382ad40b", "premultipliedAlpha": true, @@ -71,40 +71,40 @@ }, "version": 1 }, - "bufferViews": { - "bufferView_29": { - "buffer": "CesiumTexturedBoxTest", + "bufferViews": [ + { + "buffer": 0, "byteLength": 72, "byteOffset": 0, "target": 34963 }, - "bufferView_30": { - "buffer": "CesiumTexturedBoxTest", + { + "buffer": 0, "byteLength": 768, "byteOffset": 72, "target": 34962 } - }, - "buffers": { - "CesiumTexturedBoxTest": { + ], + "buffers": [ + { "byteLength": 840, "type": "arraybuffer", "uri": "CesiumTexturedBoxTest.bin" } - }, - "images": { - "Image0001": { + ], + "images": [ + { "name": "Image0001", "uri": "Cesium_Logo_Flat_Binary.png" } - }, - "materials": { - "Effect-Texture": { + ], + "materials": [ + { "name": "Texture", - "technique": "technique0", + "technique": 0, "values": { - "diffuse": "texture_Image0001", - "shininess": 256, + "diffuse": [0], + "shininess": [256], "specular": [ 0.2, 0.2, @@ -113,26 +113,26 @@ ] } } - }, - "meshes": { - "Geometry-mesh002": { + ], + "meshes": [ + { "name": "Mesh", "primitives": [ { "attributes": { - "NORMAL": "accessor_25", - "POSITION": "accessor_23", - "TEXCOORD_0": "accessor_27" + "NORMAL": 2, + "POSITION": 1, + "TEXCOORD_0": 3 }, - "indices": "accessor_21", - "material": "Effect-Texture", + "indices": 0, + "material": 0, "mode": 4 } ] } - }, - "nodes": { - "Geometry-mesh002Node": { + ], + "nodes": [ + { "children": [], "matrix": [ 1, @@ -152,14 +152,12 @@ 0, 1 ], - "meshes": [ - "Geometry-mesh002" - ], + "mesh": 0, "name": "Mesh" }, - "groupLocator030Node": { + { "children": [ - "txtrLocator026Node" + 3 ], "matrix": [ 1, @@ -181,10 +179,10 @@ ], "name": "Texture_Group" }, - "node_3": { + { "children": [ - "Geometry-mesh002Node", - "groupLocator030Node" + 0, + 1 ], "matrix": [ 1, @@ -206,7 +204,7 @@ ], "name": "Y_UP_Transform" }, - "txtrLocator026Node": { + { "children": [], "matrix": [ 1, @@ -228,47 +226,47 @@ ], "name": "Cesium_Logo_Flat__Image___Texture_" } - }, - "programs": { - "program_0": { + ], + "programs": [ + { "attributes": [ "a_normal", "a_position", "a_texcoord0" ], - "fragmentShader": "CesiumTexturedBoxTest0FS", - "vertexShader": "CesiumTexturedBoxTest0VS" + "fragmentShader": 0, + "vertexShader": 1 } - }, - "samplers": { - "sampler_0": { + ], + "samplers": [ + { "magFilter": 9729, "minFilter": 9987, "wrapS": 10497, "wrapT": 10497 } - }, - "scene": "defaultScene", - "scenes": { - "defaultScene": { + ], + "scene": 0, + "scenes": [ + { "nodes": [ - "node_3" + 2 ] } - }, - "shaders": { - "CesiumTexturedBoxTest0FS": { + ], + "shaders": [ + { "type": 35632, "uri": "CesiumTexturedBoxTest0FS_Binary.glsl" }, - "CesiumTexturedBoxTest0VS": { + { "type": 35633, "uri": "CesiumTexturedBoxTest0VS_Binary.glsl" } - }, + ], "skins": {}, - "techniques": { - "technique0": { + "techniques": [ + { "attributes": { "a_normal": "normal", "a_position": "position", @@ -309,7 +307,7 @@ "type": 35664 } }, - "program": "program_0", + "program": 0, "states": { "enable": [ 2929, @@ -325,15 +323,15 @@ "u_specular": "specular" } } - }, - "textures": { - "texture_Image0001": { + ], + "textures": [ + { "format": 6408, "internalFormat": 6408, - "sampler": "sampler_0", - "source": "Image0001", + "sampler": 0, + "source": 0, "target": 3553, "type": 5121 } - } + ] } \ No newline at end of file diff --git a/specs/data/boxTexturedUnoptimized/CesiumTexturedBoxTest_BinaryCheck.gltf b/specs/data/boxTexturedUnoptimized/CesiumTexturedBoxTest_BinaryCheck.gltf index cbd70bd7..f89736f7 100644 --- a/specs/data/boxTexturedUnoptimized/CesiumTexturedBoxTest_BinaryCheck.gltf +++ b/specs/data/boxTexturedUnoptimized/CesiumTexturedBoxTest_BinaryCheck.gltf @@ -1,15 +1,15 @@ { - "accessors": { - "accessor_21": { - "bufferView": "bufferView_29", + "accessors": [ + { + "bufferView": 0, "byteOffset": 0, "byteStride": 0, "componentType": 5123, "count": 36, "type": "SCALAR" }, - "accessor_23": { - "bufferView": "bufferView_30", + { + "bufferView": 1, "byteOffset": 0, "byteStride": 12, "componentType": 5126, @@ -26,8 +26,8 @@ ], "type": "VEC3" }, - "accessor_25": { - "bufferView": "bufferView_30", + { + "bufferView": 1, "byteOffset": 288, "byteStride": 12, "componentType": 5126, @@ -44,8 +44,8 @@ ], "type": "VEC3" }, - "accessor_27": { - "bufferView": "bufferView_30", + { + "bufferView": 1, "byteOffset": 576, "byteStride": 8, "componentType": 5126, @@ -60,8 +60,8 @@ ], "type": "VEC2" } - }, - "animations": {}, + ], + "animations": [], "asset": { "generator": "collada2gltf@ceec062e3d5793f2f249f53cbd843aee382ad40b", "premultipliedAlpha": true, @@ -71,64 +71,53 @@ }, "version": 1 }, - "bufferViews": { - "bufferView_29": { - "buffer": "binary_glTF", + "bufferViews": [ + { + "buffer": 0, "byteLength": 72, "byteOffset": 0, "target": 34963 }, - "bufferView_30": { - "buffer": "binary_glTF", + { + "buffer": 0, "byteLength": 768, "byteOffset": 72, "target": 34962 }, - "binary_bufferView0": { - "buffer": "binary_glTF", + { + "buffer": 0, "byteLength": 529, "byteOffset": 840 }, - "binary_bufferView1": { - "buffer": "binary_glTF", + { + "buffer": 0, "byteLength": 439, "byteOffset": 1369 }, - "binary_bufferView2": { - "buffer": "binary_glTF", + { + "buffer": 0, "byteLength": 11982, "byteOffset": 1808 } - }, - "buffers": { - "binary_glTF": { - "type": "arraybuffer", - "byteLength": 13790, - "uri": "data:," + ], + "buffers": [ + { + "byteLength": 13790 } - }, - "extensionsUsed": ["KHR_binary_glTF"], - "images": { - "Image0001": { + ], + "images": [ + { "name": "Image0001", - "uri": "data:,", - "extensions": { - "KHR_binary_glTF": { - "bufferView": "binary_bufferView2", - "mimeType": "image/png", - "width": 211, - "height": 211 - } - } + "bufferView": 4 } - }, - "materials": { - "Effect-Texture": { + ], + "materials": [ + { "name": "Texture", - "technique": "technique0", + "technique": 0, "values": { - "diffuse": "texture_Image0001", - "shininess": 256, + "diffuse": [0], + "shininess": [256], "specular": [ 0.2, 0.2, @@ -137,26 +126,26 @@ ] } } - }, - "meshes": { - "Geometry-mesh002": { + ], + "meshes": [ + { "name": "Mesh", "primitives": [ { "attributes": { - "NORMAL": "accessor_25", - "POSITION": "accessor_23", - "TEXCOORD_0": "accessor_27" + "NORMAL": 2, + "POSITION": 1, + "TEXCOORD_0": 3 }, - "indices": "accessor_21", - "material": "Effect-Texture", + "indices": 0, + "material": 0, "mode": 4 } ] } - }, - "nodes": { - "Geometry-mesh002Node": { + ], + "nodes": [ + { "children": [], "matrix": [ 1, @@ -176,14 +165,12 @@ 0, 1 ], - "meshes": [ - "Geometry-mesh002" - ], + "mesh": 0, "name": "Mesh" }, - "groupLocator030Node": { + { "children": [ - "txtrLocator026Node" + 3 ], "matrix": [ 1, @@ -205,10 +192,10 @@ ], "name": "Texture_Group" }, - "node_3": { + { "children": [ - "Geometry-mesh002Node", - "groupLocator030Node" + 0, + 1 ], "matrix": [ 1, @@ -230,7 +217,7 @@ ], "name": "Y_UP_Transform" }, - "txtrLocator026Node": { + { "children": [], "matrix": [ 1, @@ -252,57 +239,47 @@ ], "name": "Cesium_Logo_Flat__Image___Texture_" } - }, - "programs": { - "program_0": { + ], + "programs": [ + { "attributes": [ "a_normal", "a_position", "a_texcoord0" ], - "fragmentShader": "CesiumTexturedBoxTest0FS", - "vertexShader": "CesiumTexturedBoxTest0VS" + "fragmentShader": 0, + "vertexShader": 1 } - }, - "samplers": { - "sampler_0": { + ], + "samplers": [ + { "magFilter": 9729, "minFilter": 9987, "wrapS": 10497, "wrapT": 10497 } - }, - "scene": "defaultScene", - "scenes": { - "defaultScene": { + ], + "scene": 0, + "scenes": [ + { "nodes": [ - "node_3" + 2 ] } - }, - "shaders": { - "CesiumTexturedBoxTest0FS": { + ], + "shaders": [ + { "type": 35632, - "uri": "data:,", - "extensions": { - "KHR_binary_glTF": { - "bufferView": "binary_bufferView0" - } - } + "bufferView": 2 }, - "CesiumTexturedBoxTest0VS": { + { "type": 35633, - "uri": "data:,", - "extensions": { - "KHR_binary_glTF": { - "bufferView": "binary_bufferView1" - } - } + "bufferView": 3 } - }, - "skins": {}, - "techniques": { - "technique0": { + ], + "skins": [], + "techniques": [ + { "attributes": { "a_normal": "normal", "a_position": "position", @@ -343,7 +320,7 @@ "type": 35664 } }, - "program": "program_0", + "program": 0, "states": { "enable": [ 2929, @@ -359,15 +336,15 @@ "u_specular": "specular" } } - }, - "textures": { - "texture_Image0001": { + ], + "textures": [ + { "format": 6408, "internalFormat": 6408, - "sampler": "sampler_0", - "source": "Image0001", + "sampler": 0, + "source": 0, "target": 3553, "type": 5121 } - } + ] } \ No newline at end of file diff --git a/specs/data/boxTexturedUnoptimized/CesiumTexturedBoxTest_BinaryInput.gltf b/specs/data/boxTexturedUnoptimized/CesiumTexturedBoxTest_BinaryInput.gltf index e3b182f8..9bc578c5 100644 --- a/specs/data/boxTexturedUnoptimized/CesiumTexturedBoxTest_BinaryInput.gltf +++ b/specs/data/boxTexturedUnoptimized/CesiumTexturedBoxTest_BinaryInput.gltf @@ -1,15 +1,16 @@ { - "accessors": { - "accessor_21": { - "bufferView": "bufferView_29", + "accessors": [ + { + "bufferView": 0, "byteOffset": 0, "byteStride": 0, "componentType": 5123, "count": 36, - "type": "SCALAR" + "type": "SCALAR", + "name": "accessor_21" }, - "accessor_23": { - "bufferView": "bufferView_30", + { + "bufferView": 1, "byteOffset": 0, "byteStride": 12, "componentType": 5126, @@ -24,10 +25,11 @@ -0.5, -0.5 ], - "type": "VEC3" + "type": "VEC3", + "name": "accessor_23" }, - "accessor_25": { - "bufferView": "bufferView_30", + { + "bufferView": 1, "byteOffset": 288, "byteStride": 12, "componentType": 5126, @@ -42,10 +44,11 @@ -1, -1 ], - "type": "VEC3" + "type": "VEC3", + "name": "accessor_25" }, - "accessor_27": { - "bufferView": "bufferView_30", + { + "bufferView": 1, "byteOffset": 576, "byteStride": 8, "componentType": 5126, @@ -58,10 +61,11 @@ 0, 0 ], - "type": "VEC2" + "type": "VEC2", + "name": "accessor_27" } - }, - "animations": {}, + ], + "animations": [], "asset": { "generator": "collada2gltf@ceec062e3d5793f2f249f53cbd843aee382ad40b", "premultipliedAlpha": true, @@ -71,40 +75,40 @@ }, "version": 1 }, - "bufferViews": { - "bufferView_29": { - "buffer": "CesiumTexturedBoxTest", + "bufferViews": [ + { + "buffer": 0, "byteLength": 72, "byteOffset": 0, "target": 34963 }, - "bufferView_30": { - "buffer": "CesiumTexturedBoxTest", + { + "buffer": 0, "byteLength": 768, "byteOffset": 72, "target": 34962 } - }, - "buffers": { - "CesiumTexturedBoxTest": { + ], + "buffers": [ + { "byteLength": 840, "type": "arraybuffer", "uri": "CesiumTexturedBoxTest.bin" } - }, - "images": { - "Image0001": { + ], + "images": [ + { "name": "Image0001", "uri": "Cesium_Logo_Flat_Binary.png" } - }, - "materials": { - "Effect-Texture": { + ], + "materials": [ + { "name": "Texture", - "technique": "technique0", + "technique": 0, "values": { - "diffuse": "texture_Image0001", - "shininess": 256, + "diffuse": [0], + "shininess": [256], "specular": [ 0.2, 0.2, @@ -113,26 +117,26 @@ ] } } - }, - "meshes": { - "Geometry-mesh002": { + ], + "meshes": [ + { "name": "Mesh", "primitives": [ { "attributes": { - "NORMAL": "accessor_25", - "POSITION": "accessor_23", - "TEXCOORD_0": "accessor_27" + "NORMAL": 2, + "POSITION": 1, + "TEXCOORD_0": 3 }, - "indices": "accessor_21", - "material": "Effect-Texture", + "indices": 0, + "material": 0, "mode": 4 } ] } - }, - "nodes": { - "Geometry-mesh002Node": { + ], + "nodes": [ + { "children": [], "matrix": [ 1, @@ -152,14 +156,12 @@ 0, 1 ], - "meshes": [ - "Geometry-mesh002" - ], + "mesh": 0, "name": "Mesh" }, - "groupLocator030Node": { + { "children": [ - "txtrLocator026Node" + 3 ], "matrix": [ 1, @@ -181,10 +183,10 @@ ], "name": "Texture_Group" }, - "node_3": { + { "children": [ - "Geometry-mesh002Node", - "groupLocator030Node" + 0, + 1 ], "matrix": [ 1, @@ -206,7 +208,7 @@ ], "name": "Y_UP_Transform" }, - "txtrLocator026Node": { + { "children": [], "matrix": [ 1, @@ -228,47 +230,47 @@ ], "name": "Cesium_Logo_Flat__Image___Texture_" } - }, - "programs": { - "program_0": { + ], + "programs": [ + { "attributes": [ "a_normal", "a_position", "a_texcoord0" ], - "fragmentShader": "CesiumTexturedBoxTest0FS", - "vertexShader": "CesiumTexturedBoxTest0VS" + "fragmentShader": 0, + "vertexShader": 1 } - }, - "samplers": { - "sampler_0": { + ], + "samplers": [ + { "magFilter": 9729, "minFilter": 9987, "wrapS": 10497, "wrapT": 10497 } - }, - "scene": "defaultScene", - "scenes": { - "defaultScene": { + ], + "scene": 0, + "scenes": [ + { "nodes": [ - "node_3" + 2 ] } - }, - "shaders": { - "CesiumTexturedBoxTest0FS": { + ], + "shaders": [ + { "type": 35632, "uri": "CesiumTexturedBoxTest0FS_Binary.glsl" }, - "CesiumTexturedBoxTest0VS": { + { "type": 35633, "uri": "CesiumTexturedBoxTest0VS_Binary.glsl" } - }, - "skins": {}, - "techniques": { - "technique0": { + ], + "skins": [], + "techniques": [ + { "attributes": { "a_normal": "normal", "a_position": "position", @@ -309,7 +311,7 @@ "type": 35664 } }, - "program": "program_0", + "program": 0, "states": { "enable": [ 2929, @@ -325,15 +327,15 @@ "u_specular": "specular" } } - }, - "textures": { - "texture_Image0001": { + ], + "textures": [ + { "format": 6408, "internalFormat": 6408, - "sampler": "sampler_0", - "source": "Image0001", + "sampler": 0, + "source": 0, "target": 3553, "type": 5121 } - } + ] } \ No newline at end of file diff --git a/specs/data/combineObjects/fiveBox.gltf b/specs/data/combineObjects/fiveBox.gltf index ee97716e..0c3c4f00 100644 --- a/specs/data/combineObjects/fiveBox.gltf +++ b/specs/data/combineObjects/fiveBox.gltf @@ -1,15 +1,15 @@ { - "accessors": { - "accessor_21": { - "bufferView": "bufferView_29", + "accessors": [ + { + "bufferView": 0, "byteOffset": 0, "byteStride": 0, "componentType": 5123, "count": 36, "type": "SCALAR" }, - "accessor_23": { - "bufferView": "bufferView_30", + { + "bufferView": 1, "byteOffset": 0, "byteStride": 12, "componentType": 5126, @@ -26,16 +26,16 @@ ], "type": "VEC3" }, - "accessor_29": { - "bufferView": "bufferView_64", + { + "bufferView": 2, "byteOffset": 0, "byteStride": 0, "componentType": 5123, "count": 384, "type": "SCALAR" }, - "accessor_31": { - "bufferView": "bufferView_65", + { + "bufferView": 3, "byteOffset": 0, "byteStride": 12, "componentType": 5126, @@ -52,16 +52,16 @@ ], "type": "VEC3" }, - "accessor_56": { - "bufferView": "bufferView_64", + { + "bufferView": 2, "byteOffset": 768, "byteStride": 0, "componentType": 5123, "count": 132, "type": "SCALAR" }, - "accessor_58": { - "bufferView": "bufferView_65", + { + "bufferView": 3, "byteOffset": 7168, "byteStride": 12, "componentType": 5126, @@ -78,16 +78,16 @@ ], "type": "VEC3" }, - "accessor_29_1": { - "bufferView": "bufferView_64_1", + { + "bufferView": 4, "byteOffset": 0, "byteStride": 0, "componentType": 5123, "count": 384, "type": "SCALAR" }, - "accessor_31_1": { - "bufferView": "bufferView_65_1", + { + "bufferView": 5, "byteOffset": 0, "byteStride": 12, "componentType": 5126, @@ -104,16 +104,16 @@ ], "type": "VEC3" }, - "accessor_56_1": { - "bufferView": "bufferView_64_1", + { + "bufferView": 4, "byteOffset": 768, "byteStride": 0, "componentType": 5123, "count": 132, "type": "SCALAR" }, - "accessor_58_1": { - "bufferView": "bufferView_65_1", + { + "bufferView": 5, "byteOffset": 7168, "byteStride": 12, "componentType": 5126, @@ -130,7 +130,7 @@ ], "type": "VEC3" } - }, + ], "asset": { "generator": "collada2gltf@", "premultipliedAlpha": true, @@ -138,62 +138,62 @@ "api": "WebGL", "version": "1.0.2" }, - "version": 1 + "version": "2.0" }, - "bufferViews": { - "bufferView_29": { - "buffer": "box", + "bufferViews": [ + { + "buffer": 0, "byteLength": 72, "byteOffset": 0, "target": 34963 }, - "bufferView_30": { - "buffer": "box", + { + "buffer": 0, "byteLength": 768, "byteOffset": 72, "target": 34962 }, - "bufferView_64": { - "buffer": "input", + { + "buffer": 1, "byteLength": 1032, "byteOffset": 104, "target": 34963 }, - "bufferView_65": { - "buffer": "input", + { + "buffer": 1, "byteLength": 10240, "byteOffset": 1136, "target": 34962 }, - "bufferView_64_1": { - "buffer": "input", + { + "buffer": 1, "byteLength": 1032, "byteOffset": 104, "target": 34963 }, - "bufferView_65_1": { - "buffer": "input", + { + "buffer": 1, "byteLength": 10240, "byteOffset": 1136, "target": 34962 } - }, - "buffers": { - "box": { + ], + "buffers": [ + { "byteLength": 840, "type": "arraybuffer", "uri": "data:application/octet-stream;base64,AAABAAIAAwACAAEABAAFAAYABwAGAAUACAAJAAoACwAKAAkADAANAA4ADwAOAA0AEAARABIAEwASABEAFAAVABYAFwAWABUAAAAAvwAAAL8AAAA/AAAAPwAAAL8AAAA/AAAAvwAAAD8AAAA/AAAAPwAAAD8AAAA/AAAAPwAAAL8AAAA/AAAAvwAAAL8AAAA/AAAAPwAAAL8AAAC/AAAAvwAAAL8AAAC/AAAAPwAAAD8AAAA/AAAAPwAAAL8AAAA/AAAAPwAAAD8AAAC/AAAAPwAAAL8AAAC/AAAAvwAAAD8AAAA/AAAAPwAAAD8AAAA/AAAAvwAAAD8AAAC/AAAAPwAAAD8AAAC/AAAAvwAAAL8AAAA/AAAAvwAAAD8AAAA/AAAAvwAAAL8AAAC/AAAAvwAAAD8AAAC/AAAAvwAAAL8AAAC/AAAAvwAAAD8AAAC/AAAAPwAAAL8AAAC/AAAAPwAAAD8AAAC/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AACAPgAAAAAAAIA+oKqqPgAAAD8AAAAAAAAAP6Cqqj4AAIA+oKqqPgAAAACgqqo+AACAPrCqKj8AAAAAsKoqPwAAAD+gqqo+AACAPqCqqj4AAAA/sKoqPwAAgD6wqio/AABAP6Cqqj4AAAA/oKqqPgAAQD+wqio/AAAAP7CqKj8AAIA/oKqqPgAAQD+gqqo+AACAP7CqKj8AAEA/sKoqPwAAgD4AAIA/AAAAPwAAgD8AAIA+sKoqPwAAAD+wqio/" }, - "input": { + { "byteLength": 11376, "type": "arraybuffer", "uri": "data:application/octet-stream;base64,AACgPwAAIEAAAAAAAAAAAAAAAAAAAIA/AACAvwAAAIAAAACAEnVFrgAAAAAAAKA/AAAgQEdVbUAAAAAAAAAAAAAAAAAAAAAArkchQAAAAAAAAAAArkchQAAAAAAAAAAAAAAAAAAAAAAAAAEAAgACAAMAAAAEAAUABgAGAAcABAAIAAkACgAKAAsACAAMAA0ADgAOAA8ADAAQABEAEgASABMAEAAUABUAFgAWABcAFAAYABkAGgAaABsAGAAcAB0AHgAeAB8AHAAgACEAIgAiACMAIAAkACUAJgAmACcAJAAoACkAKgAqACsAKAAsAC0ALgAuAC8ALAAwADEAMgAyADMAMAA0ADUANgA2ADcANAA4ADkAOgA6ADsAOAA8AD0APgA+AD8APABAAEEAQgBCAEMAQABEAEUARgBGAEcARABIAEkASgBKAEsASABMAE0ATgBOAE8ATABQAFEAUgBSAFMAUABUAFUAVgBWAFcAVABYAFkAWgBaAFsAWABcAF0AXgBeAF8AXABgAGEAYgBiAGMAYABkAGUAZgBmAGcAZABoAGkAagBqAGsAaABsAG0AbgBuAG8AbABwAHEAcgByAHMAcAB0AHUAdgB2AHcAdAB4AHkAegB6AHsAeAB8AH0AfgB+AH8AfACAAIEAggCCAIMAgACEAIUAhgCGAIcAhACIAIkAigCKAIsAiACMAI0AjgCOAI8AjACQAJEAkgCSAJMAkACUAJUAlgCWAJcAlACYAJkAmgCaAJsAmACcAJ0AngCeAJ8AnAApACgAQwBDAEIAKQAFAAQAKwArACoABQBVAFQABwAHAAYAVQBBAEAAVwBXAFYAQQCgAKEAogCiAKMAoACkAKUApgCmAKcApACoAKkAqgCqAKsAqACsAK0ArgCuAK8ArACwALEAsgCyALMAsAC0ALUAtgC2ALcAtAC4ALAAswCzALkAuAC6ALQAtwC3ALsAugC8ALgAuQC5AL0AvACxALoAuwC7ALIAsQC+ALwAvQC9AL8AvgC1AL4AvwC/ALYAtQDAAMEAwgDCAMMAwADEAMUAxgDGAMcAxADIAMkAygDKAMsAyADMAM0AzgDOAM8AzADQANEA0gDSANMA0ADUANUA1gDWANcA1ADYANkA2gDaANsA2ADcAN0A3gDeAN8A3AAAAAEAAgACAAMAAAAEAAUABgAGAAcABAAIAAkA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AAAAAPcENb/3BDU/AAAAAPcENb/3BDU/AAAAAPcENb/3BDU/AAAAAPcENb8AAAAAaM0TP9EFUT8AAAAAaM0TP9EFUT8AAAAAaM0TP9EFUT8AAAAAaM0TP9EFUT8AAAAAAACAvwAAAIAAAAAAAACAvwAAAIAAAAAAAACAvwAAAIAAAAAAAACAvwAAAIAAAACAurgtP7cIPD8AAACAurgtP7cIPD8AAACAurgtP7cIPD8AAACAurgtP7cIPD/3BDW/AAAAAPcENb/3BDW/AAAAAPcENb/3BDW/AAAAAPcENb/3BDW/AAAAAPcENb/RBVE/aM0TPwAAAIDRBVE/aM0TPwAAAIDRBVE/aM0TPwAAAIDRBVE/aM0TPwAAAIDRBVG/aM0TPwAAAADRBVG/aM0TPwAAAADRBVG/aM0TPwAAAADRBVG/aM0TPwAAAAAAAAAAAACAvwAAAIAAAAAAAACAvwAAAIAAAAAAAACAvwAAAIAAAAAAAACAvwAAAID3BDW/AAAAAPcENT/3BDW/AAAAAPcENT/3BDW/AAAAAPcENT/3BDW/AAAAAPcENT8AAAAAaM0TP9EFUb8AAAAAaM0TP9EFUb8AAAAAaM0TP9EFUb8AAAAAaM0TP9EFUb+9//++GAU1v73//769//++GAU1v73//769//++GAU1v73//769//++GAU1v73//769//8+GAU1v73//769//8+GAU1v73//769//8+GAU1v73//769//8+GAU1v73//769//8+GAU1v73//z69//8+GAU1v73//z69//8+GAU1v73//z69//8+GAU1v73//z69//++GAU1v73//z69//++GAU1v73//z69//++GAU1v73//z69//++GAU1v73//z69//++GAU1P73//769//++GAU1P73//769//++GAU1P73//769//++GAU1P73//769//8+GAU1P73//769//8+GAU1P73//769//8+GAU1P73//769//8+GAU1P73//769//8+GAU1P73//z69//8+GAU1P73//z69//8+GAU1P73//z69//8+GAU1P73//z69//++GAU1P73//z69//++GAU1P73//z69//++GAU1P73//z69//++GAU1P73//z4/xvQ+lJ88vz/G9D4/xvQ+lJ88vz/G9D4/xvQ+lJ88vz/G9D4/xvQ+lJ88vz/G9D4/xvS+lJ88vz/G9D4/xvS+lJ88vz/G9D4/xvS+lJ88vz/G9D4/xvS+lJ88vz/G9D4/xvS+lJ88vz/G9L4/xvS+lJ88vz/G9L4/xvS+lJ88vz/G9L4/xvS+lJ88vz/G9L4/xvQ+lJ88vz/G9L4/xvQ+lJ88vz/G9L4/xvQ+lJ88vz/G9L4/xvQ+lJ88vz/G9L4/xvQ+lJ88Pz/G9D4/xvQ+lJ88Pz/G9D4/xvQ+lJ88Pz/G9D4/xvQ+lJ88Pz/G9D4/xvS+lJ88Pz/G9D4/xvS+lJ88Pz/G9D4/xvS+lJ88Pz/G9D4/xvS+lJ88Pz/G9D4/xvS+lJ88Pz/G9L4/xvS+lJ88Pz/G9L4/xvS+lJ88Pz/G9L4/xvS+lJ88Pz/G9L4/xvQ+lJ88Pz/G9L4/xvQ+lJ88Pz/G9L4/xvQ+lJ88Pz/G9L4/xvQ+lJ88Pz/G9L4AAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAACAAAAAAAAAgD8AAACAAAAAAAAAgD8AAACAAAAAAAAAgD8AAACAAAAAAAAAgD8AAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAACAAAAAgAAAgL8AAACAAAAAgAAAgL8AAACAAAAAgAAAgL8AAACAAAAAgAAAgL8AAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAACAAAAAgAAAgL8AAACAAAAAgAAAgL8AAACAAAAAgAAAgL8AAACAAAAAgAAAgL/3BDW/AAAAAPcENT/3BDW/AAAAAPcENT/3BDW/AAAAAPcENT/3BDW/AAAAAPcENT8AAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/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" } - }, - "materials": { - "Effect_inner": { + ], + "materials": [ + { "name": "inner", - "technique": "technique0", + "technique": 0, "values": { "diffuse": [ 0.800000011920929, @@ -210,9 +210,9 @@ ] } }, - "Effect_outer": { + { "name": "outer", - "technique": "technique0", + "technique": 0, "values": { "diffuse": [ 0.3016040027141571, @@ -229,9 +229,9 @@ ] } }, - "Effect_Red": { + { "name": "Red", - "technique": "technique0", + "technique": 0, "values": { "diffuse": [ 0.8, @@ -248,56 +248,56 @@ ] } } - }, - "meshes": { - "meshTest": { + ], + "meshes": [ + { "name": "box", "primitives": [ { "attributes": { - "POSITION": "accessor_58" + "POSITION": 5 }, - "indices": "accessor_56", - "material": "Effect_outer", + "indices": 4, + "material": 0, "mode": 4 }, { "attributes": { - "POSITION": "accessor_31" + "POSITION": 3 }, - "indices": "accessor_29", - "material": "Effect_outer", + "indices": 2, + "material": 0, "mode": 4 }, { "attributes": { - "POSITION": "accessor_58_1" + "POSITION": 9 }, - "indices": "accessor_56_1", - "material": "Effect_inner", + "indices": 8, + "material": 1, "mode": 4 }, { "attributes": { - "POSITION": "accessor_31_1" + "POSITION": 7 }, - "indices": "accessor_29_1", - "material": "Effect_inner", + "indices": 6, + "material": 1, "mode": 4 }, { "attributes": { - "POSITION": "accessor_23" + "POSITION": 1 }, - "indices": "accessor_21", - "material": "Effect_Red", + "indices": 0, + "material": 2, "mode": 4 } ] } - }, - "nodes": { - "Camera-camera002Node": { + ], + "nodes": [ + { "camera": "", "children": [], "matrix": [ @@ -320,7 +320,7 @@ ], "name": "Camera" }, - "Geometry-mesh019Node": { + { "children": [], "matrix": [ 1, @@ -340,12 +340,10 @@ 0, 1 ], - "meshes": [ - "meshTest" - ], + "mesh": 0, "name": "box" }, - "Light-sunLight011Node": { + { "children": [], "matrix": [ 0.7071067690849304, @@ -367,7 +365,7 @@ ], "name": "Directional_Light" }, - "polyRender005": { + { "children": [], "matrix": [ 1, @@ -389,41 +387,41 @@ ], "name": "Render" } - }, - "programs": { - "program_0": { + ], + "programs": [ + { "attributes": [ "a_normal", "a_position" ], - "fragmentShader": "input0FS", - "vertexShader": "input0VS" + "fragmentShader": 0, + "vertexShader": 1 } - }, - "scene": "defaultScene", - "scenes": { - "defaultScene": { + ], + "scene": 0, + "scenes": [ + { "nodes": [ - "polyRender005", - "Geometry-mesh019Node", - "Camera-camera002Node", - "Light-sunLight011Node" + 3, + 1, + 0, + 2 ] } - }, - "shaders": { - "input0FS": { + ], + "shaders": [ + { "type": 35632, "uri": "data:text/plain;base64,cHJlY2lzaW9uIGhpZ2hwIGZsb2F0Owp2YXJ5aW5nIHZlYzMgdl9ub3JtYWw7CnVuaWZvcm0gdmVjNCB1X2RpZmZ1c2U7CnVuaWZvcm0gdmVjNCB1X3NwZWN1bGFyOwp1bmlmb3JtIGZsb2F0IHVfc2hpbmluZXNzOwp1bmlmb3JtIHZlYzMgdV9saWdodDBDb2xvcjsKdmFyeWluZyB2ZWMzIHZfbGlnaHQxRGlyZWN0aW9uOwp2YXJ5aW5nIHZlYzMgdl9wb3NpdGlvbjsKdW5pZm9ybSB2ZWMzIHVfbGlnaHQxQ29sb3I7CnZvaWQgbWFpbih2b2lkKSB7CnZlYzMgbm9ybWFsID0gbm9ybWFsaXplKHZfbm9ybWFsKTsKdmVjNCBjb2xvciA9IHZlYzQoMC4sIDAuLCAwLiwgMC4pOwp2ZWM0IGRpZmZ1c2UgPSB2ZWM0KDAuLCAwLiwgMC4sIDEuKTsKdmVjMyBkaWZmdXNlTGlnaHQgPSB2ZWMzKDAuLCAwLiwgMC4pOwp2ZWM0IHNwZWN1bGFyOwpkaWZmdXNlID0gdV9kaWZmdXNlOwpzcGVjdWxhciA9IHVfc3BlY3VsYXI7CnZlYzMgc3BlY3VsYXJMaWdodCA9IHZlYzMoMC4sIDAuLCAwLik7CnZlYzMgYW1iaWVudExpZ2h0ID0gdmVjMygwLiwgMC4sIDAuKTsKewphbWJpZW50TGlnaHQgKz0gdV9saWdodDBDb2xvcjsKfQp7CmZsb2F0IHNwZWN1bGFySW50ZW5zaXR5ID0gMC47CmZsb2F0IGF0dGVudWF0aW9uID0gMS4wOwp2ZWMzIGwgPSBub3JtYWxpemUodl9saWdodDFEaXJlY3Rpb24pOwp2ZWMzIHZpZXdEaXIgPSAtbm9ybWFsaXplKHZfcG9zaXRpb24pOwpmbG9hdCBwaG9uZ1Rlcm0gPSBtYXgoMC4wLCBkb3QocmVmbGVjdCgtbCxub3JtYWwpLCB2aWV3RGlyKSk7CnNwZWN1bGFySW50ZW5zaXR5ID0gbWF4KDAuLCBwb3cocGhvbmdUZXJtICwgdV9zaGluaW5lc3MpKSAqIGF0dGVudWF0aW9uOwpzcGVjdWxhckxpZ2h0ICs9IHVfbGlnaHQxQ29sb3IgKiBzcGVjdWxhckludGVuc2l0eTsKZGlmZnVzZUxpZ2h0ICs9IHVfbGlnaHQxQ29sb3IgKiBtYXgoZG90KG5vcm1hbCxsKSwgMC4pICogYXR0ZW51YXRpb247Cn0Kc3BlY3VsYXIueHl6ICo9IHNwZWN1bGFyTGlnaHQ7CmNvbG9yLnh5eiArPSBzcGVjdWxhci54eXo7CmRpZmZ1c2UueHl6ICo9IGRpZmZ1c2VMaWdodDsKY29sb3IueHl6ICs9IGRpZmZ1c2UueHl6Owpjb2xvciA9IHZlYzQoY29sb3IucmdiICogZGlmZnVzZS5hLCBkaWZmdXNlLmEpOwpnbF9GcmFnQ29sb3IgPSBjb2xvcjsKfQo=" }, - "input0VS": { + { "type": 35633, "uri": "data:text/plain;base64,cHJlY2lzaW9uIGhpZ2hwIGZsb2F0OwphdHRyaWJ1dGUgdmVjMyBhX3Bvc2l0aW9uOwphdHRyaWJ1dGUgdmVjMyBhX25vcm1hbDsKdmFyeWluZyB2ZWMzIHZfbm9ybWFsOwp1bmlmb3JtIG1hdDMgdV9ub3JtYWxNYXRyaXg7CnVuaWZvcm0gbWF0NCB1X21vZGVsVmlld01hdHJpeDsKdW5pZm9ybSBtYXQ0IHVfcHJvamVjdGlvbk1hdHJpeDsKdmFyeWluZyB2ZWMzIHZfbGlnaHQxRGlyZWN0aW9uOwp2YXJ5aW5nIHZlYzMgdl9wb3NpdGlvbjsKdW5pZm9ybSBtYXQ0IHVfbGlnaHQxVHJhbnNmb3JtOwp2b2lkIG1haW4odm9pZCkgewp2ZWM0IHBvcyA9IHVfbW9kZWxWaWV3TWF0cml4ICogdmVjNChhX3Bvc2l0aW9uLDEuMCk7CnZfbm9ybWFsID0gdV9ub3JtYWxNYXRyaXggKiBhX25vcm1hbDsKdl9wb3NpdGlvbiA9IHBvcy54eXo7CnZfbGlnaHQxRGlyZWN0aW9uID0gbWF0Myh1X2xpZ2h0MVRyYW5zZm9ybSkgKiB2ZWMzKDAuLDAuLDEuKTsKZ2xfUG9zaXRpb24gPSB1X3Byb2plY3Rpb25NYXRyaXggKiBwb3M7Cn0K" } - }, + ], "skins": {}, - "techniques": { - "technique0": { + "techniques": [ + { "attributes": { "a_normal": "normal", "a_position": "position" @@ -449,7 +447,7 @@ ] }, "light1Transform": { - "node": "Light-sunLight011Node", + "node": 2, "semantic": "MODELVIEW", "type": 35676 }, @@ -480,7 +478,7 @@ "type": 35666 } }, - "program": "program_0", + "program": 0, "states": { "enable": [ 2929, @@ -499,5 +497,5 @@ "u_specular": "specular" } } - } + ] } \ No newline at end of file diff --git a/specs/data/dagToTree/DagTestSingleDuplicate.gltf b/specs/data/dagToTree/DagTestSingleDuplicate.gltf index 5dc6766b..78cc867b 100644 --- a/specs/data/dagToTree/DagTestSingleDuplicate.gltf +++ b/specs/data/dagToTree/DagTestSingleDuplicate.gltf @@ -1,28 +1,33 @@ { - "nodes": { - "A": { + "nodes": [ + { "children": [ - "B", - "C" - ] + 1, + 2 + ], + "name": "A" }, - "B": { + { "children": [ - "D" - ] + 3 + ], + "name": "B" }, - "C": { + { "children": [ - "D" - ] + 3 + ], + "name": "C" }, - "D": {} - }, - "scenes": { - "defaultScene": { + { + "name": "D" + } + ], + "scenes": [ + { "nodes": [ - "A" + 0 ] } - } + ] } \ No newline at end of file diff --git a/specs/data/dagToTree/DagTestSingleNode.gltf b/specs/data/dagToTree/DagTestSingleNode.gltf index 2916c5d8..3e1dc002 100644 --- a/specs/data/dagToTree/DagTestSingleNode.gltf +++ b/specs/data/dagToTree/DagTestSingleNode.gltf @@ -1,12 +1,14 @@ { - "nodes": { - "A": {} - }, - "scenes": { - "defaultScene": { + "nodes": [ + { + "name": "A" + } + ], + "scenes": [ + { "nodes": [ - "A" + 0 ] } - } + ] } \ No newline at end of file diff --git a/specs/data/dagToTree/DagTestSubgraphDuplicate.gltf b/specs/data/dagToTree/DagTestSubgraphDuplicate.gltf index 7723d4fa..ec6350e1 100644 --- a/specs/data/dagToTree/DagTestSubgraphDuplicate.gltf +++ b/specs/data/dagToTree/DagTestSubgraphDuplicate.gltf @@ -1,44 +1,52 @@ { - "nodes": { - "A": { + "nodes": [ + { "children": [ - "B", - "C" - ] + 1, + 2 + ], + "name": "A" }, - "B": { + { "children": [ - "D" - ] + 3 + ], + "name": "B" }, - "C": { + { "children": [ - "D" - ] + 3 + ], + "name": "C" }, - "D": { + { "children": [ - "E", - "F" - ] + 4, + 5 + ], + "name": "D" }, - "E": { + { "children": [ - "G" - ] + 6 + ], + "name": "E" }, - "F": { + { "children": [ - "G" - ] + 6 + ], + "name": "F" }, - "G": {} - }, - "scenes": { - "defaultScene": { + { + "name": "G" + } + ], + "scenes": [ + { "nodes": [ - "A" + 0 ] } - } + ] } \ No newline at end of file diff --git a/specs/data/dagToTree/DagTestTree.gltf b/specs/data/dagToTree/DagTestTree.gltf index 86daa9dd..267fbe69 100644 --- a/specs/data/dagToTree/DagTestTree.gltf +++ b/specs/data/dagToTree/DagTestTree.gltf @@ -1,19 +1,24 @@ { - "nodes": { - "A": { + "nodes": [ + { "children": [ - "B", - "C" - ] + 1, + 2 + ], + "name": "A" + }, + { + "name": "B" }, - "B": {}, - "C": {} - }, - "scenes": { - "defaultScene": { + { + "name": "C" + } + ], + "scenes": [ + { "nodes": [ - "A" + 0 ] } - } + ] } \ No newline at end of file diff --git a/specs/data/dagToTree/DagTestTwoRoots.gltf b/specs/data/dagToTree/DagTestTwoRoots.gltf index 3bf9dceb..d8fb234c 100644 --- a/specs/data/dagToTree/DagTestTwoRoots.gltf +++ b/specs/data/dagToTree/DagTestTwoRoots.gltf @@ -1,39 +1,46 @@ { - "nodes": { - "B": { + "nodes": [ + { "children": [ - "D" - ] + 2 + ], + "name": "B" }, - "C": { + { "children": [ - "D" - ] + 2 + ], + "name": "C" }, - "D": { + { "children": [ - "E", - "F" - ] + 3, + 4 + ], + "name": "D" }, - "E": { + { "children": [ - "G" - ] + 5 + ], + "name": "E" }, - "F": { + { "children": [ - "G" - ] + 5 + ], + "name": "F" }, - "G": {} - }, - "scenes": { - "defaultScene": { + { + "name": "G" + } + ], + "scenes": [ + { "nodes": [ - "B", - "C" + 0, + 1 ] } - } + ] } \ No newline at end of file diff --git a/specs/data/generateNormals/box_no_normals.gltf b/specs/data/generateNormals/box_no_normals.gltf index 72983ec3..f51ad6cc 100644 --- a/specs/data/generateNormals/box_no_normals.gltf +++ b/specs/data/generateNormals/box_no_normals.gltf @@ -1,15 +1,16 @@ { - "accessors": { - "accessor_index_0": { - "bufferView": "bufferView_index", + "accessors": [ + { + "bufferView": 1, "byteOffset": 0, "byteStride": 0, "componentType": 5123, "count": 36, - "type": "SCALAR" + "type": "SCALAR", + "name": "accessor_index_0" }, - "accessor_position": { - "bufferView": "bufferView_vertex", + { + "bufferView": 0, "byteOffset": 0, "byteStride": 12, "componentType": 5126, @@ -24,9 +25,10 @@ 1, 1 ], - "type": "VEC3" + "type": "VEC3", + "name": "accessor_position" } - }, + ], "asset": { "generator": "OBJ2GLTF", "premultipliedAlpha": true, @@ -36,30 +38,30 @@ }, "version": 1 }, - "buffers": { - "buffer_box": { + "buffers": [ + { "byteLength": 168, "type": "arraybuffer", "uri": "data:application/octet-stream;base64,AACAvwAAgD8AAIA/AACAvwAAgD8AAIC/AACAvwAAgL8AAIC/AACAvwAAgL8AAIA/AACAPwAAgD8AAIC/AACAPwAAgL8AAIC/AACAPwAAgD8AAIA/AACAPwAAgL8AAIA/AAABAAIAAAACAAMAAQAEAAUAAQAFAAIABAAGAAcABAAHAAUABgAAAAMABgADAAcAAwACAAUAAwAFAAcABgAEAAEABgABAAAA" } - }, - "bufferViews": { - "bufferView_vertex": { - "buffer": "buffer_box", + ], + "bufferViews": [ + { + "buffer": 0, "byteLength": 96, "byteOffset": 0, "target": 34962 }, - "bufferView_index": { - "buffer": "buffer_box", + { + "buffer": 0, "byteLength": 72, "byteOffset": 96, "target": 34963 } - }, - "images": {}, - "materials": { - "material_czmDefaultMat": { + ], + "images": [], + "materials": [ + { "name": "czmDefaultMat", "values": { "ambient": [ @@ -86,27 +88,27 @@ 0, 1 ], - "shininess": 0 + "shininess": [0] } } - }, - "meshes": { - "mesh_box": { + ], + "meshes": [ + { "name": "box", "primitives": [ { "attributes": { - "POSITION": "accessor_position" + "POSITION": 1 }, - "indices": "accessor_index_0", - "material": "material_czmDefaultMat", + "indices": 0, + "material": 0, "mode": 4 } ] } - }, - "nodes": { - "node_box": { + ], + "nodes": [ + { "children": [], "matrix": [ 1, @@ -126,22 +128,20 @@ 0, 1 ], - "meshes": [ - "mesh_box" - ], + "mesh": 0, "name": "box" } - }, - "samplers": { - "sampler_0": {} - }, - "scene": "scene_box", - "scenes": { - "scene_box": { + ], + "samplers": [ + {} + ], + "scene": 0, + "scenes": [ + { "nodes": [ - "node_box" + 0 ] } - }, - "textures": {} + ], + "textures": [] } diff --git a/specs/data/generateNormals/box_normals.gltf b/specs/data/generateNormals/box_normals.gltf index 52ffe1d4..c995de7c 100644 --- a/specs/data/generateNormals/box_normals.gltf +++ b/specs/data/generateNormals/box_normals.gltf @@ -1,7 +1,7 @@ { - "accessors": { - "accessor_index_0": { - "bufferView": "bufferView_1", + "accessors": [ + { + "bufferView": 1, "byteOffset": 0, "byteStride": 0, "componentType": 5123, @@ -12,10 +12,11 @@ ], "max": [ 23 - ] + ], + "name": "accessor_index_0" }, - "accessor_position": { - "bufferView": "bufferView_0", + { + "bufferView": 0, "byteOffset": 0, "byteStride": 0, "componentType": 5126, @@ -30,10 +31,11 @@ 1, 1 ], - "type": "VEC3" + "type": "VEC3", + "name": "accessor_position" }, - "accessor_normal": { - "bufferView": "bufferView_0", + { + "bufferView": 0, "byteOffset": 288, "byteStride": 0, "componentType": 5126, @@ -48,9 +50,10 @@ 1, 1, 1 - ] + ], + "name": "accessor_normal" } - }, + ], "asset": { "generator": "OBJ2GLTF", "premultipliedAlpha": true, @@ -60,30 +63,30 @@ }, "version": "1.0" }, - "buffers": { - "buffer_0": { + "buffers": [ + { "type": "arraybuffer", "byteLength": 648, "uri": "data:application/octet-stream;base64,AACAvwAAgD8AAIA/AACAvwAAgD8AAIC/AACAvwAAgL8AAIC/AACAvwAAgL8AAIA/AACAvwAAgD8AAIC/AACAPwAAgD8AAIC/AACAPwAAgL8AAIC/AACAvwAAgL8AAIC/AACAPwAAgD8AAIC/AACAPwAAgD8AAIA/AACAPwAAgL8AAIA/AACAPwAAgL8AAIC/AACAPwAAgD8AAIA/AACAvwAAgD8AAIA/AACAvwAAgL8AAIA/AACAPwAAgL8AAIA/AACAvwAAgL8AAIA/AACAvwAAgL8AAIC/AACAPwAAgL8AAIC/AACAPwAAgL8AAIA/AACAPwAAgD8AAIA/AACAPwAAgD8AAIC/AACAvwAAgD8AAIC/AACAvwAAgD8AAIA/AACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAABAAIAAAACAAMABAAFAAYABAAGAAcACAAJAAoACAAKAAsADAANAA4ADAAOAA8AEAARABIAEAASABMAFAAVABYAFAAWABcA" } - }, - "bufferViews": { - "bufferView_0": { - "buffer": "buffer_0", + ], + "bufferViews": [ + { + "buffer": 0, "byteLength": 576, "byteOffset": 0, "target": 34962 }, - "bufferView_1": { - "buffer": "buffer_0", + { + "buffer": 0, "byteLength": 72, "byteOffset": 576, "target": 34963 } - }, - "images": {}, - "materials": { - "material_czmDefaultMat": { + ], + "images": [], + "materials": [ + { "name": "czmDefaultMat", "extensions": {}, "values": { @@ -111,34 +114,32 @@ 0, 1 ], - "shininess": 0, - "transparency": 1 + "shininess": [0], + "transparency": [1] }, - "technique": "technique0" + "technique": 0 } - }, - "meshes": { - "mesh_box_normals": { + ], + "meshes": [ + { "name": "box_normals", "primitives": [ { "attributes": { - "POSITION": "accessor_position", - "NORMAL": "accessor_normal" + "POSITION": 1, + "NORMAL": 2 }, - "indices": "accessor_index_0", - "material": "material_czmDefaultMat", + "indices": 0, + "material": 0, "mode": 4 } ] } - }, - "nodes": { - "rootNode": { + ], + "nodes": [ + { "children": [], - "meshes": [ - "mesh_box_normals" - ], + "mesh": 0, "matrix": [ 1, 0, @@ -158,22 +159,22 @@ 1 ] } - }, - "samplers": {}, - "scene": "scene_box_normals", - "scenes": { - "scene_box_normals": { + ], + "samplers": [], + "scene": 0, + "scenes": [ + { "nodes": [ - "rootNode" + 0 ] } - }, - "textures": {}, + ], + "textures": [], "extensionsUsed": [], - "animations": {}, - "cameras": {}, - "techniques": { - "technique0": { + "animations": [], + "cameras": [], + "techniques": [ + { "attributes": { "a_position": "position", "a_normal": "normal" @@ -218,7 +219,7 @@ "type": 35665 } }, - "program": "program0", + "program": 0, "states": { "enable": [ 2884, @@ -237,27 +238,26 @@ "u_transparency": "transparency" } } - }, - "programs": { - "program0": { + ], + "programs": [ + { "attributes": [ "a_position", "a_normal" ], - "fragmentShader": "fragmentShader0", - "vertexShader": "vertexShader0" + "fragmentShader": 0, + "vertexShader": 1 } - }, - "shaders": { - "vertexShader0": { + ], + "shaders": [ + { "type": 35633, "uri": "data:text/plain;base64,cHJlY2lzaW9uIGhpZ2hwIGZsb2F0Owp1bmlmb3JtIG1hdDQgdV9tb2RlbFZpZXdNYXRyaXg7CnVuaWZvcm0gbWF0NCB1X3Byb2plY3Rpb25NYXRyaXg7CnVuaWZvcm0gbWF0MyB1X25vcm1hbE1hdHJpeDsKYXR0cmlidXRlIHZlYzMgYV9wb3NpdGlvbjsKdmFyeWluZyB2ZWMzIHZfcG9zaXRpb25FQzsKYXR0cmlidXRlIHZlYzMgYV9ub3JtYWw7CnZhcnlpbmcgdmVjMyB2X25vcm1hbDsKdm9pZCBtYWluKHZvaWQpIHsKICB2ZWM0IHBvcyA9IHVfbW9kZWxWaWV3TWF0cml4ICogdmVjNChhX3Bvc2l0aW9uLDEuMCk7CiAgdl9wb3NpdGlvbkVDID0gcG9zLnh5ejsKICBnbF9Qb3NpdGlvbiA9IHVfcHJvamVjdGlvbk1hdHJpeCAqIHBvczsKICB2X25vcm1hbCA9IHVfbm9ybWFsTWF0cml4ICogYV9ub3JtYWw7Cn0K" }, - "fragmentShader0": { + { "type": 35632, "uri": "data:text/plain;base64,cHJlY2lzaW9uIGhpZ2hwIGZsb2F0Owp1bmlmb3JtIHZlYzQgdV9hbWJpZW50Owp1bmlmb3JtIHZlYzQgdV9kaWZmdXNlOwp1bmlmb3JtIHZlYzQgdV9lbWlzc2lvbjsKdW5pZm9ybSB2ZWM0IHVfc3BlY3VsYXI7CnVuaWZvcm0gZmxvYXQgdV9zaGluaW5lc3M7CnVuaWZvcm0gZmxvYXQgdV90cmFuc3BhcmVuY3k7CnZhcnlpbmcgdmVjMyB2X3Bvc2l0aW9uRUM7CnZhcnlpbmcgdmVjMyB2X25vcm1hbDsKdm9pZCBtYWluKHZvaWQpIHsKICB2ZWMzIG5vcm1hbCA9IG5vcm1hbGl6ZSh2X25vcm1hbCk7CiAgdmVjNCBkaWZmdXNlID0gdV9kaWZmdXNlOwogIHZlYzMgZGlmZnVzZUxpZ2h0ID0gdmVjMygwLjAsIDAuMCwgMC4wKTsKICB2ZWMzIHNwZWN1bGFyID0gdV9zcGVjdWxhci5yZ2I7CiAgdmVjMyBzcGVjdWxhckxpZ2h0ID0gdmVjMygwLjAsIDAuMCwgMC4wKTsKICB2ZWMzIGVtaXNzaW9uID0gdV9lbWlzc2lvbi5yZ2I7CiAgdmVjMyBhbWJpZW50ID0gdV9hbWJpZW50LnJnYjsKICB2ZWMzIHZpZXdEaXIgPSAtbm9ybWFsaXplKHZfcG9zaXRpb25FQyk7CiAgdmVjMyBhbWJpZW50TGlnaHQgPSB2ZWMzKDAuMCwgMC4wLCAwLjApOwogIGFtYmllbnRMaWdodCArPSB2ZWMzKDAuMiwgMC4yLCAwLjIpOwogIHZlYzMgbCA9IHZlYzMoMC4wLCAwLjAsIDEuMCk7CiAgZGlmZnVzZUxpZ2h0ICs9IHZlYzMoMS4wLCAxLjAsIDEuMCkgKiBtYXgoZG90KG5vcm1hbCxsKSwgMC4pOwogIHZlYzMgaCA9IG5vcm1hbGl6ZShsICsgdmlld0Rpcik7CiAgZmxvYXQgc3BlY3VsYXJJbnRlbnNpdHkgPSBtYXgoMC4sIHBvdyhtYXgoZG90KG5vcm1hbCwgaCksIDAuKSwgdV9zaGluaW5lc3MpKTsKICBzcGVjdWxhckxpZ2h0ICs9IHZlYzMoMS4wLCAxLjAsIDEuMCkgKiBzcGVjdWxhckludGVuc2l0eTsKICB2ZWMzIGNvbG9yID0gdmVjMygwLjAsIDAuMCwgMC4wKTsKICBjb2xvciArPSBkaWZmdXNlLnJnYiAqIGRpZmZ1c2VMaWdodDsKICBjb2xvciArPSBzcGVjdWxhciAqIHNwZWN1bGFyTGlnaHQ7CiAgY29sb3IgKz0gZW1pc3Npb247CiAgY29sb3IgKz0gYW1iaWVudCAqIGFtYmllbnRMaWdodDsKICBnbF9GcmFnQ29sb3IgPSB2ZWM0KGNvbG9yICogZGlmZnVzZS5hLCBkaWZmdXNlLmEgKiB1X3RyYW5zcGFyZW5jeSk7Cn0K" } - }, - "skins": {}, - "extensions": {} + ], + "skins": [] } diff --git a/specs/data/generateTangentsBitangents/CesiumTexturedBoxTest_TangentsBitangents.gltf b/specs/data/generateTangentsBitangents/CesiumTexturedBoxTest_TangentsBitangents.gltf deleted file mode 100644 index 91df1d0e..00000000 --- a/specs/data/generateTangentsBitangents/CesiumTexturedBoxTest_TangentsBitangents.gltf +++ /dev/null @@ -1,313 +0,0 @@ -{ - "accessors": { - "accessor_21": { - "bufferView": "bufferView_1", - "byteOffset": 0, - "byteStride": 0, - "componentType": 5123, - "count": 36, - "type": "SCALAR", - "min": [ - 0 - ], - "max": [ - 23 - ] - }, - "accessor_23": { - "bufferView": "bufferView_0", - "byteOffset": 0, - "byteStride": 0, - "componentType": 5126, - "count": 24, - "max": [ - 0.5, - 0.5, - 0.5 - ], - "min": [ - -0.5, - -0.5, - -0.5 - ], - "type": "VEC3" - }, - "accessor_25": { - "bufferView": "bufferView_0", - "byteOffset": 288, - "byteStride": 0, - "componentType": 5126, - "count": 24, - "max": [ - 1, - 1, - 1 - ], - "min": [ - -1, - -1, - -1 - ], - "type": "VEC3" - }, - "accessor_27": { - "bufferView": "bufferView_0", - "byteOffset": 576, - "byteStride": 0, - "componentType": 5126, - "count": 24, - "max": [ - 6, - 1 - ], - "min": [ - 0, - 0 - ], - "type": "VEC2" - }, - "accessor_tangent": { - "bufferView": "bufferView_0", - "byteOffset": 768, - "byteStride": 0, - "componentType": 5126, - "count": 24, - "type": "VEC3", - "min": [ - -1, - 0, - 0 - ], - "max": [ - 1, - 0, - 1 - ] - }, - "accessor_bitangent": { - "bufferView": "bufferView_0", - "byteOffset": 1056, - "byteStride": 0, - "componentType": 5126, - "count": 24, - "type": "VEC3", - "min": [ - 0, - -1, - 0 - ], - "max": [ - 0, - 1, - 1 - ] - } - }, - "animations": {}, - "asset": { - "generator": "collada2gltf@ceec062e3d5793f2f249f53cbd843aee382ad40b", - "premultipliedAlpha": true, - "profile": { - "api": "WebGL", - "version": "1.0.2" - }, - "version": "1.0" - }, - "bufferViews": { - "bufferView_0": { - "buffer": "CesiumTexturedBoxTest", - "byteLength": 1344, - "byteOffset": 0, - "target": 34962 - }, - "bufferView_1": { - "buffer": "CesiumTexturedBoxTest", - "byteLength": 72, - "byteOffset": 1344, - "target": 34963 - } - }, - "buffers": { - "CesiumTexturedBoxTest": { - "type": "arraybuffer", - "byteLength": 1416, - "uri": "data:application/octet-stream;base64,AAAAvwAAAD8AAAA/AAAAPwAAAD8AAAA/AAAAvwAAAD8AAAC/AAAAPwAAAD8AAAC/AAAAPwAAAD8AAAC/AAAAPwAAAD8AAAA/AAAAPwAAAL8AAAC/AAAAPwAAAL8AAAA/AAAAvwAAAD8AAAC/AAAAPwAAAD8AAAC/AAAAvwAAAL8AAAC/AAAAPwAAAL8AAAC/AAAAPwAAAD8AAAA/AAAAvwAAAD8AAAA/AAAAPwAAAL8AAAA/AAAAvwAAAL8AAAA/AAAAvwAAAD8AAAA/AAAAvwAAAD8AAAC/AAAAvwAAAL8AAAA/AAAAvwAAAL8AAAC/AAAAvwAAAL8AAAA/AAAAvwAAAL8AAAC/AAAAPwAAAL8AAAA/AAAAPwAAAL8AAAC/AAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAADAQAAAAAAAAKBAAAAAAAAAwED+/38/AACgQP7/fz8AAIBAAAAAAAAAoEAAAAAAAACAQAAAgD8AAKBAAACAPwAAAEAAAAAAAACAPwAAAAAAAABAAACAPwAAgD8AAIA/AABAQAAAAAAAAIBAAAAAAAAAQEAAAIA/AACAQAAAgD8AAEBAAAAAAAAAAEAAAAAAAABAQAAAgD8AAABAAACAPwAAAAAAAAAAAAAAAP7/fz8AAIA/AAAAAAAAgD/+/38/AACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAAAAAAAAAIAAAIA/AAAAAAAAAIAAAIA/AAAAAAAAAIAAAIA/AAAAAAAAAIAAAIA/AAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgD8AAACAAAAAAAAAgD8AAACAAAAAAAAAgD8AAACAAAAAAAAAgD8AAACAAAAAgAAAAAAAAIA/AAAAgAAAAAAAAIA/AAAAgAAAAAAAAIA/AAAAgAAAAAAAAIA/AAABAAIAAwACAAEABAAFAAYABwAGAAUACAAJAAoACwAKAAkADAANAA4ADwAOAA0AEAARABIAEwASABEAFAAVABYAFwAWABUA" - } - }, - "images": { - "Image0001": { - "name": "Image0001", - "uri": "data:image/png;base64,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" - } - }, - "materials": { - "Effect-Texture": { - "name": "Texture", - "technique": "technique0", - "values": { - "diffuse": "texture_Image0001", - "shininess": 256, - "specular": [ - 0.2, - 0.2, - 0.2, - 1 - ] - } - } - }, - "meshes": { - "Geometry-mesh002": { - "name": "Mesh", - "primitives": [ - { - "attributes": { - "NORMAL": "accessor_25", - "POSITION": "accessor_23", - "TEXCOORD_0": "accessor_27", - "TANGENT": "accessor_tangent", - "BITANGENT": "accessor_bitangent" - }, - "indices": "accessor_21", - "material": "Effect-Texture", - "mode": 4 - } - ] - } - }, - "nodes": { - "rootNode": { - "children": [], - "meshes": [ - "Geometry-mesh002" - ], - "matrix": [ - 1, - 0, - 0, - 0, - 0, - 1, - 0, - 0, - 0, - 0, - 1, - 0, - 0, - 0, - 0, - 1 - ] - } - }, - "programs": { - "program_0": { - "attributes": [ - "a_normal", - "a_position", - "a_texcoord0" - ], - "fragmentShader": "CesiumTexturedBoxTest0FS", - "vertexShader": "CesiumTexturedBoxTest0VS" - } - }, - "samplers": { - "sampler_0": { - "magFilter": 9729, - "minFilter": 9987, - "wrapS": 10497, - "wrapT": 10497 - } - }, - "scene": "defaultScene", - "scenes": { - "defaultScene": { - "nodes": [ - "rootNode" - ] - } - }, - "shaders": { - "CesiumTexturedBoxTest0FS": { - "type": 35632, - "uri": "data:text/plain;base64,cHJlY2lzaW9uIGhpZ2hwIGZsb2F0Owp2YXJ5aW5nIHZlYzMgdl9ub3JtYWw7CnZhcnlpbmcgdmVjMiB2X3RleGNvb3JkMDsKdW5pZm9ybSBzYW1wbGVyMkQgdV9kaWZmdXNlOwp1bmlmb3JtIHZlYzQgdV9zcGVjdWxhcjsKdW5pZm9ybSBmbG9hdCB1X3NoaW5pbmVzczsKdm9pZCBtYWluKHZvaWQpIHsKdmVjMyBub3JtYWwgPSBub3JtYWxpemUodl9ub3JtYWwpOwp2ZWM0IGNvbG9yID0gdmVjNCgwLiwgMC4sIDAuLCAwLik7CnZlYzQgZGlmZnVzZSA9IHZlYzQoMC4sIDAuLCAwLiwgMS4pOwp2ZWM0IHNwZWN1bGFyOwpkaWZmdXNlID0gdGV4dHVyZTJEKHVfZGlmZnVzZSwgdl90ZXhjb29yZDApOwpzcGVjdWxhciA9IHVfc3BlY3VsYXI7CmRpZmZ1c2UueHl6ICo9IG1heChkb3Qobm9ybWFsLHZlYzMoMC4sMC4sMS4pKSwgMC4pOwpjb2xvci54eXogKz0gZGlmZnVzZS54eXo7CmNvbG9yID0gdmVjNChjb2xvci5yZ2IgKiBkaWZmdXNlLmEsIGRpZmZ1c2UuYSk7CmdsX0ZyYWdDb2xvciA9IGNvbG9yOwp9Cg==" - }, - "CesiumTexturedBoxTest0VS": { - "type": 35633, - "uri": "data:text/plain;base64,cHJlY2lzaW9uIGhpZ2hwIGZsb2F0OwphdHRyaWJ1dGUgdmVjMyBhX3Bvc2l0aW9uOwphdHRyaWJ1dGUgdmVjMyBhX25vcm1hbDsKdmFyeWluZyB2ZWMzIHZfbm9ybWFsOwp1bmlmb3JtIG1hdDMgdV9ub3JtYWxNYXRyaXg7CnVuaWZvcm0gbWF0NCB1X21vZGVsVmlld01hdHJpeDsKdW5pZm9ybSBtYXQ0IHVfcHJvamVjdGlvbk1hdHJpeDsKYXR0cmlidXRlIHZlYzIgYV90ZXhjb29yZDA7CnZhcnlpbmcgdmVjMiB2X3RleGNvb3JkMDsKdm9pZCBtYWluKHZvaWQpIHsKdmVjNCBwb3MgPSB1X21vZGVsVmlld01hdHJpeCAqIHZlYzQoYV9wb3NpdGlvbiwxLjApOwp2X25vcm1hbCA9IHVfbm9ybWFsTWF0cml4ICogYV9ub3JtYWw7CnZfdGV4Y29vcmQwID0gYV90ZXhjb29yZDA7CmdsX1Bvc2l0aW9uID0gdV9wcm9qZWN0aW9uTWF0cml4ICogcG9zOwp9Cg==" - } - }, - "skins": {}, - "techniques": { - "technique0": { - "attributes": { - "a_normal": "normal", - "a_position": "position", - "a_texcoord0": "texcoord0" - }, - "parameters": { - "diffuse": { - "type": 35678 - }, - "modelViewMatrix": { - "semantic": "MODELVIEW", - "type": 35676 - }, - "normal": { - "semantic": "NORMAL", - "type": 35665 - }, - "normalMatrix": { - "semantic": "MODELVIEWINVERSETRANSPOSE", - "type": 35675 - }, - "position": { - "semantic": "POSITION", - "type": 35665 - }, - "projectionMatrix": { - "semantic": "PROJECTION", - "type": 35676 - }, - "shininess": { - "type": 5126 - }, - "specular": { - "type": 35666 - }, - "texcoord0": { - "semantic": "TEXCOORD_0", - "type": 35664 - } - }, - "program": "program_0", - "states": { - "enable": [ - 2929, - 2884 - ] - }, - "uniforms": { - "u_diffuse": "diffuse", - "u_modelViewMatrix": "modelViewMatrix", - "u_normalMatrix": "normalMatrix", - "u_projectionMatrix": "projectionMatrix", - "u_shininess": "shininess", - "u_specular": "specular" - } - } - }, - "textures": { - "texture_Image0001": { - "format": 6408, - "internalFormat": 6408, - "sampler": "sampler_0", - "source": "Image0001", - "target": 3553, - "type": 5121 - } - }, - "extensionsUsed": [], - "cameras": {} -} diff --git a/specs/data/riggedSimpleUnoptimized/riggedSimple.bin b/specs/data/riggedSimpleUnoptimized/riggedSimple.bin deleted file mode 100644 index 4a7b5453f7f21935edfe01cadea2ea9fb26e5a9e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10468 zcmeHL3vgA{72QCH5ko}2ks_rSW1xtEyZ|A*djkO?f+!GB3}uv$UJ4bsHxS~CwE`CGRBVTi7MOO_%+S&g9cF>X}Nl)nmE0Dg3&6gtV%ai-0AAau#T0iLzf8H$?P$S~B`S{_ENt>h8Z-BO052kG)C`q5lQ zpf^orB>L1?MxkeoWHkDhCS%acR2hrDHju~A;}jW(ekaR#^gc-*2jjZ(1il5ooJNvP zBUz`BqSI)g(@526r0Fyo=`^IFnb^&}^YF9`I~ZT0*{2|82A=a-nXXU5N>8Yz0LthNZ=rl&DsU~5#kiKp zQe4ZRqTceH`~cVU@RrL8XltdsfbU+iN> zacu@>0coUa?jx%8QDyPWQfoJsYs25YdY@a=GSOtxsQ7oZj$@z`BpByDt=- zhx_|6hx?%De((lhI{l&O&hQ3eY7aos9pOEMc|Hh5w}&?va~=dmXTmGS{D(l%ZQ%`r zE`~zUt>HZay*vy>w}kg7bTk}_ZVqoG^fdyCZVYcUbT&5T5&V_kr{hXX%dcVp`bMOARSl7=+o^!?yJLV^+AM^g2lZcnXK#q#H+`!I?t#U}XANs}wvm5e@%PEU z&CPGH-heY>Ue4+r%&gD6o$OD*8k8qy%NlAXdF*Gv8n_NF{vOmY(%Vb!LB$_h?B+VS z`!z>1chAq%{s*kV#7{sCudP4G`39_k>%Rs*YiM|?+M{+@1J|h+@}>{IJ~cD7@O`hk zwnkkCU)JcKgvL&Pp*_)c@MTZ@N@&vVl|6UP-)MLuI2xUY{r8vE9QQUX)}H&@p!v~{;#t~u{K-{y>S&Ai9J#|5r~{#4rUNv;Ez zy{fd|x7=&q$;317ZRRrX_ABY!?!P@3dtUY&sU0(4d+zbtFq*No#Jxsiw)U9IXwudy z6=3wtoF>NBJauQZ4a`gD1+l)#MXeb<125(bnzP9mb7r~MoMmDf4Fm7ed%%7_kmv4_ z`9YUEKaKu;Xr1B&2eGDeqhep6>(v~*2B}Ih;^|?;}Pp(kH!Pr zMGl`FfbAlOPkeB3!O16|&t9ADPJOz_uf{s~>i-&{R-fm?XuhysZa|xj7(Qnl z{+mKeWjRsb<6h}oG%4`z|qfthxwm!u;b6yxjcu9QhuGe z*)@|dVeV|-NNd3;A=?-Tur?MM9G|9gLKbiMKUu67^a rfBW9{iF3X0<8xf^di&eyp?Z>|WtD(Gh diff --git a/specs/data/riggedSimpleUnoptimized/riggedSimple.glb b/specs/data/riggedSimpleUnoptimized/riggedSimple.glb deleted file mode 100644 index f442af824e006bd1ffcb302c9ea1de5c613eaed2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 18745 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 0).toEqual(true); - expect(Object.keys(gltf.techniques).length > 0).toEqual(true); - for (var materialID in gltf.materials) { - if (gltf.materials.hasOwnProperty(materialID)) { - expect(gltf.materials[materialID].values).toEqual(expectValues); - } + expect(gltf.materials.length).toBeGreaterThan(0); + expect(gltf.techniques.length).toBeGreaterThan(0); + var materialsLength = gltf.materials.length; + for (var materialId = 0; materialId < materialsLength; materialId++) { + expect(gltf.materials[materialId].values).toEqual(expectValues); } }); it('works with optimizeForCesium', function() { var gltf = { extensionsUsed: ['KHR_materials_common'], - materials: { - material1: { + materials: [ + { extensions: { KHR_materials_common: { technique: 'BLINN', - ambient: [0.0, 0.0, 0.0, 1.0], - diffuse: [1.0, 0.0, 0.0, 1.0], - emission: 'texture_file2' + values: { + ambient: [0.0, 0.0, 0.0, 1.0], + diffuse: [1.0, 0.0, 0.0, 1.0], + emission: [0] + } } } } - } + ] }; var gltfClone = clone(gltf, true); @@ -144,11 +144,11 @@ describe('processModelMaterialsCommon', function() { processModelMaterialsCommon(gltfClone, options); // Uses the Cesium sun as its default light source - var fragmentShaderSource = gltfClone.shaders.fragmentShader0.extras._pipeline.source; + var fragmentShaderSource = gltfClone.shaders[gltfClone.programs[0].fragmentShader].extras._pipeline.source; expect(fragmentShaderSource.indexOf('czm_sunDirectionEC') > -1).toBe(true); // Adds the _3DTILESDIFFUSE flag - var technique = gltfClone.techniques[Object.keys(gltfClone.techniques)[0]]; + var technique = gltfClone.techniques[0]; expect(technique.parameters.diffuse.semantic).toEqual('_3DTILESDIFFUSE'); gltfClone = clone(gltf, true); @@ -156,46 +156,46 @@ describe('processModelMaterialsCommon', function() { addPipelineExtras(gltfClone); processModelMaterialsCommon(gltfClone); - fragmentShaderSource = gltfClone.shaders.fragmentShader0.extras._pipeline.source; + fragmentShaderSource = gltfClone.shaders[gltfClone.programs[0].fragmentShader].extras._pipeline.source; expect(fragmentShaderSource.indexOf('czm_sunDirectionEC') > -1).toBe(false); }); it('adds nonstandard semantic', function() { var gltf = { - 'accessors': { - 'accessor_3': { - 'componentType': 5123, - 'type': 'SCALAR' + accessors: [ + { + componentType: 5123, + type: 'SCALAR' } - }, - 'extensionsUsed': [ + ], + extensionsUsed: [ 'KHR_materials_common' ], - 'meshes': { - 'mesh1' : { - 'primitives': [ + meshes: [ + { + primitives: [ { - 'attributes': { - 'NORMAL': 'accessor_1', - 'POSITION': 'accessor_2', - 'BATCHID': 'accessor_3' + attributes: { + NORMAL: 1, + POSITION: 2, + _BATCHID: 0 }, - 'indices': 'accessor_4', - 'material': 'material1', - 'mode': 4 + indices: 3, + material: 0, + mode: 4 } ] } - }, - 'materials': { - 'material1': { - 'extensions': { - 'KHR_materials_common': { - 'doubleSided': false, - 'jointCount': 0, - 'technique': 'PHONG', - 'transparent': false, - 'values': { + ], + materials: [ + { + extensions: { + KHR_materials_common: { + doubleSided: false, + jointCount: 0, + technique: 'PHONG', + transparent: false, + values: { 'diffuse': [ 0.4, 0.4, @@ -205,9 +205,9 @@ describe('processModelMaterialsCommon', function() { } } }, - 'name': 'material1' + name: 'material1' } - } + ] }; var gltfClone = clone(gltf); @@ -215,10 +215,10 @@ describe('processModelMaterialsCommon', function() { addPipelineExtras(gltfClone); processModelMaterialsCommon(gltfClone); - var material = gltfClone.materials.material1; + var material = gltfClone.materials[0]; var technique = gltfClone.techniques[material.technique]; expect(technique.attributes.a_batchid).toEqual('batchid'); - expect(technique.parameters.batchid.semantic).toEqual('BATCHID'); + expect(technique.parameters.batchid.semantic).toEqual('_BATCHID'); var program = gltfClone.programs[technique.program]; expect(program.attributes.indexOf('a_batchid') > -1).toBe(true); @@ -229,29 +229,26 @@ describe('processModelMaterialsCommon', function() { it('splits two materials with different types for JOINT and WEIGHT', function() { var gltf = { - accessors: { - jointAccessor_0: { + accessors: [ + { componentType: WebGLConstants.FLOAT, type: 'VEC4' - }, - weightAccessor_0: { + }, { componentType: WebGLConstants.FLOAT, type: 'VEC4' - }, - jointAccessor_1: { + }, { componentType: WebGLConstants.FLOAT, type: 'MAT3' - }, - weightAccessor_1: { + }, { componentType: WebGLConstants.FLOAT, type: 'MAT3' } - }, + ], extensionsUsed: [ 'KHR_materials_common' ], - materials: { - material: { + materials: [ + { extensions: { KHR_materials_common: { jointCount: 14, @@ -259,35 +256,34 @@ describe('processModelMaterialsCommon', function() { } } } - }, - meshes: { - meshVec4: { + ], + meshes: [ + { primitives: [{ attributes: { - JOINT: 'jointAccessor_0', - WEIGHT: 'weightAccessor_0' + JOINT: 0, + WEIGHT: 1 }, - material: 'material' + material: 0 }] - }, - meshMat3: { + }, { primitives: [{ attributes: { - JOINT: 'jointAccessor_1', - WEIGHT: 'weightAccessor_1' + JOINT: 2, + WEIGHT: 3 }, - material: 'material' + material: 0 }] } - } + ] }; addDefaults(gltf); addPipelineExtras(gltf); processModelMaterialsCommon(gltf); var meshes = gltf.meshes; - var primitiveVec4 = meshes.meshVec4.primitives[0]; - var primitiveMat3 = meshes.meshMat3.primitives[0]; + var primitiveVec4 = meshes[0].primitives[0]; + var primitiveMat3 = meshes[1].primitives[0]; var materialVec4Id = primitiveVec4.material; var materialMat3Id = primitiveMat3.material; expect(materialVec4Id).not.toEqual(materialMat3Id); diff --git a/specs/lib/quantizeAttributesSpec.js b/specs/lib/quantizeAttributesSpec.js index 3c87a467..f9ff6853 100644 --- a/specs/lib/quantizeAttributesSpec.js +++ b/specs/lib/quantizeAttributesSpec.js @@ -1,49 +1,43 @@ 'use strict'; var clone = require('clone'); - var byteLengthForComponentType = require('../../lib/byteLengthForComponentType'); var numberOfComponentsForType = require('../../lib/numberOfComponentsForType'); var quantizeAttributes = require('../../lib/quantizeAttributes'); +var uninterleaveAndPackBuffers = require('../../lib/uninterleaveAndPackBuffers'); describe('quantizeAttributes', function() { var buffer = new Buffer(new Uint8Array(120)); var testGltf = { - accessors : { - // Interleaved accessors in bufferView_0 - accessor_0 : { - bufferView : 'bufferView_0', + accessors : [ + { + // Interleaved accessors in bufferView_0 + bufferView : 0, byteOffset : 0, - byteStride : 18, componentType : 5126, count : 3, min : [-1.0, -1.0, -1.0], max : [1.0, 1.0, 1.0], type : 'VEC3' - }, - accessor_1 : { - bufferView : 'bufferView_0', + }, { + bufferView : 0, byteOffset : 12, - byteStride : 18, componentType : 5123, count : 3, min : [-1.0, -1.0, -1.0], max : [1.0, 1.0, 1.0], type : 'VEC2' - }, - // Block accessors in bufferView_1 - accessor_2 : { - bufferView : 'bufferView_1', + }, { + // Block accessors in bufferView_1 + bufferView : 1, byteOffset : 0, - byteStride : 12, componentType : 5126, count : 3, min : [-1.0, -1.0, -1.0], max : [1.0, 1.0, 1.0], type : 'VEC3' - }, - // Already quantized - accessor_3 : { - bufferView : 'bufferView_1', + }, { + // Already quantized + bufferView : 1, byteOffset : 36, componentType : 5126, count : 3, @@ -61,20 +55,18 @@ describe('quantizeAttributes', function() { decodeMax : [1.0, 1.0] } } - }, - // SCALAR attribute - accessor_4 : { - bufferView : 'bufferView_1', + }, { + // SCALAR attribute + bufferView : 1, byteOffset : 60, componentType : 5126, count : 3, min : [0], max : [1], type : 'SCALAR' - }, + }, { // floating-point rounding test - accessor_5 : { - bufferView : 'bufferView_2', + bufferView : 2, byteOffset : 0, componentType : 5126, count : 1, @@ -82,112 +74,115 @@ describe('quantizeAttributes', function() { max : [0.0026710000820457935], type : 'SCALAR' } - }, - bufferViews : { - bufferView_0 : { - buffer : 'buffer', + ], + bufferViews : [ + { + buffer : 0, byteLength : 48, byteOffset : 0, + byteStride : 18, target : 34962 }, - bufferView_1 : { - buffer : 'buffer', + { + buffer : 0, byteLength : 72, byteOffset : 48, target : 34962 }, - bufferView_2 : { - buffer : 'buffer_float', + { + buffer : 1, byteLength : 4, byteOffset : 0, target: 34962 } - }, - buffers : { - buffer : { + ], + buffers : [ + { byteLength : buffer.length, - type : 'arraybuffer', extras : { _pipeline : {} } }, - buffer_float : { + { byteLength : 4, - type : 'array_buffer', extras : { _pipeline : { source : new Buffer(new Float32Array([0.0026710000820457935]).buffer) } } } - }, - meshes : { - mesh : { + ], + meshes : [ + { primitives : [ { attributes : { - POSITION : 'accessor_0', - NORMAL : 'accessor_1' + POSITION : 0, + NORMAL : 1 } }, { attributes : { - POSITION : 'accessor_2', - TEXCOORD : 'accessor_3', - SCALAR_TEST : 'accessor_4' + POSITION : 2, + TEXCOORD : 3, + SCALAR_TEST : 4 } }, { attributes : { - FLOAT_TEST : 'accessor_5' + FLOAT_TEST : 5 } } ] } - } + ] }; it('Doesn\'t quantize if options.semantics is empty', function() { var gltf = clone(testGltf); - gltf.buffers.buffer.extras._pipeline.source = buffer; + gltf.buffers[0].extras._pipeline.source = buffer; quantizeAttributes(gltf, {semantics: []}); - expect(gltf.buffers.buffer.byteLength).toEqual(buffer.length); + uninterleaveAndPackBuffers(gltf); + expect(gltf.buffers[0].byteLength).toEqual(buffer.length + 4); }); it('Doesn\'t quantize excluded semantics', function() { var gltf = clone(testGltf); - gltf.buffers.buffer.extras._pipeline.source = buffer; + gltf.buffers[0].extras._pipeline.source = buffer; quantizeAttributes(gltf, {exclude: ['POSITION', 'NORMAL', 'TEXCOORD', 'SCALAR_TEST', 'FLOAT_TEST']}); - expect(gltf.buffers.buffer.byteLength).toEqual(buffer.length); + uninterleaveAndPackBuffers(gltf); + expect(gltf.buffers[0].byteLength).toEqual(buffer.length + 4); }); it('Quantizes attributes for semantic', function() { var gltf = clone(testGltf); - var accessor_0 = gltf.accessors.accessor_0; - var accessor_2 = gltf.accessors.accessor_2; + var accessor_0 = gltf.accessors[0]; + var accessor_2 = gltf.accessors[2]; var size = byteLengthForComponentType(accessor_0.componentType) * numberOfComponentsForType(accessor_0.type) * accessor_0.count; size += byteLengthForComponentType(accessor_2.componentType) * numberOfComponentsForType(accessor_2.type) * accessor_2.count; size = size/2.0; - gltf.buffers.buffer.extras._pipeline.source = buffer; + gltf.buffers[0].extras._pipeline.source = buffer; quantizeAttributes(gltf, {semantics: ['POSITION']}); - expect(gltf.buffers.buffer.byteLength + size).toEqual(buffer.length); + uninterleaveAndPackBuffers(gltf); + expect(gltf.buffers[0].byteLength + size).toEqual(buffer.length + 4); var decodeMatrix = accessor_0.extensions.WEB3D_quantized_attributes.decodeMatrix; expect(decodeMatrix[0]).toBe(2.0 / 65535.0); }); it('Quantizes attributes using options.normalized for higher precision decode', function() { var gltf = clone(testGltf); - var accessor_0 = gltf.accessors.accessor_0; - var accessor_2 = gltf.accessors.accessor_2; + var accessor_0 = gltf.accessors[0]; + var accessor_2 = gltf.accessors[2]; var size = byteLengthForComponentType(accessor_0.componentType) * numberOfComponentsForType(accessor_0.type) * accessor_0.count; size += byteLengthForComponentType(accessor_2.componentType) * numberOfComponentsForType(accessor_2.type) * accessor_2.count; size = size/2.0; - gltf.buffers.buffer.extras._pipeline.source = buffer; + gltf.buffers[0].extras._pipeline.source = buffer; quantizeAttributes(gltf, { semantics : ['POSITION'], normalized : true }); - expect(gltf.buffers.buffer.byteLength + size).toEqual(buffer.length); + uninterleaveAndPackBuffers(gltf); + expect(gltf.buffers[0].byteLength + size).toEqual(buffer.length + 4); expect(accessor_0.normalized).toBeTruthy(); expect(accessor_2.normalized).toBeTruthy(); var decodeMatrix = accessor_0.extensions.WEB3D_quantized_attributes.decodeMatrix; @@ -196,35 +191,38 @@ describe('quantizeAttributes', function() { it('Reduces the decimal places in decode matrix using options.precision', function() { var gltf = clone(testGltf); - gltf.buffers.buffer.extras._pipeline.source = buffer; + gltf.buffers[0].extras._pipeline.source = buffer; var precision = 6; quantizeAttributes(gltf, {precision: precision}); - var matrixEntry = '' + gltf.accessors.accessor_0.extensions.WEB3D_quantized_attributes.decodeMatrix[0]; + var matrixEntry = '' + gltf.accessors[0].extensions.WEB3D_quantized_attributes.decodeMatrix[0]; var calculatedPrecision = matrixEntry.substring(matrixEntry.indexOf('.')).length; expect(precision).toEqual(calculatedPrecision); }); it('Doesn\'t quantize non-float attribute', function() { var gltf = clone(testGltf); - gltf.buffers.buffer.extras._pipeline.source = buffer; + gltf.buffers[0].extras._pipeline.source = buffer; quantizeAttributes(gltf, {semantics: ['NORMAL']}); - expect(gltf.buffers.buffer.byteLength).toEqual(buffer.length); + uninterleaveAndPackBuffers(gltf); + expect(gltf.buffers[0].byteLength).toEqual(buffer.length + 4); }); it('Doesn\'t quantize already quantized attribute', function() { var gltf = clone(testGltf); - gltf.buffers.buffer.extras._pipeline.source = buffer; + gltf.buffers[0].extras._pipeline.source = buffer; quantizeAttributes(gltf, {semantics: ['TEXCOORD']}); - expect(gltf.buffers.buffer.byteLength).toEqual(buffer.length); + uninterleaveAndPackBuffers(gltf); + expect(gltf.buffers[0].byteLength).toEqual(buffer.length + 4); }); it('Quantizes scalar attribute', function() { var gltf = clone(testGltf); - var accessor_4 = gltf.accessors.accessor_4; + var accessor_4 = gltf.accessors[4]; var size = byteLengthForComponentType(accessor_4.componentType) * numberOfComponentsForType(accessor_4.type) * accessor_4.count; size = size/2.0; - gltf.buffers.buffer.extras._pipeline.source = buffer; + gltf.buffers[0].extras._pipeline.source = buffer; quantizeAttributes(gltf, {semantics: ['SCALAR_TEST']}); - expect(gltf.buffers.buffer.byteLength + size).toEqual(buffer.length); + uninterleaveAndPackBuffers(gltf); + expect(gltf.buffers[0].byteLength + size).toEqual(buffer.length + 4); }); }); \ No newline at end of file diff --git a/specs/lib/removeDuplicatePrimitivesSpec.js b/specs/lib/removeDuplicatePrimitivesSpec.js index c3b5522f..a383a42b 100644 --- a/specs/lib/removeDuplicatePrimitivesSpec.js +++ b/specs/lib/removeDuplicatePrimitivesSpec.js @@ -5,8 +5,8 @@ var removeDuplicatePrimitives = require('../../lib/removeDuplicatePrimitives'); describe('removeDuplicatePrimitives', function() { it('removes duplicate primitives', function() { var gltf = { - meshes : { - mesh : { + meshes : [ + { primitives : [ { attributes : { @@ -34,18 +34,18 @@ describe('removeDuplicatePrimitives', function() { } ] } - } + ] }; removeDuplicatePrimitives(gltf); - var primitives = gltf.meshes.mesh.primitives; + var primitives = gltf.meshes[0].primitives; expect(primitives.length).toEqual(2); expect(primitives[1].indices).toEqual(8); }); it('combines duplicate primitives across meshes', function() { var gltf = { - meshes : { - meshA : { + meshes : [ + { primitives : [ { attributes : { @@ -57,7 +57,7 @@ describe('removeDuplicatePrimitives', function() { } ] }, - meshB : { + { primitives : [ { attributes : { @@ -69,13 +69,13 @@ describe('removeDuplicatePrimitives', function() { } ] } - } + ] }; removeDuplicatePrimitives(gltf); var meshes = gltf.meshes; - expect(meshes['mesh-split']).toBeDefined(); - expect(meshes['mesh-split'].primitives.length).toEqual(1); - expect(meshes.meshA.primitives.length).toEqual(0); - expect(meshes.meshB.primitives.length).toEqual(0); + expect(meshes.length).toEqual(3); + expect(meshes[2].primitives.length).toEqual(1); + expect(meshes[0].primitives.length).toEqual(0); + expect(meshes[1].primitives.length).toEqual(0); }); }); \ No newline at end of file diff --git a/specs/lib/removeUnusedVerticesSpec.js b/specs/lib/removeUnusedVerticesSpec.js index 1df660fe..50a7ccbc 100644 --- a/specs/lib/removeUnusedVerticesSpec.js +++ b/specs/lib/removeUnusedVerticesSpec.js @@ -1,9 +1,10 @@ 'use strict'; var clone = require('clone'); -var removeUnusedVertices = require('../../lib/removeUnusedVertices'); +var AccessorReader = require('../../lib/AccessorReader'); var byteLengthForComponentType = require('../../lib/byteLengthForComponentType'); var numberOfComponentsForType = require('../../lib/numberOfComponentsForType'); - +var removeUnusedVertices = require('../../lib/removeUnusedVertices'); +var uninterleaveAndPackBuffers = require('../../lib/uninterleaveAndPackBuffers'); describe('removeUnusedVertices', function() { var indices = new Uint16Array([0, 1, 2]); @@ -15,248 +16,273 @@ describe('removeUnusedVertices', function() { var attributesBuffer = Buffer.concat([attributeOne, attributeTwo, attributeThree]); var testGltf = { - accessors : { - indexAccessor : { + accessors : [ + { byteOffset : 0, - byteStride : 0, - bufferView : 'indexBufferView', + bufferView : 0, componentType : 5123, type : 'SCALAR' }, - attributeAccessor1 : { - byteStride : 0, - bufferView : 'attributesBufferView', + { + bufferView : 1, componentType : 5126, count : 3, byteOffset : 0, type : 'VEC3' }, - attributeAccessor2 : { - byteStride : 0, - bufferView : 'attributesBufferView', + { + bufferView : 1, componentType : 5123, count : 3, byteOffset : attributeOne.length, type : 'VEC2' }, - attributeAccessor3 : { - byteStride : 0, - bufferView : 'attributesBufferView', + { + bufferView : 1, componentType : 5123, count : 3, byteOffset : 0, type : 'VEC3' } - }, - buffers : { - indexBuffer : { - type : 'arraybuffer', + ], + buffers : [ + { extras : { _pipeline : {} } }, - attributesBuffer : { + { byteLength : attributesBuffer.length, - type : 'arraybuffer', extras : { _pipeline : { source : attributesBuffer } } } - }, - bufferViews : { - indexBufferView : { - buffer : 'indexBuffer', + ], + bufferViews : [ + { + buffer : 0, byteOffset : 0, target : 34963 }, - attributesBufferView : { - buffer : 'attributesBuffer', + { + buffer : 1, byteOffset : 0, byteLength : attributesBuffer.length, target : 34962 } - }, - meshes : { - mesh : { + ], + meshes : [ + { primitives : [ { attributes : { - POSITION : 'attributeAccessor1', - NORMAL : 'attributeAccessor2' + POSITION : 1, + NORMAL : 2 }, - indices : 'indexAccessor' + indices : 0 } ] } - } + ] }; it('does not remove any data if all attribute values are accessed', function() { var gltf = clone(testGltf); - var gltfIndexBuffer = gltf.buffers.indexBuffer; + var gltfIndexBuffer = gltf.buffers[0]; var indexBuffer = new Buffer(indices.buffer); gltfIndexBuffer.extras._pipeline.source = indexBuffer; gltfIndexBuffer.byteLength = indexBuffer.length; - gltf.bufferViews.indexBufferView.byteLength = indexBuffer.length; - var indexAccessor = gltf.accessors.indexAccessor; + gltf.bufferViews[0].byteLength = indexBuffer.length; + var indexAccessor = gltf.accessors[0]; indexAccessor.count = indices.length; - var attributesBuffer = gltf.buffers.attributesBuffer; var byteLength = attributesBuffer.byteLength; removeUnusedVertices(gltf); + uninterleaveAndPackBuffers(gltf); expect(attributesBuffer.byteLength).toEqual(byteLength); }); it('removes one unused attribute', function() { var gltf = clone(testGltf); - var gltfIndexBuffer = gltf.buffers.indexBuffer; + var gltfIndexBuffer = gltf.buffers[0]; var indexBuffer = new Buffer(indicesOneUnused.slice(0).buffer); gltfIndexBuffer.extras._pipeline.source = indexBuffer; gltfIndexBuffer.byteLength = indexBuffer.length; - gltf.bufferViews.indexBufferView.byteLength = indexBuffer.length; - var indexAccessor = gltf.accessors.indexAccessor; + gltf.bufferViews[0].byteLength = indexBuffer.length; + var indexAccessor = gltf.accessors[0]; indexAccessor.count = indicesOneUnused.length; - var attributesBuffer = gltf.buffers.attributesBuffer; + var attributesBuffer = gltf.buffers[1]; var byteLength = attributesBuffer.byteLength; - var attributeAccessor1 = gltf.accessors.attributeAccessor1; + var attributeAccessor1 = gltf.accessors[1]; var expectBytesDropped1 = numberOfComponentsForType(attributeAccessor1.type) * byteLengthForComponentType(attributeAccessor1.componentType); - var attributeAccessor2 = gltf.accessors.attributeAccessor2; + var attributeAccessor2 = gltf.accessors[2]; var expectBytesDropped2 = numberOfComponentsForType(attributeAccessor2.type) * byteLengthForComponentType(attributeAccessor2.componentType); var expectBytesDropped = expectBytesDropped1 + expectBytesDropped2; removeUnusedVertices(gltf); - expect(attributesBuffer.byteLength + expectBytesDropped).toEqual(byteLength); - - var expectAttribute1 = new Float32Array([0, 1, 2, 6, 7, 8]); - var expectAttribute2 = new Uint16Array([0, 1, 4, 5]); - var attributesSource = Uint8Array.from(attributesBuffer.extras._pipeline.source); - var check1 = new Float32Array(attributesSource.buffer, attributeAccessor1.byteOffset, expectAttribute1.length); - var check2 = new Uint16Array(attributesSource.buffer, attributeAccessor2.byteOffset, expectAttribute2.length); - expect(check1).toEqual(expectAttribute1); - expect(check2).toEqual(expectAttribute2); - - var expectIndices = new Uint16Array([0, 1]); - var indicesSource = Uint8Array.from(gltf.buffers.indexBuffer.extras._pipeline.source); - var check = new Uint16Array(indicesSource.buffer, 0, expectIndices.length); - expect(check).toEqual(expectIndices); + uninterleaveAndPackBuffers(gltf); + expect(gltf.buffers[0].byteLength - indexBuffer.length + expectBytesDropped).toEqual(byteLength); + + var expectAttribute1 = [[0, 1, 2], [6, 7, 8]]; + var reader = new AccessorReader(gltf, attributeAccessor1); + var components = []; + var i = 0; + while(!reader.pastEnd()) { + reader.read(components); + expect(components).toEqual(expectAttribute1[i]); + reader.next(); + i++; + } + var expectAttribute2 = [[0, 1], [4, 5]]; + reader = new AccessorReader(gltf, attributeAccessor2); + components = []; + i = 0; + while(!reader.pastEnd()) { + reader.read(components); + expect(components).toEqual(expectAttribute2[i]); + reader.next(); + i++; + } + var expectIndices = [[0], [1]]; + reader = new AccessorReader(gltf, indexAccessor); + components = []; + i = 0; + while(!reader.pastEnd()) { + reader.read(components); + expect(components).toEqual(expectIndices[i]); + reader.next(); + i++; + } }); it('removes two unused attributes', function() { var gltf = clone(testGltf); - var gltfIndexBuffer = gltf.buffers.indexBuffer; + var gltfIndexBuffer = gltf.buffers[0]; var indexBuffer = new Buffer(indicesTwoUnused.slice(0).buffer); gltfIndexBuffer.extras._pipeline.source = indexBuffer; gltfIndexBuffer.byteLength = indexBuffer.length; - gltf.bufferViews.indexBufferView.byteLength = indexBuffer.length; - var indexAccessor = gltf.accessors.indexAccessor; + gltf.bufferViews[0].byteLength = indexBuffer.length; + var indexAccessor = gltf.accessors[0]; indexAccessor.count = indicesTwoUnused.length; - var attributesBuffer = gltf.buffers.attributesBuffer; + var attributesBuffer = gltf.buffers[1]; var byteLength = attributesBuffer.byteLength; - var attributeAccessor1 = gltf.accessors.attributeAccessor1; + var attributeAccessor1 = gltf.accessors[1]; var expectBytesDropped1 = numberOfComponentsForType(attributeAccessor1.type) * byteLengthForComponentType(attributeAccessor1.componentType); - var attributeAccessor2 = gltf.accessors.attributeAccessor2; + var attributeAccessor2 = gltf.accessors[2]; var expectBytesDropped2 = numberOfComponentsForType(attributeAccessor2.type) * byteLengthForComponentType(attributeAccessor2.componentType); var expectBytesDropped = 2 * (expectBytesDropped1 + expectBytesDropped2); removeUnusedVertices(gltf); - expect(attributesBuffer.byteLength + expectBytesDropped).toEqual(byteLength); - - var expectAttribute1 = [3, 4, 5]; - var expectAttribute2 = [2, 3]; - var attributesSource = Uint8Array.from(attributesBuffer.extras._pipeline.source); - var check1 = new Float32Array(attributesSource.buffer, attributeAccessor1.byteOffset, expectAttribute1.length); - var check2 = new Uint16Array(attributesSource.buffer, attributeAccessor2.byteOffset, expectAttribute2.length); - var i; - for (i = 0; i < expectAttribute1.length; i++) { - expect(expectAttribute1[i]).toEqual(check1[i]); + uninterleaveAndPackBuffers(gltf); + expect(gltf.buffers[0].byteLength - indexBuffer.length + expectBytesDropped).toEqual(byteLength); + + var expectAttribute1 = [[3, 4, 5]]; + var reader = new AccessorReader(gltf, attributeAccessor1); + var components = []; + var i = 0; + while (!reader.pastEnd()) { + reader.read(components); + expect(components).toEqual(expectAttribute1[i]); + reader.next(); + i++; } - for (i = 0; i < expectAttribute2.length; i++) { - expect(expectAttribute2[i]).toEqual(check2[i]); + var expectAttribute2 = [[2, 3]]; + reader = new AccessorReader(gltf, attributeAccessor2); + components = []; + i = 0; + while (!reader.pastEnd()) { + reader.read(components); + expect(components).toEqual(expectAttribute2[i]); + reader.next(); + i++; } - - var expectIndices = [0]; - var indicesSource = Uint8Array.from(gltfIndexBuffer.extras._pipeline.source); - var check = new Uint16Array(indicesSource.buffer, 0, expectIndices.length); - for (i = 0; i < expectIndices.length; i++) { - expect(expectIndices[i]).toEqual(check[i]); + var expectIndices = [[0]]; + reader = new AccessorReader(gltf, indexAccessor); + components = []; + i = 0; + while (!reader.pastEnd()) { + reader.read(components); + expect(components).toEqual(expectIndices[i]); + reader.next(); + i++; } }); it('handles when primitives use the same accessors with different indices', function() { var gltf = clone(testGltf); - var gltfIndexBuffer = gltf.buffers.indexBuffer; + var gltfIndexBuffer = gltf.buffers[0]; var indexBuffer = new Buffer(indicesTwoUnused.slice(0).buffer); gltfIndexBuffer.extras._pipeline.source = indexBuffer; gltfIndexBuffer.byteLength = indexBuffer.length; - var indexBufferView = gltf.bufferViews.indexBufferView; + var indexBufferView = gltf.bufferViews[0]; indexBufferView.byteLength = indexBuffer.length; var gltfIndexBuffer2 = clone(gltfIndexBuffer); var indexBuffer2 = new Buffer(indicesOneUnused.slice(0).buffer); gltfIndexBuffer2.extras._pipeline.source = indexBuffer2; gltfIndexBuffer2.byteLength = indexBuffer2.length; - gltf.buffers.indexBuffer2 = gltfIndexBuffer2; + gltf.buffers.push(gltfIndexBuffer2); var gltfIndexBufferView2 = clone(indexBufferView); - gltfIndexBufferView2.buffer = 'indexBuffer2'; + gltfIndexBufferView2.buffer = 2; gltfIndexBufferView2.byteLength = indexBuffer2.length; - gltf.bufferViews.indexBufferView2 = gltfIndexBufferView2; + gltf.bufferViews.push(gltfIndexBufferView2); - var gltfIndexAccessor = gltf.accessors.indexAccessor; + var gltfIndexAccessor = gltf.accessors[0]; gltfIndexAccessor.count = indicesTwoUnused.length; var gltfIndexAccessor2 = clone(gltfIndexAccessor); gltfIndexAccessor2.count = indicesOneUnused.length; - gltfIndexAccessor2.bufferView = 'indexBufferView2'; - gltf.accessors.indexAccessor2 = gltfIndexAccessor2; + gltfIndexAccessor2.bufferView = 2; + gltf.accessors.push(gltfIndexAccessor2); - var mesh2 = clone(gltf.meshes.mesh); - mesh2.primitives[0].indices = 'indexAccessor2'; - gltf.meshes.mesh2 = mesh2; + var mesh2 = clone(gltf.meshes[0]); + mesh2.primitives[0].indices = 4; + gltf.meshes.push(mesh2); // All indices are used, 0 and 2 by the first primitive and 1 by the other - var attributesBuffer = gltf.buffers.attributesBuffer; - var byteLength = attributesBuffer.byteLength; + var byteLength = gltf.buffers[0].byteLength + gltf.buffers[1].byteLength + gltf.buffers[2].byteLength; removeUnusedVertices(gltf); - expect(attributesBuffer.byteLength).toEqual(byteLength); + uninterleaveAndPackBuffers(gltf); + expect(gltf.buffers[0].byteLength).toEqual(byteLength); }); it('handles when primitives use the same accessors along with different accessors with different indices', function() { var gltf = clone(testGltf); - var gltfIndexBuffer = gltf.buffers.indexBuffer; + var gltfIndexBuffer = gltf.buffers[0]; var indexBuffer = new Buffer(indicesTwoUnused.slice(0).buffer); gltfIndexBuffer.extras._pipeline.source = indexBuffer; gltfIndexBuffer.byteLength = indexBuffer.length; - var indexBufferView = gltf.bufferViews.indexBufferView; + var indexBufferView = gltf.bufferViews[0]; indexBufferView.byteLength = indexBuffer.length; var gltfIndexBuffer2 = clone(gltfIndexBuffer); var indexBuffer2 = new Buffer(indicesOneUnused.slice(0).buffer); gltfIndexBuffer2.extras._pipeline.source = indexBuffer2; gltfIndexBuffer2.byteLength = indexBuffer2.length; - gltf.buffers.indexBuffer2 = gltfIndexBuffer2; + gltf.buffers.push(gltfIndexBuffer2); var gltfIndexBufferView2 = clone(indexBufferView); - gltfIndexBufferView2.buffer = 'indexBuffer2'; + gltfIndexBufferView2.buffer = 2; gltfIndexBufferView2.byteLength = indexBuffer2.length; - gltf.bufferViews.indexBufferView2 = gltfIndexBufferView2; + gltf.bufferViews.push(gltfIndexBufferView2); - var gltfIndexAccessor = gltf.accessors.indexAccessor; + var gltfIndexAccessor = gltf.accessors[0]; gltfIndexAccessor.count = indicesTwoUnused.length; var gltfIndexAccessor2 = clone(gltfIndexAccessor); gltfIndexAccessor2.count = indicesOneUnused.length; - gltfIndexAccessor2.bufferView = 'indexBufferView2'; - gltf.accessors.indexAccessor2 = gltfIndexAccessor2; + gltfIndexAccessor2.bufferView = 2; + gltf.accessors.push(gltfIndexAccessor2); - var mesh2 = clone(gltf.meshes.mesh); + var mesh2 = clone(gltf.meshes[0]); var primitive = mesh2.primitives[0]; - primitive.attributes.POSITION = 'attributeAccessor3'; - primitive.indices = 'indexAccessor2'; - gltf.meshes.mesh2 = mesh2; + primitive.attributes.POSITION = 3; + primitive.indices = 4; + gltf.meshes.push(mesh2); // All indices are used, 0 and 2 by the first primitive and 1 by the other - var attributesBuffer = gltf.buffers.attributesBuffer; - var byteLength = attributesBuffer.byteLength; + var byteLength = gltf.buffers[0].byteLength + gltf.buffers[1].byteLength + gltf.buffers[2].byteLength; removeUnusedVertices(gltf); - expect(attributesBuffer.byteLength).toEqual(byteLength); + uninterleaveAndPackBuffers(gltf); + expect(gltf.buffers[0].byteLength).toEqual(byteLength); }); it('handles when there is a cross-dependency between two groups of primitives', function() { @@ -269,92 +295,79 @@ describe('removeUnusedVertices', function() { var indexData2 = new Uint16Array([0, 1, 3, 4, 3, 1, 0]); var indexDataBuffer2 = new Buffer(indexData2.buffer); var gltf = { - accessors : { - attributeAccessor1 : { - bufferView : 'attributeBufferView1', - byteStride : 0, + accessors : [ + { + bufferView : 0, byteOffset : 0, componentType : 5126, count : 5, type : 'VEC3' - }, - attributeAccessor2 : { - bufferView : 'attributeBufferView2', - byteStride : 0, + }, { + bufferView : 1, byteOffset : 0, componentType : 5126, count : 5, type : 'VEC3' - }, - indexAccessor1 : { - bufferView : 'indexBufferView1', - byteStride : 0, + }, { + bufferView : 2, byteOffset : 0, componentType : 5123, count : 9, type : 'SCALAR' - }, - indexAccessor2 : { - bufferView : 'indexBufferView2', - byteStride : 0, + }, { + bufferView : 3, byteOffset : 0, componentType : 5123, count : 7, type : 'SCALAR' } - }, - bufferViews : { - attributeBufferView1 : { - buffer : 'attributeBuffer1', + ], + bufferViews : [ + { + buffer : 0, byteOffset : 0, byteLength : attributeDataBuffer1.length, target : 34962 - }, - attributeBufferView2 : { - buffer : 'attributeBuffer2', + }, { + buffer : 1, byteOffset : 0, byteLength : attributeDataBuffer2.length, target : 34962 - }, - indexBufferView1 : { - buffer : 'indexBuffer1', + }, { + buffer : 2, byteOffset : 0, byteLength : indexDataBuffer1.length, target : 34963 - }, - indexBufferView2 : { - buffer : 'indexBuffer2', + }, { + buffer : 3, byteOffset : 0, byteLength : indexDataBuffer2.length, target : 34963 } - }, - buffers : { - attributeBuffer1 : { + ], + buffers : [ + { byteLength : attributeDataBuffer1.length, extras : { _pipeline : { source : attributeDataBuffer1.slice(0) } } - }, - attributeBuffer2 : { + }, { byteLength : attributeDataBuffer2.length, extras : { _pipeline : { source : attributeDataBuffer2.slice(0) } } - }, - indexBuffer1 : { + }, { byteLength : indexDataBuffer1.length, extras : { _pipeline : { source : indexDataBuffer1.slice(0) } } - }, - indexBuffer2 : { + }, { byteLength : indexDataBuffer2.length, extras : { _pipeline : { @@ -362,38 +375,35 @@ describe('removeUnusedVertices', function() { } } } - }, - meshes : { - mesh : { + ], + meshes : [ + { primitives: [ { attributes : { - TEST : 'attributeAccessor1' + TEST : 0 }, - indices : 'indexAccessor1' - }, - { + indices : 2 + }, { attributes : { - TEST : 'attributeAccessor2' + TEST : 1 }, - indices : 'indexAccessor2' - }, - { + indices : 3 + }, { attributes : { - TEST : 'attributeAccessor1' + TEST : 0 }, - indices : 'indexAccessor2' + indices : 3 } ] } - } + ] }; removeUnusedVertices(gltf); - var buffers = gltf.buffers; - expect(buffers.indexBuffer1.extras._pipeline.source).toEqual(indexDataBuffer1); - expect(buffers.indexBuffer2.extras._pipeline.source).toEqual(indexDataBuffer2); - expect(buffers.attributeBuffer1.extras._pipeline.source).toEqual(attributeDataBuffer1); - expect(buffers.attributeBuffer2.extras._pipeline.source).toEqual(attributeDataBuffer2); + uninterleaveAndPackBuffers(gltf); + var bufferViews = gltf.bufferViews; + expect(bufferViews[0].byteLength).toEqual(attributeDataBuffer1.length + attributeDataBuffer2.length); + expect(bufferViews[1].byteLength).toEqual(indexDataBuffer1.length + indexDataBuffer2.length); }); it('removes parts of the buffer based on the attribute type if the stride is 0', function() { @@ -421,76 +431,73 @@ describe('removeUnusedVertices', function() { var dataBuffer = Buffer.concat([indicesBuffer, positionsBuffer]); var testGltf = { - "accessors": { - "accessor_index": { - "bufferView": "index_view", - "byteOffset": 0, - "componentType": 5123, - "count": 6, - "type": "SCALAR", - "extras": { - "_pipeline": {} + accessors : [ + { + bufferView : 1, + byteOffset : 0, + componentType : 5123, + count : 6, + type : 'SCALAR', + extras : { + _pipeline: {} } - }, - "accessor_position": { - "bufferView": "position_view", - "byteOffset": 0, - "componentType": 5126, - "count": 4, - "type": "VEC3", - "extras": { - "_pipeline": {} + }, { + bufferView : 0, + byteOffset : 0, + componentType : 5126, + count : 4, + type : 'VEC3', + extras : { + _pipeline : {} } } - }, - "bufferViews": { - "position_view": { - "buffer": "buffer_0", - "byteOffset": 6 * 2, - "byteLength": 7 * 3 * 4, - "target": 34962, - "extras": { - "_pipeline": {} + ], + bufferViews : [ + { + buffer : 0, + byteOffset : 6 * 2, + byteLength : 7 * 3 * 4, + target : 34962, + extras : { + _pipeline : {} } - }, - "index_view": { - "buffer": "buffer_0", - "byteOffset": 0, - "byteLength": 6 * 2, - "target": 34963, - "extras": { - "_pipeline": {} + }, { + buffer : 0, + byteOffset : 0, + byteLength : 6 * 2, + target : 34963, + extras : { + _pipeline : {} } } - }, - "buffers": { - "buffer_0": { - "uri": "data:", - "byteLength": indices.length * 2 + positions.length * 4, - "extras": { - "_pipeline": { - "source": dataBuffer + ], + buffers : [ + { + byteLength : indices.length * 2 + positions.length * 4, + extras : { + _pipeline : { + source : dataBuffer } } } - }, - "meshes": { - "mesh_square": { - "name": "square", - "primitives": [ + ], + meshes : [ + { + name : 'square', + primitives : [ { - "attributes": { - "POSITION": "accessor_position" + attributes : { + POSITION : 1 }, - "indices": "accessor_index" + indices : 0 } ] } - } + ] }; - removeUnusedVertices(testGltf); - expect(testGltf.buffers.buffer_0.byteLength).toEqual(6 * 2 + 4 * 3 * 4); + uninterleaveAndPackBuffers(testGltf); + expect(testGltf.buffers[0].byteLength).toEqual(6 * 2 + 4 * 3 * 4); }); it('handles 8 bit indices', function(){ @@ -518,75 +525,73 @@ describe('removeUnusedVertices', function() { var dataBuffer = Buffer.concat([indicesBuffer, positionsBuffer]); var testGltf = { - "accessors": { - "accessor_index": { - "bufferView": "index_view", - "byteOffset": 0, - "componentType": 5121, // unsigned short - "count": 6, - "type": "SCALAR", - "extras": { - "_pipeline": {} + accessors: [ + { + bufferView : 1, + byteOffset: 0, + componentType: 5121, // unsigned short + count: 6, + type: 'SCALAR', + extras: { + _pipeline: {} } - }, - "accessor_position": { - "bufferView": "position_view", - "byteOffset": 0, - "componentType": 5126, - "count": 4, - "type": "VEC3", - "extras": { - "_pipeline": {} + }, { + bufferView: 0, + byteOffset: 0, + componentType: 5126, + count: 4, + type: 'VEC3', + extras: { + _pipeline: {} } } - }, - "bufferViews": { - "position_view": { - "buffer": "buffer_0", - "byteOffset": 6, - "byteLength": 7 * 3 * 4, - "target": 34962, - "extras": { - "_pipeline": {} + ], + bufferViews: [ + { + buffer: 0, + byteOffset: 6, + byteLength: 7 * 3 * 4, + target: 34962, + extras: { + _pipeline: {} } }, - "index_view": { - "buffer": "buffer_0", - "byteOffset": 0, - "byteLength": 6, - "target": 34963, - "extras": { - "_pipeline": {} + { + buffer: 0, + byteOffset: 0, + byteLength: 6, + target: 34963, + extras: { + _pipeline: {} } } - }, - "buffers": { - "buffer_0": { - "uri": "data:", - "byteLength": indices.length + positions.length * 4, - "extras": { - "_pipeline": { - "source": dataBuffer + ], + buffers: [ + { + byteLength: indices.length + positions.length * 4, + extras: { + _pipeline: { + source: dataBuffer } } } - }, - "meshes": { - "mesh_square": { - "name": "square", - "primitives": [ + ], + meshes: [ + { + name: 'square', + primitives: [ { - "attributes": { - "POSITION": "accessor_position" + attributes: { + POSITION: 1 }, - "indices": "accessor_index" + indices: 0 } ] } - } + ] }; - removeUnusedVertices(testGltf); - expect(testGltf.buffers.buffer_0.byteLength).toEqual(6 + 4 * 3 * 4); + uninterleaveAndPackBuffers(testGltf); + expect(testGltf.buffers[0].byteLength).toEqual(6 + 4 * 3 * 4); }); }); \ No newline at end of file diff --git a/specs/lib/uninterleaveAndPackBuffersSpec.js b/specs/lib/uninterleaveAndPackBuffersSpec.js index b0efc610..3234a85c 100644 --- a/specs/lib/uninterleaveAndPackBuffersSpec.js +++ b/specs/lib/uninterleaveAndPackBuffersSpec.js @@ -1,120 +1,116 @@ 'use strict'; var clone = require('clone'); - var byteLengthForComponentType = require('../../lib/byteLengthForComponentType'); var numberOfComponentsForType = require('../../lib/numberOfComponentsForType'); -var packBuffers = require('../../lib/uninterleaveAndPackBuffers'); +var Remove = require('../../lib/Remove'); +var uninterleaveAndPackBuffers = require('../../lib/uninterleaveAndPackBuffers'); describe('uninterleaveAndPackBuffers', function() { - var buffer = new Uint8Array(96); + var buffer = new Buffer(96); var testGltf = { - accessors : { + accessors : [ // Interleaved accessors in bufferView_0 - accessor_0 : { - bufferView : 'bufferView_0', + { + bufferView : 0, byteOffset : 0, - byteStride : 18, componentType : 5126, count : 3, type : 'VEC3' }, - accessor_1 : { - bufferView : 'bufferView_0', + { + bufferView : 0, byteOffset : 12, - byteStride : 18, componentType : 5123, count : 3, type : 'VEC2' }, // Block accessors in bufferView_1 - accessor_2 : { - bufferView : 'bufferView_1', + { + bufferView : 1, byteOffset : 0, - byteStride : 12, componentType : 5126, count : 3, type : 'VEC3' }, - accessor_3 : { - bufferView : 'bufferView_1', + { + bufferView : 1, byteOffset : 36, componentType : 5123, count : 3, type : 'VEC2' } - }, - bufferViews : { - bufferView_0 : { - buffer : 'buffer', + ], + bufferViews : [ + { + buffer : 0, byteLength : 48, byteOffset : 0, + byteStride: 18, target : 34962 }, - bufferView_1 : { - buffer : 'buffer', + { + buffer : 0, byteLength : 48, byteOffset : 48, target : 34963 } - }, - buffers : { - buffer : { + ], + buffers : [ + { byteLength : buffer.length, - type : 'arraybuffer', extras : { - _pipeline : {} + _pipeline : { + source: buffer + } } } - } + ] }; it('doesn\'t remove any data if the whole buffer is used', function() { var gltf = clone(testGltf); - gltf.buffers.buffer.extras._pipeline.source = buffer; - packBuffers(gltf); - expect(gltf.buffers.buffer.byteLength).toEqual(testGltf.buffers.buffer.byteLength); + gltf.buffers[0].extras._pipeline.source = buffer; + uninterleaveAndPackBuffers(gltf); + expect(gltf.buffers[0].byteLength).toEqual(testGltf.buffers[0].byteLength); }); it('removes extra trailing data on the buffer', function() { var gltf = clone(testGltf); - gltf.buffers.buffer.extras._pipeline.source = new Uint8Array(buffer.length * 2); - packBuffers(gltf); - expect(gltf.buffers.buffer.byteLength).toEqual(testGltf.buffers.buffer.byteLength); + gltf.buffers[0].extras._pipeline.source = new Buffer(buffer.length * 2); + uninterleaveAndPackBuffers(gltf); + expect(gltf.buffers[0].byteLength).toEqual(testGltf.buffers[0].byteLength); }); it('removes interleaved unused data', function() { var gltf = clone(testGltf); - gltf.buffers.buffer.extras._pipeline.source = buffer; - var deletedAccessorId = 'accessor_1'; - var deletedAccessor = gltf.accessors[deletedAccessorId]; + gltf.buffers[0].extras._pipeline.source = buffer; + var deletedAccessor = gltf.accessors[1]; var size = byteLengthForComponentType(deletedAccessor.componentType) * numberOfComponentsForType(deletedAccessor.type) * deletedAccessor.count; - delete gltf.accessors[deletedAccessorId]; - packBuffers(gltf); - expect(gltf.buffers.buffer.byteLength + size).toEqual(testGltf.buffers.buffer.byteLength); + Remove.accessor(gltf, 1); + uninterleaveAndPackBuffers(gltf); + expect(gltf.buffers[0].byteLength + size).toEqual(testGltf.buffers[0].byteLength); }); it('removes block unused data', function() { var gltf = clone(testGltf); - gltf.buffers.buffer.extras._pipeline.source = buffer; - var deletedAccessorId = 'accessor_2'; - var deletedAccessor = gltf.accessors[deletedAccessorId]; + gltf.buffers[0].extras._pipeline.source = buffer; + var deletedAccessor = gltf.accessors[2]; var size = byteLengthForComponentType(deletedAccessor.componentType) * numberOfComponentsForType(deletedAccessor.type) * deletedAccessor.count; - delete gltf.accessors[deletedAccessorId]; - packBuffers(gltf); - expect(gltf.buffers.buffer.byteLength + size).toEqual(testGltf.buffers.buffer.byteLength); - var bufferView1 = gltf.bufferViews.bufferView_1; - expect(bufferView1.byteLength).toEqual(gltf.buffers.buffer.byteLength - bufferView1.byteOffset); + Remove.accessor(gltf, 2); + uninterleaveAndPackBuffers(gltf); + expect(gltf.buffers[0].byteLength + size).toEqual(testGltf.buffers[0].byteLength); + var bufferView = gltf.bufferViews[1]; + expect(bufferView.byteLength).toEqual(gltf.buffers[0].byteLength - bufferView.byteOffset); }); it('removes unused bufferView', function() { var gltf = clone(testGltf); - gltf.buffers.buffer.extras._pipeline.source = buffer; - var size = gltf.bufferViews.bufferView_0.byteLength; - delete gltf.accessors.accessor_0; - delete gltf.accessors.accessor_1; - packBuffers(gltf); - expect(gltf.buffers.buffer.byteLength + size).toEqual(testGltf.buffers.buffer.byteLength); - var bufferViewCount = Object.keys(gltf.bufferViews).length; - expect(bufferViewCount).toEqual(1); + gltf.buffers[0].extras._pipeline.source = buffer; + var size = gltf.bufferViews[0].byteLength; + Remove.accessor(gltf, 0); + Remove.accessor(gltf, 0); + uninterleaveAndPackBuffers(gltf); + expect(gltf.buffers[0].byteLength + size).toEqual(testGltf.buffers[0].byteLength); + expect(gltf.bufferViews.length).toEqual(1); }); }); \ No newline at end of file diff --git a/specs/lib/updateVersionSpec.js b/specs/lib/updateVersionSpec.js index 2ba3838a..109f2f48 100644 --- a/specs/lib/updateVersionSpec.js +++ b/specs/lib/updateVersionSpec.js @@ -14,13 +14,33 @@ describe('updateVersion', function() { expect(gltf.asset.version).toEqual('1.0'); }); - it('updates empty glTF with version from 0.8 to 1.0', function() { + it('updates empty glTF with version from 0.8 to 2.0', function() { var gltf = { version: '0.8' }; updateVersion(gltf); expect(gltf.version).not.toBeDefined(); - expect(gltf.asset.version).toEqual('1.0'); + expect(gltf.asset.version).toEqual('2.0'); + }); + + it('updates empty glTF with version 1.0 to 2.0', function() { + var gltf = { + asset : { + version: '1.0' + } + }; + updateVersion(gltf); + expect(gltf.asset.version).toEqual('2.0'); + }); + + it('updates a glTF with non-standard version to 2.0', function() { + var gltf = { + asset : { + version: '1.0.1' + } + }; + updateVersion(gltf); + expect(gltf.asset.version).toEqual('2.0'); }); it('updates glTF from 0.8 to 1.0', function() { @@ -119,4 +139,228 @@ describe('updateVersion', function() { }); expect(technique.states).toEqual(['TEST_STATE']); }); + + it('updates glTF from 1.0 to 2.0', function() { + var arrayBuffer = new Buffer(new Int16Array([-2.0, 1.0, 0.0, 1.0, 2.0, 3.0]).buffer); + var gltf = { + asset: { + profile: { + version: '1.0.3' + }, + version: '1.0' + }, + animations: { + animation: { + samplers: { + sampler: { + input: 'INPUT', + output: 'OUTPUT' + } + }, + parameters: { + INPUT: 'accessor_input', + OUTPUT: 'accessor_output' + } + } + }, + extensionsUsed: [ + 'KHR_materials_common', + 'WEB3D_quantized_attributes', + 'UNKOWN_EXTENSION' + ], + meshes: { + mesh: { + primitives: [ + { + attributes: { + TEXCOORD: 'accessor_texcoord', + COLOR: 'accessor_color', + APPLICATIONSPECIFIC: 'accessor', + _TEMPERATURE: 'accessor_temperature' + }, + indices: 'accessor_indices' + } + ] + } + }, + materials: { + material: { + values: { + shininess: 1.0 + } + } + }, + techniques: { + technique: { + states: { + enable: [ WebGLConstants.SCISSOR_TEST ], + functions: { + blendColor: [-1.0, 0.0, 0.0, 2.0], + depthRange: [1.0, -1.0], + scissor: [0.0, 0.0, 0.0, 0.0] + } + }, + attributes: { + a_application: 'application' + }, + parameters: { + lightAttenuation: { + value: 1.0 + }, + texcoord: { + semantic: 'TEXCOORD' + }, + color: { + semantic: 'COLOR' + }, + application: { + semantic: 'APPLICATIONSPECIFIC', + count: 1, + value: 2 + }, + jointMatrix: { + semantic: 'JOINTMATRIX', + count: 2 + }, + notJointMatrix: { + count: 3 + }, + notJointMatrixWithSemantic: { + count: 4 + } + } + } + }, + accessors: { + accessor: { + byteOffset: 0, + bufferView: 'bufferView', + componentType: WebGLConstants.SHORT, + count: 6, + type: 'SCALAR' + }, + accessor_indices: { + componentType: WebGLConstants.UNSIGNED_INT + }, + accessor_input: {}, + accessor_output: {}, + accessor_texcoord: {}, + accessor_color: {}, + accessor_temperature: {} + }, + bufferViews: { + bufferView: { + buffer: 'buffer', + byteOffset: 0 + } + }, + buffers: { + buffer: { + type: 'arraybuffer', + extras: { + _pipeline: { + source: arrayBuffer + } + } + } + }, + cameras: { + camera: { + perspective: { + aspectRatio: 0.0, + yfov: 0.0 + } + } + }, + nodes: { + rootTransform: { + children: [ + 'skeletonNode', + 'meshNode' + ], + matrix: [ + 1, 0, 0, 0, + 0, 0, -1, 0, + 0, 1, 0, 0, + 0, 0, 0, 1 + ] + }, + skeletonNode: {}, + meshNode: { + skin: 'someSkin', + skeletons: [ + 'skeletonNode' + ] + } + }, + scene: 'defaultScene', + scenes: { + defaultScene: { + nodes: [ + 'rootTransform' + ] + } + }, + skins: { + someSkin: {} + } + }; + updateVersion(gltf); + expect(gltf.asset.version).toEqual('2.0'); + expect(gltf.asset.profile).not.toBeDefined(); + var extensionsUsed = gltf.extensionsUsed; + expect(extensionsUsed).toEqual([ + 'KHR_materials_common', + 'WEB3D_quantized_attributes', + 'UNKOWN_EXTENSION', + 'KHR_technique_webgl' + ]); + var extensionsRequired = gltf.extensionsRequired; + expect(extensionsRequired).toEqual([ + 'KHR_materials_common', + 'WEB3D_quantized_attributes', + 'KHR_technique_webgl' + ]); + var animation = gltf.animations[0]; + var sampler = animation.samplers[0]; + expect(sampler.input).toEqual(2); + expect(sampler.output).toEqual(3); + expect(animation.parameters).not.toBeDefined(); + var material = gltf.materials[0]; + expect(material.values.shininess).toEqual([1.0]); + var technique = gltf.techniques[0]; + expect(technique.parameters.lightAttenuation.value).toEqual([1.0]); + expect(technique.parameters.application.value).not.toBeDefined(); + expect(technique.parameters.texcoord.semantic).toEqual('TEXCOORD_0'); + expect(technique.parameters.color.semantic).toEqual('COLOR_0'); + expect(technique.parameters.application.semantic).toEqual('_APPLICATIONSPECIFIC'); + var states = technique.states; + expect(states.enable).toEqual([]); + expect(states.functions.scissor).not.toBeDefined(); + expect(states.functions.blendColor).toEqual([0.0, 0.0, 0.0, 1.0]); + expect(states.functions.depthRange).toEqual([0.0, 0.0]); + var accessor = gltf.accessors[0]; + expect(accessor.min).toEqual([-2.0]); + expect(accessor.max).toEqual([3.0]); + var primitive = gltf.meshes[0].primitives[0]; + expect(primitive.attributes.TEXCOORD).not.toBeDefined(); + expect(primitive.attributes.TEXCOORD_0).toEqual(4); + expect(primitive.attributes.COLOR).not.toBeDefined(); + expect(primitive.attributes.COLOR_0).toEqual(5); + expect(primitive.attributes.APPLICATIONSPECIFIC).not.toBeDefined(); + expect(primitive.attributes._APPLICATIONSPECIFIC).toEqual(0); + expect(primitive.attributes._TEMPERATURE).toEqual(6); + var camera = gltf.cameras[0]; + expect(camera.perspective.aspectRatio).not.toBeDefined(); + expect(camera.perspective.yfov).toEqual(1.0); + var buffer = gltf.buffers[0]; + expect(buffer.type).not.toBeDefined(); + expect(buffer.byteLength).toEqual(arrayBuffer.length); + var bufferView = gltf.bufferViews[0]; + expect(bufferView.byteLength).toEqual(arrayBuffer.length); + expect(technique.parameters.application.count).toEqual(1); + expect(technique.parameters.jointMatrix.count).toEqual(2); + expect(technique.parameters.notJointMatrix.count).not.toBeDefined(); + expect(technique.parameters.notJointMatrixWithSemantic.count).not.toBeDefined(); + }); }); \ No newline at end of file diff --git a/specs/lib/writeBinaryGltfSpec.js b/specs/lib/writeBinaryGltfSpec.js index 79bd671e..f059e813 100644 --- a/specs/lib/writeBinaryGltfSpec.js +++ b/specs/lib/writeBinaryGltfSpec.js @@ -8,7 +8,6 @@ var loadGltfUris = require('../../lib/loadGltfUris'); var readGltf = require('../../lib/readGltf'); var writeBinaryGltf = require('../../lib/writeBinaryGltf'); -var gltfPath = './specs/data/boxTexturedUnoptimized/CesiumTexturedBoxTest.gltf'; var outputGltfPath = './output/CesiumTexturedBoxTest.glb'; var invalidPath = './specs/data/boxTexturedUnoptimized/CesiumTexturedBoxTest.exe'; @@ -22,11 +21,9 @@ describe('writeBinaryGltf', function() { createDirectory : false }; - expect(readGltf(gltfPath) + var gltf = {}; + expect(writeBinaryGltf(gltf, writeOptions) .then(function(gltf) { - return writeBinaryGltf(gltf, writeOptions); - }) - .then(function() { expect(path.normalize(spy.calls.first().args[0])).toEqual(path.normalize(outputGltfPath)); }) .catch(function (err) { @@ -34,7 +31,7 @@ describe('writeBinaryGltf', function() { }), done).toResolve(); }); - it('throws an invalid output path error', function(done) { + it('throws an invalid output path error', function() { var writeOptions = { outputPath : undefined, embed : true, @@ -42,15 +39,13 @@ describe('writeBinaryGltf', function() { createDirectory : true }; - expect(readGltf(gltfPath) - .then(function(gltf) { - expect(function() { - writeBinaryGltf(gltf, writeOptions); - }).toThrowError('Output path is undefined.'); - }), done).toResolve(); + var gltf = {}; + expect(function() { + writeBinaryGltf(gltf, writeOptions); + }).toThrowError('Output path is undefined.'); }); - it('throws an invalid output extension error', function(done) { + it('throws an invalid output extension error', function() { var writeOptions = { outputPath : invalidPath, embed : true, @@ -58,11 +53,9 @@ describe('writeBinaryGltf', function() { createDirectory : true }; - expect(readGltf(gltfPath) - .then(function(gltf) { - expect(function() { - writeBinaryGltf(gltf, writeOptions); - }).toThrowError('Invalid output path extension.'); - }), done).toResolve(); + var gltf = {}; + expect(function() { + writeBinaryGltf(gltf, writeOptions); + }).toThrowError('Invalid output path extension.'); }); }); diff --git a/specs/lib/writeBuffersSpec.js b/specs/lib/writeBuffersSpec.js index 98b32369..5f668521 100644 --- a/specs/lib/writeBuffersSpec.js +++ b/specs/lib/writeBuffersSpec.js @@ -22,17 +22,18 @@ describe('writeBuffers', function() { .then(function(data) { bufferData = data; testGltf = { - "buffers": { - "CesiumTexturedBoxTest": { - "uri": "CesiumTexturedBoxTest.bin", - "extras": { - "_pipeline": { - "source": bufferData, - "extension": '.bin' + buffers: [ + { + uri: 'CesiumTexturedBoxTest.bin', + extras: { + _pipeline: { + source: bufferData, + extension: '.bin' } - } + }, + name: 'CesiumTexturedBoxTest' } - } + ] }; }), done).toResolve(); }); @@ -48,8 +49,8 @@ describe('writeBuffers', function() { expect(writeGltf(gltf, options) .then(function() { - expect(gltf.buffers.CesiumTexturedBoxTest.extras).not.toBeDefined(); - expect(gltf.buffers.CesiumTexturedBoxTest.uri).toEqual('CesiumTexturedBoxTest.bin'); + expect(gltf.buffers[0].extras).not.toBeDefined(); + expect(gltf.buffers[0].uri).toEqual('CesiumTexturedBoxTest.bin'); return fsReadFile(outputBufferPath); }) .then(function(outputData) { @@ -68,8 +69,8 @@ describe('writeBuffers', function() { expect(writeGltf(gltf, options) .then(function() { - expect(gltf.buffers.CesiumTexturedBoxTest.extras).not.toBeDefined(); - expect(gltf.buffers.CesiumTexturedBoxTest.uri).toEqual(bufferUri); + expect(gltf.buffers[0].extras).not.toBeDefined(); + expect(gltf.buffers[0].uri).toEqual(bufferUri); }), done).toResolve(); }); }); \ No newline at end of file diff --git a/specs/lib/writeImagesSpec.js b/specs/lib/writeImagesSpec.js index ce19ae3d..c5a380ca 100644 --- a/specs/lib/writeImagesSpec.js +++ b/specs/lib/writeImagesSpec.js @@ -22,17 +22,18 @@ describe('writeImages', function() { .then(function(data) { imageData = data; testGltf = { - "images": { - "Cesium_Logo_Flat_Low": { - "uri": imageUri, - "extras": { - "_pipeline": { - "source": imageData, - "extension": '.png' + images: [ + { + uri: imageUri, + extras: { + _pipeline: { + source: imageData, + extension: '.png' } - } + }, + name: 'Cesium_Logo_Flat_Low' } - } + ] }; }), done).toResolve(); }); @@ -48,8 +49,8 @@ describe('writeImages', function() { expect(writeGltf(gltf, options) .then(function() { - expect(gltf.images.Cesium_Logo_Flat_Low.extras).not.toBeDefined(); - expect(gltf.images.Cesium_Logo_Flat_Low.uri).toEqual('Cesium_Logo_Flat_Low.png'); + expect(gltf.images[0].extras).not.toBeDefined(); + expect(gltf.images[0].uri).toEqual('Cesium_Logo_Flat_Low.png'); return fsReadFile(outputImagePath); }) .then(function (outputData) { @@ -68,8 +69,8 @@ describe('writeImages', function() { expect(writeGltf(gltf, options) .then(function() { - expect(gltf.images.Cesium_Logo_Flat_Low.extras).not.toBeDefined(); - expect(gltf.images.Cesium_Logo_Flat_Low.uri).toEqual(imageUri); + expect(gltf.images[0].extras).not.toBeDefined(); + expect(gltf.images[0].uri).toEqual(imageUri); }), done).toResolve(); }); @@ -84,8 +85,8 @@ describe('writeImages', function() { expect(writeGltf(gltf, options) .then(function() { - expect(gltf.images.Cesium_Logo_Flat_Low.extras).not.toBeDefined(); - expect(gltf.images.Cesium_Logo_Flat_Low.uri).toEqual('Cesium_Logo_Flat_Low.png'); + expect(gltf.images[0].extras).not.toBeDefined(); + expect(gltf.images[0].uri).toEqual('Cesium_Logo_Flat_Low.png'); }), done).toResolve(); }); }); diff --git a/specs/lib/writeShadersSpec.js b/specs/lib/writeShadersSpec.js index 462877e6..20194cc8 100644 --- a/specs/lib/writeShadersSpec.js +++ b/specs/lib/writeShadersSpec.js @@ -21,21 +21,22 @@ describe('writeShaders', function() { expect(fsReadFile(fragmentShaderPath) .then(function(data) { fragmentShaderData = data; + fragmentShaderUri = 'data:text/plain;base64,' + new Buffer(fragmentShaderData).toString('base64'); testGltf = { - "shaders": { - "CesiumTexturedBoxTest0FS": { - "type": 35632, - "uri": fragmentShaderUri, - "extras": { - "_pipeline": { - "source": fragmentShaderData, - "extension": '.glsl' + shaders: [ + { + type: 35632, + uri: fragmentShaderUri, + name: 'CesiumTexturedBoxTest0FS', + extras: { + _pipeline: { + source: fragmentShaderData, + extension: '.glsl' } } } - } + ] }; - fragmentShaderUri = 'data:text/plain;base64,' + new Buffer(fragmentShaderData).toString('base64'); }), done).toResolve(); }); @@ -50,8 +51,8 @@ describe('writeShaders', function() { expect(writeGltf(gltf, options) .then(function() { - expect(gltf.shaders.CesiumTexturedBoxTest0FS.extras).not.toBeDefined(); - expect(gltf.shaders.CesiumTexturedBoxTest0FS.uri).toEqual('CesiumTexturedBoxTest0FS.glsl'); + expect(gltf.shaders[0].extras).not.toBeDefined(); + expect(gltf.shaders[0].uri).toEqual('CesiumTexturedBoxTest0FS.glsl'); return fsReadFile(outputFragmentShaderPath); }) .then(function(outputData) { @@ -70,8 +71,8 @@ describe('writeShaders', function() { expect(writeGltf(gltf, options) .then(function() { - expect(gltf.shaders.CesiumTexturedBoxTest0FS.extras).not.toBeDefined(); - expect(gltf.shaders.CesiumTexturedBoxTest0FS.uri).toEqual(fragmentShaderUri); + expect(gltf.shaders[0].extras).not.toBeDefined(); + expect(gltf.shaders[0].uri).toEqual(fragmentShaderUri); }), done).toResolve(); }); }); From 06a09540dc71828680fb4e93f6b5a9ac3eec90ea Mon Sep 17 00:00:00 2001 From: Robert Taglang Date: Fri, 28 Apr 2017 11:17:17 -0400 Subject: [PATCH 02/35] Added pbrToMaterialsCommon --- lib/pbrToMaterialsCommon.js | 93 +++++++++++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100644 lib/pbrToMaterialsCommon.js diff --git a/lib/pbrToMaterialsCommon.js b/lib/pbrToMaterialsCommon.js new file mode 100644 index 00000000..438b5404 --- /dev/null +++ b/lib/pbrToMaterialsCommon.js @@ -0,0 +1,93 @@ +'use strict'; +var Cesium = require('cesium'); +var ForEach = require('./ForEach'); + +var defined = Cesium.defined; + +module.exports = pbrToMaterialsCommon; + +/** + * Convert PBR materials to use a KHR_materials_common PHONG shader. + * This is a lossy conversion, and as such is only to be used for + * compatibility reasons. Normal texture and metallic roughness information + * will be lost, and some color or texture information may be lost. + * + * The preferred solution is to properly + * implement PBR materials, and as such this function will likely + * by deprecated in the future. + * + * @param {Object} gltf A javascript object containing a glTF asset. + * @returns {Object} The glTF asset with materials converted to KHR_materials_common + */ +function pbrToMaterialsCommon(gltf) { + ForEach.material(gltf, function(material) { + var values = { + ambient : [ 0.0, 0.0, 0.0, 1.0 ], + diffuse : [ 0.0, 0.0, 0.0, 1.0 ], + emission : [ 0.0, 0.0, 0.0, 1.0 ], + specular : [ 0.0, 0.0, 0.0, 1.0], + shininess : [ 0.0 ] + }; + var pbrMetallicRoughness = material.pbrMetallicRoughness; + if (defined(pbrMetallicRoughness)) { + var baseColorFactor = pbrMetallicRoughness.baseColorFactor; + if (defined(baseColorFactor)) { + values.diffuse = baseColorFactor; + } + var baseColorTexture = pbrMetallicRoughness.baseColorTexture; + if (defined(baseColorTexture)) { + values.diffuse = [ baseColorTexture.index ]; + } + } + var extensions = material.extensions; + if (defined(extensions)) { + var pbrSpecularGlossiness = extensions.KHR_materials_pbrSpecularGlossiness; + if (defined(pbrSpecularGlossiness)) { + var diffuseFactor = pbrSpecularGlossiness.diffuseFactor; + // Use baseColorTexture if it was defined + if (defined(diffuseFactor) && values.diffuse.length > 1) { + values.diffuse = diffuseFactor; + } + // diffuseTexture should be used instead of baseColorTexture if defined + var diffuseTexture = pbrSpecularGlossiness.diffuseTexture; + if (defined(diffuseTexture)) { + values.diffuse = [ diffuseTexture.index ]; + } + var specularFactor = pbrSpecularGlossiness.specularFactor; + if (defined(specularFactor)) { + values.specular[0] = specularFactor[0]; + values.specular[1] = specularFactor[1]; + values.specular[2] = specularFactor[2]; + } + var glossinessFactor = pbrSpecularGlossiness.glossinessFactor; + if (defined(glossinessFactor)) { + values.shininess[0] = glossinessFactor; + } + var specularGlossinessTexture = pbrSpecularGlossiness.specularGlossinessTexture; + if (defined(specularGlossinessTexture)) { + values.specular = [ specularGlossinessTexture.index ]; + } + } + } + var occlusionTexture = material.occlusionTexture; + if (defined(occlusionTexture)) { + values.ambient = [ occlusionTexture.index ]; + } + var emissiveFactor = material.emissiveFactor; + if (defined(emissiveFactor)) { + values.emission[0] = emissiveFactor[0]; + values.emission[1] = emissiveFactor[1]; + values.emission[2] = emissiveFactor[2]; + } + delete material.emissiveFactor; + delete material.normalTexture; + delete material.occlusionTexture; + delete material.pbrMetallicRoughness; + material.extensions = { + technique : 'PHONG', + KHR_materials_common : { + values: values + } + }; + }); +} \ No newline at end of file From d373dc2f38c41b2d78d6291909bd90e3c3804bcb Mon Sep 17 00:00:00 2001 From: Robert Taglang Date: Fri, 28 Apr 2017 14:22:32 -0400 Subject: [PATCH 03/35] Moved out getJointCountForMaterials as a separate function and added pbr->materialsCommon generation --- gulpfile.js | 2 + lib/generateModelMaterialsCommon.js | 184 ++++++--------- lib/getJointCountForMaterials.js | 47 ++++ lib/pbrToMaterialsCommon.js | 64 ++++-- lib/processModelMaterialsCommon.js | 4 +- specs/lib/generateModelMaterialsCommonSpec.js | 128 ++++++----- specs/lib/pbrToMaterialsCommonSpec.js | 214 ++++++++++++++++++ 7 files changed, 440 insertions(+), 203 deletions(-) create mode 100644 lib/getJointCountForMaterials.js create mode 100644 specs/lib/pbrToMaterialsCommonSpec.js diff --git a/gulpfile.js b/gulpfile.js index da431bae..d10e983a 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -285,9 +285,11 @@ gulp.task('build-cesium', function () { 'findAccessorMinMax.js', 'ForEach.js', 'getAccessorByteStride.js', + 'getJointCountForMaterials.js', 'getStatistics.js', 'numberOfComponentsForType.js', 'parseBinaryGltf.js', + 'pbrToMaterialsCommon.js', 'processModelMaterialsCommon.js', 'removePipelineExtras.js', 'removeExtensionsRequired.js', diff --git a/lib/generateModelMaterialsCommon.js b/lib/generateModelMaterialsCommon.js index 51cd0b39..c07516d3 100644 --- a/lib/generateModelMaterialsCommon.js +++ b/lib/generateModelMaterialsCommon.js @@ -1,6 +1,8 @@ 'use strict'; var Cesium = require('cesium'); var addExtensionsRequired = require('./addExtensionsRequired'); +var ForEach = require('./ForEach'); +var getJointCountForMaterials = require('./getJointCountForMaterials'); var defaultValue = Cesium.defaultValue; var defined = Cesium.defined; @@ -26,7 +28,6 @@ function generateModelMaterialsCommon(gltf, kmcOptions) { kmcOptions.technique = defaultValue(kmcOptions.technique, 'PHONG'); addExtensionsRequired(gltf, 'KHR_materials_common'); var materialsCommon; - var materials = gltf.materials; var nodes = gltf.nodes; var techniques = gltf.techniques; var jointCountForMaterialId = getJointCountForMaterials(gltf); @@ -41,133 +42,82 @@ function generateModelMaterialsCommon(gltf, kmcOptions) { var lights = {}; materialsCommon.lights = lights; - for (var materialId in materials) { - if (materials.hasOwnProperty(materialId)) { - var material = materials[materialId]; - var technique = techniques[material.technique]; - var techniqueParameters = technique.parameters; - if (defined(techniqueParameters.ambient) && !defined(lights.defaultAmbient)) { - lights.defaultAmbient = { - ambient: { - color: [1, 1, 1] - }, - name: 'defaultAmbient', - type: 'ambient' - }; - } - for (var parameterId in techniqueParameters) { - if (techniqueParameters.hasOwnProperty(parameterId)) { - if (parameterId.indexOf('light') === 0 && parameterId.indexOf('Transform') >= 0) { - var lightId = parameterId.substring(0, parameterId.indexOf('Transform')); - var lightTransform = techniqueParameters[parameterId]; - var lightNodeId = lightTransform.node; - var lightNode = nodes[lightNodeId]; - var nodeExtensions = lightNode.extensions; - if (!defined(nodeExtensions)) { - nodeExtensions = {}; - lightNode.extensions = nodeExtensions; - } - materialsCommon = {}; - nodeExtensions.KHR_materials_common = materialsCommon; - materialsCommon.light = lightId; - var lightColor = techniqueParameters[lightId + 'Color']; - var light = { - name: lightId, - type: 'directional', - directional: { - color: defaultValue(lightColor.value, [1, 1, 1]) - } - }; - lights[lightId] = light; + ForEach.material(gltf, function(material, materialId) { + var technique = techniques[material.technique]; + var techniqueParameters = technique.parameters; + if (defined(techniqueParameters.ambient) && !defined(lights.defaultAmbient)) { + lights.defaultAmbient = { + ambient: { + color: [1, 1, 1] + }, + name: 'defaultAmbient', + type: 'ambient' + }; + } + for (var parameterId in techniqueParameters) { + if (techniqueParameters.hasOwnProperty(parameterId)) { + if (parameterId.indexOf('light') === 0 && parameterId.indexOf('Transform') >= 0) { + var lightId = parameterId.substring(0, parameterId.indexOf('Transform')); + var lightTransform = techniqueParameters[parameterId]; + var lightNodeId = lightTransform.node; + var lightNode = nodes[lightNodeId]; + var nodeExtensions = lightNode.extensions; + if (!defined(nodeExtensions)) { + nodeExtensions = {}; + lightNode.extensions = nodeExtensions; } + materialsCommon = {}; + nodeExtensions.KHR_materials_common = materialsCommon; + materialsCommon.light = lightId; + var lightColor = techniqueParameters[lightId + 'Color']; + var light = { + name: lightId, + type: 'directional', + directional: { + color: defaultValue(lightColor.value, [1, 1, 1]) + } + }; + lights[lightId] = light; } } + } - delete material.technique; - var extensions = material.extensions; - if (!defined(extensions)) { - extensions = {}; - material.extensions = extensions; - } - materialsCommon = {}; - extensions.KHR_materials_common = materialsCommon; - for (var kmcOption in kmcOptions) { - if (kmcOptions.hasOwnProperty(kmcOption) && kmcOption !== 'enable') { - materialsCommon[kmcOption] = kmcOptions[kmcOption]; - } - } - var jointCount = jointCountForMaterialId[materialId]; - if (defined(jointCount)) { - materialsCommon.jointCount = jointCount; + delete material.technique; + var extensions = material.extensions; + if (!defined(extensions)) { + extensions = {}; + material.extensions = extensions; + } + materialsCommon = {}; + extensions.KHR_materials_common = materialsCommon; + for (var kmcOption in kmcOptions) { + if (kmcOptions.hasOwnProperty(kmcOption) && kmcOption !== 'enable') { + materialsCommon[kmcOption] = kmcOptions[kmcOption]; } + } + var jointCount = jointCountForMaterialId[materialId]; + if (defined(jointCount)) { + materialsCommon.jointCount = jointCount; + } - var materialValues = material.values; - var diffuseColor, transparency; - if (defined(materialValues)) { - diffuseColor = materialValues.diffuse; - transparency = materialValues.transparency; - materialsCommon.values = materialValues; - } + var materialValues = material.values; + var diffuseColor, transparency; + if (defined(materialValues)) { + diffuseColor = materialValues.diffuse; + transparency = materialValues.transparency; + materialsCommon.values = materialValues; + } - // Check if we have transparency and set transparent flag - if ((defined(transparency) && transparency < 1.0) || - (defined(diffuseColor) && Array.isArray(diffuseColor) && diffuseColor[3] < 1.0)) { - materialsCommon.values.transparent = true; - } - delete material.values; + // Check if we have transparency and set transparent flag + if ((defined(transparency) && transparency < 1.0) || + (defined(diffuseColor) && Array.isArray(diffuseColor) && diffuseColor[3] < 1.0)) { + materialsCommon.values.transparent = true; } - } + delete material.values; + }); delete gltf.techniques; delete gltf.programs; delete gltf.shaders; return gltf; } -function getJointCountForMaterials(gltf) { - var accessors = gltf.accessors; - var meshes = gltf.meshes; - var nodes = gltf.nodes; - var skins = gltf.skins; - var jointCountForMaterialId = {}; - - var nodesForSkinId = {}; - for (var nodeId in nodes) { - if (nodes.hasOwnProperty(nodeId)) { - var node = nodes[nodeId]; - if (defined(node.skin)) { - if (!defined(nodesForSkinId[node.skin])) { - nodesForSkinId[node.skin] = []; - } - nodesForSkinId[node.skin].push(node); - } - } - } - - for (var skinId in skins) { - if (skins.hasOwnProperty(skinId)) { - var skin = skins[skinId]; - var jointCount = 1; - if (defined(skin.inverseBindMatrices)) { - jointCount = accessors[skin.inverseBindMatrices].count; - } - var skinnedNodes = nodesForSkinId[skinId]; - var skinnedNodesLength = skinnedNodes.length; - for (var i = 0; i < skinnedNodesLength; i++) { - var skinnedNode = skinnedNodes[i]; - var nodeMeshes = skinnedNode.meshes; - var nodeMeshesLength = nodeMeshes.length; - for (var j = 0; j < nodeMeshesLength; j++) { - var meshId = nodeMeshes[j]; - var mesh = meshes[meshId]; - var primitives = mesh.primitives; - var primitivesLength = primitives.length; - for (var k = 0; k < primitivesLength; k++) { - var primitive = primitives[k]; - jointCountForMaterialId[primitive.material] = jointCount; - } - } - } - } - } - return jointCountForMaterialId; -} diff --git a/lib/getJointCountForMaterials.js b/lib/getJointCountForMaterials.js new file mode 100644 index 00000000..25b2fd95 --- /dev/null +++ b/lib/getJointCountForMaterials.js @@ -0,0 +1,47 @@ +'use strict'; +var Cesium = require('cesium'); +var ForEach = require('./ForEach'); + +var defined = Cesium.defined; + +module.exports = getJointCountForMaterials; + +function getJointCountForMaterials(gltf) { + var accessors = gltf.accessors; + 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 = 1; + if (defined(skin.inverseBindMatrices)) { + jointCount = accessors[skin.inverseBindMatrices].count; + } + 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]; + var primitives = mesh.primitives; + var primitivesLength = primitives.length; + for (var k = 0; k < primitivesLength; k++) { + var primitive = primitives[k]; + jointCountForMaterialId[primitive.material] = jointCount; + } + } + } + }); + + return jointCountForMaterialId; +} diff --git a/lib/pbrToMaterialsCommon.js b/lib/pbrToMaterialsCommon.js index 438b5404..c2510e3e 100644 --- a/lib/pbrToMaterialsCommon.js +++ b/lib/pbrToMaterialsCommon.js @@ -1,26 +1,26 @@ 'use strict'; var Cesium = require('cesium'); +var addExtensionsRequired = require('./addExtensionsRequired'); var ForEach = require('./ForEach'); +var getJointCountForMaterials = require('./getJointCountForMaterials'); +var removeExtensionsUsed = require('./removeExtensionsUsed'); var defined = Cesium.defined; module.exports = pbrToMaterialsCommon; /** - * Convert PBR materials to use a KHR_materials_common PHONG shader. - * This is a lossy conversion, and as such is only to be used for + * Convert PBR materials to use a KHR_materials_common BLINN shader. + * This is a lossy conversion, and as such should only be used for * compatibility reasons. Normal texture and metallic roughness information * will be lost, and some color or texture information may be lost. * - * The preferred solution is to properly - * implement PBR materials, and as such this function will likely - * by deprecated in the future. - * * @param {Object} gltf A javascript object containing a glTF asset. * @returns {Object} The glTF asset with materials converted to KHR_materials_common */ function pbrToMaterialsCommon(gltf) { - ForEach.material(gltf, function(material) { + var materialJointCount = getJointCountForMaterials(gltf); + ForEach.material(gltf, function(material, materialId) { var values = { ambient : [ 0.0, 0.0, 0.0, 1.0 ], diffuse : [ 0.0, 0.0, 0.0, 1.0 ], @@ -29,6 +29,13 @@ function pbrToMaterialsCommon(gltf) { shininess : [ 0.0 ] }; var pbrMetallicRoughness = material.pbrMetallicRoughness; + var isPBR = defined(pbrMetallicRoughness) || + (defined(material.extensions) && defined(material.extensions.KHR_materials_pbrSpecularGlossiness) || + defined(material.occlusionTexture) || + defined(material.emissiveFactor) || + defined(material.emissiveTexture) || + defined(material.doubleSided)); + if (defined(pbrMetallicRoughness)) { var baseColorFactor = pbrMetallicRoughness.baseColorFactor; if (defined(baseColorFactor)) { @@ -36,7 +43,7 @@ function pbrToMaterialsCommon(gltf) { } var baseColorTexture = pbrMetallicRoughness.baseColorTexture; if (defined(baseColorTexture)) { - values.diffuse = [ baseColorTexture.index ]; + values.diffuse = [baseColorTexture.index]; } } var extensions = material.extensions; @@ -51,7 +58,7 @@ function pbrToMaterialsCommon(gltf) { // diffuseTexture should be used instead of baseColorTexture if defined var diffuseTexture = pbrSpecularGlossiness.diffuseTexture; if (defined(diffuseTexture)) { - values.diffuse = [ diffuseTexture.index ]; + values.diffuse = [diffuseTexture.index]; } var specularFactor = pbrSpecularGlossiness.specularFactor; if (defined(specularFactor)) { @@ -65,13 +72,13 @@ function pbrToMaterialsCommon(gltf) { } var specularGlossinessTexture = pbrSpecularGlossiness.specularGlossinessTexture; if (defined(specularGlossinessTexture)) { - values.specular = [ specularGlossinessTexture.index ]; + values.specular = [specularGlossinessTexture.index]; } } } var occlusionTexture = material.occlusionTexture; if (defined(occlusionTexture)) { - values.ambient = [ occlusionTexture.index ]; + values.ambient = [occlusionTexture.index]; } var emissiveFactor = material.emissiveFactor; if (defined(emissiveFactor)) { @@ -79,15 +86,34 @@ function pbrToMaterialsCommon(gltf) { values.emission[1] = emissiveFactor[1]; values.emission[2] = emissiveFactor[2]; } - delete material.emissiveFactor; - delete material.normalTexture; - delete material.occlusionTexture; - delete material.pbrMetallicRoughness; - material.extensions = { - technique : 'PHONG', - KHR_materials_common : { + var emissiveTexture = material.emissiveTexture; + if (defined(emissiveTexture)) { + values.emission = [emissiveTexture.index]; + } + var doubleSided = material.doubleSided; + if (isPBR) { + delete material.doubleSided; + delete material.emissiveFactor; + delete material.emissiveTexture; + delete material.normalTexture; + delete material.occlusionTexture; + delete material.pbrMetallicRoughness; + var materialsCommon = { + technique: 'BLINN', values: values + }; + var jointCount = materialJointCount[materialId]; + if (defined(jointCount)) { + materialsCommon.jointCount = jointCount; } - }; + if (defined(doubleSided)) { + materialsCommon.doubleSided = doubleSided; + } + material.extensions = { + KHR_materials_common: materialsCommon + }; + addExtensionsRequired(gltf, 'KHR_materials_common'); + removeExtensionsUsed(gltf, 'KHR_materials_pbrSpecularGlossiness'); + } }); } \ No newline at end of file diff --git a/lib/processModelMaterialsCommon.js b/lib/processModelMaterialsCommon.js index 39cae316..ea562a55 100644 --- a/lib/processModelMaterialsCommon.js +++ b/lib/processModelMaterialsCommon.js @@ -486,7 +486,7 @@ function generateTechnique(gltf, khrMaterialsCommon, lightParameters, optimizeFo var colorCreationBlock = ' vec3 color = vec3(0.0, 0.0, 0.0);\n'; if (hasNormals) { fragmentShader += ' vec3 normal = normalize(v_normal);\n'; - if (parameterValues.doubleSided) { + if (khrMaterialsCommon.doubleSided) { fragmentShader += ' if (gl_FrontFacing == false)\n'; fragmentShader += ' {\n'; fragmentShader += ' normal = -normal;\n'; @@ -581,7 +581,7 @@ function generateTechnique(gltf, khrMaterialsCommon, lightParameters, optimizeFo ] } }; - } else if (parameterValues.doubleSided) { + } else if (khrMaterialsCommon.doubleSided) { techniqueStates = { enable: [ WebGLConstants.DEPTH_TEST diff --git a/specs/lib/generateModelMaterialsCommonSpec.js b/specs/lib/generateModelMaterialsCommonSpec.js index 72bf1c64..d7304e83 100644 --- a/specs/lib/generateModelMaterialsCommonSpec.js +++ b/specs/lib/generateModelMaterialsCommonSpec.js @@ -4,9 +4,9 @@ var generateModelMaterialsCommon = require('../../lib/generateModelMaterialsComm describe('generateModelMaterialsCommon', function () { it('removes techniques, programs, and shaders', function () { var gltf = { - techniques: {}, - programs: {}, - shaders: {} + techniques: [], + programs: [], + shaders: [] }; generateModelMaterialsCommon(gltf); expect(gltf.extensionsUsed).toEqual(['KHR_materials_common']); @@ -17,20 +17,20 @@ describe('generateModelMaterialsCommon', function () { it('generates a KHR_materials_common material with values', function () { var gltf = { - materials: { - material: { + materials: [ + { values: { ambient: [0, 0, 0, 1], otherAttribute: true }, - technique: 'technique' + technique: 0 } - }, - techniques: { - technique: { + ], + techniques: [ + { parameters: {} } - } + ] }; generateModelMaterialsCommon(gltf, { technique: 'PHONG', @@ -38,7 +38,7 @@ describe('generateModelMaterialsCommon', function () { someAttribute: true }); expect(gltf.extensionsUsed).toEqual(['KHR_materials_common']); - var material = gltf.materials.material; + var material = gltf.materials[0]; var materialsCommon = material.extensions.KHR_materials_common; expect(materialsCommon.doubleSided).toBe(true); expect(materialsCommon.technique).toBe('PHONG'); @@ -50,23 +50,23 @@ describe('generateModelMaterialsCommon', function () { it('generates a KHR_materials_common with correct transparent flag set if diffuse alpha is less than 1', function () { var gltf = { - materials: { - material: { + materials: [ + { values: { diffuse: [1, 0, 0, 0.5] }, - technique: 'technique' + technique: 0 } - }, - techniques: { - technique: { + ], + techniques: [ + { parameters: {} } - } + ] }; generateModelMaterialsCommon(gltf); expect(gltf.extensionsUsed).toEqual(['KHR_materials_common']); - var material = gltf.materials.material; + var material = gltf.materials[0]; var materialsCommon = material.extensions.KHR_materials_common; expect(materialsCommon.technique).toBe('PHONG'); var values = materialsCommon.values; @@ -76,24 +76,24 @@ describe('generateModelMaterialsCommon', function () { it('generates a KHR_materials_common with correct transparent flag set if transparency less than 1', function () { var gltf = { - materials: { - material: { + materials: [ + { values: { diffuse: [1, 0, 0, 1], transparency: 0.5 }, - technique: 'technique' + technique: 0 } - }, - techniques: { - technique: { + ], + techniques: [ + { parameters: {} } - } + ] }; generateModelMaterialsCommon(gltf); expect(gltf.extensionsUsed).toEqual(['KHR_materials_common']); - var material = gltf.materials.material; + var material = gltf.materials[0]; var materialsCommon = material.extensions.KHR_materials_common; expect(materialsCommon.technique).toBe('PHONG'); var values = materialsCommon.values; @@ -104,30 +104,30 @@ describe('generateModelMaterialsCommon', function () { it('generates lights from a technique', function () { var gltf = { - materials: { - material: { - technique: 'technique' + materials: [ + { + technique: 0 } - }, - nodes: { - lightNode: {} - }, - techniques: { - technique: { + ], + nodes: [ + {} + ], + techniques: [ + { parameters: { ambient: {}, light0Color: { value: [1, 1, 0.5] }, light0Transform: { - node: 'lightNode' + node: 0 } } } - } + ] }; generateModelMaterialsCommon(gltf); - expect(gltf.nodes.lightNode.extensions.KHR_materials_common.light).toBe('light0'); + expect(gltf.nodes[0].extensions.KHR_materials_common.light).toBe('light0'); var lights = gltf.extensions.KHR_materials_common.lights; expect(lights.defaultAmbient.ambient.color).toEqual([1, 1, 1]); expect(lights.light0.directional.color).toEqual([1, 1, 0.5]); @@ -136,46 +136,44 @@ describe('generateModelMaterialsCommon', function () { it('declares jointCount for skinned nodes', function () { var gltf = { - accessors: { - accessor: { + accessors: [ + { count: 4 } - }, - materials: { - material: { - technique: 'technique' + ], + materials: [ + { + technique: 0 } - }, - meshes: { - mesh: { + ], + meshes: [ + { primitives: [ { - material: 'material' + material: 0 } ] } - }, - nodes: { - skinnedNode: { - meshes: [ - 'mesh' - ], - skin: 'skin' + ], + nodes: [ + { + mesh: 0, + skin: 0 } - }, - skins: { - skin: { - inverseBindMatrices: 'accessor' + ], + skins: [ + { + inverseBindMatrices: 0 } - }, - techniques: { - technique: { + ], + techniques: [ + { parameters: {} } - } + ] }; generateModelMaterialsCommon(gltf); - var material = gltf.materials.material; + var material = gltf.materials[0]; var materialsCommon = material.extensions.KHR_materials_common; expect(materialsCommon.jointCount).toBe(4); }); diff --git a/specs/lib/pbrToMaterialsCommonSpec.js b/specs/lib/pbrToMaterialsCommonSpec.js new file mode 100644 index 00000000..779b331c --- /dev/null +++ b/specs/lib/pbrToMaterialsCommonSpec.js @@ -0,0 +1,214 @@ +'use strict'; +var pbrToMaterialsCommon = require('../../lib/pbrToMaterialsCommon'); + +describe('pbrToMaterialsCommon', function() { + it('deletes PBR properties and modifies extensionsRequired', function() { + var gltf = { + materials : [ + { + doubleSided : true, + emissiveFactor : [], + emissiveTexture : {}, + extensions : { + KHR_materials_pbrSpecularGlossiness : {} + }, + normalTexture : {}, + occlusionTexture : {}, + pbrMetallicRoughness : {} + } + ], + extensionsRequired : [ 'KHR_materials_pbrSpecularGlossiness' ], + extensionsUsed : [ 'KHR_materials_pbrSpecularGlossiness' ] + }; + pbrToMaterialsCommon(gltf); + var material = gltf.materials[0]; + expect(material.doubleSided).not.toBeDefined(); + expect(material.emissiveFactor).not.toBeDefined(); + expect(material.emissiveTexture).not.toBeDefined(); + expect(material.extensions.KHR_materials_pbrSpecularGlossiness).not.toBeDefined(); + expect(material.normalTexture).not.toBeDefined(); + expect(material.occlusionTexture).not.toBeDefined(); + expect(material.pbrMetallicRoughness).not.toBeDefined(); + expect(gltf.extensionsRequired).toEqual([ 'KHR_materials_common' ]); + expect(gltf.extensionsUsed).toEqual([ 'KHR_materials_common' ]); + }); + + it('maps baseColorFactor -> diffuse', function() { + var gltf = { + materials : [ + { + pbrMetallicRoughness : { + baseColorFactor : [ 1.0, 1.0, 1.0, 1.0 ] + } + } + ] + }; + pbrToMaterialsCommon(gltf); + expect(gltf.materials[0].extensions.KHR_materials_common.values.diffuse).toEqual([ 1.0, 1.0, 1.0, 1.0 ]); + }); + + it('maps baseColorTexture -> diffuse, overriding baseColorFactor', function() { + var gltf = { + materials : [ + { + pbrMetallicRoughness : { + baseColorFactor : [ 1.0, 1.0, 1.0, 1.0 ], + baseColorTexture : { + index : 2 + } + } + } + ] + }; + pbrToMaterialsCommon(gltf); + expect(gltf.materials[0].extensions.KHR_materials_common.values.diffuse).toEqual([ 2 ]); + }); + + it('maps pbrSpecularGlossiness.diffuseFactor -> diffuse', function() { + var gltf = { + materials : [ + { + extensions : { + KHR_materials_pbrSpecularGlossiness : { + diffuseFactor : [ 1.0, 1.0, 1.0, 1.0 ] + } + } + } + ] + }; + pbrToMaterialsCommon(gltf); + expect(gltf.materials[0].extensions.KHR_materials_common.values.diffuse).toEqual([ 1.0, 1.0, 1.0, 1.0 ]); + }); + + it('maps baseColorTexture -> diffuse even if pbrSpecularGlossiness.diffuseFactor is defined', function() { + var gltf = { + materials : [ + { + pbrMetallicRoughness : { + baseColorFactor : [ 1.0, 1.0, 1.0, 1.0 ], + baseColorTexture : { + index : 2 + } + }, + extensions : { + KHR_materials_pbrSpecularGlossiness : { + diffuseFactor : [ 1.0, 1.0, 1.0, 1.0 ] + } + } + } + ] + }; + pbrToMaterialsCommon(gltf); + expect(gltf.materials[0].extensions.KHR_materials_common.values.diffuse).toEqual([ 2 ]); + }); + + it('maps pbrSpecularGlossiness.diffuseTexture -> diffuse to overwrite baseColorTexture', function() { + var gltf = { + materials : [ + { + pbrMetallicRoughness : { + baseColorFactor : [ 1.0, 1.0, 1.0, 1.0 ], + baseColorTexture : { + index : 2 + } + }, + extensions : { + KHR_materials_pbrSpecularGlossiness : { + diffuseFactor : [ 1.0, 1.0, 1.0, 1.0 ], + diffuseTexture : { + index : 3 + } + } + } + } + ] + }; + pbrToMaterialsCommon(gltf); + expect(gltf.materials[0].extensions.KHR_materials_common.values.diffuse).toEqual([ 3 ]); + }); + + it('maps pbrSpecularGlossiness.specularFactor -> specular', function() { + var gltf = { + materials : [ + { + extensions : { + KHR_materials_pbrSpecularGlossiness : { + specularFactor : [ 1.0, 2.0, 3.0 ] + } + } + } + ] + }; + pbrToMaterialsCommon(gltf); + expect(gltf.materials[0].extensions.KHR_materials_common.values.specular).toEqual([ 1.0, 2.0, 3.0, 1.0 ]); + }); + + it('maps pbrSpecularGlossiness.glossinessFactor -> shininess', function() { + var gltf = { + materials : [ + { + extensions : { + KHR_materials_pbrSpecularGlossiness : { + glossinessFactor : 100.0 + } + } + } + ] + }; + pbrToMaterialsCommon(gltf); + expect(gltf.materials[0].extensions.KHR_materials_common.values.shininess).toEqual([ 100.0 ]); + }); + + it('maps occlusionTexture -> ambient', function() { + var gltf = { + materials : [ + { + occlusionTexture : { + index : 4 + } + } + ] + }; + pbrToMaterialsCommon(gltf); + expect(gltf.materials[0].extensions.KHR_materials_common.values.ambient).toEqual([ 4 ]); + }); + + it('maps emissiveFactor -> emission', function() { + var gltf = { + materials : [ + { + emissiveFactor : [1.0, 2.0, 3.0] + } + ] + }; + pbrToMaterialsCommon(gltf); + expect(gltf.materials[0].extensions.KHR_materials_common.values.emission).toEqual([ 1.0, 2.0, 3.0, 1.0 ]); + }); + + it('maps emissiveTexture -> emission', function() { + var gltf = { + materials : [ + { + emissiveFactor : [1.0, 2.0, 3.0], + emissiveTexture : { + index : 5 + } + } + ] + }; + pbrToMaterialsCommon(gltf); + expect(gltf.materials[0].extensions.KHR_materials_common.values.emission).toEqual([ 5 ]); + }); + + it('preserves doubleSided', function () { + var gltf = { + materials : [ + { + doubleSided : true + } + ] + }; + pbrToMaterialsCommon(gltf); + expect(gltf.materials[0].extensions.KHR_materials_common.doubleSided).toEqual(true); + }); +}); \ No newline at end of file From c43c6d838ba96c822651ad15bce3a0accbea052f Mon Sep 17 00:00:00 2001 From: Robert Taglang Date: Fri, 28 Apr 2017 15:11:24 -0400 Subject: [PATCH 04/35] Infer missing bufferView targets --- lib/addDefaults.js | 43 ++++++++++++++++++++++++++++++++++++ specs/lib/addDefaultsSpec.js | 35 +++++++++++++++++++++++++++++ 2 files changed, 78 insertions(+) diff --git a/lib/addDefaults.js b/lib/addDefaults.js index d3a5aa67..d45e7250 100644 --- a/lib/addDefaults.js +++ b/lib/addDefaults.js @@ -1,6 +1,7 @@ 'use strict'; var Cesium = require('cesium'); var addToArray = require('./addToArray'); +var ForEach = require('./ForEach'); var clone = Cesium.clone; var defaultValue = Cesium.defaultValue; @@ -428,6 +429,47 @@ function optimizeForCesium(gltf) { } } +function inferBufferViewTargets(gltf) { + // If bufferView elements are missing targets, we can infer their type from their use + var needsTarget = {}; + var shouldTraverse = false; + ForEach.bufferView(gltf, function(bufferView, bufferViewId) { + if (!defined(bufferView.target)) { + needsTarget[bufferViewId] = true; + shouldTraverse = true; + } + }); + if (shouldTraverse) { + 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; + } + } + } + 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; + } + } + }); + }); + }); + } +} + /** * Adds default glTF values if they don't exist. * @@ -448,6 +490,7 @@ function addDefaults(gltf, options) { addDefaultTechnique(gltf); enableDiffuseTransparency(gltf); selectDefaultScene(gltf); + inferBufferViewTargets(gltf); if (options.optimizeForCesium) { optimizeForCesium(gltf); } diff --git a/specs/lib/addDefaultsSpec.js b/specs/lib/addDefaultsSpec.js index 99e270f5..080b253b 100644 --- a/specs/lib/addDefaultsSpec.js +++ b/specs/lib/addDefaultsSpec.js @@ -437,4 +437,39 @@ describe('addDefaults', function() { expect(gltf.scene).toEqual(0); }); + + it('infers missing bufferView targets', function() { + var gltf = { + accessors: [ + { + bufferView: 0 + }, { + bufferView: 1 + }, { + bufferView: 2 + } + ], + bufferViews: [ + {}, + {}, + {} + ], + meshes: [ + { + primitives: [ + { + attributes: { + POSITION: 0 + }, + indices: 1 + } + ] + } + ] + }; + addDefaults(gltf); + expect(gltf.bufferViews[0].target).toEqual(WebGLConstants.ARRAY_BUFFER); + expect(gltf.bufferViews[1].target).toEqual(WebGLConstants.ELEMENT_ARRAY_BUFFER); + expect(gltf.bufferViews[2].target).not.toBeDefined(); + }); }); From 119d008480b44c4b89e7ea36b863385e59688777 Mon Sep 17 00:00:00 2001 From: lasalvavida Date: Wed, 3 May 2017 11:31:59 -0400 Subject: [PATCH 05/35] Add option to break from object iterator --- lib/ForEach.js | 10 +++++++--- lib/addDefaults.js | 13 ++++++++++--- specs/lib/addDefaultsSpec.js | 13 +++++++++++++ 3 files changed, 30 insertions(+), 6 deletions(-) diff --git a/lib/ForEach.js b/lib/ForEach.js index e4880ea9..31e3379b 100644 --- a/lib/ForEach.js +++ b/lib/ForEach.js @@ -1,7 +1,6 @@ 'use strict'; var Cesium = require('cesium'); -var defaultValue = Cesium.defaultValue; var defined = Cesium.defined; module.exports = ForEach; @@ -17,8 +16,13 @@ ForEach.object = function(arrayOfObjects, handler) { if (defined(arrayOfObjects)) { for (var i = 0; i < arrayOfObjects.length; i++) { var object = arrayOfObjects[i]; - var offset = defaultValue(handler(object, i), 0); - i += offset; + var returnValue = handler(object, i); + if (typeof returnValue === 'number') { + i += returnValue; + } + else if (returnValue) { + break; + } } } }; diff --git a/lib/addDefaults.js b/lib/addDefaults.js index d45e7250..8c9443d6 100644 --- a/lib/addDefaults.js +++ b/lib/addDefaults.js @@ -432,14 +432,14 @@ function optimizeForCesium(gltf) { function inferBufferViewTargets(gltf) { // If bufferView elements are missing targets, we can infer their type from their use var needsTarget = {}; - var shouldTraverse = false; + var shouldTraverse = 0; ForEach.bufferView(gltf, function(bufferView, bufferViewId) { if (!defined(bufferView.target)) { needsTarget[bufferViewId] = true; - shouldTraverse = true; + shouldTraverse++; } }); - if (shouldTraverse) { + if (shouldTraverse > 0) { var accessors = gltf.accessors; var bufferViews = gltf.bufferViews; ForEach.mesh(gltf, function (mesh) { @@ -452,6 +452,8 @@ function inferBufferViewTargets(gltf) { var bufferView = bufferViews[bufferViewId]; if (defined(bufferView)) { bufferView.target = WebGLConstants.ELEMENT_ARRAY_BUFFER; + needsTarget[bufferViewId] = false; + shouldTraverse--; } } } @@ -462,10 +464,15 @@ function inferBufferViewTargets(gltf) { var bufferView = bufferViews[bufferViewId]; if (defined(bufferView)) { bufferView.target = WebGLConstants.ARRAY_BUFFER; + needsTarget[bufferViewId] = false; + shouldTraverse--; } } }); }); + if (shouldTraverse === 0) { + return true; + } }); } } diff --git a/specs/lib/addDefaultsSpec.js b/specs/lib/addDefaultsSpec.js index 080b253b..ac03d883 100644 --- a/specs/lib/addDefaultsSpec.js +++ b/specs/lib/addDefaultsSpec.js @@ -447,9 +447,12 @@ describe('addDefaults', function() { bufferView: 1 }, { bufferView: 2 + }, { + bufferView: 3 } ], bufferViews: [ + {}, {}, {}, {} @@ -464,6 +467,15 @@ describe('addDefaults', function() { indices: 1 } ] + }, { + primitives: [ + { + attributes: { + POSITION: 3 + }, + indices: 1 + } + ] } ] }; @@ -471,5 +483,6 @@ describe('addDefaults', function() { expect(gltf.bufferViews[0].target).toEqual(WebGLConstants.ARRAY_BUFFER); expect(gltf.bufferViews[1].target).toEqual(WebGLConstants.ELEMENT_ARRAY_BUFFER); expect(gltf.bufferViews[2].target).not.toBeDefined(); + expect(gltf.bufferViews[3].target).toEqual(WebGLConstants.ARRAY_BUFFER); }); }); From 8c909e82be1a519f08ad9f30367fb073f0143bc0 Mon Sep 17 00:00:00 2001 From: Sean Lilley Date: Wed, 3 May 2017 12:06:25 -0400 Subject: [PATCH 06/35] Style tweaks --- lib/ForEach.js | 1 - lib/addCesiumRTC.js | 2 +- lib/byteLengthForComponentType.js | 2 - lib/cesiumGeometryToGltfPrimitive.js | 4 +- lib/combineNodes.js | 3 +- lib/createAccessor.js | 2 +- lib/createAccessorUsageTables.js | 2 +- lib/getAccessorByteStride.js | 1 + lib/getPrimitiveAttributeSemantics.js | 2 +- lib/numberOfComponentsForType.js | 2 +- lib/updateVersion.js | 122 +++++++++++++------------- lib/writeAccessor.js | 2 +- 12 files changed, 70 insertions(+), 75 deletions(-) diff --git a/lib/ForEach.js b/lib/ForEach.js index e4880ea9..ac248fce 100644 --- a/lib/ForEach.js +++ b/lib/ForEach.js @@ -6,7 +6,6 @@ var defined = Cesium.defined; module.exports = ForEach; - /** * Contains traversal functions for processing elements of the glTF hierarchy. * @constructor diff --git a/lib/addCesiumRTC.js b/lib/addCesiumRTC.js index b9d196b4..d600fd83 100644 --- a/lib/addCesiumRTC.js +++ b/lib/addCesiumRTC.js @@ -25,7 +25,7 @@ module.exports = addCesiumRTC; * @param {Ellipsoid} [options.ellipsoid=Ellipsoid.WGS84] The ellipsoid to use for lat-long mapping. */ function addCesiumRTC(gltf, options) { - options = defaultValue(options, {}); + options = defaultValue(options, []); var positionArray = []; var ellipsoid = defaultValue(options.ellipsoid, Ellipsoid.WGS84); var position = options.position; diff --git a/lib/byteLengthForComponentType.js b/lib/byteLengthForComponentType.js index afe81611..4803b22c 100644 --- a/lib/byteLengthForComponentType.js +++ b/lib/byteLengthForComponentType.js @@ -13,8 +13,6 @@ module.exports = byteLengthForComponentType; * 5122 (SHORT) : 2 * 5123 (UNSIGNED_SHORT) : 2 * 5126 (FLOAT) : 4 - * - * Allowed by extension: * 5125 (UNSIGNED_INT) : 4 * * @param {Number} [componentType] diff --git a/lib/cesiumGeometryToGltfPrimitive.js b/lib/cesiumGeometryToGltfPrimitive.js index a6fd9510..62ead8a6 100644 --- a/lib/cesiumGeometryToGltfPrimitive.js +++ b/lib/cesiumGeometryToGltfPrimitive.js @@ -1,6 +1,5 @@ 'use strict'; var Cesium = require('cesium'); - var createAccessor = require('./createAccessor'); var findAccessorMinMax = require('./findAccessorMinMax'); var getPrimitiveAttributeSemantics = require('./getPrimitiveAttributeSemantics'); @@ -32,13 +31,12 @@ function getFirstAttributeSemantic(gltf, primitive, semantic, packedLength) { return semantics[0]; } -// Helper function to write attributes to gltf primitive from cesium geometry function mapGeometryAttributeToPrimitive(gltf, primitive, geometry, semantic) { var attributeSemantic; var values; var packedAttributeLength = geometry.attributes.position.values.length; - switch(semantic) { + switch (semantic) { case 'position': attributeSemantic = getFirstAttributeSemantic(gltf, primitive, 'POSITION', packedAttributeLength); values = geometry.attributes.position.values; diff --git a/lib/combineNodes.js b/lib/combineNodes.js index cc87eab5..78c6c0fd 100644 --- a/lib/combineNodes.js +++ b/lib/combineNodes.js @@ -5,8 +5,9 @@ var NodeHelpers = require('./NodeHelpers'); var PrimitiveHelpers = require('./PrimitiveHelpers'); var RemoveUnusedProperties = require('./RemoveUnusedProperties'); -var Matrix4 = Cesium.Matrix4; var defined = Cesium.defined; +var Matrix4 = Cesium.Matrix4; + var removeMeshes = RemoveUnusedProperties.removeMeshes; var removeNodes = RemoveUnusedProperties.removeNodes; diff --git a/lib/createAccessor.js b/lib/createAccessor.js index b7d74f28..285f7663 100644 --- a/lib/createAccessor.js +++ b/lib/createAccessor.js @@ -15,7 +15,7 @@ module.exports = createAccessor; * Creates an accessor from data and adds it to the glTF asset. * * @param {Object} gltf A javascript object containing a glTF asset. - * @param {Array.|Number} dataOrLength The data to store in the accessor buffer or the length of data to allocate. + * @param {Number[]|Number} dataOrLength The data to store in the accessor buffer or the length of data to allocate. * @param {String} type glTF type (e.g. 'scalar', 'vec3') * @param {Number} componentType glTF component type (e.g. 5126 (float)) * @param {Number} target glTF bufferView target (e.g. 34962 (ARRAY_BUFFER), 34963 (ELEMENT_ARRAY_BUFFER) diff --git a/lib/createAccessorUsageTables.js b/lib/createAccessorUsageTables.js index c3301b97..b06b2aa2 100644 --- a/lib/createAccessorUsageTables.js +++ b/lib/createAccessorUsageTables.js @@ -151,7 +151,7 @@ function createAccessorUsageTables(gltf) { } } } - }) ; + }); }); var finalTables = []; var tablesLength = tables.length; diff --git a/lib/getAccessorByteStride.js b/lib/getAccessorByteStride.js index f691e5d3..c144b7f4 100644 --- a/lib/getAccessorByteStride.js +++ b/lib/getAccessorByteStride.js @@ -11,6 +11,7 @@ module.exports = getAccessorByteStride; * Returns the byte stride of the provided accessor. * If the byteStride is 0, it is calculated based on type and componentType * + * @param {Object} gltf A javascript object containing a glTF asset. * @param {Object} accessor The accessor. * @returns {Number} The byte stride of the accessor. */ diff --git a/lib/getPrimitiveAttributeSemantics.js b/lib/getPrimitiveAttributeSemantics.js index ac8ec211..10c71f01 100644 --- a/lib/getPrimitiveAttributeSemantics.js +++ b/lib/getPrimitiveAttributeSemantics.js @@ -10,7 +10,7 @@ module.exports = getPrimitiveAttributeSemantics; * * @param {Object} primitive A javascript object containing a glTF primitive. * @param {String} semanticPrefix The search string for semantics. Matched semantics start with this string. - * @returns {Array.} The primitive semantics starting with semanticPrefix. + * @returns {String[]} The primitive semantics starting with semanticPrefix. */ function getPrimitiveAttributeSemantics(primitive, semanticPrefix) { var attributes = primitive.attributes; diff --git a/lib/numberOfComponentsForType.js b/lib/numberOfComponentsForType.js index fa44e94b..600cda8a 100644 --- a/lib/numberOfComponentsForType.js +++ b/lib/numberOfComponentsForType.js @@ -9,7 +9,7 @@ module.exports = numberOfComponentsForType; * 'VEC2' : 2 * 'VEC3' : 3 * 'VEC4' : 4 - * 'MAT2' : 4 + * 'MAT2' : 4 * 'MAT3' : 9 * 'MAT4' : 16 * diff --git a/lib/updateVersion.js b/lib/updateVersion.js index 91eae7d9..83767d28 100644 --- a/lib/updateVersion.js +++ b/lib/updateVersion.js @@ -2,16 +2,16 @@ var Cesium = require('cesium'); var addExtensionsRequired = require('./addExtensionsRequired'); var addToArray = require('./addToArray'); -var ForEach = require('./ForEach'); var findAccessorMinMax = require('./findAccessorMinMax'); +var ForEach = require('./ForEach'); var Cartesian3 = Cesium.Cartesian3; var CesiumMath = Cesium.Math; -var Quaternion = Cesium.Quaternion; -var WebGLConstants = Cesium.WebGLConstants; var clone = Cesium.clone; var defaultValue = Cesium.defaultValue; var defined = Cesium.defined; +var Quaternion = Cesium.Quaternion; +var WebGLConstants = Cesium.WebGLConstants; module.exports = updateVersion; @@ -507,45 +507,44 @@ function requireKnownExtensions(gltf) { function removeBufferType(gltf) { ForEach.buffer(gltf, function(buffer) { delete buffer.type; - }); } function makeMaterialValuesArrays(gltf) { ForEach.material(gltf, function(material) { - ForEach.materialValue(material, function(value, name) { - if (!Array.isArray(value)) { - material.values[name] = [value]; - } - }) ; + ForEach.materialValue(material, function(value, name) { + if (!Array.isArray(value)) { + material.values[name] = [value]; + } + }); }); } function requireAttributeSetIndex(gltf) { ForEach.mesh(gltf, function(mesh) { - ForEach.meshPrimitive(mesh, function(primitive) { - ForEach.meshPrimitiveAttribute(primitive, function(accessorId, semantic) { - if (semantic === 'TEXCOORD') { - primitive.attributes.TEXCOORD_0 = accessorId; - } else if (semantic === 'COLOR') { - primitive.attributes.COLOR_0 = accessorId; - } - }); - delete primitive.attributes.TEXCOORD; - delete primitive.attributes.COLOR; - }); + ForEach.meshPrimitive(mesh, function(primitive) { + ForEach.meshPrimitiveAttribute(primitive, function(accessorId, semantic) { + if (semantic === 'TEXCOORD') { + primitive.attributes.TEXCOORD_0 = accessorId; + } else if (semantic === 'COLOR') { + primitive.attributes.COLOR_0 = accessorId; + } + }); + delete primitive.attributes.TEXCOORD; + delete primitive.attributes.COLOR; + }); }); ForEach.technique(gltf, function(technique) { - ForEach.techniqueParameter(technique, function(parameter) { - var semantic = parameter.semantic; - if (defined(semantic)) { - if (semantic === 'TEXCOORD') { - parameter.semantic = 'TEXCOORD_0'; - } else if (semantic === 'COLOR') { - parameter.semantic = 'COLOR_0'; - } - } - }); + ForEach.techniqueParameter(technique, function(parameter) { + var semantic = parameter.semantic; + if (defined(semantic)) { + if (semantic === 'TEXCOORD') { + parameter.semantic = 'TEXCOORD_0'; + } else if (semantic === 'COLOR') { + parameter.semantic = 'COLOR_0'; + } + } + }); }); } @@ -560,30 +559,30 @@ var knownSemantics = { function underscoreApplicationSpecificSemantics(gltf) { var mappedSemantics = {}; ForEach.mesh(gltf, function(mesh) { - ForEach.meshPrimitive(mesh, function(primitive) { - /* jshint unused:vars */ - ForEach.meshPrimitiveAttribute(primitive, function(accessorId, semantic) { - if (semantic.charAt(0) !== '_') { - var setIndex = semantic.search(/_[0-9]+/g); - var strippedSemantic = semantic; - if (setIndex >= 0) { - strippedSemantic = semantic.substring(0, setIndex); - } - if (!defined(knownSemantics[strippedSemantic])) { - var newSemantic = '_' + semantic; - mappedSemantics[semantic] = newSemantic; - } - } - }); - for(var semantic in mappedSemantics) { - if (mappedSemantics.hasOwnProperty(semantic)) { - var mappedSemantic = mappedSemantics[semantic]; - var accessorId = primitive.attributes[semantic]; - delete primitive.attributes[semantic]; - primitive.attributes[mappedSemantic] = accessorId; - } - } - }); + ForEach.meshPrimitive(mesh, function(primitive) { + /* jshint unused:vars */ + ForEach.meshPrimitiveAttribute(primitive, function(accessorId, semantic) { + if (semantic.charAt(0) !== '_') { + var setIndex = semantic.search(/_[0-9]+/g); + var strippedSemantic = semantic; + if (setIndex >= 0) { + strippedSemantic = semantic.substring(0, setIndex); + } + if (!defined(knownSemantics[strippedSemantic])) { + var newSemantic = '_' + semantic; + mappedSemantics[semantic] = newSemantic; + } + } + }); + for (var semantic in mappedSemantics) { + if (mappedSemantics.hasOwnProperty(semantic)) { + var mappedSemantic = mappedSemantics[semantic]; + var accessorId = primitive.attributes[semantic]; + delete primitive.attributes[semantic]; + primitive.attributes[mappedSemantic] = accessorId; + } + } + }); }); ForEach.technique(gltf, function(technique) { ForEach.techniqueParameter(technique, function(parameter) { @@ -626,7 +625,6 @@ function removeScissorFromTechniques(gltf) { } function clampTechniqueFunctionStates(gltf) { - var i; ForEach.technique(gltf, function(technique) { var techniqueStates = technique.states; if (defined(techniqueStates)) { @@ -634,7 +632,7 @@ function clampTechniqueFunctionStates(gltf) { if (defined(functions)) { var blendColor = functions.blendColor; if (defined(blendColor)) { - for (i = 0; i < 4; i++) { + for (var i = 0; i < 4; i++) { blendColor[i] = CesiumMath.clamp(blendColor[i], 0.0, 1.0); } } @@ -709,12 +707,12 @@ function requireAccessorMinMax(gltf) { 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; - } - }); + ForEach.techniqueAttribute(technique, function(attribute) { + var parameter = technique.parameters[attribute]; + if (defined(parameter.value)) { + delete parameter.value; + } + }); }); } diff --git a/lib/writeAccessor.js b/lib/writeAccessor.js index 7f1eac7e..1d568db0 100644 --- a/lib/writeAccessor.js +++ b/lib/writeAccessor.js @@ -5,7 +5,7 @@ var numberOfComponentsForType = require('./numberOfComponentsForType'); module.exports = writeAccessor; /** - * Writes the contents of dataArray into a glTF accessor. + * Writes values into a glTF accessor. * * The glTF asset must be initialized for the pipeline. * From 5b041326ffbc7c4412a7e5cf6337ced6c9ba02a8 Mon Sep 17 00:00:00 2001 From: Sean Lilley Date: Wed, 3 May 2017 13:10:46 -0400 Subject: [PATCH 07/35] Mistake from previous commit --- lib/addCesiumRTC.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/addCesiumRTC.js b/lib/addCesiumRTC.js index d600fd83..b9d196b4 100644 --- a/lib/addCesiumRTC.js +++ b/lib/addCesiumRTC.js @@ -25,7 +25,7 @@ module.exports = addCesiumRTC; * @param {Ellipsoid} [options.ellipsoid=Ellipsoid.WGS84] The ellipsoid to use for lat-long mapping. */ function addCesiumRTC(gltf, options) { - options = defaultValue(options, []); + options = defaultValue(options, {}); var positionArray = []; var ellipsoid = defaultValue(options.ellipsoid, Ellipsoid.WGS84); var position = options.position; From 9891c3937031dcce6c8a65e798d965fecae9c063 Mon Sep 17 00:00:00 2001 From: lasalvavida Date: Sun, 14 May 2017 20:57:21 -0400 Subject: [PATCH 08/35] Added some unit tests for ForEach iterator --- specs/lib/ForEachSpec.js | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 specs/lib/ForEachSpec.js diff --git a/specs/lib/ForEachSpec.js b/specs/lib/ForEachSpec.js new file mode 100644 index 00000000..8429464d --- /dev/null +++ b/specs/lib/ForEachSpec.js @@ -0,0 +1,39 @@ +'use strict'; +var ForEach = require('../../lib/ForEach'); + +describe('ForEach', function() { + describe('object', function() { + it('iterates over items in an array', function() { + var array= ['0', '1', '2', '3', '4', '5']; + var count = 0; + ForEach.object(array, function(value, index) { + expect(index).toEqual(count); + expect(value).toEqual('' + count); + count++; + }); + expect(count).toEqual(6); + }); + + it('adjusts iterator based on the returned value', function() { + var array = [0, 1, 2, 3, 4, 5]; + var count = 0; + ForEach.object(array, function() { + count++; + return 1; + }); + expect(count).toEqual(3); + }); + + it('ends iteration early if handler returns true', function() { + var array = [0, 1, 2, 3, 4, 5]; + var count = 0; + ForEach.object(array, function(value) { + if (value === 3) { + return true; + } + count++; + }); + expect(count).toEqual(3); + }); + }); +}); \ No newline at end of file From d9842a0d09244841f76887dd2740bfdb516411a3 Mon Sep 17 00:00:00 2001 From: Robert Taglang Date: Fri, 9 Jun 2017 10:52:03 -0400 Subject: [PATCH 09/35] Added spec for getJointCountForMaterials and some cleanup --- lib/getJointCountForMaterials.js | 12 +++------ lib/pbrToMaterialsCommon.js | 2 +- specs/lib/getJointCountForMaterialsSpec.js | 29 ++++++++++++++++++++++ 3 files changed, 33 insertions(+), 10 deletions(-) create mode 100644 specs/lib/getJointCountForMaterialsSpec.js diff --git a/lib/getJointCountForMaterials.js b/lib/getJointCountForMaterials.js index 25b2fd95..6f985450 100644 --- a/lib/getJointCountForMaterials.js +++ b/lib/getJointCountForMaterials.js @@ -22,10 +22,7 @@ function getJointCountForMaterials(gltf) { }); ForEach.skin(gltf, function(skin, skinId) { - var jointCount = 1; - if (defined(skin.inverseBindMatrices)) { - jointCount = accessors[skin.inverseBindMatrices].count; - } + var jointCount = skin.joints.length; var skinnedNodes = nodesForSkinId[skinId]; var skinnedNodesLength = skinnedNodes.length; for (var i = 0; i < skinnedNodesLength; i++) { @@ -33,12 +30,9 @@ function getJointCountForMaterials(gltf) { var meshId = skinnedNode.mesh; if (defined(meshId)) { var mesh = meshes[meshId]; - var primitives = mesh.primitives; - var primitivesLength = primitives.length; - for (var k = 0; k < primitivesLength; k++) { - var primitive = primitives[k]; + ForEach.meshPrimitive(mesh, function(primitive) { jointCountForMaterialId[primitive.material] = jointCount; - } + }); } } }); diff --git a/lib/pbrToMaterialsCommon.js b/lib/pbrToMaterialsCommon.js index c2510e3e..13a8873e 100644 --- a/lib/pbrToMaterialsCommon.js +++ b/lib/pbrToMaterialsCommon.js @@ -26,7 +26,7 @@ function pbrToMaterialsCommon(gltf) { diffuse : [ 0.0, 0.0, 0.0, 1.0 ], emission : [ 0.0, 0.0, 0.0, 1.0 ], specular : [ 0.0, 0.0, 0.0, 1.0], - shininess : [ 0.0 ] + shininess : [ 0.0 ] }; var pbrMetallicRoughness = material.pbrMetallicRoughness; var isPBR = defined(pbrMetallicRoughness) || diff --git a/specs/lib/getJointCountForMaterialsSpec.js b/specs/lib/getJointCountForMaterialsSpec.js new file mode 100644 index 00000000..a0d740a8 --- /dev/null +++ b/specs/lib/getJointCountForMaterialsSpec.js @@ -0,0 +1,29 @@ +'use strict'; +var getJointCountForMaterials = require('../../lib/getJointCountForMaterials'); + +describe('getJointCountForMaterials', function() { + fit('gets joint counts for materials on skinned meshes', function() { + var gltf = { + materials : [{}, {}], + meshes : [{ + primitives : [{ + material : 1 + }] + }, { + primitives : [{ + material : 0 + }] + }], + nodes : [{ + mesh : 0, + skin : 0 + }], + skins : [{ + joints : [0, 1, 2, 3, 4] + }] + }; + var jointCounts = getJointCountForMaterials(gltf); + expect(jointCounts[0]).not.toBeDefined(); + expect(jointCounts[1]).toEqual(5); + }); +}); \ No newline at end of file From 5c722f96c934591213efeabab1853dadb63ea944 Mon Sep 17 00:00:00 2001 From: Robert Taglang Date: Fri, 9 Jun 2017 11:02:25 -0400 Subject: [PATCH 10/35] Clean up jsHint --- lib/getJointCountForMaterials.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/getJointCountForMaterials.js b/lib/getJointCountForMaterials.js index 6f985450..e769e292 100644 --- a/lib/getJointCountForMaterials.js +++ b/lib/getJointCountForMaterials.js @@ -7,7 +7,6 @@ var defined = Cesium.defined; module.exports = getJointCountForMaterials; function getJointCountForMaterials(gltf) { - var accessors = gltf.accessors; var meshes = gltf.meshes; var jointCountForMaterialId = {}; @@ -23,6 +22,9 @@ function getJointCountForMaterials(gltf) { 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++) { @@ -30,9 +32,7 @@ function getJointCountForMaterials(gltf) { var meshId = skinnedNode.mesh; if (defined(meshId)) { var mesh = meshes[meshId]; - ForEach.meshPrimitive(mesh, function(primitive) { - jointCountForMaterialId[primitive.material] = jointCount; - }); + ForEach.meshPrimitive(mesh, meshPrimitiveFunction); } } }); From d7d939149731292cfe62362ee1f42e6fab1fe91a Mon Sep 17 00:00:00 2001 From: Robert Taglang Date: Fri, 9 Jun 2017 11:03:55 -0400 Subject: [PATCH 11/35] fit -> it --- specs/lib/getJointCountForMaterialsSpec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/lib/getJointCountForMaterialsSpec.js b/specs/lib/getJointCountForMaterialsSpec.js index a0d740a8..9b16f7db 100644 --- a/specs/lib/getJointCountForMaterialsSpec.js +++ b/specs/lib/getJointCountForMaterialsSpec.js @@ -2,7 +2,7 @@ var getJointCountForMaterials = require('../../lib/getJointCountForMaterials'); describe('getJointCountForMaterials', function() { - fit('gets joint counts for materials on skinned meshes', function() { + it('gets joint counts for materials on skinned meshes', function() { var gltf = { materials : [{}, {}], meshes : [{ From 8f83cc2a5fd66c8e18faf9252ee20c85af761fd2 Mon Sep 17 00:00:00 2001 From: Robert Taglang Date: Fri, 9 Jun 2017 11:06:36 -0400 Subject: [PATCH 12/35] Fix failing test --- specs/lib/generateModelMaterialsCommonSpec.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/specs/lib/generateModelMaterialsCommonSpec.js b/specs/lib/generateModelMaterialsCommonSpec.js index d7304e83..979934fe 100644 --- a/specs/lib/generateModelMaterialsCommonSpec.js +++ b/specs/lib/generateModelMaterialsCommonSpec.js @@ -163,7 +163,8 @@ describe('generateModelMaterialsCommon', function () { ], skins: [ { - inverseBindMatrices: 0 + inverseBindMatrices: 0, + joints: [1, 2, 3, 4] } ], techniques: [ From 715ebc2db4c58283a33fe2e8b8ae443738c855cb Mon Sep 17 00:00:00 2001 From: Mohamad Moneimne Date: Tue, 11 Jul 2017 15:23:56 -0400 Subject: [PATCH 13/35] Added processPbrMetallicRoughness --- lib/processPbrMetallicRoughness.js | 774 +++++++++++++++++++++++++++++ 1 file changed, 774 insertions(+) create mode 100644 lib/processPbrMetallicRoughness.js diff --git a/lib/processPbrMetallicRoughness.js b/lib/processPbrMetallicRoughness.js new file mode 100644 index 00000000..2d40540c --- /dev/null +++ b/lib/processPbrMetallicRoughness.js @@ -0,0 +1,774 @@ +/*global define*/ +define([ + './addToArray', + './ForEach', + './numberOfComponentsForType', + './techniqueParameterForSemantic', + '../../Core/clone', + '../../Core/defined', + '../../Core/defaultValue', + '../../Core/WebGLConstants' +], function( + addToArray, + ForEach, + numberOfComponentsForType, + techniqueParameterForSemantic, + clone, + defined, + defaultValue, + WebGLConstants) { + 'use strict'; + + function webGLConstantToGlslType(webGLValue) { + switch (webGLValue) { + case WebGLConstants.FLOAT: + return 'float'; + case WebGLConstants.FLOAT_VEC2: + return 'vec2'; + case WebGLConstants.FLOAT_VEC3: + return 'vec3'; + case WebGLConstants.FLOAT_VEC4: + return 'vec4'; + case WebGLConstants.FLOAT_MAT2: + return 'mat2'; + case WebGLConstants.FLOAT_MAT3: + return 'mat3'; + case WebGLConstants.FLOAT_MAT4: + return 'mat4'; + case WebGLConstants.SAMPLER_2D: + return 'sampler2D'; + case WebGLConstants.BOOL: + return 'bool'; + } + } + + 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; + } + } + + function generateTechnique(gltf, material, frameState, optimizeForCesium) { + var techniques = gltf.techniques; + var shaders = gltf.shaders; + var programs = gltf.programs; + + var parameterValues = material.pbrMetallicRoughness; + for (var additional in material) { + if (material.hasOwnProperty(additional) && ((additional.indexOf('Texture') >= 0) || additional.indexOf('Factor') >= 0) || additional === 'doubleSided') { + parameterValues[additional] = material[additional]; + } + } + + var vertexShader = 'precision highp float;\n'; + var fragmentShader = 'precision highp float;\n'; + + var skin = gltf.skins[0]; + var joints = (defined(skin)) ? skin.joints : []; + var jointCount = joints.length; + var hasSkinning = jointCount > 0; + var skinningInfo = {}; + if (hasSkinning) { + skinningInfo = material.extras._pipeline.skinning; + } + + var hasNormals = true; + var hasTangents = false; + var hasMorphTargets = false; + var morphTargets; + for (var entry in gltf.meshes) { + if (defined(entry)) { + var mesh = gltf.meshes[entry]; + var primitives = mesh.primitives; + for (var primitive in primitives) { + if (defined(primitive)) { + var targets = primitives[primitive].targets; + if (!hasMorphTargets && defined(targets)) { + hasMorphTargets = true; + morphTargets = targets; + } + var attributes = primitives[primitive].attributes; + for (var attribute in attributes) { + if (attribute.indexOf('TANGENT') >= 0) { + hasTangents = true; + } + } + } + } + } + } + + // Add techniques + var techniqueParameters = { + // Add matrices + modelViewMatrix: { + semantic: 'MODELVIEW', + type: WebGLConstants.FLOAT_MAT4 + }, + projectionMatrix: { + semantic: 'PROJECTION', + type: WebGLConstants.FLOAT_MAT4 + } + }; + + if (hasNormals) { + techniqueParameters.normalMatrix = { + semantic: 'MODELVIEWINVERSETRANSPOSE', + type: WebGLConstants.FLOAT_MAT3 + }; + } + + if (hasSkinning) { + techniqueParameters.jointMatrix = { + count: jointCount, + semantic: 'JOINTMATRIX', + type: WebGLConstants.FLOAT_MAT4 + }; + } + + if (hasMorphTargets) { + techniqueParameters.morphWeights = { + count: morphTargets.length, + semantic: 'MORPHWEIGHTS', + type: WebGLConstants.FLOAT + }; + } + + // Add material parameters + var hasTexCoords = false; + for (var name in parameterValues) { + //generate shader parameters + if (parameterValues.hasOwnProperty(name)) { + var valType = getPBRValueType(name, parameterValues[name]); + if (!hasTexCoords && (valType === WebGLConstants.SAMPLER_2D)) { + hasTexCoords = true; + } + techniqueParameters[name] = { + type: valType + }; + } + } + + // 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; + } else { + vertexShader += 'uniform ' + webGLConstantToGlslType(param.type) + ' u_' + paramName + arraySize + ';\n'; + } + } + } + + // Add attributes with semantics + var vertexShaderMain = ''; + if (hasSkinning) { + var i, j; + var numberOfComponents = numberOfComponentsForType(skinningInfo.type); + var matrix = false; + if (skinningInfo.type.indexOf('MAT') === 0) { + matrix = true; + numberOfComponents = Math.sqrt(numberOfComponents); + } + if (!matrix) { + for (i = 0; i < numberOfComponents; i++) { + if (i === 0) { + vertexShaderMain += ' mat4 skinMat = '; + } else { + vertexShaderMain += ' skinMat += '; + } + vertexShaderMain += 'a_weight[' + i + '] * u_jointMatrix[int(a_joint[' + i + '])];\n'; + } + } else { + for (i = 0; i < numberOfComponents; i++) { + for (j = 0; j < numberOfComponents; j++) { + if (i === 0 && j === 0) { + vertexShaderMain += ' mat4 skinMat = '; + } else { + vertexShaderMain += ' skinMat += '; + } + vertexShaderMain += 'a_weight[' + i + '][' + j + '] * u_jointMatrix[int(a_joint[' + i + '][' + j + '])];\n'; + } + } + } + } + + // Add position always + var techniqueAttributes = { + a_position: 'position' + }; + techniqueParameters.position = { + semantic: 'POSITION', + type: WebGLConstants.FLOAT_VEC3 + }; + vertexShader += 'attribute vec3 a_position;\n'; + vertexShader += 'varying vec3 v_positionEC;\n'; + + // Morph Target Weighting + vertexShaderMain += ' vec3 weightedPos = a_position;\n'; + if (hasNormals) { + vertexShaderMain += ' vec3 weightedNormal = a_normal;\n'; + } + if (hasTangents) { + vertexShaderMain += ' vec3 weightedTangent = a_tangent;\n'; + } + if (hasMorphTargets) { + for (var target in morphTargets) { + var targetAttributes = morphTargets[target]; + for (var targetAttribute in targetAttributes) { + if (targetAttribute !== 'extras') { + var attributeLower = targetAttribute.toLowerCase() + '_' + target; + techniqueAttributes['a_' + attributeLower] = attributeLower; + techniqueParameters[attributeLower] = { + semantic : targetAttribute + '_' + target, + type : WebGLConstants.FLOAT_VEC3 + } + vertexShader += 'attribute vec3 a_' + attributeLower + ';\n'; + if (targetAttribute === 'POSITION') { + vertexShaderMain += ' weightedPos += u_morphWeights[' + target + '] * a_' + attributeLower + ';\n'; + } else if (targetAttribute === 'NORMAL') { + vertexShaderMain += ' weightedNormal += u_morphWeights[' + target + '] * a_' + attributeLower + ';\n'; + } else if (targetAttribute === 'TANGENT') { + vertexShaderMain += ' weightedTangent += u_morphWeights[' + target + '] * a_' + attributeLower + ';\n'; + } else { + // Invalid attribute + } + } + } + } + } + + // Final position computation + if (hasSkinning) { + vertexShaderMain += ' vec4 pos = u_modelViewMatrix * skinMat * vec4(weightedPos,1.0);\n'; + } else { + vertexShaderMain += ' vec4 pos = u_modelViewMatrix * vec4(weightedPos,1.0);\n'; + } + vertexShaderMain += ' v_positionEC = pos.xyz;\n'; + vertexShaderMain += ' gl_Position = u_projectionMatrix * pos;\n'; + fragmentShader += 'varying vec3 v_positionEC;\n'; + + // Final normal computation + if (hasNormals) { + techniqueAttributes.a_normal = 'normal'; + techniqueParameters.normal = { + semantic: 'NORMAL', + type: WebGLConstants.FLOAT_VEC3 + }; + vertexShader += 'attribute vec3 a_normal;\n'; + vertexShader += 'varying vec3 v_normal;\n'; + if (hasSkinning) { + vertexShaderMain += ' v_normal = u_normalMatrix * mat3(skinMat) * weightedNormal;\n'; + } else { + vertexShaderMain += ' v_normal = u_normalMatrix * weightedNormal;\n'; + } + + fragmentShader += 'varying vec3 v_normal;\n'; + } + + // Read tangents if available + if (hasTangents) { + techniqueAttributes.a_tangent = 'tangent'; + techniqueParameters.tangent = { + semantic: 'TANGENT', + type: WebGLConstants.FLOAT_VEC3 + }; + vertexShader += 'attribute vec3 a_tangent;\n'; + vertexShader += 'varying vec3 v_tangent;\n'; + vertexShaderMain += ' v_tangent = (u_modelViewMatrix * vec4(weightedTangent, 1.0)).xyz;\n'; + + fragmentShader += 'varying vec3 v_tangent;\n'; + } + + // 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 + }; + + v_texcoord = 'v_texcoord_0'; + vertexShader += 'attribute vec2 a_texcoord_0;\n'; + vertexShader += 'varying vec2 ' + v_texcoord + ';\n'; + vertexShaderMain += ' ' + v_texcoord + ' = a_texcoord_0;\n'; + + fragmentShader += 'varying vec2 ' + v_texcoord + ';\n'; + } + + // 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 + }; + techniqueAttributes.a_weight = 'weight'; + techniqueParameters.weight = { + semantic: 'WEIGHTS_0', + type: webGLConstant + }; + + vertexShader += 'attribute ' + attributeType + ' a_joint;\n'; + vertexShader += 'attribute ' + attributeType + ' a_weight;\n'; + } + + vertexShader += 'void main(void) {\n'; + vertexShader += vertexShaderMain; + vertexShader += '}\n'; + + // Fragment shader lighting + fragmentShader += 'const float M_PI = 3.141592653589793;\n'; + + var lambertianDiffuse = ''; + lambertianDiffuse += 'vec3 lambertianDiffuse(vec3 baseColor) {\n'; + lambertianDiffuse += ' return baseColor / M_PI;\n'; + lambertianDiffuse += '}\n\n'; + + var fresnelSchlick2 = ''; + fresnelSchlick2 += 'vec3 fresnelSchlick2(vec3 f0, vec3 f90, float VdotH) {\n'; + fresnelSchlick2 += ' return f0 + (f90 - f0) * pow(clamp(1.0 - VdotH, 0.0, 1.0), 5.0);\n'; + fresnelSchlick2 += '}\n\n'; + + var fresnelSchlick = ''; + fresnelSchlick += 'vec3 fresnelSchlick(float metalness, float VdotH) {\n'; + fresnelSchlick += ' return metalness + (vec3(1.0) - metalness) * pow(1.0 - VdotH, 5.0);\n'; + fresnelSchlick += '}\n\n'; + + var smithVisibilityG1 = ''; + smithVisibilityG1 += 'float smithVisibilityG1(float NdotV, float roughness) {\n'; + smithVisibilityG1 += ' float k = (roughness + 1.0) * (roughness + 1.0) / 8.0;\n'; + smithVisibilityG1 += ' return NdotV / (NdotV * (1.0 - k) + k);\n'; + smithVisibilityG1 += '}\n\n'; + + var smithVisibilityGGX = ''; + smithVisibilityGGX += 'float smithVisibilityGGX(float roughness, float NdotL, float NdotV) {\n'; + smithVisibilityGGX += ' return smithVisibilityG1(NdotL, roughness) * smithVisibilityG1(NdotV, roughness);\n'; + smithVisibilityGGX += '}\n\n'; + + var GGX = ''; + GGX += 'float GGX(float roughness, float NdotH) {\n'; + GGX += ' float roughnessSquared = roughness * roughness;\n'; + GGX += ' float f = (NdotH * roughnessSquared - NdotH) * NdotH + 1.0;\n'; + GGX += ' return roughnessSquared / (M_PI * f * f);\n'; + GGX += '}\n\n'; + + fragmentShader += lambertianDiffuse + fresnelSchlick2 + fresnelSchlick + smithVisibilityG1 + smithVisibilityGGX + GGX; + + var fragmentShaderMain = ''; + fragmentShaderMain += 'void main(void) {\n'; + + // Add normal mapping to fragment shader + if (hasNormals) { + fragmentShaderMain += ' vec3 ng = normalize(v_normal);\n'; + if (defined(parameterValues.normalTexture) && (hasTangents || frameState.context._standardDerivatives)) { + if (hasTangents) { + // Read tangents from varying + fragmentShaderMain += ' vec3 t = normalize(v_tangent);\n'; + } else { + // Compute tangents + fragmentShader = '#extension GL_OES_standard_derivatives : enable\n' + fragmentShader; + fragmentShaderMain += ' vec3 pos_dx = dFdx(v_positionEC);\n'; + fragmentShaderMain += ' vec3 pos_dy = dFdy(v_positionEC);\n'; + fragmentShaderMain += ' vec3 tex_dx = dFdx(vec3(' + v_texcoord + ',0.0));\n'; + fragmentShaderMain += ' vec3 tex_dy = dFdy(vec3(' + v_texcoord + ',0.0));\n'; + fragmentShaderMain += ' vec3 t = (tex_dy.t * pos_dx - tex_dx.t * pos_dy) / (tex_dx.s * tex_dy.t - tex_dy.s * tex_dx.t);\n'; + fragmentShaderMain += ' t = normalize(t - ng * dot(ng, t));\n'; + } + fragmentShaderMain += ' vec3 b = normalize(cross(ng, t));\n'; + fragmentShaderMain += ' mat3 tbn = mat3(t, b, ng);\n'; + fragmentShaderMain += ' vec3 n = texture2D(u_normalTexture, ' + v_texcoord + ').rgb;\n'; + fragmentShaderMain += ' n = normalize(tbn * (2.0 * n - 1.0));\n'; + } else { + fragmentShaderMain += ' vec3 n = ng;\n'; + } + if (parameterValues.doubleSided) { + fragmentShaderMain += ' if (!gl_FrontFacing)\n'; + fragmentShaderMain += ' {\n'; + fragmentShaderMain += ' n = -n;\n'; + fragmentShaderMain += ' }\n'; + } + } + + // Add base color to fragment shader + if (defined(parameterValues.baseColorTexture)) { + fragmentShaderMain += ' vec3 baseColor = texture2D(u_baseColorTexture, ' + v_texcoord + ').rgb;\n'; + if (defined(parameterValues.baseColorFactor)) { + fragmentShaderMain += ' baseColor *= u_baseColorFactor.rgb;\n'; + } + } else { + if (defined(parameterValues.baseColorFactor)) { + fragmentShaderMain += ' vec3 baseColor = u_baseColorFactor.rgb;\n'; + } else { + fragmentShaderMain += ' vec3 baseColor = vec3(1.0);\n'; + } + } + // Add metallic-roughness to fragment shader + if (defined(parameterValues.metallicRoughnessTexture)) { + fragmentShaderMain += ' vec3 metallicRoughness = texture2D(u_metallicRoughnessTexture, ' + v_texcoord + ').rgb;\n'; + fragmentShaderMain += ' float metalness = clamp(metallicRoughness.b, 0.0, 1.0);\n'; + fragmentShaderMain += ' float roughness = clamp(metallicRoughness.g, 0.04, 1.0);\n'; + if (defined(parameterValues.metallicFactor)) { + fragmentShaderMain += ' metalness *= u_metallicFactor;\n'; + } + if (defined(parameterValues.roughnessFactor)) { + fragmentShaderMain += ' roughness *= u_roughnessFactor;\n'; + } + } else { + if (defined(parameterValues.metallicFactor)) { + fragmentShaderMain += ' float metalness = clamp(u_metallicFactor, 0.0, 1.0);\n'; + } else { + fragmentShaderMain += ' float metalness = 1.0;\n'; + } + if (defined(parameterValues.roughnessFactor)) { + fragmentShaderMain += ' float roughness = clamp(u_roughnessFactor, 0.04, 1.0);\n'; + } else { + fragmentShaderMain += ' float roughness = 1.0;\n'; + } + } + fragmentShaderMain += ' vec3 v = -normalize(v_positionEC);\n'; + + // Generate fragment shader's lighting block + var fragmentLightingBlock = ''; + fragmentLightingBlock += ' vec3 lightColor = vec3(1.0, 1.0, 1.0);\n'; + fragmentLightingBlock += ' vec3 l = normalize(czm_sunDirectionEC);\n'; + fragmentLightingBlock += ' vec3 h = normalize(v + l);\n'; + fragmentLightingBlock += ' vec3 r = normalize(reflect(v, n));\n'; + fragmentLightingBlock += ' float NdotL = clamp(dot(n, l), 0.001, 1.0);\n'; + fragmentLightingBlock += ' float NdotV = abs(dot(n, v)) + 0.001;\n'; + fragmentLightingBlock += ' float NdotH = clamp(dot(n, h), 0.0, 1.0);\n'; + fragmentLightingBlock += ' float LdotH = clamp(dot(l, h), 0.0, 1.0);\n'; + fragmentLightingBlock += ' float VdotH = clamp(dot(v, h), 0.0, 1.0);\n'; + + fragmentLightingBlock += ' vec3 f0 = vec3(0.04);\n'; + fragmentLightingBlock += ' float alpha = roughness * roughness;\n'; + fragmentLightingBlock += ' vec3 diffuseColor = baseColor * (1.0 - metalness);\n'; + fragmentLightingBlock += ' vec3 specularColor = mix(f0, baseColor, metalness);\n'; + fragmentLightingBlock += ' float reflectance = max(max(specularColor.r, specularColor.g), specularColor.b);\n'; + fragmentLightingBlock += ' vec3 r90 = vec3(clamp(reflectance * 25.0, 0.0, 1.0));\n'; + fragmentLightingBlock += ' vec3 r0 = specularColor.rgb;\n'; + + fragmentLightingBlock += ' vec3 F = fresnelSchlick2(r0, r90, VdotH);\n'; + fragmentLightingBlock += ' float G = smithVisibilityGGX(alpha, NdotL, NdotV);\n'; + fragmentLightingBlock += ' float D = GGX(alpha, NdotH);\n'; + + fragmentLightingBlock += ' vec3 diffuseContribution = (1.0 - F) * lambertianDiffuse(baseColor);\n'; + fragmentLightingBlock += ' vec3 specularContribution = F * G * D / (4.0 * NdotL * NdotV);\n'; + fragmentLightingBlock += ' vec3 color = NdotL * lightColor * (diffuseContribution + specularContribution);\n'; + + fragmentLightingBlock += ' vec3 diffuseIrradiance = vec3(0.5);\n'; + fragmentLightingBlock += ' vec3 specularIrradiance = textureCube(czm_cubeMap, r).rgb;\n'; + fragmentLightingBlock += ' specularIrradiance = mix(specularIrradiance, diffuseIrradiance, roughness);\n'; // Fake LOD + fragmentLightingBlock += ' vec2 brdfLUT = texture2D(czm_brdfLUT, vec2(NdotV, 1.0 - roughness)).rg;\n'; + fragmentLightingBlock += ' vec3 IBLColor = (diffuseIrradiance * diffuseColor) + (specularIrradiance * (specularColor * brdfLUT.x + brdfLUT.y));\n'; + fragmentLightingBlock += ' color += IBLColor;\n'; + + if (defined(parameterValues.occlusionTexture)) { + fragmentLightingBlock += ' color *= texture2D(u_occlusionTexture, ' + v_texcoord + ').r;\n'; + } + if (defined(parameterValues.emissiveTexture)) { + fragmentLightingBlock += ' vec3 emissive = texture2D(u_emissiveTexture, ' + v_texcoord + ').rgb;\n'; + if (defined(parameterValues.emissiveFactor)) { + fragmentLightingBlock += ' emissive *= u_emissiveFactor;\n'; + } + fragmentLightingBlock += ' color += emissive;\n'; + } + else { + if (defined(parameterValues.emissiveFactor)) { + fragmentLightingBlock += ' color += u_emissiveFactor;\n'; + } + } + + var finalColorComputation; + finalColorComputation = ' gl_FragColor = vec4(color, 1.0);\n'; + + fragmentShaderMain += fragmentLightingBlock; + fragmentShaderMain += finalColorComputation; + fragmentShaderMain += '}\n'; + + fragmentShader += fragmentShaderMain; + + var techniqueStates; + 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, + extras: { + _pipeline: { + source: vertexShader, + extension: '.glsl' + } + } + }); + + var fragmentShaderId = addToArray(shaders, { + type: WebGLConstants.FRAGMENT_SHADER, + extras: { + _pipeline: { + source: fragmentShader, + extension: '.glsl' + } + } + }); + + // 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 + }); + + return techniqueId; + } + + function getPBRValueType(paramName, paramValue) { + var value; + + // Backwards compatibility for COLLADA2GLTF v1.0-draft + if (defined(paramValue.value)) { + value = paramValue.value; + } else { + value = paramValue; + } + + switch (paramName) { + case 'baseColorFactor': + return WebGLConstants.FLOAT_VEC4; + case 'metallicFactor': + return WebGLConstants.FLOAT; + case 'roughnessFactor': + return WebGLConstants.FLOAT; + case 'baseColorTexture': + return WebGLConstants.SAMPLER_2D; + case 'metallicRoughnessTexture': + return WebGLConstants.SAMPLER_2D; + case 'normalTexture': + return WebGLConstants.SAMPLER_2D; + case 'occlusionTexture': + return WebGLConstants.SAMPLER_2D; + case 'emissiveTexture': + return WebGLConstants.SAMPLER_2D; + case '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) { + 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]; + if (semantic.charAt(0) === '_') { + semantic = semantic.slice(1); + } + var attributeName = 'a_' + semantic; + technique.parameters[semantic] = { + semantic: semantic, + type: accessor.componentType + }; + technique.attributes[attributeName] = semantic; + 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 splitIncompatibleSkins(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 skinningInfo = material.extras._pipeline.skinning; + if (!defined(skinningInfo)) { + material.extras._pipeline.skinning = { + skinned: isSkinned, + componentType: componentType, + type: type + }; + } else if ((skinningInfo.skinned !== isSkinned) || (skinningInfo.type !== type)) { + // This primitive uses the same material as another one that either isn't skinned or uses a different type to store joints and weights + var clonedMaterial = clone(material, true); + clonedMaterial.material.extras._pipeline.skinning = { + skinned: isSkinned, + componentType: componentType, + type: type + }; + // Split this off as a separate material + materialId = addToArray(materials, clonedMaterial); + primitive.material = materialId; + } + }); + }); + } + + /** + * @private + */ + function processPbrMetallicRoughness(gltf, frameState, options) { + options = defaultValue(options, {}); + + if (!defined(gltf)) { + return undefined; + } + + var hasExtension = false; + ForEach.material(gltf, function(material) { + if (material.hasOwnProperty('pbrMetallicRoughness')) { + hasExtension = true; + } + }); + + if (hasExtension) { + if (!defined(gltf.programs)) { + gltf.programs = []; + } + if (!defined(gltf.shaders)) { + gltf.shaders = []; + } + if (!defined(gltf.techniques)) { + gltf.techniques = []; + } + + // Pre-processing to assign skinning info and address incompatibilities + splitIncompatibleSkins(gltf); + + var techniques = {}; + ForEach.material(gltf, function(material) { + if (material.hasOwnProperty('pbrMetallicRoughness')) { + var pbrMetallicRoughness = material.pbrMetallicRoughness; + var technique = generateTechnique(gltf, material, frameState, options.optimizeForCesium); + + material.values = {}; + var values = pbrMetallicRoughness; + for (var valueName in values) { + if (values.hasOwnProperty(valueName)) { + var value = values[valueName]; + material.values[valueName] = value; + } + } + + material.technique = technique; + } + }); + + if (defined(gltf.extensions)) { + delete gltf.extensions.KHR_materials_common; + if (Object.keys(gltf.extensions).length === 0) { + delete gltf.extensions; + } + } + + // If any primitives have semantics that aren't declared in the generated + // shaders, we want to preserve them. + ensureSemanticExistence(gltf); + } + + return gltf; + } + + return processPbrMetallicRoughness; +}); From 40a76009459c143cc31bc8587233e04631cbd7e3 Mon Sep 17 00:00:00 2001 From: Mohamad Moneimne Date: Thu, 13 Jul 2017 15:25:00 -0400 Subject: [PATCH 14/35] Updated processPbrMetallicRoughness per PR comments and fixed bug that removes textures from gltf --- lib/Pipeline.js | 2 + lib/RemoveUnusedProperties.js | 2 +- lib/isTexture.js | 9 +- lib/processModelMaterialsCommon.js | 181 ++-- lib/processPbrMetallicRoughness.js | 1374 ++++++++++++++-------------- 5 files changed, 775 insertions(+), 793 deletions(-) diff --git a/lib/Pipeline.js b/lib/Pipeline.js index a9229424..c3c1be45 100644 --- a/lib/Pipeline.js +++ b/lib/Pipeline.js @@ -24,6 +24,7 @@ var mergeDuplicateVertices = require('./mergeDuplicateVertices'); var octEncodeNormals = require('./octEncodeNormals'); var optimizeForVertexCache = require('./optimizeForVertexCache'); var processModelMaterialsCommon = require('./processModelMaterialsCommon'); +var processPbrMetallicRoughness = require('./processPbrMetallicRoughness'); var readGltf = require('./readGltf'); var removeDuplicatePrimitives = require('./removeDuplicatePrimitives'); var removeNormals = require('./removeNormals'); @@ -93,6 +94,7 @@ Pipeline.processJSONWithExtras = function(gltfWithExtras, options) { addPipelineExtras(gltfWithExtras); addDefaults(gltfWithExtras, options); processModelMaterialsCommon(gltfWithExtras, options); + processPbrMetallicRoughness(gltfWithExtras, options); // Print statistics for unoptimized input if (options.stats) { diff --git a/lib/RemoveUnusedProperties.js b/lib/RemoveUnusedProperties.js index 3d039c7a..b03932f6 100644 --- a/lib/RemoveUnusedProperties.js +++ b/lib/RemoveUnusedProperties.js @@ -258,7 +258,7 @@ RemoveUnusedProperties.removeTextures = function(gltf) { ForEach.material(gltf, function(material) { ForEach.materialValue(material, function(value, name) { if (isTexture(name, value)) { - usedTextureIds[value[0]] = true; + usedTextureIds[value.index] = true; } }); }); diff --git a/lib/isTexture.js b/lib/isTexture.js index 064e4a08..e60ca002 100644 --- a/lib/isTexture.js +++ b/lib/isTexture.js @@ -5,13 +5,6 @@ var defined = Cesium.defined; module.exports = isTexture; -var textureNames = { - ambient: true, - diffuse: true, - emission: true, - specular: true -}; - function isTexture(name, value) { - return value.length === 1 && defined(textureNames[name]); + return defined(value.index); } \ No newline at end of file diff --git a/lib/processModelMaterialsCommon.js b/lib/processModelMaterialsCommon.js index ea562a55..59b6ef6c 100644 --- a/lib/processModelMaterialsCommon.js +++ b/lib/processModelMaterialsCommon.js @@ -12,6 +12,96 @@ var WebGLConstants = Cesium.WebGLConstants; module.exports = processModelMaterialsCommon; +/** + * @private + */ +function processModelMaterialsCommon(gltf, options) { + options = defaultValue(options, {}); + + if (!defined(gltf)) { + return undefined; + } + + 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) { + 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 assign skinning info and address incompatibilities + splitIncompatibleSkins(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.optimizeForCesium); + techniques[techniqueKey] = technique; + } + + // 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; + } + } + + material.technique = technique; + + delete material.extensions.KHR_materials_common; + if (Object.keys(material.extensions).length === 0) { + delete material.extensions; + } + } + }); + + if (defined(gltf.extensions)) { + delete gltf.extensions.KHR_materials_common; + if (Object.keys(gltf.extensions).length === 0) { + delete gltf.extensions; + } + } + + // If any primitives have semantics that aren't declared in the generated + // shaders, we want to preserve them. + ensureSemanticExistence(gltf); + } + + return gltf; +} + function webGLConstantToGlslType(webGLValue) { switch (webGLValue) { case WebGLConstants.FLOAT: @@ -864,94 +954,3 @@ function splitIncompatibleSkins(gltf) { }); }); } - - -/** - * @private - */ -function processModelMaterialsCommon(gltf, options) { - options = defaultValue(options, {}); - - if (!defined(gltf)) { - return undefined; - } - - 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) { - 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 assign skinning info and address incompatibilities - splitIncompatibleSkins(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.optimizeForCesium); - techniques[techniqueKey] = technique; - } - - // 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; - } - } - - material.technique = technique; - - delete material.extensions.KHR_materials_common; - if (Object.keys(material.extensions).length === 0) { - delete material.extensions; - } - } - }); - - if (defined(gltf.extensions)) { - delete gltf.extensions.KHR_materials_common; - if (Object.keys(gltf.extensions).length === 0) { - delete gltf.extensions; - } - } - - // If any primitives have semantics that aren't declared in the generated - // shaders, we want to preserve them. - ensureSemanticExistence(gltf); - } - - return gltf; -} diff --git a/lib/processPbrMetallicRoughness.js b/lib/processPbrMetallicRoughness.js index 2d40540c..b7860ff6 100644 --- a/lib/processPbrMetallicRoughness.js +++ b/lib/processPbrMetallicRoughness.js @@ -1,774 +1,762 @@ -/*global define*/ -define([ - './addToArray', - './ForEach', - './numberOfComponentsForType', - './techniqueParameterForSemantic', - '../../Core/clone', - '../../Core/defined', - '../../Core/defaultValue', - '../../Core/WebGLConstants' -], function( - addToArray, - ForEach, - numberOfComponentsForType, - techniqueParameterForSemantic, - clone, - defined, - defaultValue, - WebGLConstants) { - 'use strict'; - - function webGLConstantToGlslType(webGLValue) { - switch (webGLValue) { - case WebGLConstants.FLOAT: - return 'float'; - case WebGLConstants.FLOAT_VEC2: - return 'vec2'; - case WebGLConstants.FLOAT_VEC3: - return 'vec3'; - case WebGLConstants.FLOAT_VEC4: - return 'vec4'; - case WebGLConstants.FLOAT_MAT2: - return 'mat2'; - case WebGLConstants.FLOAT_MAT3: - return 'mat3'; - case WebGLConstants.FLOAT_MAT4: - return 'mat4'; - case WebGLConstants.SAMPLER_2D: - return 'sampler2D'; - case WebGLConstants.BOOL: - return 'bool'; - } - } +'use strict'; +var Cesium = require('cesium'); +var addToArray = require('./addToArray'); +var ForEach = require('./ForEach'); +var numberOfComponentsForType = require('./numberOfComponentsForType'); +var techniqueParameterForSemantic = require('./techniqueParameterForSemantic'); - 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; - } - } +var clone = Cesium.clone; +var defined = Cesium.defined; +var defaultValue = Cesium.defaultValue; +var WebGLConstants = Cesium.WebGLConstants; - function generateTechnique(gltf, material, frameState, optimizeForCesium) { - var techniques = gltf.techniques; - var shaders = gltf.shaders; - var programs = gltf.programs; +module.exports = processPbrMetallicRoughness; - var parameterValues = material.pbrMetallicRoughness; - for (var additional in material) { - if (material.hasOwnProperty(additional) && ((additional.indexOf('Texture') >= 0) || additional.indexOf('Factor') >= 0) || additional === 'doubleSided') { - parameterValues[additional] = material[additional]; - } - } +/** + * @private + */ +function processPbrMetallicRoughness(gltf, options) { + options = defaultValue(options, {}); - var vertexShader = 'precision highp float;\n'; - var fragmentShader = 'precision highp float;\n'; + var hasPbrMetallicRoughness = false; + ForEach.material(gltf, function(material) { + if (material.hasOwnProperty('pbrMetallicRoughness')) { + hasPbrMetallicRoughness = true; + } + }); - var skin = gltf.skins[0]; - var joints = (defined(skin)) ? skin.joints : []; - var jointCount = joints.length; - var hasSkinning = jointCount > 0; - var skinningInfo = {}; - if (hasSkinning) { - skinningInfo = material.extras._pipeline.skinning; + if (hasPbrMetallicRoughness) { + if (!defined(gltf.programs)) { + gltf.programs = []; + } + if (!defined(gltf.shaders)) { + gltf.shaders = []; } + if (!defined(gltf.techniques)) { + gltf.techniques = []; + } + + // Pre-processing to assign skinning info and address incompatibilities + splitIncompatibleSkins(gltf); - var hasNormals = true; - var hasTangents = false; - var hasMorphTargets = false; - var morphTargets; - for (var entry in gltf.meshes) { - if (defined(entry)) { - var mesh = gltf.meshes[entry]; - var primitives = mesh.primitives; - for (var primitive in primitives) { - if (defined(primitive)) { - var targets = primitives[primitive].targets; - if (!hasMorphTargets && defined(targets)) { - hasMorphTargets = true; - morphTargets = targets; - } - var attributes = primitives[primitive].attributes; - for (var attribute in attributes) { - if (attribute.indexOf('TANGENT') >= 0) { - hasTangents = true; - } - } + if (!defined(gltf.techniques)) { + gltf.techniques = []; + } + var materials = []; + ForEach.material(gltf, function(material) { + if (material.hasOwnProperty('pbrMetallicRoughness')) { + var pbrMetallicRoughness = material.pbrMetallicRoughness; + var technique = generateTechnique(gltf, material, options.optimizeForCesium); + + var values = {}; + var values = pbrMetallicRoughness; + for (var valueName in values) { + if (values.hasOwnProperty(valueName)) { + var value = values[valueName]; + values[valueName] = value; } } + + var newMaterial = {values : values}; + newMaterial.technique = technique; + materials.push(newMaterial); } + }); + gltf.materials = materials; + + // If any primitives have semantics that aren't declared in the generated + // shaders, we want to preserve them. + ensureSemanticExistence(gltf); + } + + return gltf; +} + +function webGLConstantToGlslType(webGLValue) { + switch (webGLValue) { + case WebGLConstants.FLOAT: + return 'float'; + case WebGLConstants.FLOAT_VEC2: + return 'vec2'; + case WebGLConstants.FLOAT_VEC3: + return 'vec3'; + case WebGLConstants.FLOAT_VEC4: + return 'vec4'; + case WebGLConstants.FLOAT_MAT2: + return 'mat2'; + case WebGLConstants.FLOAT_MAT3: + return 'mat3'; + case WebGLConstants.FLOAT_MAT4: + return 'mat4'; + case WebGLConstants.SAMPLER_2D: + return 'sampler2D'; + case WebGLConstants.BOOL: + return 'bool'; + } +} + +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; + } +} + +function generateTechnique(gltf, material, optimizeForCesium) { + var techniques = gltf.techniques; + var shaders = gltf.shaders; + var programs = gltf.programs; + + var parameterValues = material.pbrMetallicRoughness; + for (var additional in material) { + if (material.hasOwnProperty(additional) && ((additional.indexOf('Texture') >= 0) || additional.indexOf('Factor') >= 0) || additional === 'doubleSided') { + parameterValues[additional] = material[additional]; } + } + + var vertexShader = 'precision highp float;\n'; + var fragmentShader = 'precision highp float;\n'; + + var skin; + if (defined(gltf.skins)) { + skin = gltf.skins[0]; + } + var joints = (defined(skin)) ? skin.joints : []; + var jointCount = joints.length; + var hasSkinning = jointCount > 0; + var skinningInfo = {}; + if (hasSkinning) { + skinningInfo = material.extras._pipeline.skinning; + } - // Add techniques - var techniqueParameters = { - // Add matrices - modelViewMatrix: { - semantic: 'MODELVIEW', - type: WebGLConstants.FLOAT_MAT4 - }, - projectionMatrix: { - semantic: 'PROJECTION', - type: WebGLConstants.FLOAT_MAT4 + var hasNormals = true; + var hasTangents = false; + var hasMorphTargets = false; + var morphTargets; + ForEach.mesh(gltf, function(mesh) { + ForEach.meshPrimitive(mesh, function(primitive) { + var targets = primitive.targets; + if (!hasMorphTargets && defined(targets)) { + hasMorphTargets = true; + morphTargets = targets; + } + var attributes = primitive.attributes; + for (var attribute in attributes) { + if (attribute.indexOf('TANGENT') >= 0) { + hasTangents = true; + } } + }); + }); + + // Add techniques + var techniqueParameters = { + // Add matrices + modelViewMatrix : { + semantic : 'MODELVIEW', + type : WebGLConstants.FLOAT_MAT4 + }, + projectionMatrix : { + semantic : 'PROJECTION', + type : WebGLConstants.FLOAT_MAT4 + } + }; + + if (hasNormals) { + techniqueParameters.normalMatrix = { + semantic : 'MODELVIEWINVERSETRANSPOSE', + type : WebGLConstants.FLOAT_MAT3 }; + } - if (hasNormals) { - techniqueParameters.normalMatrix = { - semantic: 'MODELVIEWINVERSETRANSPOSE', - type: WebGLConstants.FLOAT_MAT3 - }; - } + if (hasSkinning) { + techniqueParameters.jointMatrix = { + count : jointCount, + semantic : 'JOINTMATRIX', + type : WebGLConstants.FLOAT_MAT4 + }; + } - if (hasSkinning) { - techniqueParameters.jointMatrix = { - count: jointCount, - semantic: 'JOINTMATRIX', - type: WebGLConstants.FLOAT_MAT4 - }; - } + if (hasMorphTargets) { + techniqueParameters.morphWeights = { + count : morphTargets.length, + semantic : 'MORPHWEIGHTS', + type : WebGLConstants.FLOAT + }; + } - if (hasMorphTargets) { - techniqueParameters.morphWeights = { - count: morphTargets.length, - semantic: 'MORPHWEIGHTS', - type: WebGLConstants.FLOAT + // Add material parameters + var hasTexCoords = false; + for (var name in parameterValues) { + //generate shader parameters + if (parameterValues.hasOwnProperty(name)) { + var valType = getPBRValueType(name, parameterValues[name]); + if (!hasTexCoords && (valType === WebGLConstants.SAMPLER_2D)) { + hasTexCoords = true; + } + techniqueParameters[name] = { + type : valType }; } + } - // Add material parameters - var hasTexCoords = false; - for (var name in parameterValues) { - //generate shader parameters - if (parameterValues.hasOwnProperty(name)) { - var valType = getPBRValueType(name, parameterValues[name]); - if (!hasTexCoords && (valType === WebGLConstants.SAMPLER_2D)) { - hasTexCoords = true; - } - techniqueParameters[name] = { - type: valType - }; + // 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; + } else { + vertexShader += 'uniform ' + webGLConstantToGlslType(param.type) + ' u_' + paramName + arraySize + ';\n'; } } + } - // 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 attributes with semantics + var vertexShaderMain = ''; + if (hasSkinning) { + var i, j; + var numberOfComponents = numberOfComponentsForType(skinningInfo.type); + var matrix = false; + if (skinningInfo.type.indexOf('MAT') === 0) { + matrix = true; + numberOfComponents = Math.sqrt(numberOfComponents); + } + if (!matrix) { + for (i = 0; i < numberOfComponents; i++) { + if (i === 0) { + vertexShaderMain += ' mat4 skinMatrix = '; } else { - vertexShader += 'uniform ' + webGLConstantToGlslType(param.type) + ' u_' + paramName + arraySize + ';\n'; + vertexShaderMain += ' skinMatrix += '; } + vertexShaderMain += 'a_weight[' + i + '] * u_jointMatrix[int(a_joint[' + i + '])];\n'; } - } - - // Add attributes with semantics - var vertexShaderMain = ''; - if (hasSkinning) { - var i, j; - var numberOfComponents = numberOfComponentsForType(skinningInfo.type); - var matrix = false; - if (skinningInfo.type.indexOf('MAT') === 0) { - matrix = true; - numberOfComponents = Math.sqrt(numberOfComponents); - } - if (!matrix) { - for (i = 0; i < numberOfComponents; i++) { - if (i === 0) { - vertexShaderMain += ' mat4 skinMat = '; + } else { + for (i = 0; i < numberOfComponents; i++) { + for (j = 0; j < numberOfComponents; j++) { + if (i === 0 && j === 0) { + vertexShaderMain += ' mat4 skinMatrix = '; } else { - vertexShaderMain += ' skinMat += '; - } - vertexShaderMain += 'a_weight[' + i + '] * u_jointMatrix[int(a_joint[' + i + '])];\n'; - } - } else { - for (i = 0; i < numberOfComponents; i++) { - for (j = 0; j < numberOfComponents; j++) { - if (i === 0 && j === 0) { - vertexShaderMain += ' mat4 skinMat = '; - } else { - vertexShaderMain += ' skinMat += '; - } - vertexShaderMain += 'a_weight[' + i + '][' + j + '] * u_jointMatrix[int(a_joint[' + i + '][' + j + '])];\n'; + vertexShaderMain += ' skinMatrix += '; } + vertexShaderMain += 'a_weight[' + i + '][' + j + '] * u_jointMatrix[int(a_joint[' + i + '][' + j + '])];\n'; } } } + } - // Add position always - var techniqueAttributes = { - a_position: 'position' - }; - techniqueParameters.position = { - semantic: 'POSITION', - type: WebGLConstants.FLOAT_VEC3 - }; - vertexShader += 'attribute vec3 a_position;\n'; - vertexShader += 'varying vec3 v_positionEC;\n'; - - // Morph Target Weighting - vertexShaderMain += ' vec3 weightedPos = a_position;\n'; - if (hasNormals) { - vertexShaderMain += ' vec3 weightedNormal = a_normal;\n'; - } - if (hasTangents) { - vertexShaderMain += ' vec3 weightedTangent = a_tangent;\n'; - } - if (hasMorphTargets) { - for (var target in morphTargets) { - var targetAttributes = morphTargets[target]; - for (var targetAttribute in targetAttributes) { - if (targetAttribute !== 'extras') { - var attributeLower = targetAttribute.toLowerCase() + '_' + target; - techniqueAttributes['a_' + attributeLower] = attributeLower; - techniqueParameters[attributeLower] = { - semantic : targetAttribute + '_' + target, - type : WebGLConstants.FLOAT_VEC3 - } - vertexShader += 'attribute vec3 a_' + attributeLower + ';\n'; - if (targetAttribute === 'POSITION') { - vertexShaderMain += ' weightedPos += u_morphWeights[' + target + '] * a_' + attributeLower + ';\n'; - } else if (targetAttribute === 'NORMAL') { - vertexShaderMain += ' weightedNormal += u_morphWeights[' + target + '] * a_' + attributeLower + ';\n'; - } else if (targetAttribute === 'TANGENT') { - vertexShaderMain += ' weightedTangent += u_morphWeights[' + target + '] * a_' + attributeLower + ';\n'; - } else { - // Invalid attribute - } + // Add position always + var techniqueAttributes = { + a_position : 'position' + }; + techniqueParameters.position = { + semantic : 'POSITION', + type : WebGLConstants.FLOAT_VEC3 + }; + vertexShader += 'attribute vec3 a_position;\n'; + vertexShader += 'varying vec3 v_positionEC;\n'; + + // Morph Target Weighting + vertexShaderMain += ' vec3 weightedPosition = a_position;\n'; + if (hasNormals) { + vertexShaderMain += ' vec3 weightedNormal = a_normal;\n'; + } + if (hasTangents) { + vertexShaderMain += ' vec3 weightedTangent = a_tangent;\n'; + } + if (hasMorphTargets) { + for (var i = 0; i < morphTargets.length; i++) { + var targetAttributes = morphTargets[i]; + for (var targetAttribute in targetAttributes) { + if (targetAttributes.hasOwnProperty(targetAttribute) && targetAttribute !== 'extras') { + var attributeLower = targetAttribute.toLowerCase() + '_' + i; + techniqueAttributes['a_' + attributeLower] = attributeLower; + techniqueParameters[attributeLower] = { + semantic : targetAttribute + '_' + i, + type : WebGLConstants.FLOAT_VEC3 + } + vertexShader += 'attribute vec3 a_' + attributeLower + ';\n'; + if (targetAttribute === 'POSITION') { + vertexShaderMain += ' weightedPosition += u_morphWeights[' + i + '] * a_' + attributeLower + ';\n'; + } else if (targetAttribute === 'NORMAL') { + vertexShaderMain += ' weightedNormal += u_morphWeights[' + i + '] * a_' + attributeLower + ';\n'; + } else if (targetAttribute === 'TANGENT') { + vertexShaderMain += ' weightedTangent += u_morphWeights[' + i + '] * a_' + attributeLower + ';\n'; } } } } + } - // Final position computation + // Final position computation + if (hasSkinning) { + vertexShaderMain += ' vec4 position = u_modelViewMatrix * skinMatrix * vec4(weightedPosition, 1.0);\n'; + } else { + vertexShaderMain += ' vec4 position = u_modelViewMatrix * vec4(weightedPosition, 1.0);\n'; + } + vertexShaderMain += ' v_positionEC = position.xyz;\n'; + vertexShaderMain += ' gl_Position = u_projectionMatrix * position;\n'; + fragmentShader += 'varying vec3 v_positionEC;\n'; + + // Final normal computation + if (hasNormals) { + techniqueAttributes.a_normal = 'normal'; + techniqueParameters.normal = { + semantic : 'NORMAL', + type : WebGLConstants.FLOAT_VEC3 + }; + vertexShader += 'attribute vec3 a_normal;\n'; + vertexShader += 'varying vec3 v_normal;\n'; if (hasSkinning) { - vertexShaderMain += ' vec4 pos = u_modelViewMatrix * skinMat * vec4(weightedPos,1.0);\n'; + vertexShaderMain += ' v_normal = u_normalMatrix * mat3(skinMatrix) * weightedNormal;\n'; } else { - vertexShaderMain += ' vec4 pos = u_modelViewMatrix * vec4(weightedPos,1.0);\n'; + vertexShaderMain += ' v_normal = u_normalMatrix * weightedNormal;\n'; } - vertexShaderMain += ' v_positionEC = pos.xyz;\n'; - vertexShaderMain += ' gl_Position = u_projectionMatrix * pos;\n'; - fragmentShader += 'varying vec3 v_positionEC;\n'; - - // Final normal computation - if (hasNormals) { - techniqueAttributes.a_normal = 'normal'; - techniqueParameters.normal = { - semantic: 'NORMAL', - type: WebGLConstants.FLOAT_VEC3 - }; - vertexShader += 'attribute vec3 a_normal;\n'; - vertexShader += 'varying vec3 v_normal;\n'; - if (hasSkinning) { - vertexShaderMain += ' v_normal = u_normalMatrix * mat3(skinMat) * weightedNormal;\n'; - } else { - vertexShaderMain += ' v_normal = u_normalMatrix * weightedNormal;\n'; - } - fragmentShader += 'varying vec3 v_normal;\n'; - } - - // Read tangents if available - if (hasTangents) { - techniqueAttributes.a_tangent = 'tangent'; - techniqueParameters.tangent = { - semantic: 'TANGENT', - type: WebGLConstants.FLOAT_VEC3 - }; - vertexShader += 'attribute vec3 a_tangent;\n'; - vertexShader += 'varying vec3 v_tangent;\n'; - vertexShaderMain += ' v_tangent = (u_modelViewMatrix * vec4(weightedTangent, 1.0)).xyz;\n'; + fragmentShader += 'varying vec3 v_normal;\n'; + } - fragmentShader += 'varying vec3 v_tangent;\n'; - } + // Read tangents if available + if (hasTangents) { + techniqueAttributes.a_tangent = 'tangent'; + techniqueParameters.tangent = { + semantic : 'TANGENT', + type : WebGLConstants.FLOAT_VEC3 + }; + vertexShader += 'attribute vec3 a_tangent;\n'; + vertexShader += 'varying vec3 v_tangent;\n'; + vertexShaderMain += ' v_tangent = (u_modelViewMatrix * vec4(weightedTangent, 1.0)).xyz;\n'; - // 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 - }; + fragmentShader += 'varying vec3 v_tangent;\n'; + } - v_texcoord = 'v_texcoord_0'; - vertexShader += 'attribute vec2 a_texcoord_0;\n'; - vertexShader += 'varying vec2 ' + v_texcoord + ';\n'; - vertexShaderMain += ' ' + v_texcoord + ' = a_texcoord_0;\n'; + // 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 + }; - fragmentShader += 'varying vec2 ' + v_texcoord + ';\n'; - } + v_texcoord = 'v_texcoord_0'; + vertexShader += 'attribute vec2 a_texcoord_0;\n'; + vertexShader += 'varying vec2 ' + v_texcoord + ';\n'; + vertexShaderMain += ' ' + v_texcoord + ' = a_texcoord_0;\n'; - // Add skinning information if available - if (hasSkinning) { - techniqueAttributes.a_joint = 'joint'; - var attributeType = getShaderVariable(skinningInfo.type); - var webGLConstant = glslTypeToWebGLConstant(attributeType); + fragmentShader += 'varying vec2 ' + v_texcoord + ';\n'; + } - techniqueParameters.joint = { - semantic: 'JOINTS_0', - type: webGLConstant - }; - techniqueAttributes.a_weight = 'weight'; - techniqueParameters.weight = { - semantic: 'WEIGHTS_0', - type: webGLConstant - }; + // Add skinning information if available + if (hasSkinning) { + techniqueAttributes.a_joint = 'joint'; + var attributeType = getShaderVariable(skinningInfo.type); + var webGLConstant = glslTypeToWebGLConstant(attributeType); - vertexShader += 'attribute ' + attributeType + ' a_joint;\n'; - vertexShader += 'attribute ' + attributeType + ' a_weight;\n'; - } + techniqueParameters.joint = { + semantic : 'JOINTS_0', + type : webGLConstant + }; + techniqueAttributes.a_weight = 'weight'; + techniqueParameters.weight = { + semantic : 'WEIGHTS_0', + type : webGLConstant + }; - vertexShader += 'void main(void) {\n'; - vertexShader += vertexShaderMain; - vertexShader += '}\n'; - - // Fragment shader lighting - fragmentShader += 'const float M_PI = 3.141592653589793;\n'; - - var lambertianDiffuse = ''; - lambertianDiffuse += 'vec3 lambertianDiffuse(vec3 baseColor) {\n'; - lambertianDiffuse += ' return baseColor / M_PI;\n'; - lambertianDiffuse += '}\n\n'; - - var fresnelSchlick2 = ''; - fresnelSchlick2 += 'vec3 fresnelSchlick2(vec3 f0, vec3 f90, float VdotH) {\n'; - fresnelSchlick2 += ' return f0 + (f90 - f0) * pow(clamp(1.0 - VdotH, 0.0, 1.0), 5.0);\n'; - fresnelSchlick2 += '}\n\n'; - - var fresnelSchlick = ''; - fresnelSchlick += 'vec3 fresnelSchlick(float metalness, float VdotH) {\n'; - fresnelSchlick += ' return metalness + (vec3(1.0) - metalness) * pow(1.0 - VdotH, 5.0);\n'; - fresnelSchlick += '}\n\n'; - - var smithVisibilityG1 = ''; - smithVisibilityG1 += 'float smithVisibilityG1(float NdotV, float roughness) {\n'; - smithVisibilityG1 += ' float k = (roughness + 1.0) * (roughness + 1.0) / 8.0;\n'; - smithVisibilityG1 += ' return NdotV / (NdotV * (1.0 - k) + k);\n'; - smithVisibilityG1 += '}\n\n'; - - var smithVisibilityGGX = ''; - smithVisibilityGGX += 'float smithVisibilityGGX(float roughness, float NdotL, float NdotV) {\n'; - smithVisibilityGGX += ' return smithVisibilityG1(NdotL, roughness) * smithVisibilityG1(NdotV, roughness);\n'; - smithVisibilityGGX += '}\n\n'; - - var GGX = ''; - GGX += 'float GGX(float roughness, float NdotH) {\n'; - GGX += ' float roughnessSquared = roughness * roughness;\n'; - GGX += ' float f = (NdotH * roughnessSquared - NdotH) * NdotH + 1.0;\n'; - GGX += ' return roughnessSquared / (M_PI * f * f);\n'; - GGX += '}\n\n'; - - fragmentShader += lambertianDiffuse + fresnelSchlick2 + fresnelSchlick + smithVisibilityG1 + smithVisibilityGGX + GGX; - - var fragmentShaderMain = ''; - fragmentShaderMain += 'void main(void) {\n'; - - // Add normal mapping to fragment shader - if (hasNormals) { - fragmentShaderMain += ' vec3 ng = normalize(v_normal);\n'; - if (defined(parameterValues.normalTexture) && (hasTangents || frameState.context._standardDerivatives)) { - if (hasTangents) { - // Read tangents from varying - fragmentShaderMain += ' vec3 t = normalize(v_tangent);\n'; - } else { - // Compute tangents - fragmentShader = '#extension GL_OES_standard_derivatives : enable\n' + fragmentShader; - fragmentShaderMain += ' vec3 pos_dx = dFdx(v_positionEC);\n'; - fragmentShaderMain += ' vec3 pos_dy = dFdy(v_positionEC);\n'; - fragmentShaderMain += ' vec3 tex_dx = dFdx(vec3(' + v_texcoord + ',0.0));\n'; - fragmentShaderMain += ' vec3 tex_dy = dFdy(vec3(' + v_texcoord + ',0.0));\n'; - fragmentShaderMain += ' vec3 t = (tex_dy.t * pos_dx - tex_dx.t * pos_dy) / (tex_dx.s * tex_dy.t - tex_dy.s * tex_dx.t);\n'; - fragmentShaderMain += ' t = normalize(t - ng * dot(ng, t));\n'; - } - fragmentShaderMain += ' vec3 b = normalize(cross(ng, t));\n'; - fragmentShaderMain += ' mat3 tbn = mat3(t, b, ng);\n'; - fragmentShaderMain += ' vec3 n = texture2D(u_normalTexture, ' + v_texcoord + ').rgb;\n'; - fragmentShaderMain += ' n = normalize(tbn * (2.0 * n - 1.0));\n'; - } else { - fragmentShaderMain += ' vec3 n = ng;\n'; - } - if (parameterValues.doubleSided) { - fragmentShaderMain += ' if (!gl_FrontFacing)\n'; - fragmentShaderMain += ' {\n'; - fragmentShaderMain += ' n = -n;\n'; - fragmentShaderMain += ' }\n'; - } - } + vertexShader += 'attribute ' + attributeType + ' a_joint;\n'; + vertexShader += 'attribute ' + attributeType + ' a_weight;\n'; + } - // Add base color to fragment shader - if (defined(parameterValues.baseColorTexture)) { - fragmentShaderMain += ' vec3 baseColor = texture2D(u_baseColorTexture, ' + v_texcoord + ').rgb;\n'; - if (defined(parameterValues.baseColorFactor)) { - fragmentShaderMain += ' baseColor *= u_baseColorFactor.rgb;\n'; - } - } else { - if (defined(parameterValues.baseColorFactor)) { - fragmentShaderMain += ' vec3 baseColor = u_baseColorFactor.rgb;\n'; + vertexShader += 'void main(void) \n{\n'; + vertexShader += vertexShaderMain; + vertexShader += '}\n'; + + // Fragment shader lighting + fragmentShader += 'const float M_PI = 3.141592653589793;\n'; + + var lambertianDiffuse = 'vec3 lambertianDiffuse(vec3 baseColor) \n' + + '{\n' + + ' return baseColor / M_PI;\n' + + '}\n\n'; + + var fresnelSchlick2 = 'vec3 fresnelSchlick2(vec3 f0, vec3 f90, float VdotH) \n' + + '{\n' + + ' return f0 + (f90 - f0) * pow(clamp(1.0 - VdotH, 0.0, 1.0), 5.0);\n' + + '}\n\n'; + + var fresnelSchlick = 'vec3 fresnelSchlick(float metalness, float VdotH) \n' + + '{\n' + + ' return metalness + (vec3(1.0) - metalness) * pow(1.0 - VdotH, 5.0);\n' + + '}\n\n'; + + var smithVisibilityG1 = 'float smithVisibilityG1(float NdotV, float roughness) \n' + + '{\n' + + ' float k = (roughness + 1.0) * (roughness + 1.0) / 8.0;\n' + + ' return NdotV / (NdotV * (1.0 - k) + k);\n' + + '}\n\n'; + + var smithVisibilityGGX = 'float smithVisibilityGGX(float roughness, float NdotL, float NdotV) \n' + + '{\n' + + ' return smithVisibilityG1(NdotL, roughness) * smithVisibilityG1(NdotV, roughness);\n' + + '}\n\n'; + + var GGX = 'float GGX(float roughness, float NdotH) \n' + + '{\n' + + ' float roughnessSquared = roughness * roughness;\n' + + ' float f = (NdotH * roughnessSquared - NdotH) * NdotH + 1.0;\n' + + ' return roughnessSquared / (M_PI * f * f);\n' + + '}\n\n'; + + fragmentShader += lambertianDiffuse + fresnelSchlick2 + fresnelSchlick + smithVisibilityG1 + smithVisibilityGGX + GGX; + + fragmentShader += 'void main(void) \n{\n'; + + // Add normal mapping to fragment shader + if (hasNormals) { + fragmentShader += ' vec3 ng = normalize(v_normal);\n'; + if (defined(parameterValues.normalTexture)) { + if (hasTangents) { + // Read tangents from varying + fragmentShader += ' vec3 t = normalize(v_tangent);\n'; + fragmentShader += ' vec3 b = normalize(cross(ng, t));\n'; + fragmentShader += ' mat3 tbn = mat3(t, b, ng);\n'; + fragmentShader += ' vec3 n = texture2D(u_normalTexture, ' + v_texcoord + ').rgb;\n'; + fragmentShader += ' n = normalize(tbn * (2.0 * n - 1.0));\n'; } else { - fragmentShaderMain += ' vec3 baseColor = vec3(1.0);\n'; - } - } - // Add metallic-roughness to fragment shader - if (defined(parameterValues.metallicRoughnessTexture)) { - fragmentShaderMain += ' vec3 metallicRoughness = texture2D(u_metallicRoughnessTexture, ' + v_texcoord + ').rgb;\n'; - fragmentShaderMain += ' float metalness = clamp(metallicRoughness.b, 0.0, 1.0);\n'; - fragmentShaderMain += ' float roughness = clamp(metallicRoughness.g, 0.04, 1.0);\n'; - if (defined(parameterValues.metallicFactor)) { - fragmentShaderMain += ' metalness *= u_metallicFactor;\n'; - } - if (defined(parameterValues.roughnessFactor)) { - fragmentShaderMain += ' roughness *= u_roughnessFactor;\n'; + // Add standard derivatives extension + fragmentShader = '#ifdef GL_OES_standard_derivatives\n#extension GL_OES_standard_derivatives : enable\n#endif\n' + fragmentShader; + // Compute tangents + fragmentShader += '#ifdef GL_OES_standard_derivatives\n'; + fragmentShader += ' vec3 pos_dx = dFdx(v_positionEC);\n'; + fragmentShader += ' vec3 pos_dy = dFdy(v_positionEC);\n'; + fragmentShader += ' vec3 tex_dx = dFdx(vec3(' + v_texcoord + ',0.0));\n'; + fragmentShader += ' vec3 tex_dy = dFdy(vec3(' + v_texcoord + ',0.0));\n'; + fragmentShader += ' vec3 t = (tex_dy.t * pos_dx - tex_dx.t * pos_dy) / (tex_dx.s * tex_dy.t - tex_dy.s * tex_dx.t);\n'; + fragmentShader += ' t = normalize(t - ng * dot(ng, t));\n'; + fragmentShader += ' vec3 b = normalize(cross(ng, t));\n'; + fragmentShader += ' mat3 tbn = mat3(t, b, ng);\n'; + fragmentShader += ' vec3 n = texture2D(u_normalTexture, ' + v_texcoord + ').rgb;\n'; + fragmentShader += ' n = normalize(tbn * (2.0 * n - 1.0));\n'; + fragmentShader += '#else\n'; + fragmentShader += ' vec3 n = ng;\n'; + fragmentShader += '#endif\n'; } } else { - if (defined(parameterValues.metallicFactor)) { - fragmentShaderMain += ' float metalness = clamp(u_metallicFactor, 0.0, 1.0);\n'; - } else { - fragmentShaderMain += ' float metalness = 1.0;\n'; - } - if (defined(parameterValues.roughnessFactor)) { - fragmentShaderMain += ' float roughness = clamp(u_roughnessFactor, 0.04, 1.0);\n'; - } else { - fragmentShaderMain += ' float roughness = 1.0;\n'; - } - } - fragmentShaderMain += ' vec3 v = -normalize(v_positionEC);\n'; - - // Generate fragment shader's lighting block - var fragmentLightingBlock = ''; - fragmentLightingBlock += ' vec3 lightColor = vec3(1.0, 1.0, 1.0);\n'; - fragmentLightingBlock += ' vec3 l = normalize(czm_sunDirectionEC);\n'; - fragmentLightingBlock += ' vec3 h = normalize(v + l);\n'; - fragmentLightingBlock += ' vec3 r = normalize(reflect(v, n));\n'; - fragmentLightingBlock += ' float NdotL = clamp(dot(n, l), 0.001, 1.0);\n'; - fragmentLightingBlock += ' float NdotV = abs(dot(n, v)) + 0.001;\n'; - fragmentLightingBlock += ' float NdotH = clamp(dot(n, h), 0.0, 1.0);\n'; - fragmentLightingBlock += ' float LdotH = clamp(dot(l, h), 0.0, 1.0);\n'; - fragmentLightingBlock += ' float VdotH = clamp(dot(v, h), 0.0, 1.0);\n'; - - fragmentLightingBlock += ' vec3 f0 = vec3(0.04);\n'; - fragmentLightingBlock += ' float alpha = roughness * roughness;\n'; - fragmentLightingBlock += ' vec3 diffuseColor = baseColor * (1.0 - metalness);\n'; - fragmentLightingBlock += ' vec3 specularColor = mix(f0, baseColor, metalness);\n'; - fragmentLightingBlock += ' float reflectance = max(max(specularColor.r, specularColor.g), specularColor.b);\n'; - fragmentLightingBlock += ' vec3 r90 = vec3(clamp(reflectance * 25.0, 0.0, 1.0));\n'; - fragmentLightingBlock += ' vec3 r0 = specularColor.rgb;\n'; - - fragmentLightingBlock += ' vec3 F = fresnelSchlick2(r0, r90, VdotH);\n'; - fragmentLightingBlock += ' float G = smithVisibilityGGX(alpha, NdotL, NdotV);\n'; - fragmentLightingBlock += ' float D = GGX(alpha, NdotH);\n'; - - fragmentLightingBlock += ' vec3 diffuseContribution = (1.0 - F) * lambertianDiffuse(baseColor);\n'; - fragmentLightingBlock += ' vec3 specularContribution = F * G * D / (4.0 * NdotL * NdotV);\n'; - fragmentLightingBlock += ' vec3 color = NdotL * lightColor * (diffuseContribution + specularContribution);\n'; - - fragmentLightingBlock += ' vec3 diffuseIrradiance = vec3(0.5);\n'; - fragmentLightingBlock += ' vec3 specularIrradiance = textureCube(czm_cubeMap, r).rgb;\n'; - fragmentLightingBlock += ' specularIrradiance = mix(specularIrradiance, diffuseIrradiance, roughness);\n'; // Fake LOD - fragmentLightingBlock += ' vec2 brdfLUT = texture2D(czm_brdfLUT, vec2(NdotV, 1.0 - roughness)).rg;\n'; - fragmentLightingBlock += ' vec3 IBLColor = (diffuseIrradiance * diffuseColor) + (specularIrradiance * (specularColor * brdfLUT.x + brdfLUT.y));\n'; - fragmentLightingBlock += ' color += IBLColor;\n'; - - if (defined(parameterValues.occlusionTexture)) { - fragmentLightingBlock += ' color *= texture2D(u_occlusionTexture, ' + v_texcoord + ').r;\n'; + fragmentShader += ' vec3 n = ng;\n'; } - if (defined(parameterValues.emissiveTexture)) { - fragmentLightingBlock += ' vec3 emissive = texture2D(u_emissiveTexture, ' + v_texcoord + ').rgb;\n'; - if (defined(parameterValues.emissiveFactor)) { - fragmentLightingBlock += ' emissive *= u_emissiveFactor;\n'; - } - fragmentLightingBlock += ' color += emissive;\n'; - } - else { - if (defined(parameterValues.emissiveFactor)) { - fragmentLightingBlock += ' color += u_emissiveFactor;\n'; - } + if (parameterValues.doubleSided) { + fragmentShader += ' if (!gl_FrontFacing)\n'; + fragmentShader += ' {\n'; + fragmentShader += ' n = -n;\n'; + fragmentShader += ' }\n'; } + } - var finalColorComputation; - finalColorComputation = ' gl_FragColor = vec4(color, 1.0);\n'; - - fragmentShaderMain += fragmentLightingBlock; - fragmentShaderMain += finalColorComputation; - fragmentShaderMain += '}\n'; - - fragmentShader += fragmentShaderMain; - - var techniqueStates; - if (parameterValues.doubleSided) { - techniqueStates = { - enable: [ - WebGLConstants.DEPTH_TEST - ] - }; + // Add base color to fragment shader + if (defined(parameterValues.baseColorTexture)) { + fragmentShader += ' vec3 baseColor = texture2D(u_baseColorTexture, ' + v_texcoord + ').rgb;\n'; + if (defined(parameterValues.baseColorFactor)) { + fragmentShader += ' baseColor *= u_baseColorFactor.rgb;\n'; + } + } else { + if (defined(parameterValues.baseColorFactor)) { + fragmentShader += ' vec3 baseColor = u_baseColorFactor.rgb;\n'; } else { - techniqueStates = { - enable: [ - WebGLConstants.CULL_FACE, - WebGLConstants.DEPTH_TEST - ] - }; + fragmentShader += ' vec3 baseColor = vec3(1.0);\n'; } - - // Add shaders - var vertexShaderId = addToArray(shaders, { - type: WebGLConstants.VERTEX_SHADER, - extras: { - _pipeline: { - source: vertexShader, - extension: '.glsl' - } - } - }); - - var fragmentShaderId = addToArray(shaders, { - type: WebGLConstants.FRAGMENT_SHADER, - extras: { - _pipeline: { - source: fragmentShader, - extension: '.glsl' - } - } - }); - - // 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 - }); - - return techniqueId; } - - function getPBRValueType(paramName, paramValue) { - var value; - - // Backwards compatibility for COLLADA2GLTF v1.0-draft - if (defined(paramValue.value)) { - value = paramValue.value; + // Add metallic-roughness to fragment shader + if (defined(parameterValues.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)) { + fragmentShader += ' metalness *= u_metallicFactor;\n'; + } + if (defined(parameterValues.roughnessFactor)) { + fragmentShader += ' roughness *= u_roughnessFactor;\n'; + } + } else { + if (defined(parameterValues.metallicFactor)) { + fragmentShader += ' float metalness = clamp(u_metallicFactor, 0.0, 1.0);\n'; } else { - value = paramValue; + fragmentShader += ' float metalness = 1.0;\n'; } - - switch (paramName) { - case 'baseColorFactor': - return WebGLConstants.FLOAT_VEC4; - case 'metallicFactor': - return WebGLConstants.FLOAT; - case 'roughnessFactor': - return WebGLConstants.FLOAT; - case 'baseColorTexture': - return WebGLConstants.SAMPLER_2D; - case 'metallicRoughnessTexture': - return WebGLConstants.SAMPLER_2D; - case 'normalTexture': - return WebGLConstants.SAMPLER_2D; - case 'occlusionTexture': - return WebGLConstants.SAMPLER_2D; - case 'emissiveTexture': - return WebGLConstants.SAMPLER_2D; - case 'emissiveFactor': - return WebGLConstants.FLOAT_VEC3; - case 'doubleSided': - return WebGLConstants.BOOL; + if (defined(parameterValues.roughnessFactor)) { + fragmentShader += ' float roughness = clamp(u_roughnessFactor, 0.04, 1.0);\n'; + } else { + fragmentShader += ' float roughness = 1.0;\n'; } } + fragmentShader += ' vec3 v = -normalize(v_positionEC);\n'; + + // Generate fragment shader's lighting block + fragmentShader += ' vec3 lightColor = vec3(1.0, 1.0, 1.0);\n'; + if (optimizeForCesium) { + fragmentShader += ' vec3 l = normalize(czm_sunDirectionEC);\n'; + } else { + fragmentShader += ' vec3 l = vec3(0.0, 0.0, 1.0);\n'; + } + fragmentShader += ' vec3 h = normalize(v + l);\n'; + fragmentShader += ' vec3 r = normalize(reflect(v, n));\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'; + fragmentShader += ' float LdotH = clamp(dot(l, h), 0.0, 1.0);\n'; + fragmentShader += ' float VdotH = clamp(dot(v, h), 0.0, 1.0);\n'; + + fragmentShader += ' vec3 f0 = vec3(0.04);\n'; + fragmentShader += ' float alpha = roughness * roughness;\n'; + fragmentShader += ' vec3 diffuseColor = baseColor * (1.0 - metalness);\n'; + fragmentShader += ' vec3 specularColor = mix(f0, baseColor, metalness);\n'; + fragmentShader += ' float reflectance = max(max(specularColor.r, specularColor.g), specularColor.b);\n'; + fragmentShader += ' vec3 r90 = vec3(clamp(reflectance * 25.0, 0.0, 1.0));\n'; + fragmentShader += ' vec3 r0 = specularColor.rgb;\n'; + + fragmentShader += ' vec3 F = fresnelSchlick2(r0, r90, VdotH);\n'; + fragmentShader += ' float G = smithVisibilityGGX(alpha, NdotL, NdotV);\n'; + fragmentShader += ' float D = GGX(alpha, NdotH);\n'; + + fragmentShader += ' vec3 diffuseContribution = (1.0 - F) * lambertianDiffuse(baseColor);\n'; + fragmentShader += ' vec3 specularContribution = F * G * D / (4.0 * NdotL * NdotV);\n'; + fragmentShader += ' vec3 color = NdotL * lightColor * (diffuseContribution + specularContribution);\n'; + + if (optimizeForCesium) { + fragmentShader += ' vec3 diffuseIrradiance = vec3(0.5);\n'; + fragmentShader += ' vec3 specularIrradiance = textureCube(czm_cubeMap, r).rgb;\n'; + fragmentShader += ' specularIrradiance = mix(specularIrradiance, diffuseIrradiance, roughness);\n'; // Fake LOD + fragmentShader += ' vec2 brdfLUT = texture2D(czm_brdfLUT, vec2(NdotV, 1.0 - roughness)).rg;\n'; + fragmentShader += ' vec3 IBLColor = (diffuseIrradiance * diffuseColor) + (specularIrradiance * (specularColor * brdfLUT.x + brdfLUT.y));\n'; + fragmentShader += ' color += IBLColor;\n'; + } - 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) { - var targetAttributes = targets[target]; - for (var attribute in targetAttributes) { - if (attribute !== 'extras') { - attributes[attribute + '_' + target] = targetAttributes[attribute]; - } - } + if (defined(parameterValues.occlusionTexture)) { + fragmentShader += ' color *= texture2D(u_occlusionTexture, ' + v_texcoord + ').r;\n'; + } + if (defined(parameterValues.emissiveTexture)) { + fragmentShader += ' vec3 emissive = texture2D(u_emissiveTexture, ' + v_texcoord + ').rgb;\n'; + if (defined(parameterValues.emissiveFactor)) { + fragmentShader += ' emissive *= u_emissiveFactor;\n'; } - 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]; - if (semantic.charAt(0) === '_') { - semantic = semantic.slice(1); - } - var attributeName = 'a_' + semantic; - technique.parameters[semantic] = { - semantic: semantic, - type: accessor.componentType - }; - technique.attributes[attributeName] = semantic; - program.attributes.push(attributeName); - var pipelineExtras = vertexShader.extras._pipeline; - var shaderText = pipelineExtras.source; - shaderText = 'attribute ' + getShaderVariable(accessor.type) + ' ' + attributeName + ';\n' + shaderText; - pipelineExtras.source = shaderText; - } - } + fragmentShader += ' color += emissive;\n'; + } + else { + if (defined(parameterValues.emissiveFactor)) { + fragmentShader += ' color += u_emissiveFactor;\n'; } } - function ensureSemanticExistence(gltf) { - ForEach.mesh(gltf, function(mesh) { - ForEach.meshPrimitive(mesh, function(primitive) { - ensureSemanticExistenceForPrimitive(gltf, primitive); - }); - }); - } + // Final color + fragmentShader += ' gl_FragColor = vec4(color, 1.0);\n'; + fragmentShader += '}\n'; - function splitIncompatibleSkins(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 skinningInfo = material.extras._pipeline.skinning; - if (!defined(skinningInfo)) { - material.extras._pipeline.skinning = { - skinned: isSkinned, - componentType: componentType, - type: type - }; - } else if ((skinningInfo.skinned !== isSkinned) || (skinningInfo.type !== type)) { - // This primitive uses the same material as another one that either isn't skinned or uses a different type to store joints and weights - var clonedMaterial = clone(material, true); - clonedMaterial.material.extras._pipeline.skinning = { - skinned: isSkinned, - componentType: componentType, - type: type - }; - // Split this off as a separate material - materialId = addToArray(materials, clonedMaterial); - primitive.material = materialId; - } - }); - }); + var techniqueStates; + if (parameterValues.doubleSided) { + techniqueStates = { + enable : [ + WebGLConstants.DEPTH_TEST + ] + }; + } else { + techniqueStates = { + enable : [ + WebGLConstants.CULL_FACE, + WebGLConstants.DEPTH_TEST + ] + }; } - /** - * @private - */ - function processPbrMetallicRoughness(gltf, frameState, options) { - options = defaultValue(options, {}); - - if (!defined(gltf)) { - return undefined; - } - - var hasExtension = false; - ForEach.material(gltf, function(material) { - if (material.hasOwnProperty('pbrMetallicRoughness')) { - hasExtension = true; + // Add shaders + var vertexShaderId = addToArray(shaders, { + type : WebGLConstants.VERTEX_SHADER, + extras : { + _pipeline : { + source : vertexShader, + extension : '.glsl' } - }); + } + }); - if (hasExtension) { - if (!defined(gltf.programs)) { - gltf.programs = []; - } - if (!defined(gltf.shaders)) { - gltf.shaders = []; - } - if (!defined(gltf.techniques)) { - gltf.techniques = []; + var fragmentShaderId = addToArray(shaders, { + type : WebGLConstants.FRAGMENT_SHADER, + extras : { + _pipeline : { + source : fragmentShader, + extension : '.glsl' } + } + }); + + // 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 + }); + + return techniqueId; +} + +function getPBRValueType(paramName, paramValue) { + var value; + + // Backwards compatibility for COLLADA2GLTF v1.0-draft + if (defined(paramValue.value)) { + value = paramValue.value; + } else { + value = paramValue; + } - // Pre-processing to assign skinning info and address incompatibilities - splitIncompatibleSkins(gltf); - - var techniques = {}; - ForEach.material(gltf, function(material) { - if (material.hasOwnProperty('pbrMetallicRoughness')) { - var pbrMetallicRoughness = material.pbrMetallicRoughness; - var technique = generateTechnique(gltf, material, frameState, options.optimizeForCesium); - - material.values = {}; - var values = pbrMetallicRoughness; - for (var valueName in values) { - if (values.hasOwnProperty(valueName)) { - var value = values[valueName]; - material.values[valueName] = value; - } - } - - material.technique = technique; - } - }); + switch (paramName) { + case 'baseColorFactor': + return WebGLConstants.FLOAT_VEC4; + case 'metallicFactor': + return WebGLConstants.FLOAT; + case 'roughnessFactor': + return WebGLConstants.FLOAT; + case 'baseColorTexture': + return WebGLConstants.SAMPLER_2D; + case 'metallicRoughnessTexture': + return WebGLConstants.SAMPLER_2D; + case 'normalTexture': + return WebGLConstants.SAMPLER_2D; + case 'occlusionTexture': + return WebGLConstants.SAMPLER_2D; + case 'emissiveTexture': + return WebGLConstants.SAMPLER_2D; + case 'emissiveFactor': + return WebGLConstants.FLOAT_VEC3; + case 'doubleSided': + return WebGLConstants.BOOL; + } +} - if (defined(gltf.extensions)) { - delete gltf.extensions.KHR_materials_common; - if (Object.keys(gltf.extensions).length === 0) { - delete gltf.extensions; +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) { + 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]; + if (semantic.charAt(0) === '_') { + semantic = semantic.slice(1); } + var attributeName = 'a_' + semantic; + technique.parameters[semantic] = { + semantic : semantic, + type : accessor.componentType + }; + technique.attributes[attributeName] = semantic; + program.attributes.push(attributeName); + var pipelineExtras = vertexShader.extras._pipeline; + var shaderText = pipelineExtras.source; + shaderText = 'attribute ' + getShaderVariable(accessor.type) + ' ' + attributeName + ';\n' + shaderText; + pipelineExtras.source = shaderText; } - - // If any primitives have semantics that aren't declared in the generated - // shaders, we want to preserve them. - ensureSemanticExistence(gltf); } - - return gltf; } +} - return processPbrMetallicRoughness; -}); +function ensureSemanticExistence(gltf) { + ForEach.mesh(gltf, function(mesh) { + ForEach.meshPrimitive(mesh, function(primitive) { + ensureSemanticExistenceForPrimitive(gltf, primitive); + }); + }); +} + +function splitIncompatibleSkins(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 skinningInfo = material.extras._pipeline.skinning; + if (!defined(skinningInfo)) { + material.extras._pipeline.skinning = { + skinned : isSkinned, + componentType : componentType, + type : type + }; + } else if ((skinningInfo.skinned !== isSkinned) || (skinningInfo.type !== type)) { + // This primitive uses the same material as another one that either isn't skinned or uses a different type to store joints and weights + var clonedMaterial = clone(material, true); + clonedMaterial.material.extras._pipeline.skinning = { + skinned : isSkinned, + componentType : componentType, + type : type + }; + // Split this off as a separate material + materialId = addToArray(materials, clonedMaterial); + primitive.material = materialId; + } + }); + }); +} From 7785d21edda2e16448f20f3da9ee653c8a11c8e8 Mon Sep 17 00:00:00 2001 From: Mohamad Moneimne Date: Thu, 13 Jul 2017 15:51:55 -0400 Subject: [PATCH 15/35] Split glsl type and webGL conversions into separate files --- lib/glslTypeToWebGLConstant.js | 27 ++++++++++++++++++ lib/processModelMaterialsCommon.js | 44 ++-------------------------- lib/processPbrMetallicRoughness.js | 46 ++---------------------------- lib/webGLConstantToGlslType.js | 29 +++++++++++++++++++ 4 files changed, 60 insertions(+), 86 deletions(-) create mode 100644 lib/glslTypeToWebGLConstant.js create mode 100644 lib/webGLConstantToGlslType.js diff --git a/lib/glslTypeToWebGLConstant.js b/lib/glslTypeToWebGLConstant.js new file mode 100644 index 00000000..cce17bb4 --- /dev/null +++ b/lib/glslTypeToWebGLConstant.js @@ -0,0 +1,27 @@ +'use strict'; +var Cesium = require('cesium'); + +var WebGLConstants = Cesium.WebGLConstants; + +module.exports = glslTypeToWebGLConstant; + +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; + } +} \ No newline at end of file diff --git a/lib/processModelMaterialsCommon.js b/lib/processModelMaterialsCommon.js index 59b6ef6c..492b2f42 100644 --- a/lib/processModelMaterialsCommon.js +++ b/lib/processModelMaterialsCommon.js @@ -4,6 +4,8 @@ var addToArray = require('./addToArray'); var ForEach = require('./ForEach'); var numberOfComponentsForType = require('./numberOfComponentsForType'); var techniqueParameterForSemantic = require('./techniqueParameterForSemantic'); +var webGLConstantToGlslType = require('./webGLConstantToGlslType'); +var glslTypeToWebGLConstant = require('./glslTypeToWebGLConstant') var clone = Cesium.clone; var defined = Cesium.defined; @@ -102,48 +104,6 @@ function processModelMaterialsCommon(gltf, options) { return gltf; } -function webGLConstantToGlslType(webGLValue) { - switch (webGLValue) { - case WebGLConstants.FLOAT: - return 'float'; - case WebGLConstants.FLOAT_VEC2: - return 'vec2'; - case WebGLConstants.FLOAT_VEC3: - return 'vec3'; - case WebGLConstants.FLOAT_VEC4: - return 'vec4'; - case WebGLConstants.FLOAT_MAT2: - return 'mat2'; - case WebGLConstants.FLOAT_MAT3: - return 'mat3'; - case WebGLConstants.FLOAT_MAT4: - return 'mat4'; - case WebGLConstants.SAMPLER_2D: - return 'sampler2D'; - } -} - -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; - } -} - function generateLightParameters(gltf) { var result = {}; diff --git a/lib/processPbrMetallicRoughness.js b/lib/processPbrMetallicRoughness.js index b7860ff6..5fb83a5e 100644 --- a/lib/processPbrMetallicRoughness.js +++ b/lib/processPbrMetallicRoughness.js @@ -4,6 +4,8 @@ var addToArray = require('./addToArray'); var ForEach = require('./ForEach'); var numberOfComponentsForType = require('./numberOfComponentsForType'); var techniqueParameterForSemantic = require('./techniqueParameterForSemantic'); +var webGLConstantToGlslType = require('./webGLConstantToGlslType'); +var glslTypeToWebGLConstant = require('./glslTypeToWebGLConstant') var clone = Cesium.clone; var defined = Cesium.defined; @@ -72,50 +74,6 @@ function processPbrMetallicRoughness(gltf, options) { return gltf; } -function webGLConstantToGlslType(webGLValue) { - switch (webGLValue) { - case WebGLConstants.FLOAT: - return 'float'; - case WebGLConstants.FLOAT_VEC2: - return 'vec2'; - case WebGLConstants.FLOAT_VEC3: - return 'vec3'; - case WebGLConstants.FLOAT_VEC4: - return 'vec4'; - case WebGLConstants.FLOAT_MAT2: - return 'mat2'; - case WebGLConstants.FLOAT_MAT3: - return 'mat3'; - case WebGLConstants.FLOAT_MAT4: - return 'mat4'; - case WebGLConstants.SAMPLER_2D: - return 'sampler2D'; - case WebGLConstants.BOOL: - return 'bool'; - } -} - -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; - } -} - function generateTechnique(gltf, material, optimizeForCesium) { var techniques = gltf.techniques; var shaders = gltf.shaders; diff --git a/lib/webGLConstantToGlslType.js b/lib/webGLConstantToGlslType.js new file mode 100644 index 00000000..d4e9ac75 --- /dev/null +++ b/lib/webGLConstantToGlslType.js @@ -0,0 +1,29 @@ +'use strict'; +var Cesium = require('cesium'); + +var WebGLConstants = Cesium.WebGLConstants; + +module.exports = webGLConstantToGlslType; + +function webGLConstantToGlslType(webGLValue) { + switch (webGLValue) { + case WebGLConstants.FLOAT: + return 'float'; + case WebGLConstants.FLOAT_VEC2: + return 'vec2'; + case WebGLConstants.FLOAT_VEC3: + return 'vec3'; + case WebGLConstants.FLOAT_VEC4: + return 'vec4'; + case WebGLConstants.FLOAT_MAT2: + return 'mat2'; + case WebGLConstants.FLOAT_MAT3: + return 'mat3'; + case WebGLConstants.FLOAT_MAT4: + return 'mat4'; + case WebGLConstants.SAMPLER_2D: + return 'sampler2D'; + case WebGLConstants.BOOL: + return 'bool'; + } +} \ No newline at end of file From 6c9cc6972dce2941501e96cb94614f57dc192ac8 Mon Sep 17 00:00:00 2001 From: Mohamad Moneimne Date: Fri, 14 Jul 2017 10:49:00 -0400 Subject: [PATCH 16/35] Added default byteOffset to accessors --- lib/addDefaults.js | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/lib/addDefaults.js b/lib/addDefaults.js index 8c9443d6..2dd79e8a 100644 --- a/lib/addDefaults.js +++ b/lib/addDefaults.js @@ -357,6 +357,17 @@ function addDefaultTechnique(gltf) { } } +function addDefaultByteOffsets(gltf) { + var accessors = gltf.accessors; + + for (var i = 0; i < accessors.length; i++) { + var accessor = accessors[i]; + if (!defined(accessor.byteOffset)) { + accessor.byteOffset = 0; + } + } +} + function enableDiffuseTransparency(gltf) { var materials = gltf.materials; var techniques = gltf.techniques; @@ -495,6 +506,7 @@ function addDefaults(gltf, options) { addDefaultsFromTemplate(gltf, gltfTemplate); addDefaultMaterial(gltf); addDefaultTechnique(gltf); + addDefaultByteOffsets(gltf); enableDiffuseTransparency(gltf); selectDefaultScene(gltf); inferBufferViewTargets(gltf); From 8f7cf8711b54b7d7d85611f11c065bfbf2630ce2 Mon Sep 17 00:00:00 2001 From: Mohamad Moneimne Date: Fri, 14 Jul 2017 13:54:35 -0400 Subject: [PATCH 17/35] Added default byteOffset to bufferViews --- lib/addDefaults.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/lib/addDefaults.js b/lib/addDefaults.js index 2dd79e8a..94f19fd9 100644 --- a/lib/addDefaults.js +++ b/lib/addDefaults.js @@ -366,6 +366,15 @@ function addDefaultByteOffsets(gltf) { accessor.byteOffset = 0; } } + + var bufferViews = gltf.bufferViews; + + for (var i = 0; i < bufferViews.length; i++) { + var bufferView = bufferViews[i]; + if (!defined(bufferView.byteOffset)) { + bufferView.byteOffset = 0; + } + } } function enableDiffuseTransparency(gltf) { From 357aaa720a5477ae1ade93343a00a63d40df9a52 Mon Sep 17 00:00:00 2001 From: Mohamad Moneimne Date: Fri, 14 Jul 2017 16:27:02 -0400 Subject: [PATCH 18/35] Took uninterleaveAndPackBuffers from master and upgraded to 2.0 --- lib/uninterleaveAndPackBuffers.js | 253 +++++++++++++++++------------- 1 file changed, 143 insertions(+), 110 deletions(-) diff --git a/lib/uninterleaveAndPackBuffers.js b/lib/uninterleaveAndPackBuffers.js index 53bf67df..c9f4f8d6 100644 --- a/lib/uninterleaveAndPackBuffers.js +++ b/lib/uninterleaveAndPackBuffers.js @@ -1,13 +1,13 @@ 'use strict'; var Cesium = require('cesium'); -var AccessorReader = require('./AccessorReader'); -var byteLengthForComponentType = require('./byteLengthForComponentType'); -var ForEach = require('./ForEach'); -var numberOfComponentsForType = require('./numberOfComponentsForType'); -var Remove = require('./Remove'); -var writeBufferComponent = require('./writeBufferComponent'); var WebGLConstants = Cesium.WebGLConstants; +var defined = Cesium.defined; +var defaultValue = Cesium.defaultValue; + +var byteLengthForComponentType = require('./byteLengthForComponentType'); +var getAccessorByteStride = require('./getAccessorByteStride'); +var numberOfComponentsForType = require('./numberOfComponentsForType'); module.exports = uninterleaveAndPackBuffers; @@ -24,122 +24,155 @@ module.exports = uninterleaveAndPackBuffers; * @see loadGltfUris */ function uninterleaveAndPackBuffers(gltf) { - var arrayBufferDataOffset = 0; - var arrayBufferDataLength = 0; - var elementArrayBufferDataOffset = 0; - var elementArrayBufferDataLength = 0; - var otherDataOffset = 0; - var otherDataLength = 0; + var accessors = gltf.accessors; + var buffers = gltf.buffers; + var packBufferViews = []; + for (var bufferId in buffers) { + if (buffers.hasOwnProperty(bufferId)) { + packGltfBuffer(gltf, bufferId, packBufferViews); + } + } + gltf.bufferViews = packBufferViews; - // compute the total size for each arraybuffer type - ForEach.accessor(gltf, function (accessor) { - var bufferView = gltf.bufferViews[accessor.bufferView]; - var accessorLength = byteLengthForComponentType(accessor.componentType) * numberOfComponentsForType(accessor.type) * accessor.count; - switch (bufferView.target) { - case WebGLConstants.ARRAY_BUFFER: - arrayBufferDataLength += accessorLength; - break; - case WebGLConstants.ELEMENT_ARRAY_BUFFER: - elementArrayBufferDataLength += accessorLength; - break; - default: - otherDataLength += accessorLength; - break; + // Change the accessor bufferViews to point to the new bufferViews + for (var accessorId in accessors) { + if (accessors.hasOwnProperty(accessorId)) { + var accessor = accessors[accessorId]; + accessor.bufferView = accessor.extras._pipeline.bufferView; } - }); + } + return gltf; +} - // allocate buffer data - var bufferData = new Buffer(arrayBufferDataLength + elementArrayBufferDataLength + otherDataLength); - var arrayBufferData = bufferData.slice(0, arrayBufferDataLength); - var elementArrayBufferData = bufferData.slice(arrayBufferDataLength, arrayBufferDataLength + elementArrayBufferDataLength); - var otherData = bufferData.slice(arrayBufferDataLength + elementArrayBufferDataLength); +function packGltfBuffer(gltf, bufferId, packBufferViews) { + var buffers = gltf.buffers; + var buffer = buffers[bufferId]; + var source = buffer.extras._pipeline.source; + var packBuffer = new Uint8Array(source.length + 6); // Account for extra padding between targets + var accessors = getAccessorsByTargetAndByteLength(gltf, bufferId); + var offset = 0; - // read data from accessors into the new buffers - ForEach.accessor(gltf, function (accessor) { - var reader = new AccessorReader(gltf, accessor); - var components = []; - var bufferView = gltf.bufferViews[accessor.bufferView]; - var componentByteLength = byteLengthForComponentType(accessor.componentType); - var bytesWritten = 0; + var targets = [WebGLConstants.ARRAY_BUFFER, 0, WebGLConstants.ELEMENT_ARRAY_BUFFER]; + for (var i = 0; i < targets.length; i++) { + var target = targets[i]; + var accessorsByByteLength = accessors[target]; + if (defined(accessorsByByteLength)) { + offset = packAccessorsForTarget(gltf, bufferId, target, accessorsByByteLength, source, packBuffer, packBufferViews, offset); - while (!reader.pastEnd()) { - reader.read(components); - var componentsLength = components.length; - for (var i = 0; i < componentsLength; i++) { - switch (bufferView.target) { - case WebGLConstants.ARRAY_BUFFER: - writeBufferComponent(arrayBufferData, accessor.componentType, components[i], arrayBufferDataOffset); - arrayBufferDataOffset += componentByteLength; - break; - case WebGLConstants.ELEMENT_ARRAY_BUFFER: - writeBufferComponent(elementArrayBufferData, accessor.componentType, components[i], elementArrayBufferDataOffset); - elementArrayBufferDataOffset += componentByteLength; - break; - default: - writeBufferComponent(otherData, accessor.componentType, components[i], otherDataOffset); - otherDataOffset += componentByteLength; - break; + // End this target on a 4-byte boundary so the byteOffset of the next target's first accessor is 0 + // Don't add padding to the last target + for (var j = i + 1; j < targets.length; ++j) { + if (defined(accessors[targets[j]])) { + offset += offset % 4; + break; } - bytesWritten += componentByteLength; } - reader.next(); } - // assign bufferViews and offsets since we're done reading - switch (bufferView.target) { - case WebGLConstants.ARRAY_BUFFER: - accessor.bufferView = 0; - accessor.byteOffset = arrayBufferDataOffset - bytesWritten; - break; - case WebGLConstants.ELEMENT_ARRAY_BUFFER: - accessor.bufferView = 1; - accessor.byteOffset = elementArrayBufferDataOffset - bytesWritten; - break; - default: - accessor.bufferView = 2; - accessor.byteOffset = otherDataOffset - bytesWritten; - break; - } - }); + } + packBuffer = new Buffer(new Uint8Array(packBuffer.buffer, 0, offset)); + buffer.extras._pipeline.source = packBuffer; + buffer.byteLength = packBuffer.length; +} - var buffers = [{ - byteLength: bufferData.length, - extras: { - _pipeline: { - source: bufferData, - extension: '.bin' - } +function packAccessorsForTarget(gltf, bufferId, target, accessorsByByteLength, sourceBuffer, packBuffer, packBufferViews, offset) { + var bufferViewId = packBufferViews.length; + var originalOffset = offset; + var byteLengths = [4, 2, 1]; + var packOffset = offset; + for (var i = 0; i < byteLengths.length; i++) { + var byteLength = byteLengths[i]; + var accessorIds = accessorsByByteLength[byteLength]; + if (defined(accessorIds) && accessorIds.length > 0) { + // Byte-boundary align the offset if it isn't already + packOffset += packOffset % byteLength; + packOffset = packAccessors(gltf, accessorIds, sourceBuffer, packBuffer, bufferViewId, originalOffset, packOffset); } - }]; - - var bufferViews = [{ - buffer: 0, - byteLength: arrayBufferDataLength, - byteOffset: 0, - byteStride: 0 - }, { - buffer: 0, - byteLength: elementArrayBufferDataLength, - byteOffset: arrayBufferDataLength - }, { - buffer: 0, - byteLength: otherDataLength, - byteOffset: arrayBufferDataLength + elementArrayBufferDataLength, - byteStride: 0 - }]; - - gltf.buffers = buffers; - gltf.bufferViews = bufferViews; + } + var packBufferView = { + buffer : bufferId, + byteLength : packOffset - originalOffset, + byteOffset : originalOffset, + extras : { + _pipeline : {} + } + }; + if (target > 0) { + packBufferView.target = target; + } + packBufferViews[bufferViewId] = packBufferView; + return packOffset; +} - var removed = 0; - if (arrayBufferDataLength === 0) { - Remove.bufferView(gltf, 0); - removed++; +function getPipelineExtras(object) { + var extras = object.extras; + if (!defined(extras)) { + extras = {}; + object.extras = extras; } - if (elementArrayBufferDataLength === 0) { - Remove.bufferView(gltf, 1 - removed); - removed++; + var pipeline = extras._pipeline; + if (!defined(pipeline)) { + pipeline = {}; + extras._pipeline = pipeline; } - if (otherDataLength === 0) { - Remove.bufferView(gltf, 2 - removed); + return pipeline; +} + +function packAccessors(gltf, accessorsToPack, sourceBuffer, packBuffer, bufferViewId, originalOffset, packOffset) { + var accessors = gltf.accessors; + var bufferViews = gltf.bufferViews; + var length = accessorsToPack.length; + var bytesWritten = 0; + for (var i = 0; i < length; i++) { + var accessorId = accessorsToPack[i]; + var accessor = accessors[accessorId]; + var bufferView = bufferViews[accessor.bufferView]; + var byteStride = getAccessorByteStride(gltf, accessor); + var byteOffset = accessor.byteOffset + bufferView.byteOffset; + var numberOfComponents = numberOfComponentsForType(accessor.type); + var componentByteLength = byteLengthForComponentType(accessor.componentType); + var byteLength = numberOfComponents * componentByteLength; + var offset = byteOffset; + var count = accessor.count; + accessor.byteStride = 0; + // Store as temp for now, finalize later + var extras = getPipelineExtras(accessor); + extras.bufferView = bufferViewId; + accessor.byteOffset = packOffset - originalOffset + bytesWritten; + for (var num = 0; num < count; num++) { + for (var j = 0; j < byteLength; j++) { + packBuffer[packOffset + bytesWritten] = sourceBuffer[offset + j]; + bytesWritten++; + } + offset += byteStride; + } + } + return packOffset + bytesWritten; +} + +function getAccessorsByTargetAndByteLength(gltf, bufferId) { + var accessors = gltf.accessors; + var bufferViews = gltf.bufferViews; + var accessorsByTargetAndByteLength = {}; + for (var accessorId in accessors) { + if (accessors.hasOwnProperty(accessorId)) { + var accessor = accessors[accessorId]; + var bufferView = bufferViews[accessor.bufferView]; + if (bufferView.buffer === parseInt(bufferId)) { + var target = defaultValue(bufferView.target, 0); + var accessorsByByteLength = accessorsByTargetAndByteLength[target]; + if (!defined(accessorsByByteLength)) { + accessorsByByteLength = {}; + accessorsByTargetAndByteLength[target] = accessorsByByteLength; + } + var byteLength = byteLengthForComponentType(accessor.componentType); + var accessorIds = accessorsByByteLength[byteLength]; + if (!defined(accessorIds)) { + accessorIds = []; + accessorsByByteLength[byteLength] = accessorIds; + } + accessorIds.push(accessorId); + } + } } + return accessorsByTargetAndByteLength; } \ No newline at end of file From 401691d10521b6a5e3aa38766a22f6f04d78d1a7 Mon Sep 17 00:00:00 2001 From: Mohamad Moneimne Date: Mon, 17 Jul 2017 17:22:04 -0400 Subject: [PATCH 19/35] Fixed jsHint issues and removeUnusedProperties tests --- lib/Remove.js | 16 +++++----- lib/RemoveUnusedProperties.js | 10 +++---- lib/addDefaults.js | 4 +-- lib/bakeAmbientOcclusion.js | 2 +- lib/isTexture.js | 2 +- lib/processModelMaterialsCommon.js | 2 +- lib/processPbrMetallicRoughness.js | 29 ++++++++++--------- .../CesiumTexturedBoxTestUnusedTree.gltf | 4 ++- specs/lib/RemoveUnusedPropertiesSpec.js | 24 ++++++++++----- 9 files changed, 52 insertions(+), 41 deletions(-) diff --git a/lib/Remove.js b/lib/Remove.js index ef888055..acc3d3dc 100644 --- a/lib/Remove.js +++ b/lib/Remove.js @@ -245,22 +245,22 @@ Remove.texture = function(gltf, textureId) { textures.splice(textureId, 1); ForEach.material(gltf, function(material) { - ForEach.materialValue(material, function(value, name) { - if (isTexture(name, value)) { - if (value[0] > textureId) { - value[0]--; + ForEach.materialValue(material, function(value) { + if (isTexture(value)) { + if (value.index > textureId) { + value.index--; } } }); }); ForEach.technique(gltf, function(technique) { - ForEach.techniqueParameter(technique, function(parameter, name) { + ForEach.techniqueParameter(technique, function(parameter) { var value = parameter.value; if (defined(value)) { - if (isTexture(name, value)) { - if (value[0] > textureId) { - value[0]--; + if (isTexture(value)) { + if (value.index > textureId) { + value.index--; } } } diff --git a/lib/RemoveUnusedProperties.js b/lib/RemoveUnusedProperties.js index b03932f6..d130e4e7 100644 --- a/lib/RemoveUnusedProperties.js +++ b/lib/RemoveUnusedProperties.js @@ -256,19 +256,19 @@ RemoveUnusedProperties.removeTextures = function(gltf) { var usedTextureIds = {}; ForEach.material(gltf, function(material) { - ForEach.materialValue(material, function(value, name) { - if (isTexture(name, value)) { + ForEach.materialValue(material, function(value) { + if (isTexture(value)) { usedTextureIds[value.index] = true; } }); }); ForEach.technique(gltf, function(technique) { - ForEach.techniqueParameter(technique, function(parameter, name) { + ForEach.techniqueParameter(technique, function(parameter) { var value = parameter.value; if (defined(value)) { - if (isTexture(name, value)) { - usedTextureIds[value[0]] = true; + if (isTexture(value)) { + usedTextureIds[value.index] = true; } } }); diff --git a/lib/addDefaults.js b/lib/addDefaults.js index 94f19fd9..654025be 100644 --- a/lib/addDefaults.js +++ b/lib/addDefaults.js @@ -369,8 +369,8 @@ function addDefaultByteOffsets(gltf) { var bufferViews = gltf.bufferViews; - for (var i = 0; i < bufferViews.length; i++) { - var bufferView = bufferViews[i]; + for (var j = 0; j < bufferViews.length; j++) { + var bufferView = bufferViews[j]; if (!defined(bufferView.byteOffset)) { bufferView.byteOffset = 0; } diff --git a/lib/bakeAmbientOcclusion.js b/lib/bakeAmbientOcclusion.js index 5ab3466c..95ea88e7 100644 --- a/lib/bakeAmbientOcclusion.js +++ b/lib/bakeAmbientOcclusion.js @@ -573,7 +573,7 @@ function bakeToTexture(gltf, options) { for (var materialId = 0; materialId < materialsLength; materialId++) { var material = materials[materialId]; if (defined(material.values) && defined(material.values.diffuse)) { - if (isTexture('diffuse', material.values.diffuse)) { + if (isTexture(material.values.diffuse)) { exampleMaterialID = materialId; exampleTextureID = material.values.diffuse; exampleImageID = textures[exampleTextureID].source; diff --git a/lib/isTexture.js b/lib/isTexture.js index e60ca002..80a00f64 100644 --- a/lib/isTexture.js +++ b/lib/isTexture.js @@ -5,6 +5,6 @@ var defined = Cesium.defined; module.exports = isTexture; -function isTexture(name, value) { +function isTexture(value) { return defined(value.index); } \ No newline at end of file diff --git a/lib/processModelMaterialsCommon.js b/lib/processModelMaterialsCommon.js index 492b2f42..a75da3a8 100644 --- a/lib/processModelMaterialsCommon.js +++ b/lib/processModelMaterialsCommon.js @@ -5,7 +5,7 @@ var ForEach = require('./ForEach'); var numberOfComponentsForType = require('./numberOfComponentsForType'); var techniqueParameterForSemantic = require('./techniqueParameterForSemantic'); var webGLConstantToGlslType = require('./webGLConstantToGlslType'); -var glslTypeToWebGLConstant = require('./glslTypeToWebGLConstant') +var glslTypeToWebGLConstant = require('./glslTypeToWebGLConstant'); var clone = Cesium.clone; var defined = Cesium.defined; diff --git a/lib/processPbrMetallicRoughness.js b/lib/processPbrMetallicRoughness.js index 5fb83a5e..0631ae0c 100644 --- a/lib/processPbrMetallicRoughness.js +++ b/lib/processPbrMetallicRoughness.js @@ -5,7 +5,7 @@ var ForEach = require('./ForEach'); var numberOfComponentsForType = require('./numberOfComponentsForType'); var techniqueParameterForSemantic = require('./techniqueParameterForSemantic'); var webGLConstantToGlslType = require('./webGLConstantToGlslType'); -var glslTypeToWebGLConstant = require('./glslTypeToWebGLConstant') +var glslTypeToWebGLConstant = require('./glslTypeToWebGLConstant'); var clone = Cesium.clone; var defined = Cesium.defined; @@ -50,7 +50,6 @@ function processPbrMetallicRoughness(gltf, options) { var pbrMetallicRoughness = material.pbrMetallicRoughness; var technique = generateTechnique(gltf, material, options.optimizeForCesium); - var values = {}; var values = pbrMetallicRoughness; for (var valueName in values) { if (values.hasOwnProperty(valueName)) { @@ -242,23 +241,23 @@ function generateTechnique(gltf, material, optimizeForCesium) { vertexShaderMain += ' vec3 weightedTangent = a_tangent;\n'; } if (hasMorphTargets) { - for (var i = 0; i < morphTargets.length; i++) { - var targetAttributes = morphTargets[i]; + for (var k = 0; k < morphTargets.length; k++) { + var targetAttributes = morphTargets[k]; for (var targetAttribute in targetAttributes) { if (targetAttributes.hasOwnProperty(targetAttribute) && targetAttribute !== 'extras') { - var attributeLower = targetAttribute.toLowerCase() + '_' + i; + var attributeLower = targetAttribute.toLowerCase() + '_' + k; techniqueAttributes['a_' + attributeLower] = attributeLower; techniqueParameters[attributeLower] = { - semantic : targetAttribute + '_' + i, + semantic : targetAttribute + '_' + k, type : WebGLConstants.FLOAT_VEC3 - } + }; vertexShader += 'attribute vec3 a_' + attributeLower + ';\n'; if (targetAttribute === 'POSITION') { - vertexShaderMain += ' weightedPosition += u_morphWeights[' + i + '] * a_' + attributeLower + ';\n'; + vertexShaderMain += ' weightedPosition += u_morphWeights[' + k + '] * a_' + attributeLower + ';\n'; } else if (targetAttribute === 'NORMAL') { - vertexShaderMain += ' weightedNormal += u_morphWeights[' + i + '] * a_' + attributeLower + ';\n'; + vertexShaderMain += ' weightedNormal += u_morphWeights[' + k + '] * a_' + attributeLower + ';\n'; } else if (targetAttribute === 'TANGENT') { - vertexShaderMain += ' weightedTangent += u_morphWeights[' + i + '] * a_' + attributeLower + ';\n'; + vertexShaderMain += ' weightedTangent += u_morphWeights[' + k + '] * a_' + attributeLower + ';\n'; } } } @@ -634,10 +633,12 @@ function ensureSemanticExistenceForPrimitive(gltf, primitive) { var attributes = primitive.attributes; for (var target in targets) { - var targetAttributes = targets[target]; - for (var attribute in targetAttributes) { - if (attribute !== 'extras') { - attributes[attribute + '_' + target] = targetAttributes[attribute]; + if (defined(target)) { + var targetAttributes = targets[target]; + for (var attribute in targetAttributes) { + if (attribute !== 'extras') { + attributes[attribute + '_' + target] = targetAttributes[attribute]; + } } } } diff --git a/specs/data/boxTexturedUnoptimized/CesiumTexturedBoxTestUnusedTree.gltf b/specs/data/boxTexturedUnoptimized/CesiumTexturedBoxTestUnusedTree.gltf index 8dcd9c7e..ba61ef98 100644 --- a/specs/data/boxTexturedUnoptimized/CesiumTexturedBoxTestUnusedTree.gltf +++ b/specs/data/boxTexturedUnoptimized/CesiumTexturedBoxTestUnusedTree.gltf @@ -54,7 +54,9 @@ { "technique": 0, "values": { - "diffuse": [0] + "baseColorTexture": { + "index": 0 + } } } ], diff --git a/specs/lib/RemoveUnusedPropertiesSpec.js b/specs/lib/RemoveUnusedPropertiesSpec.js index c593ab2b..3676cd7c 100644 --- a/specs/lib/RemoveUnusedPropertiesSpec.js +++ b/specs/lib/RemoveUnusedPropertiesSpec.js @@ -654,7 +654,9 @@ describe('RemoveUnusedProperties', function() { materials: [ { values: { - diffuse: [1] + baseColorTexture: { + "index": 1 + } } } ], @@ -671,7 +673,7 @@ describe('RemoveUnusedProperties', function() { removeTextures(gltf); expect(gltf.textures.length).toEqual(1); expect(gltf.textures[0].name).not.toEqual('unused'); - expect(gltf.materials[0].values.diffuse[0]).toEqual(0); + expect(gltf.materials[0].values.baseColorTexture.index).toEqual(0); }); it('removes a texture unused by technique', function () { @@ -679,8 +681,10 @@ describe('RemoveUnusedProperties', function() { techniques: [ { parameters: { - diffuse: { - value: [1] + baseColorTexture: { + value: { + "index": 1 + } } } } @@ -698,7 +702,7 @@ describe('RemoveUnusedProperties', function() { removeTextures(gltf); expect(gltf.textures.length).toEqual(1); expect(gltf.textures[0].name).not.toEqual('unused'); - expect(gltf.techniques[0].parameters.diffuse.value[0]).toEqual(0); + expect(gltf.techniques[0].parameters.baseColorTexture.value.index).toEqual(0); }); it('does not remove any textures', function () { @@ -706,15 +710,19 @@ describe('RemoveUnusedProperties', function() { materials: [ { values: { - diffuse: [0] + baseColorTexture: { + "index": 0 + } } } ], techniques: [ { parameters: { - diffuse: { - value: [1] + baseColorTexture: { + value: { + "index": 1 + } } } } From 58ca4b620a541f15b7efe8b1c524f1051a48f637 Mon Sep 17 00:00:00 2001 From: Mohamad Moneimne Date: Thu, 20 Jul 2017 10:46:59 -0400 Subject: [PATCH 20/35] Fixed removeUnusedVertices tests by changing according to master --- specs/lib/removeUnusedVerticesSpec.js | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/specs/lib/removeUnusedVerticesSpec.js b/specs/lib/removeUnusedVerticesSpec.js index 50a7ccbc..ced259b2 100644 --- a/specs/lib/removeUnusedVerticesSpec.js +++ b/specs/lib/removeUnusedVerticesSpec.js @@ -121,7 +121,7 @@ describe('removeUnusedVertices', function() { var expectBytesDropped = expectBytesDropped1 + expectBytesDropped2; removeUnusedVertices(gltf); uninterleaveAndPackBuffers(gltf); - expect(gltf.buffers[0].byteLength - indexBuffer.length + expectBytesDropped).toEqual(byteLength); + expect(gltf.buffers[1].byteLength + expectBytesDropped).toEqual(byteLength); var expectAttribute1 = [[0, 1, 2], [6, 7, 8]]; var reader = new AccessorReader(gltf, attributeAccessor1); @@ -173,7 +173,7 @@ describe('removeUnusedVertices', function() { var expectBytesDropped = 2 * (expectBytesDropped1 + expectBytesDropped2); removeUnusedVertices(gltf); uninterleaveAndPackBuffers(gltf); - expect(gltf.buffers[0].byteLength - indexBuffer.length + expectBytesDropped).toEqual(byteLength); + expect(gltf.buffers[1].byteLength + expectBytesDropped).toEqual(byteLength); var expectAttribute1 = [[3, 4, 5]]; var reader = new AccessorReader(gltf, attributeAccessor1); @@ -239,10 +239,11 @@ describe('removeUnusedVertices', function() { gltf.meshes.push(mesh2); // All indices are used, 0 and 2 by the first primitive and 1 by the other - var byteLength = gltf.buffers[0].byteLength + gltf.buffers[1].byteLength + gltf.buffers[2].byteLength; + var attributesBuffer = gltf.buffers[1]; + var byteLength = attributesBuffer.byteLength; removeUnusedVertices(gltf); uninterleaveAndPackBuffers(gltf); - expect(gltf.buffers[0].byteLength).toEqual(byteLength); + expect(attributesBuffer.byteLength).toEqual(byteLength); }); it('handles when primitives use the same accessors along with different accessors with different indices', function() { @@ -279,10 +280,11 @@ describe('removeUnusedVertices', function() { gltf.meshes.push(mesh2); // All indices are used, 0 and 2 by the first primitive and 1 by the other - var byteLength = gltf.buffers[0].byteLength + gltf.buffers[1].byteLength + gltf.buffers[2].byteLength; + var attributesBuffer = gltf.buffers[1]; + var byteLength = attributesBuffer.byteLength; removeUnusedVertices(gltf); uninterleaveAndPackBuffers(gltf); - expect(gltf.buffers[0].byteLength).toEqual(byteLength); + expect(attributesBuffer.byteLength).toEqual(byteLength); }); it('handles when there is a cross-dependency between two groups of primitives', function() { @@ -401,9 +403,11 @@ describe('removeUnusedVertices', function() { }; removeUnusedVertices(gltf); uninterleaveAndPackBuffers(gltf); - var bufferViews = gltf.bufferViews; - expect(bufferViews[0].byteLength).toEqual(attributeDataBuffer1.length + attributeDataBuffer2.length); - expect(bufferViews[1].byteLength).toEqual(indexDataBuffer1.length + indexDataBuffer2.length); + var buffers = gltf.buffers; + expect(buffers[0].extras._pipeline.source).toEqual(attributeDataBuffer1); + expect(buffers[1].extras._pipeline.source).toEqual(attributeDataBuffer2); + expect(buffers[2].extras._pipeline.source).toEqual(indexDataBuffer1); + expect(buffers[3].extras._pipeline.source).toEqual(indexDataBuffer2); }); it('removes parts of the buffer based on the attribute type if the stride is 0', function() { From 81b8b3279901c1fa6726f74c3ec6cd749dc6287f Mon Sep 17 00:00:00 2001 From: Mohamad Moneimne Date: Thu, 20 Jul 2017 10:50:38 -0400 Subject: [PATCH 21/35] Fixed quantizeAttributes tests by changing according to master --- specs/lib/quantizeAttributesSpec.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/specs/lib/quantizeAttributesSpec.js b/specs/lib/quantizeAttributesSpec.js index f9ff6853..f4f46746 100644 --- a/specs/lib/quantizeAttributesSpec.js +++ b/specs/lib/quantizeAttributesSpec.js @@ -143,7 +143,7 @@ describe('quantizeAttributes', function() { gltf.buffers[0].extras._pipeline.source = buffer; quantizeAttributes(gltf, {semantics: []}); uninterleaveAndPackBuffers(gltf); - expect(gltf.buffers[0].byteLength).toEqual(buffer.length + 4); + expect(gltf.buffers[0].byteLength).toEqual(buffer.length); }); it('Doesn\'t quantize excluded semantics', function() { @@ -151,7 +151,7 @@ describe('quantizeAttributes', function() { gltf.buffers[0].extras._pipeline.source = buffer; quantizeAttributes(gltf, {exclude: ['POSITION', 'NORMAL', 'TEXCOORD', 'SCALAR_TEST', 'FLOAT_TEST']}); uninterleaveAndPackBuffers(gltf); - expect(gltf.buffers[0].byteLength).toEqual(buffer.length + 4); + expect(gltf.buffers[0].byteLength).toEqual(buffer.length); }); it('Quantizes attributes for semantic', function() { @@ -164,7 +164,7 @@ describe('quantizeAttributes', function() { gltf.buffers[0].extras._pipeline.source = buffer; quantizeAttributes(gltf, {semantics: ['POSITION']}); uninterleaveAndPackBuffers(gltf); - expect(gltf.buffers[0].byteLength + size).toEqual(buffer.length + 4); + expect(gltf.buffers[0].byteLength + size).toEqual(buffer.length); var decodeMatrix = accessor_0.extensions.WEB3D_quantized_attributes.decodeMatrix; expect(decodeMatrix[0]).toBe(2.0 / 65535.0); }); @@ -182,7 +182,7 @@ describe('quantizeAttributes', function() { normalized : true }); uninterleaveAndPackBuffers(gltf); - expect(gltf.buffers[0].byteLength + size).toEqual(buffer.length + 4); + expect(gltf.buffers[0].byteLength + size).toEqual(buffer.length); expect(accessor_0.normalized).toBeTruthy(); expect(accessor_2.normalized).toBeTruthy(); var decodeMatrix = accessor_0.extensions.WEB3D_quantized_attributes.decodeMatrix; @@ -204,7 +204,7 @@ describe('quantizeAttributes', function() { gltf.buffers[0].extras._pipeline.source = buffer; quantizeAttributes(gltf, {semantics: ['NORMAL']}); uninterleaveAndPackBuffers(gltf); - expect(gltf.buffers[0].byteLength).toEqual(buffer.length + 4); + expect(gltf.buffers[0].byteLength).toEqual(buffer.length); }); it('Doesn\'t quantize already quantized attribute', function() { @@ -212,7 +212,7 @@ describe('quantizeAttributes', function() { gltf.buffers[0].extras._pipeline.source = buffer; quantizeAttributes(gltf, {semantics: ['TEXCOORD']}); uninterleaveAndPackBuffers(gltf); - expect(gltf.buffers[0].byteLength).toEqual(buffer.length + 4); + expect(gltf.buffers[0].byteLength).toEqual(buffer.length); }); it('Quantizes scalar attribute', function() { @@ -223,6 +223,6 @@ describe('quantizeAttributes', function() { gltf.buffers[0].extras._pipeline.source = buffer; quantizeAttributes(gltf, {semantics: ['SCALAR_TEST']}); uninterleaveAndPackBuffers(gltf); - expect(gltf.buffers[0].byteLength + size).toEqual(buffer.length + 4); + expect(gltf.buffers[0].byteLength + size).toEqual(buffer.length); }); }); \ No newline at end of file From ff7af4a723bbb5be2fccf627b4aa6cc382d7e28a Mon Sep 17 00:00:00 2001 From: Mohamad Moneimne Date: Thu, 20 Jul 2017 11:05:37 -0400 Subject: [PATCH 22/35] Fixed mergeDuplicateVertices tests by changing according to master --- specs/lib/mergeDuplicateVerticesSpec.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/specs/lib/mergeDuplicateVerticesSpec.js b/specs/lib/mergeDuplicateVerticesSpec.js index 8ce1ceac..335c9a70 100644 --- a/specs/lib/mergeDuplicateVerticesSpec.js +++ b/specs/lib/mergeDuplicateVerticesSpec.js @@ -97,7 +97,8 @@ describe('mergeDuplicateVertices', function() { reader.next(); i++; } - expect(gltf.buffers[0].byteLength).toEqual(A.length - 24 + B.length - 8 + C.length); + expect(gltf.buffers[0].byteLength).toEqual(A.length - 24); + expect(gltf.buffers[1].byteLength).toEqual(B.length - 8); }); it('merges duplicate vertices with repeated index accessors', function() { @@ -236,6 +237,7 @@ describe('mergeDuplicateVertices', function() { reader.next(); i++; } - expect(gltf.buffers[0].byteLength).toEqual(A.length - 24 + B.length - 8 + A2.length + B2.length + C.length); + expect(gltf.buffers[0].byteLength).toEqual(A.length - 12); + expect(gltf.buffers[2].byteLength).toEqual(B.length - 4); }); }); \ No newline at end of file From abcc18ad6948671b68f4787f4cdf71b853a09a2e Mon Sep 17 00:00:00 2001 From: Mohamad Moneimne Date: Thu, 20 Jul 2017 11:12:40 -0400 Subject: [PATCH 23/35] Fixed generateTangentsBitangents test to account for tangent and bitangent count --- specs/lib/generateTangentsBitangentsSpec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/lib/generateTangentsBitangentsSpec.js b/specs/lib/generateTangentsBitangentsSpec.js index f3703f20..0c63c5a0 100644 --- a/specs/lib/generateTangentsBitangentsSpec.js +++ b/specs/lib/generateTangentsBitangentsSpec.js @@ -94,7 +94,7 @@ describe('generateTangentsBitangents', function(){ uninterleaveAndPackBuffers(gltf); var attributes = gltf.meshes[0].primitives[0].attributes; - var byteLengthAfter = gltf.buffers[0].byteLength; + var byteLengthAfter = gltf.buffers[0].byteLength + gltf.buffers[1].byteLength + gltf.buffers[2].byteLength; expect(attributes.TANGENT).toBeDefined(); expect(attributes.BITANGENT).toBeDefined(); expect(gltf.accessors[attributes.TANGENT]).toBeDefined(); From e2097f9dd5beda73bed768bb3da9ba183821cd99 Mon Sep 17 00:00:00 2001 From: Mohamad Moneimne Date: Fri, 21 Jul 2017 10:31:00 -0400 Subject: [PATCH 24/35] Updated gulpfile and added skinning upgrade to 2.0 --- gulpfile.js | 5 +- lib/bakeAmbientOcclusion.js | 2 +- lib/updateVersion.js | 105 +++++++++++++++++++++++++++--------- 3 files changed, 84 insertions(+), 28 deletions(-) diff --git a/gulpfile.js b/gulpfile.js index d10e983a..90d6fafb 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -287,15 +287,18 @@ gulp.task('build-cesium', function () { 'getAccessorByteStride.js', 'getJointCountForMaterials.js', 'getStatistics.js', + 'glslTypeToWebGLConstant.js', 'numberOfComponentsForType.js', 'parseBinaryGltf.js', 'pbrToMaterialsCommon.js', 'processModelMaterialsCommon.js', + 'processPbrMetallicRoughness.js', 'removePipelineExtras.js', 'removeExtensionsRequired.js', 'removeExtensionsUsed.js', 'techniqueParameterForSemantic.js', - 'updateVersion.js' + 'updateVersion.js', + 'webGLConstantToGlslType.js' ]; var subDependencyMapping = { cesium : { diff --git a/lib/bakeAmbientOcclusion.js b/lib/bakeAmbientOcclusion.js index 95ea88e7..5ab3466c 100644 --- a/lib/bakeAmbientOcclusion.js +++ b/lib/bakeAmbientOcclusion.js @@ -573,7 +573,7 @@ function bakeToTexture(gltf, options) { for (var materialId = 0; materialId < materialsLength; materialId++) { var material = materials[materialId]; if (defined(material.values) && defined(material.values.diffuse)) { - if (isTexture(material.values.diffuse)) { + if (isTexture('diffuse', material.values.diffuse)) { exampleMaterialID = materialId; exampleTextureID = material.values.diffuse; exampleImageID = textures[exampleTextureID].source; diff --git a/lib/updateVersion.js b/lib/updateVersion.js index 83767d28..c78f247f 100644 --- a/lib/updateVersion.js +++ b/lib/updateVersion.js @@ -327,11 +327,7 @@ function objectsToArrays(gltf) { } }); }); - ForEach.skin(gltf, function(skin) { - if (defined(skin.inverseBindMatrices)) { - skin.inverseBindMatrices = globalMapping.accessors[skin.inverseBindMatrices]; - } - }); + var allSkeletons = []; ForEach.node(gltf, function(node) { var children = node.children; if (defined(children)) { @@ -371,17 +367,8 @@ function objectsToArrays(gltf) { var skeletons = node.skeletons; var skeletonsLength = skeletons.length; if (skeletonsLength > 0) { - node.skeleton = globalMapping.nodes[skeletons[0]]; - for (i = 1; i < skeletonsLength; i++) { - var skeletonNode = { - skeleton: globalMapping.nodes[skeletons[i]] - }; - var skeletonNodeId = addToArray(gltf.nodes, skeletonNode); - if (!defined(children)) { - children = []; - node.children = children; - } - children.push(skeletonNodeId); + for (i = 0; i < skeletonsLength; i++) { + allSkeletons.push(globalMapping.nodes[skeletons[i]]); } } delete node.skeletons; @@ -389,6 +376,25 @@ function objectsToArrays(gltf) { if (defined(node.skin)) { node.skin = globalMapping.skins[node.skin]; } + if (defined(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; + for (i = 0; i < jointNames.length; i++) { + var jointNodeIndex = globalMapping.nodes[jointNames[i]]; + joints[i] = jointNodeIndex; + if (allSkeletons.includes(jointNodeIndex)) { + skin.skeleton = jointNodeIndex; + } + } + skin.joints = joints; + delete skin.jointNames; }); ForEach.scene(gltf, function(scene) { var sceneNodes = scene.nodes; @@ -678,19 +684,66 @@ function requireByteLength(gltf) { } function moveByteStrideToBufferView(gltf) { + var bufferViews = gltf.bufferViews; + var bufferViewsToDelete = {}; ForEach.accessor(gltf, function(accessor) { - if (defined(accessor.byteStride)) { - var byteStride = accessor.byteStride; - if (byteStride !== 0) { - var bufferView = gltf.bufferViews[accessor.bufferView]; - if (defined(bufferView.byteStride) && bufferView.byteStride !== byteStride) { - // another accessor uses this with a different byte stride - bufferView = clone(bufferView); - accessor.bufferView = addToArray(gltf.bufferViews, bufferView); + var oldBufferViewId = accessor.bufferView; + if (defined(oldBufferViewId)) { + if (!defined(bufferViewsToDelete[oldBufferViewId])) { + bufferViewsToDelete[oldBufferViewId] = true; + } + var bufferView = clone(bufferViews[oldBufferViewId]); + var accessorByteStride = accessor.byteStride; + if (defined(accessorByteStride)) { + bufferView.byteStride = accessorByteStride; + if (bufferView.byteStride !== 0) { + bufferView.byteLength = accessor.count * bufferView.byteStride; } - bufferView.byteStride = byteStride; + bufferView.byteOffset += accessor.byteOffset; + accessor.byteOffset = 0; + delete accessor.byteStride; } - delete accessor.byteStride; + accessor.bufferView = addToArray(bufferViews, bufferView); + } + }); + + var bufferViewShiftMap = {}; + var bufferViewRemovalCount = 0; + ForEach.bufferView(gltf, function(bufferView, bufferViewId) { + if (defined(bufferViewsToDelete[bufferViewId])) { + bufferViewRemovalCount++; + } else { + bufferViewShiftMap[bufferViewId] = bufferViewId - bufferViewRemovalCount; + } + }); + + var removedCount = 0; + for (var bufferViewId in bufferViewsToDelete) { + if (defined(bufferViewId)) { + var index = parseInt(bufferViewId) - removedCount; + bufferViews.splice(index, 1); + removedCount++; + } + } + + ForEach.accessor(gltf, function(accessor) { + var accessorBufferView = accessor.bufferView; + if (defined(accessorBufferView)) { + accessor.bufferView = bufferViewShiftMap[accessorBufferView]; + } + }); + + ForEach.shader(gltf, function(shader) { + var shaderBufferView = shader.bufferView; + if (defined(shaderBufferView)) { + shader.bufferView = bufferViewShiftMap[shaderBufferView]; + } + }); + + ForEach.image(gltf, function(image) { + var imageBufferView = image.bufferView; + if (defined(imageBufferView)) { + image.bufferView = bufferViewShiftMap[imageBufferView]; } }); } From ccdf46b43554cd6503ddd35539ce23f3ce5a33e2 Mon Sep 17 00:00:00 2001 From: Mohamad Moneimne Date: Fri, 21 Jul 2017 13:44:51 -0400 Subject: [PATCH 25/35] Keep extensions as object instead of array --- lib/updateVersion.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/updateVersion.js b/lib/updateVersion.js index c78f247f..ad3a4382 100644 --- a/lib/updateVersion.js +++ b/lib/updateVersion.js @@ -241,7 +241,7 @@ function objectsToArrays(gltf) { }; // Convert top level objects to arrays for (var topLevelId in gltf) { - if (gltf.hasOwnProperty(topLevelId) && topLevelId !== 'extras' && topLevelId !== 'asset') { + if (gltf.hasOwnProperty(topLevelId) && topLevelId !== 'extras' && topLevelId !== 'asset' && topLevelId !== 'extensions') { var objectMapping = {}; var object = gltf[topLevelId]; if (typeof(object) === 'object' && !Array.isArray(object)) { From a67e5e763859657ec266c14ad20b6db50a07d2b7 Mon Sep 17 00:00:00 2001 From: Mohamad Moneimne Date: Fri, 21 Jul 2017 15:22:55 -0400 Subject: [PATCH 26/35] Should not change materials to arrays for 1.0 --- lib/addDefaults.js | 4 ++-- lib/updateVersion.js | 16 +++------------- 2 files changed, 5 insertions(+), 15 deletions(-) diff --git a/lib/addDefaults.js b/lib/addDefaults.js index 654025be..b30acf8b 100644 --- a/lib/addDefaults.js +++ b/lib/addDefaults.js @@ -388,8 +388,8 @@ function enableDiffuseTransparency(gltf) { // Check if the diffuse texture/color is transparent var diffuse = material.values.diffuse; var diffuseTransparent = false; - if (diffuse.length === 1) { - diffuseTransparent = gltf.images[gltf.textures[diffuse[0]].source].extras._pipeline.transparent; + if (defined(diffuse.index)) { + diffuseTransparent = gltf.images[gltf.textures[diffuse.index].source].extras._pipeline.transparent; } else { diffuseTransparent = diffuse[3] < 1.0; } diff --git a/lib/updateVersion.js b/lib/updateVersion.js index ad3a4382..130dbe24 100644 --- a/lib/updateVersion.js +++ b/lib/updateVersion.js @@ -439,7 +439,9 @@ function objectsToArrays(gltf) { } } else if (typeof value === 'string') { - material.values[name] = [globalMapping.textures[value]]; + material.values[name] = { + index : globalMapping.textures[value] + }; } }); var extensions = material.extensions; @@ -516,16 +518,6 @@ function removeBufferType(gltf) { }); } -function makeMaterialValuesArrays(gltf) { - ForEach.material(gltf, function(material) { - ForEach.materialValue(material, function(value, name) { - if (!Array.isArray(value)) { - material.values[name] = [value]; - } - }); - }); -} - function requireAttributeSetIndex(gltf) { ForEach.mesh(gltf, function(mesh) { ForEach.meshPrimitive(mesh, function(primitive) { @@ -815,8 +807,6 @@ function glTF10to20(gltf) { requireAttributeSetIndex(gltf); // Add underscores to application-specific parameters underscoreApplicationSpecificSemantics(gltf); - // material.values should be arrays - makeMaterialValuesArrays(gltf); // technique.parameters.value should be arrays makeTechniqueValuesArrays(gltf); // remove scissor from techniques From cae42798caa30784fa22aeff978ef98bc95c53e7 Mon Sep 17 00:00:00 2001 From: Mohamad Moneimne Date: Fri, 21 Jul 2017 15:30:07 -0400 Subject: [PATCH 27/35] Only try to switch jointNames over if defined --- lib/updateVersion.js | 16 +++++++++------- specs/lib/updateVersionSpec.js | 2 +- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/lib/updateVersion.js b/lib/updateVersion.js index 130dbe24..94202dff 100644 --- a/lib/updateVersion.js +++ b/lib/updateVersion.js @@ -386,15 +386,17 @@ function objectsToArrays(gltf) { } var joints = []; var jointNames = skin.jointNames; - for (i = 0; i < jointNames.length; i++) { - var jointNodeIndex = globalMapping.nodes[jointNames[i]]; - joints[i] = jointNodeIndex; - if (allSkeletons.includes(jointNodeIndex)) { - skin.skeleton = jointNodeIndex; + if (defined(jointNames)) { + for (i = 0; i < jointNames.length; i++) { + var jointNodeIndex = globalMapping.nodes[jointNames[i]]; + joints[i] = jointNodeIndex; + if (allSkeletons.includes(jointNodeIndex)) { + skin.skeleton = jointNodeIndex; + } } + skin.joints = joints; + delete skin.jointNames; } - skin.joints = joints; - delete skin.jointNames; }); ForEach.scene(gltf, function(scene) { var sceneNodes = scene.nodes; diff --git a/specs/lib/updateVersionSpec.js b/specs/lib/updateVersionSpec.js index 109f2f48..8c1f8738 100644 --- a/specs/lib/updateVersionSpec.js +++ b/specs/lib/updateVersionSpec.js @@ -327,7 +327,7 @@ describe('updateVersion', function() { expect(sampler.output).toEqual(3); expect(animation.parameters).not.toBeDefined(); var material = gltf.materials[0]; - expect(material.values.shininess).toEqual([1.0]); + expect(material.values.shininess).toEqual(1); var technique = gltf.techniques[0]; expect(technique.parameters.lightAttenuation.value).toEqual([1.0]); expect(technique.parameters.application.value).not.toBeDefined(); From 8a444f769c5d6dace47edfaee263e8d3af86caae Mon Sep 17 00:00:00 2001 From: Mohamad Moneimne Date: Fri, 21 Jul 2017 15:46:37 -0400 Subject: [PATCH 28/35] Updated tests to support changes to diffuse texture changes --- .../CesiumTexturedBoxTestTransparent.gltf | 6 ++++-- specs/lib/addDefaultsSpec.js | 4 +++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/specs/data/boxTexturedUnoptimized/CesiumTexturedBoxTestTransparent.gltf b/specs/data/boxTexturedUnoptimized/CesiumTexturedBoxTestTransparent.gltf index a819dae0..f9e2b26f 100644 --- a/specs/data/boxTexturedUnoptimized/CesiumTexturedBoxTestTransparent.gltf +++ b/specs/data/boxTexturedUnoptimized/CesiumTexturedBoxTestTransparent.gltf @@ -102,7 +102,9 @@ "name": "Texture", "technique": 0, "values": { - "diffuse": [0], + "diffuse": { + "index": 0 + }, "shininess": [256], "specular": [ 0.2, @@ -333,4 +335,4 @@ "type": 5121 } ] -} \ No newline at end of file +} diff --git a/specs/lib/addDefaultsSpec.js b/specs/lib/addDefaultsSpec.js index ac03d883..b82fda26 100644 --- a/specs/lib/addDefaultsSpec.js +++ b/specs/lib/addDefaultsSpec.js @@ -136,7 +136,9 @@ describe('addDefaults', function() { materials: [{ values: { ambient: [0, 0, 0, 1], - diffuse: [0], + diffuse: { + index: 0 + }, emission: [1, 0, 0, 1] } }] From 59f4478bd598fa0cd1ab885bbdb639b402eb7ba8 Mon Sep 17 00:00:00 2001 From: Mohamad Moneimne Date: Tue, 25 Jul 2017 16:35:06 -0400 Subject: [PATCH 29/35] Updated per changes in Cesium --- lib/ForEach.js | 16 +++++++++ lib/addDefaults.js | 11 +++++++ lib/parseBinaryGltf.js | 2 +- lib/processModelMaterialsCommon.js | 31 +++++++++++++++--- lib/processPbrMetallicRoughness.js | 52 ++++++++++++++++++++++++++---- lib/updateVersion.js | 9 ++++-- 6 files changed, 105 insertions(+), 16 deletions(-) diff --git a/lib/ForEach.js b/lib/ForEach.js index 54ff5c1e..a9ae98e9 100644 --- a/lib/ForEach.js +++ b/lib/ForEach.js @@ -115,6 +115,22 @@ ForEach.meshPrimitiveAttribute = function(primitive, handler) { } }; +ForEach.meshPrimitiveTargetAttribute = 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); + } + } + } + } + } +}; + ForEach.node = function(gltf, handler) { ForEach.topLevel(gltf, 'nodes', handler); }; diff --git a/lib/addDefaults.js b/lib/addDefaults.js index b30acf8b..485cf659 100644 --- a/lib/addDefaults.js +++ b/lib/addDefaults.js @@ -489,6 +489,17 @@ function inferBufferViewTargets(gltf) { } } }); + 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; diff --git a/lib/parseBinaryGltf.js b/lib/parseBinaryGltf.js index 89e84af1..c611f323 100644 --- a/lib/parseBinaryGltf.js +++ b/lib/parseBinaryGltf.js @@ -87,7 +87,7 @@ function parseBinaryGltf(data) { byteOffset += chunkLength; // Load JSON chunk if (chunkType === 0x4E4F534A) { - var jsonString = chunkBuffer.toString(); + var jsonString = getStringFromTypedArray(chunkBuffer); gltf = JSON.parse(jsonString); addPipelineExtras(gltf); } diff --git a/lib/processModelMaterialsCommon.js b/lib/processModelMaterialsCommon.js index a75da3a8..d2c03488 100644 --- a/lib/processModelMaterialsCommon.js +++ b/lib/processModelMaterialsCommon.js @@ -65,7 +65,7 @@ function processModelMaterialsCommon(gltf, options) { var techniqueKey = getTechniqueKey(khrMaterialsCommon); var technique = techniques[techniqueKey]; if (!defined(technique)) { - technique = generateTechnique(gltf, khrMaterialsCommon, lightParameters, options.optimizeForCesium); + technique = generateTechnique(gltf, khrMaterialsCommon, lightParameters, options); techniques[techniqueKey] = technique; } @@ -218,7 +218,11 @@ function generateLightParameters(gltf) { return result; } -function generateTechnique(gltf, khrMaterialsCommon, lightParameters, optimizeForCesium) { +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); + var techniques = gltf.techniques; var shaders = gltf.shaders; var programs = gltf.programs; @@ -228,6 +232,12 @@ function generateTechnique(gltf, khrMaterialsCommon, lightParameters, optimizeFo 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 hasSkinning = jointCount > 0; @@ -245,7 +255,7 @@ function generateTechnique(gltf, khrMaterialsCommon, lightParameters, optimizeFo var techniqueParameters = { // Add matrices modelViewMatrix: { - semantic: 'MODELVIEW', + semantic: hasCesiumRTCExtension ? 'CESIUM_RTC_MODELVIEW' : 'MODELVIEW', type: WebGLConstants.FLOAT_MAT4 }, projectionMatrix: { @@ -424,6 +434,15 @@ function generateTechnique(gltf, khrMaterialsCommon, lightParameters, optimizeFo vertexShader += 'attribute ' + attributeType + ' a_weight;\n'; } + if (addBatchIdToGeneratedShaders) { + techniqueAttributes.a_batchId = 'batchId'; + techniqueParameters.batchId = { + semantic: '_BATCHID', + type: WebGLConstants.FLOAT + }; + vertexShader += 'attribute float a_batchId;\n'; + } + var hasSpecular = hasNormals && ((lightingModel === 'BLINN') || (lightingModel === 'PHONG')) && defined(techniqueParameters.specular) && defined(techniqueParameters.shininess); @@ -693,6 +712,8 @@ function getKHRMaterialsCommonValueType(paramName, paramValue) { // materials using KHR_materials_common with explicit type/value members if (defined(paramValue.value)) { value = paramValue.value; + } else if (defined(paramValue.index)) { + value = [paramValue.index]; } else { value = paramValue; } @@ -735,9 +756,9 @@ function getTechniqueKey(khrMaterialsCommon) { } } - var doubleSided = defaultValue(khrMaterialsCommon.doubleSided, false); + var doubleSided = defaultValue(khrMaterialsCommon.doubleSided, defaultValue(khrMaterialsCommon.values.doubleSided, false)); techniqueKey += doubleSided.toString() + ';'; - var transparent = defaultValue(khrMaterialsCommon.transparent, false); + var transparent = defaultValue(khrMaterialsCommon.transparent, defaultValue(khrMaterialsCommon.values.transparent, false)); techniqueKey += transparent.toString() + ';'; var jointCount = defaultValue(khrMaterialsCommon.jointCount, 0); techniqueKey += jointCount.toString() + ';'; diff --git a/lib/processPbrMetallicRoughness.js b/lib/processPbrMetallicRoughness.js index 0631ae0c..d7923ffa 100644 --- a/lib/processPbrMetallicRoughness.js +++ b/lib/processPbrMetallicRoughness.js @@ -430,17 +430,18 @@ function generateTechnique(gltf, material, optimizeForCesium) { // Add base color to fragment shader if (defined(parameterValues.baseColorTexture)) { - fragmentShader += ' vec3 baseColor = texture2D(u_baseColorTexture, ' + v_texcoord + ').rgb;\n'; + fragmentShader += ' vec4 baseColorWithAlpha = texture2D(u_baseColorTexture, ' + v_texcoord + ');\n'; if (defined(parameterValues.baseColorFactor)) { - fragmentShader += ' baseColor *= u_baseColorFactor.rgb;\n'; + fragmentShader += ' baseColorWithAlpha *= u_baseColorFactor;\n'; } } else { if (defined(parameterValues.baseColorFactor)) { - fragmentShader += ' vec3 baseColor = u_baseColorFactor.rgb;\n'; + fragmentShader += ' vec4 baseColorWithAlpha = u_baseColorFactor;\n'; } else { - fragmentShader += ' vec3 baseColor = vec3(1.0);\n'; + fragmentShader += ' vec4 baseColorWithAlpha = vec4(1.0);\n'; } } + fragmentShader += ' vec3 baseColor = baseColorWithAlpha.rgb;\n'; // Add metallic-roughness to fragment shader if (defined(parameterValues.metallicRoughnessTexture)) { fragmentShader += ' vec3 metallicRoughness = texture2D(u_metallicRoughnessTexture, ' + v_texcoord + ').rgb;\n'; @@ -467,7 +468,7 @@ function generateTechnique(gltf, material, optimizeForCesium) { fragmentShader += ' vec3 v = -normalize(v_positionEC);\n'; // Generate fragment shader's lighting block - fragmentShader += ' vec3 lightColor = vec3(1.0, 1.0, 1.0);\n'; + fragmentShader += ' vec3 lightColor = vec3(1.0, 1.0, 1.0) * 2.0;\n'; if (optimizeForCesium) { fragmentShader += ' vec3 l = normalize(czm_sunDirectionEC);\n'; } else { @@ -523,11 +524,48 @@ function generateTechnique(gltf, material, optimizeForCesium) { } // Final color - fragmentShader += ' gl_FragColor = vec4(color, 1.0);\n'; + var alphaMode = material.alphaMode; + if (defined(alphaMode)) { + if (alphaMode === 'MASK') { + var alphaCutoff = material.alphaCutoff; + if (defined(alphaCutoff)) { + fragmentShader += ' gl_FragColor = vec4(color, int(baseColorWithAlpha.a >= ' + alphaCutoff + '));\n'; + } else { + fragmentShader += ' gl_FragColor = vec4(color, 1.0);\n'; + } + } else if (alphaMode === 'BLEND') { + fragmentShader += ' gl_FragColor = vec4(color, baseColorWithAlpha.a);\n'; + } else { + fragmentShader += ' gl_FragColor = vec4(color, 1.0);\n'; + } + } else { + fragmentShader += ' gl_FragColor = vec4(color, 1.0);\n'; + } fragmentShader += '}\n'; + console.log(fragmentShader); var techniqueStates; - if (parameterValues.doubleSided) { + if (defined(alphaMode) && alphaMode !== 'OPAQUE') { + 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 (parameterValues.doubleSided) { techniqueStates = { enable : [ WebGLConstants.DEPTH_TEST diff --git a/lib/updateVersion.js b/lib/updateVersion.js index 94202dff..bf5dd97d 100644 --- a/lib/updateVersion.js +++ b/lib/updateVersion.js @@ -4,6 +4,7 @@ var addExtensionsRequired = require('./addExtensionsRequired'); var addToArray = require('./addToArray'); var findAccessorMinMax = require('./findAccessorMinMax'); var ForEach = require('./ForEach'); +var getAccessorByteStride = require('./getAccessorByteStride'); var Cartesian3 = Cesium.Cartesian3; var CesiumMath = Cesium.Math; @@ -460,7 +461,9 @@ function objectsToArrays(gltf) { } } else if (typeof value === 'string') { - materialsCommon.values[name] = [globalMapping.textures[value]]; + materialsCommon.values[name] = { + index: globalMapping.textures[value] + }; } }); } @@ -687,11 +690,11 @@ function moveByteStrideToBufferView(gltf) { bufferViewsToDelete[oldBufferViewId] = true; } var bufferView = clone(bufferViews[oldBufferViewId]); - var accessorByteStride = accessor.byteStride; + var accessorByteStride = getAccessorByteStride(gltf, accessor); if (defined(accessorByteStride)) { bufferView.byteStride = accessorByteStride; if (bufferView.byteStride !== 0) { - bufferView.byteLength = accessor.count * bufferView.byteStride; + bufferView.byteLength = accessor.count * accessorByteStride; } bufferView.byteOffset += accessor.byteOffset; accessor.byteOffset = 0; From f24ef8aca241e30320b046a224bd59d28f624ba1 Mon Sep 17 00:00:00 2001 From: Mohamad Moneimne Date: Wed, 26 Jul 2017 09:29:32 -0400 Subject: [PATCH 30/35] Another update per Cesium changes --- lib/findAccessorMinMax.js | 5 +++-- lib/parseBinaryGltf.js | 11 ++++++++--- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/lib/findAccessorMinMax.js b/lib/findAccessorMinMax.js index e13a12d2..aecd1edc 100644 --- a/lib/findAccessorMinMax.js +++ b/lib/findAccessorMinMax.js @@ -1,6 +1,7 @@ 'use strict'; var Cesium = require('cesium'); +var arrayFill = Cesium.arrayFill; var ComponentDatatype = Cesium.ComponentDatatype; var defined = Cesium.defined; @@ -26,8 +27,8 @@ function findAccessorMinMax(gltf, accessor) { var buffers = gltf.buffers; var bufferViewId = accessor.bufferView; var numberOfComponents = numberOfComponentsForType(accessor.type); - var min = new Array(numberOfComponents).fill(Number.POSITIVE_INFINITY); - var max = new Array(numberOfComponents).fill(Number.NEGATIVE_INFINITY); + 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; diff --git a/lib/parseBinaryGltf.js b/lib/parseBinaryGltf.js index c611f323..ec8e529c 100644 --- a/lib/parseBinaryGltf.js +++ b/lib/parseBinaryGltf.js @@ -47,10 +47,15 @@ function parseBinaryGltf(data) { if (contentFormat !== 0) { throw new DeveloperError('Binary glTF scene format is not JSON'); } - var contentString = getStringFromTypedArray(data.slice(20, 20 + contentLength)); + var contentString = getStringFromTypedArray(data, 20, contentLength); gltf = JSON.parse(contentString); - var binaryData = data.slice(20 + contentLength, length); + // Clone the binary data into a new typed array to avoid keeping the whole ArrayBuffer in memory. + var binaryStart = 20 + contentLength; + var binaryLength = length - binaryStart; + var binaryData = new Uint8Array(binaryLength); + binaryData.set(data.subarray(binaryStart)); + buffers = gltf.buffers; if (defined(buffers) && Object.keys(buffers).length > 0) { var binaryGltfBuffer = buffers.binary_glTF; @@ -83,7 +88,7 @@ function parseBinaryGltf(data) { var chunkLength = chunkHeaderView[0]; var chunkType = chunkHeaderView[1]; byteOffset += 8; - var chunkBuffer = data.slice(byteOffset, byteOffset + chunkLength); + var chunkBuffer = new Uint8Array(data.buffer, data.byteOffset + byteOffset, chunkLength); byteOffset += chunkLength; // Load JSON chunk if (chunkType === 0x4E4F534A) { From b10c842a1904b756f54d40cc9450b0e39bb97cb3 Mon Sep 17 00:00:00 2001 From: Mohamad Moneimne Date: Wed, 26 Jul 2017 09:50:49 -0400 Subject: [PATCH 31/35] Removed print statement --- lib/processPbrMetallicRoughness.js | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/processPbrMetallicRoughness.js b/lib/processPbrMetallicRoughness.js index d7923ffa..509c2328 100644 --- a/lib/processPbrMetallicRoughness.js +++ b/lib/processPbrMetallicRoughness.js @@ -542,7 +542,6 @@ function generateTechnique(gltf, material, optimizeForCesium) { fragmentShader += ' gl_FragColor = vec4(color, 1.0);\n'; } fragmentShader += '}\n'; - console.log(fragmentShader); var techniqueStates; if (defined(alphaMode) && alphaMode !== 'OPAQUE') { From 1ae7781e5df812b12d320802987e46d40778e9cc Mon Sep 17 00:00:00 2001 From: Mohamad Moneimne Date: Wed, 26 Jul 2017 10:54:11 -0400 Subject: [PATCH 32/35] Updated per Cesium cmpt tiles fix --- lib/parseBinaryGltf.js | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/lib/parseBinaryGltf.js b/lib/parseBinaryGltf.js index ec8e529c..ed0bc3ca 100644 --- a/lib/parseBinaryGltf.js +++ b/lib/parseBinaryGltf.js @@ -47,14 +47,15 @@ function parseBinaryGltf(data) { if (contentFormat !== 0) { throw new DeveloperError('Binary glTF scene format is not JSON'); } - var contentString = getStringFromTypedArray(data, 20, contentLength); + + var jsonStart = 20; + var binaryStart = jsonStart + contentLength; + + var contentString = getStringFromTypedArray(data, jsonStart, contentLength); gltf = JSON.parse(contentString); - // Clone the binary data into a new typed array to avoid keeping the whole ArrayBuffer in memory. - var binaryStart = 20 + contentLength; - var binaryLength = length - binaryStart; - var binaryData = new Uint8Array(binaryLength); - binaryData.set(data.subarray(binaryStart)); + // Clone just the binary chunk so the underlying buffer can be freed + var binaryData = new Uint8Array(data.subarray(binaryStart, length)); buffers = gltf.buffers; if (defined(buffers) && Object.keys(buffers).length > 0) { @@ -88,7 +89,7 @@ function parseBinaryGltf(data) { var chunkLength = chunkHeaderView[0]; var chunkType = chunkHeaderView[1]; byteOffset += 8; - var chunkBuffer = new Uint8Array(data.buffer, data.byteOffset + byteOffset, chunkLength); + var chunkBuffer = data.subarray(byteOffset, byteOffset + chunkLength); byteOffset += chunkLength; // Load JSON chunk if (chunkType === 0x4E4F534A) { @@ -98,7 +99,8 @@ function parseBinaryGltf(data) { } // Load Binary chunk else if (chunkType === 0x004E4942) { - binaryBuffer = chunkBuffer; + // Clone just the binary chunk so the underlying buffer can be freed + binaryBuffer = new Uint8Array(chunkBuffer); } } if (defined(gltf) && defined(binaryBuffer)) { From bacada92e18c0c5293bc110b74d0c8ee688a8669 Mon Sep 17 00:00:00 2001 From: Ed Mackey Date: Thu, 27 Jul 2017 15:09:07 -0400 Subject: [PATCH 33/35] Emulate the Earth with a set of gradients. --- lib/processPbrMetallicRoughness.js | 59 ++++++++++++++++++++++++++---- 1 file changed, 51 insertions(+), 8 deletions(-) diff --git a/lib/processPbrMetallicRoughness.js b/lib/processPbrMetallicRoughness.js index 509c2328..f5e6e9c0 100644 --- a/lib/processPbrMetallicRoughness.js +++ b/lib/processPbrMetallicRoughness.js @@ -231,6 +231,9 @@ function generateTechnique(gltf, material, optimizeForCesium) { }; vertexShader += 'attribute vec3 a_position;\n'; vertexShader += 'varying vec3 v_positionEC;\n'; + if (optimizeForCesium) { + vertexShader += 'varying vec3 v_positionWC;\n'; + } // Morph Target Weighting vertexShaderMain += ' vec3 weightedPosition = a_position;\n'; @@ -266,13 +269,20 @@ function generateTechnique(gltf, material, optimizeForCesium) { // Final position computation if (hasSkinning) { - vertexShaderMain += ' vec4 position = u_modelViewMatrix * skinMatrix * vec4(weightedPosition, 1.0);\n'; + vertexShaderMain += ' vec4 position = skinMatrix * vec4(weightedPosition, 1.0);\n'; } else { - vertexShaderMain += ' vec4 position = u_modelViewMatrix * vec4(weightedPosition, 1.0);\n'; + vertexShaderMain += ' vec4 position = vec4(weightedPosition, 1.0);\n'; } + if (optimizeForCesium) { + vertexShaderMain += ' v_positionWC = (czm_model * position).xyz;\n'; + } + vertexShaderMain += ' position = u_modelViewMatrix * position;\n'; vertexShaderMain += ' v_positionEC = position.xyz;\n'; vertexShaderMain += ' gl_Position = u_projectionMatrix * position;\n'; fragmentShader += 'varying vec3 v_positionEC;\n'; + if (optimizeForCesium) { + fragmentShader += 'varying vec3 v_positionWC;\n'; + } // Final normal computation if (hasNormals) { @@ -468,14 +478,27 @@ function generateTechnique(gltf, material, optimizeForCesium) { fragmentShader += ' vec3 v = -normalize(v_positionEC);\n'; // Generate fragment shader's lighting block - fragmentShader += ' vec3 lightColor = vec3(1.0, 1.0, 1.0) * 2.0;\n'; + fragmentShader += ' vec3 lightColor = vec3(1.0, 1.0, 1.0);\n'; if (optimizeForCesium) { fragmentShader += ' vec3 l = normalize(czm_sunDirectionEC);\n'; } else { fragmentShader += ' vec3 l = vec3(0.0, 0.0, 1.0);\n'; } fragmentShader += ' vec3 h = normalize(v + l);\n'; - fragmentShader += ' vec3 r = normalize(reflect(v, n));\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 - 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 += ' 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'; @@ -499,12 +522,32 @@ function generateTechnique(gltf, material, optimizeForCesium) { fragmentShader += ' vec3 color = NdotL * lightColor * (diffuseContribution + specularContribution);\n'; if (optimizeForCesium) { - fragmentShader += ' vec3 diffuseIrradiance = vec3(0.5);\n'; - fragmentShader += ' vec3 specularIrradiance = textureCube(czm_cubeMap, r).rgb;\n'; - fragmentShader += ' specularIrradiance = mix(specularIrradiance, diffuseIrradiance, roughness);\n'; // Fake LOD + fragmentShader += ' float inverseRoughness = 1.0 - roughness;\n'; + fragmentShader += ' inverseRoughness *= inverseRoughness;\n'; + fragmentShader += ' vec3 sceneSkyBox = textureCube(czm_cubeMap, 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 farAboveHorizon = clamp(horizonDotNadir - blendRegionSize * 0.5, 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 += ' float lightScale = smoothstepHeight * 1.5 + 1.0;\n'; + + fragmentShader += ' vec3 diffuseIrradiance = mix(vec3(0.5), vec3(0.05), smoothstepHeight);\n'; + fragmentShader += ' vec3 belowHorizonColor = mix(vec3(0.1, 0.2, 0.4), vec3(0.2, 0.5, 0.7), smoothstepHeight);\n'; + fragmentShader += ' vec3 nadirColor = belowHorizonColor * 0.5;\n'; + fragmentShader += ' vec3 aboveHorizonColor = vec3(0.8, 0.9, 0.95);\n'; + fragmentShader += ' vec3 blueSkyColor = mix(vec3(0.09, 0.13, 0.24), aboveHorizonColor, reflectionDotNadir * inverseRoughness * 0.5 + 0.5);\n'; + fragmentShader += ' vec3 zenithColor = mix(blueSkyColor, sceneSkyBox, smoothstepHeight);\n'; + + fragmentShader += ' vec3 specularIrradiance = mix(zenithColor, aboveHorizonColor, smoothstep(farAboveHorizon, aroundHorizon, reflectionDotNadir) * inverseRoughness);\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 * (specularColor * brdfLUT.x + brdfLUT.y));\n'; - fragmentShader += ' color += IBLColor;\n'; + fragmentShader += ' color = color * lightScale + IBLColor;\n'; } if (defined(parameterValues.occlusionTexture)) { From bf832116403fa28c5271ebc6b3036ff20639ec95 Mon Sep 17 00:00:00 2001 From: Mohamad Moneimne Date: Mon, 7 Aug 2017 09:32:32 -0400 Subject: [PATCH 34/35] Updated per changes to Cesium for gltf-2.0 PR --- lib/addDefaults.js | 92 ++++++--------------- lib/processPbrMetallicRoughness.js | 128 ++++++++++++++--------------- lib/updateVersion.js | 51 ++++++++---- 3 files changed, 120 insertions(+), 151 deletions(-) diff --git a/lib/addDefaults.js b/lib/addDefaults.js index 485cf659..5b459303 100644 --- a/lib/addDefaults.js +++ b/lib/addDefaults.js @@ -267,17 +267,17 @@ var defaultVertexShader = { _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' + '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' } } }; @@ -288,14 +288,14 @@ var defaultFragmentShader = { _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' + 'precision highp float;\n' + + '\n' + + 'uniform vec4 u_emission;\n' + + '\n' + + 'void main(void)\n' + + '{\n' + + ' gl_FragColor = u_emission;\n' + + '}\n' } } }; @@ -360,7 +360,8 @@ function addDefaultTechnique(gltf) { function addDefaultByteOffsets(gltf) { var accessors = gltf.accessors; - for (var i = 0; i < accessors.length; i++) { + var accessorLength = accessors.length; + for (var i = 0; i < accessorLength; i++) { var accessor = accessors[i]; if (!defined(accessor.byteOffset)) { accessor.byteOffset = 0; @@ -369,7 +370,8 @@ function addDefaultByteOffsets(gltf) { var bufferViews = gltf.bufferViews; - for (var j = 0; j < bufferViews.length; j++) { + var bufferViewsLength = bufferViews.length; + for (var j = 0; j < bufferViewsLength; j++) { var bufferView = bufferViews[j]; if (!defined(bufferView.byteOffset)) { bufferView.byteOffset = 0; @@ -377,53 +379,6 @@ function addDefaultByteOffsets(gltf) { } } -function enableDiffuseTransparency(gltf) { - var materials = gltf.materials; - var techniques = gltf.techniques; - - var materialsLength = materials.length; - for (var materialId = 0; materialId < materialsLength; materialId++) { - var material = materials[materialId]; - if (defined(material.values) && defined(material.values.diffuse)) { - // Check if the diffuse texture/color is transparent - var diffuse = material.values.diffuse; - var diffuseTransparent = false; - if (defined(diffuse.index)) { - diffuseTransparent = gltf.images[gltf.textures[diffuse.index].source].extras._pipeline.transparent; - } else { - diffuseTransparent = diffuse[3] < 1.0; - } - - var technique = techniques[material.technique]; - var blendingEnabled = technique.states.enable.indexOf(WebGLConstants.BLEND) > -1; - - // Override the technique's states if blending isn't already enabled - if (diffuseTransparent && !blendingEnabled) { - technique.states = { - enable: [ - WebGLConstants.DEPTH_TEST, - WebGLConstants.BLEND - ], - depthMask: false, - functions: { - blendEquationSeparate: [ - WebGLConstants.FUNC_ADD, - WebGLConstants.FUNC_ADD - ], - blendFuncSeparate: [ - WebGLConstants.ONE, - WebGLConstants.ONE_MINUS_SRC_ALPHA, - WebGLConstants.ONE, - WebGLConstants.ONE_MINUS_SRC_ALPHA - ] - } - }; - } - - } - } -} - function selectDefaultScene(gltf) { var scenes = gltf.scenes; @@ -527,7 +482,6 @@ function addDefaults(gltf, options) { addDefaultMaterial(gltf); addDefaultTechnique(gltf); addDefaultByteOffsets(gltf); - enableDiffuseTransparency(gltf); selectDefaultScene(gltf); inferBufferViewTargets(gltf); if (options.optimizeForCesium) { diff --git a/lib/processPbrMetallicRoughness.js b/lib/processPbrMetallicRoughness.js index f5e6e9c0..11acb46e 100644 --- a/lib/processPbrMetallicRoughness.js +++ b/lib/processPbrMetallicRoughness.js @@ -22,7 +22,7 @@ function processPbrMetallicRoughness(gltf, options) { var hasPbrMetallicRoughness = false; ForEach.material(gltf, function(material) { - if (material.hasOwnProperty('pbrMetallicRoughness')) { + if (defined(material.pbrMetallicRoughness)) { hasPbrMetallicRoughness = true; } }); @@ -46,20 +46,14 @@ function processPbrMetallicRoughness(gltf, options) { } var materials = []; ForEach.material(gltf, function(material) { - if (material.hasOwnProperty('pbrMetallicRoughness')) { + if (defined(material.pbrMetallicRoughness)) { var pbrMetallicRoughness = material.pbrMetallicRoughness; - var technique = generateTechnique(gltf, material, options.optimizeForCesium); + var technique = generateTechnique(gltf, material, options); - var values = pbrMetallicRoughness; - for (var valueName in values) { - if (values.hasOwnProperty(valueName)) { - var value = values[valueName]; - values[valueName] = value; - } - } - - var newMaterial = {values : values}; - newMaterial.technique = technique; + var newMaterial = { + values : pbrMetallicRoughness, + technique : technique + }; materials.push(newMaterial); } }); @@ -73,7 +67,11 @@ function processPbrMetallicRoughness(gltf, options) { return gltf; } -function generateTechnique(gltf, material, optimizeForCesium) { +function generateTechnique(gltf, material, 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; @@ -94,11 +92,8 @@ function generateTechnique(gltf, material, optimizeForCesium) { } var joints = (defined(skin)) ? skin.joints : []; var jointCount = joints.length; - var hasSkinning = jointCount > 0; - var skinningInfo = {}; - if (hasSkinning) { - skinningInfo = material.extras._pipeline.skinning; - } + var skinningInfo = material.extras._pipeline.skinning; + var hasSkinning = defined(skinningInfo.type); var hasNormals = true; var hasTangents = false; @@ -124,7 +119,7 @@ function generateTechnique(gltf, material, optimizeForCesium) { var techniqueParameters = { // Add matrices modelViewMatrix : { - semantic : 'MODELVIEW', + semantic : hasCesiumRTCExtension ? 'CESIUM_RTC_MODELVIEW' : 'MODELVIEW', type : WebGLConstants.FLOAT_MAT4 }, projectionMatrix : { @@ -353,6 +348,15 @@ function generateTechnique(gltf, material, optimizeForCesium) { vertexShader += 'attribute ' + attributeType + ' a_weight;\n'; } + if (addBatchIdToGeneratedShaders) { + techniqueAttributes.a_batchId = 'batchId'; + techniqueParameters.batchId = { + semantic: '_BATCHID', + type: WebGLConstants.FLOAT + }; + vertexShader += 'attribute float a_batchId;\n'; + } + vertexShader += 'void main(void) \n{\n'; vertexShader += vertexShaderMain; vertexShader += '}\n'; @@ -360,40 +364,38 @@ function generateTechnique(gltf, material, optimizeForCesium) { // Fragment shader lighting fragmentShader += 'const float M_PI = 3.141592653589793;\n'; - var lambertianDiffuse = 'vec3 lambertianDiffuse(vec3 baseColor) \n' + - '{\n' + - ' return baseColor / M_PI;\n' + - '}\n\n'; - - var fresnelSchlick2 = 'vec3 fresnelSchlick2(vec3 f0, vec3 f90, float VdotH) \n' + - '{\n' + - ' return f0 + (f90 - f0) * pow(clamp(1.0 - VdotH, 0.0, 1.0), 5.0);\n' + - '}\n\n'; - - var fresnelSchlick = 'vec3 fresnelSchlick(float metalness, float VdotH) \n' + - '{\n' + - ' return metalness + (vec3(1.0) - metalness) * pow(1.0 - VdotH, 5.0);\n' + - '}\n\n'; - - var smithVisibilityG1 = 'float smithVisibilityG1(float NdotV, float roughness) \n' + - '{\n' + - ' float k = (roughness + 1.0) * (roughness + 1.0) / 8.0;\n' + - ' return NdotV / (NdotV * (1.0 - k) + k);\n' + - '}\n\n'; - - var smithVisibilityGGX = 'float smithVisibilityGGX(float roughness, float NdotL, float NdotV) \n' + - '{\n' + - ' return smithVisibilityG1(NdotL, roughness) * smithVisibilityG1(NdotV, roughness);\n' + - '}\n\n'; - - var GGX = 'float GGX(float roughness, float NdotH) \n' + - '{\n' + - ' float roughnessSquared = roughness * roughness;\n' + - ' float f = (NdotH * roughnessSquared - NdotH) * NdotH + 1.0;\n' + - ' return roughnessSquared / (M_PI * f * f);\n' + - '}\n\n'; - - fragmentShader += lambertianDiffuse + fresnelSchlick2 + fresnelSchlick + smithVisibilityG1 + smithVisibilityGGX + GGX; + fragmentShader += 'vec3 lambertianDiffuse(vec3 baseColor) \n' + + '{\n' + + ' return baseColor / M_PI;\n' + + '}\n\n'; + + fragmentShader += 'vec3 fresnelSchlick2(vec3 f0, vec3 f90, float VdotH) \n' + + '{\n' + + ' return f0 + (f90 - f0) * pow(clamp(1.0 - VdotH, 0.0, 1.0), 5.0);\n' + + '}\n\n'; + + fragmentShader += 'vec3 fresnelSchlick(float metalness, float VdotH) \n' + + '{\n' + + ' return metalness + (vec3(1.0) - metalness) * pow(1.0 - VdotH, 5.0);\n' + + '}\n\n'; + + fragmentShader += 'float smithVisibilityG1(float NdotV, float roughness) \n' + + '{\n' + + ' float k = (roughness + 1.0) * (roughness + 1.0) / 8.0;\n' + + ' return NdotV / (NdotV * (1.0 - k) + k);\n' + + '}\n\n'; + + fragmentShader += 'float smithVisibilityGGX(float roughness, float NdotL, float NdotV) \n' + + '{\n' + + ' return smithVisibilityG1(NdotL, roughness) * smithVisibilityG1(NdotV, roughness);\n' + + '}\n\n'; + + fragmentShader += 'float GGX(float roughness, float NdotH) \n' + + '{\n' + + ' float roughnessSquared = roughness * roughness;\n' + + ' float f = (NdotH * roughnessSquared - NdotH) * NdotH + 1.0;\n' + + ' return roughnessSquared / (M_PI * f * f);\n' + + '}\n\n'; fragmentShader += 'void main(void) \n{\n'; @@ -410,7 +412,10 @@ function generateTechnique(gltf, material, optimizeForCesium) { fragmentShader += ' n = normalize(tbn * (2.0 * n - 1.0));\n'; } else { // Add standard derivatives extension - fragmentShader = '#ifdef GL_OES_standard_derivatives\n#extension GL_OES_standard_derivatives : enable\n#endif\n' + fragmentShader; + fragmentShader = '#ifdef GL_OES_standard_derivatives\n' + + '#extension GL_OES_standard_derivatives : enable\n' + + '#endif\n' + + fragmentShader; // Compute tangents fragmentShader += '#ifdef GL_OES_standard_derivatives\n'; fragmentShader += ' vec3 pos_dx = dFdx(v_positionEC);\n'; @@ -524,7 +529,7 @@ function generateTechnique(gltf, material, optimizeForCesium) { if (optimizeForCesium) { fragmentShader += ' float inverseRoughness = 1.0 - roughness;\n'; fragmentShader += ' inverseRoughness *= inverseRoughness;\n'; - fragmentShader += ' vec3 sceneSkyBox = textureCube(czm_cubeMap, r).rgb * 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'; @@ -545,8 +550,8 @@ function generateTechnique(gltf, material, optimizeForCesium) { 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 * (specularColor * brdfLUT.x + brdfLUT.y));\n'; + fragmentShader += ' vec2 brdfLut = texture2D(czm_brdfLut, vec2(NdotV, 1.0 - roughness)).rg;\n'; + fragmentShader += ' vec3 IBLColor = (diffuseIrradiance * diffuseColor) + (specularIrradiance * (specularColor * brdfLut.x + brdfLut.y));\n'; fragmentShader += ' color = color * lightScale + IBLColor;\n'; } @@ -665,13 +670,6 @@ function generateTechnique(gltf, material, optimizeForCesium) { function getPBRValueType(paramName, paramValue) { var value; - // Backwards compatibility for COLLADA2GLTF v1.0-draft - if (defined(paramValue.value)) { - value = paramValue.value; - } else { - value = paramValue; - } - switch (paramName) { case 'baseColorFactor': return WebGLConstants.FLOAT_VEC4; diff --git a/lib/updateVersion.js b/lib/updateVersion.js index bf5dd97d..22f6a19e 100644 --- a/lib/updateVersion.js +++ b/lib/updateVersion.js @@ -208,7 +208,6 @@ function removeAnimationSamplersIndirection(gltf) { } } - function objectToArray(object, mapping) { var array = []; for (var id in object) { @@ -240,6 +239,20 @@ function objectsToArrays(gltf) { skins: {}, techniques: {} }; + + // Map joint names to id names + var jointName; + var jointNameToId = {}; + var nodes = gltf.nodes; + for (var id in nodes) { + if (nodes.hasOwnProperty(id)) { + jointName = nodes[id].jointName; + if (defined(jointName)) { + jointNameToId[jointName] = id; + } + } + } + // Convert top level objects to arrays for (var topLevelId in gltf) { if (gltf.hasOwnProperty(topLevelId) && topLevelId !== 'extras' && topLevelId !== 'asset' && topLevelId !== 'extensions') { @@ -256,6 +269,14 @@ function objectsToArrays(gltf) { } } } + + // Remap joint names to array indexes + for (jointName in jointNameToId) { + if (jointNameToId.hasOwnProperty(jointName)) { + jointNameToId[jointName] = globalMapping.nodes[jointNameToId[jointName]]; + } + } + // Fix references if (defined(gltf.scene)) { gltf.scene = globalMapping.scenes[gltf.scene]; @@ -328,7 +349,6 @@ function objectsToArrays(gltf) { } }); }); - var allSkeletons = []; ForEach.node(gltf, function(node) { var children = node.children; if (defined(children)) { @@ -364,13 +384,12 @@ function objectsToArrays(gltf) { node.camera = globalMapping.cameras[node.camera]; } if (defined(node.skeletons)) { - // Split out skeletons on nodes + // Assign skeletons to skins var skeletons = node.skeletons; var skeletonsLength = skeletons.length; - if (skeletonsLength > 0) { - for (i = 0; i < skeletonsLength; i++) { - allSkeletons.push(globalMapping.nodes[skeletons[i]]); - } + if ((skeletonsLength > 0) && defined(node.skin)) { + var skin = gltf.skins[globalMapping.skins[node.skin]]; + skin.skeleton = globalMapping.nodes[skeletons[0]]; } delete node.skeletons; } @@ -389,11 +408,7 @@ function objectsToArrays(gltf) { var jointNames = skin.jointNames; if (defined(jointNames)) { for (i = 0; i < jointNames.length; i++) { - var jointNodeIndex = globalMapping.nodes[jointNames[i]]; - joints[i] = jointNodeIndex; - if (allSkeletons.includes(jointNodeIndex)) { - skin.skeleton = jointNodeIndex; - } + joints[i] = jointNameToId[jointNames[i]]; } skin.joints = joints; delete skin.jointNames; @@ -581,8 +596,10 @@ function underscoreApplicationSpecificSemantics(gltf) { if (mappedSemantics.hasOwnProperty(semantic)) { var mappedSemantic = mappedSemantics[semantic]; var accessorId = primitive.attributes[semantic]; - delete primitive.attributes[semantic]; - primitive.attributes[mappedSemantic] = accessorId; + if (defined(accessorId)) { + delete primitive.attributes[semantic]; + primitive.attributes[mappedSemantic] = accessorId; + } } } }); @@ -792,6 +809,8 @@ function glTF10to20(gltf) { } var asset = gltf.asset; 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 @@ -804,8 +823,6 @@ function glTF10to20(gltf) { requireByteLength(gltf); // byteStride moved from accessor to bufferView moveByteStrideToBufferView(gltf); - // accessor.min and accessor.max must be defined - requireAccessorMinMax(gltf); // buffer.type is unnecessary and should be removed removeBufferType(gltf); // TEXCOORD and COLOR attributes must be written with a set index (TEXCOORD_#) @@ -826,4 +843,4 @@ function glTF10to20(gltf) { stripTechniqueParameterCount(gltf); // add KHR_technique_webgl extension addKHRTechniqueExtension(gltf); -} +} \ No newline at end of file From bdbcdc96f843c5bbf51a9e2cb10f51fba67a4e97 Mon Sep 17 00:00:00 2001 From: Sean Lilley Date: Mon, 7 Aug 2017 11:13:45 -0400 Subject: [PATCH 35/35] Removed a couple files from cesium-combine gul task --- gulpfile.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/gulpfile.js b/gulpfile.js index 90d6fafb..40952a17 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -286,11 +286,9 @@ gulp.task('build-cesium', function () { 'ForEach.js', 'getAccessorByteStride.js', 'getJointCountForMaterials.js', - 'getStatistics.js', 'glslTypeToWebGLConstant.js', 'numberOfComponentsForType.js', 'parseBinaryGltf.js', - 'pbrToMaterialsCommon.js', 'processModelMaterialsCommon.js', 'processPbrMetallicRoughness.js', 'removePipelineExtras.js',