From be6fffa227cde101fab1c5dcb8f4272e4a3ac1c9 Mon Sep 17 00:00:00 2001
From: ggetz
Date: Mon, 16 Jul 2018 16:13:33 -0400
Subject: [PATCH 01/52] Update gltf pipeline files and support
KHR_techniques_webgl and KHR_blend extensions
---
.../webGLConstantToGlslType.js | 2 +-
Source/Scene/ClassificationModel.js | 54 +-
Source/Scene/Model.js | 663 +++++++++---------
Source/Scene/ModelInstanceCollection.js | 41 +-
Source/Scene/ModelMaterial.js | 4 +
Source/Scene/ModelUtility.js | 359 ++++++++--
.../processModelMaterialsCommon.js | 500 ++++---------
.../processPbrMetallicRoughness.js | 575 +++++----------
Source/ThirdParty/GltfPipeline/ForEach.js | 326 +++++++--
Source/ThirdParty/GltfPipeline/addDefaults.js | 593 ++++------------
.../GltfPipeline/addExtensionsRequired.js | 5 +-
.../GltfPipeline/addExtensionsUsed.js | 5 +-
.../GltfPipeline/addPipelineExtras.js | 77 +-
Source/ThirdParty/GltfPipeline/addToArray.js | 9 +
.../byteLengthForComponentType.js | 34 -
.../GltfPipeline/findAccessorMinMax.js | 67 +-
.../GltfPipeline/getAccessorByteStride.js | 18 +-
.../GltfPipeline/getComponentReader.js | 80 +++
.../GltfPipeline/getJointCountForMaterials.js | 44 --
.../GltfPipeline/glslTypeToWebGLConstant.js | 28 -
.../ThirdParty/GltfPipeline/hasExtension.js | 21 +
.../GltfPipeline/moveTechniqueRenderStates.js | 138 ++++
.../GltfPipeline/moveTechniquesToExtension.js | 128 ++++
.../GltfPipeline/numberOfComponentsForType.js | 11 +-
.../GltfPipeline/parseBinaryGltf.js | 122 ----
Source/ThirdParty/GltfPipeline/parseGlb.js | 126 ++++
.../GltfPipeline/removeExtensionsRequired.js | 2 +
.../GltfPipeline/removeExtensionsUsed.js | 3 +
.../GltfPipeline/removePipelineExtras.js | 34 -
.../GltfPipeline/removeUnusedElements.js | 266 +++++++
.../techniqueParameterForSemantic.js | 29 -
.../ThirdParty/GltfPipeline/updateVersion.js | 507 ++++++--------
32 files changed, 2505 insertions(+), 2366 deletions(-)
rename Source/{ThirdParty/GltfPipeline => Core}/webGLConstantToGlslType.js (96%)
rename Source/{ThirdParty/GltfPipeline => Scene}/processModelMaterialsCommon.js (62%)
rename Source/{ThirdParty/GltfPipeline => Scene}/processPbrMetallicRoughness.js (52%)
delete mode 100644 Source/ThirdParty/GltfPipeline/byteLengthForComponentType.js
create mode 100644 Source/ThirdParty/GltfPipeline/getComponentReader.js
delete mode 100644 Source/ThirdParty/GltfPipeline/getJointCountForMaterials.js
delete mode 100644 Source/ThirdParty/GltfPipeline/glslTypeToWebGLConstant.js
create mode 100644 Source/ThirdParty/GltfPipeline/hasExtension.js
create mode 100644 Source/ThirdParty/GltfPipeline/moveTechniqueRenderStates.js
create mode 100644 Source/ThirdParty/GltfPipeline/moveTechniquesToExtension.js
delete mode 100644 Source/ThirdParty/GltfPipeline/parseBinaryGltf.js
create mode 100644 Source/ThirdParty/GltfPipeline/parseGlb.js
delete mode 100644 Source/ThirdParty/GltfPipeline/removePipelineExtras.js
create mode 100644 Source/ThirdParty/GltfPipeline/removeUnusedElements.js
delete mode 100644 Source/ThirdParty/GltfPipeline/techniqueParameterForSemantic.js
diff --git a/Source/ThirdParty/GltfPipeline/webGLConstantToGlslType.js b/Source/Core/webGLConstantToGlslType.js
similarity index 96%
rename from Source/ThirdParty/GltfPipeline/webGLConstantToGlslType.js
rename to Source/Core/webGLConstantToGlslType.js
index 1a7a03716250..dce11822bc26 100644
--- a/Source/ThirdParty/GltfPipeline/webGLConstantToGlslType.js
+++ b/Source/Core/webGLConstantToGlslType.js
@@ -1,5 +1,5 @@
define([
- '../../Core/WebGLConstants'
+ './WebGLConstants'
], function(
WebGLConstants) {
'use strict';
diff --git a/Source/Scene/ClassificationModel.js b/Source/Scene/ClassificationModel.js
index 60d67a11dd62..e628df0e348e 100644
--- a/Source/Scene/ClassificationModel.js
+++ b/Source/Scene/ClassificationModel.js
@@ -24,7 +24,7 @@ define([
'../ThirdParty/GltfPipeline/ForEach',
'../ThirdParty/GltfPipeline/getAccessorByteStride',
'../ThirdParty/GltfPipeline/numberOfComponentsForType',
- '../ThirdParty/GltfPipeline/parseBinaryGltf',
+ '../ThirdParty/GltfPipeline/parseGlb',
'../ThirdParty/when',
'./Axis',
'./ClassificationType',
@@ -59,7 +59,7 @@ define([
ForEach,
getAccessorByteStride,
numberOfComponentsForType,
- parseBinaryGltf,
+ parseGlb,
when,
Axis,
ClassificationType,
@@ -124,7 +124,7 @@ define([
if (gltf instanceof Uint8Array) {
// Binary glTF
- gltf = parseBinaryGltf(gltf);
+ gltf = parseGlb(gltf);
} else {
throw new RuntimeError('Only binary glTF is supported as a classifier.');
}
@@ -132,17 +132,17 @@ define([
var gltfNodes = gltf.nodes;
var gltfMeshes = gltf.meshes;
- var gltfNode = gltfNodes[0];
- var meshId = gltfNode.mesh;
- if (gltfNodes.length !== 1 || !defined(meshId)) {
+ var gltfNode = gltfNodes.rootNode;
+ if (!defined(gltfNode)) {
throw new RuntimeError('Only one node is supported for classification and it must have a mesh.');
}
- if (gltfMeshes.length !== 1) {
- throw new RuntimeError('Only one mesh is supported when using b3dm for classification.');
+ var nodeMesh = gltfNode.meshes[0];
+ if (!defined(nodeMesh)) {
+ throw new RuntimeError('Only one node is supported for classification and it must have a mesh.');
}
- var gltfPrimitives = gltfMeshes[0].primitives;
+ var gltfPrimitives = gltfMeshes[nodeMesh].primitives;
if (gltfPrimitives.length !== 1) {
throw new RuntimeError('Only one primitive per mesh is supported when using b3dm for classification.');
}
@@ -499,8 +499,8 @@ define([
var min = new Cartesian3(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE);
var max = new Cartesian3(-Number.MAX_VALUE, -Number.MAX_VALUE, -Number.MAX_VALUE);
- var n = gltfNodes[0];
- var meshId = n.mesh;
+ var n = gltfNodes.rootNode;
+ var meshId = n.meshes[0];
var transformToRoot = ModelUtility.getTransform(n);
var mesh = gltfMeshes[meshId];
@@ -646,7 +646,9 @@ define([
}
function modifyShaderForQuantizedAttributes(shader, model) {
- var primitive = model.gltf.meshes[0].primitives[0];
+ var gltfMeshes = model.gltf.meshes;
+ var gltfRootNode = model.gltf.nodes.rootNode;
+ var primitive = gltfMeshes[gltfRootNode.meshes[0]].primitives[0];
var result = ModelUtility.modifyShaderForQuantizedAttributes(model.gltf, primitive, shader);
model._quantizedUniforms = result.uniforms;
return result.shader;
@@ -748,7 +750,8 @@ define([
var gltf = model.gltf;
var accessors = gltf.accessors;
var meshes = gltf.meshes;
- var primitives = meshes[0].primitives;
+ var rootNode = gltf.nodes.rootNode;
+ var primitives = meshes[rootNode.meshes[0]].primitives;
var primitive = primitives[0];
var attributeLocations = getAttributeLocations();
@@ -804,23 +807,19 @@ define([
return;
}
- var techniques = model.gltf.techniques;
- var technique = techniques[0];
- var parameters = technique.parameters;
- var uniforms = technique.uniforms;
-
var uniformMap = {};
- for (var name in uniforms) {
- if (uniforms.hasOwnProperty(name) && name !== 'extras') {
- var parameterName = uniforms[name];
+ ForEach.technique(model.gltf, function(technique) {
+ var parameters = technique.parameters;
+ ForEach.techniqueUniform(technique, function(parameterName, uniformName) {
var parameter = parameters[parameterName];
if (!defined(parameter.semantic) || !defined(gltfSemanticUniforms[parameter.semantic])) {
- continue;
+ return;
}
- uniformMap[name] = gltfSemanticUniforms[parameter.semantic](context.uniformState, model);
- }
- }
+
+ uniformMap[uniformName] = gltfSemanticUniforms[parameter.semantic](context.uniformState, model);
+ });
+ });
model._uniformMap = uniformMap;
}
@@ -850,7 +849,8 @@ define([
var gltf = model.gltf;
var accessors = gltf.accessors;
var gltfMeshes = gltf.meshes;
- var primitive = gltfMeshes[0].primitives[0];
+ var gltfRootNode = gltf.nodes.rootNode;
+ var primitive = gltfMeshes[gltfRootNode.meshes[0]].primitives[0];
var ix = accessors[primitive.indices];
var positionAccessor = primitive.attributes.POSITION;
@@ -999,7 +999,7 @@ define([
var gltf = model.gltf;
var nodes = gltf.nodes;
- var gltfNode = nodes[0];
+ var gltfNode = nodes.rootNode;
model._nodeMatrix = ModelUtility.getTransform(gltfNode, model._nodeMatrix);
createPrimitive(model);
diff --git a/Source/Scene/Model.js b/Source/Scene/Model.js
index bcb23f30f26d..63bd0356e635 100644
--- a/Source/Scene/Model.js
+++ b/Source/Scene/Model.js
@@ -1,6 +1,5 @@
define([
'../Core/BoundingSphere',
- '../Core/Cartesian2',
'../Core/Cartesian3',
'../Core/Cartesian4',
'../Core/Cartographic',
@@ -22,14 +21,11 @@ define([
'../Core/loadImageFromTypedArray',
'../Core/loadKTX',
'../Core/Math',
- '../Core/Matrix2',
'../Core/Matrix3',
'../Core/Matrix4',
'../Core/PixelFormat',
- '../Core/Plane',
'../Core/PrimitiveType',
'../Core/Quaternion',
- '../Core/Queue',
'../Core/Resource',
'../Core/RuntimeError',
'../Core/Transforms',
@@ -50,14 +46,11 @@ define([
'../ThirdParty/GltfPipeline/addPipelineExtras',
'../ThirdParty/GltfPipeline/ForEach',
'../ThirdParty/GltfPipeline/getAccessorByteStride',
+ '../ThirdParty/GltfPipeline/hasExtension',
'../ThirdParty/GltfPipeline/numberOfComponentsForType',
- '../ThirdParty/GltfPipeline/parseBinaryGltf',
- '../ThirdParty/GltfPipeline/processModelMaterialsCommon',
- '../ThirdParty/GltfPipeline/processPbrMetallicRoughness',
+ '../ThirdParty/GltfPipeline/parseGlb',
'../ThirdParty/GltfPipeline/updateVersion',
- '../ThirdParty/Uri',
'../ThirdParty/when',
- './AttributeType',
'./Axis',
'./BlendingState',
'./ClippingPlaneCollection',
@@ -74,11 +67,12 @@ define([
'./ModelMesh',
'./ModelNode',
'./ModelUtility',
+ './processModelMaterialsCommon',
+ './processPbrMetallicRoughness',
'./SceneMode',
'./ShadowMode'
], function(
BoundingSphere,
- Cartesian2,
Cartesian3,
Cartesian4,
Cartographic,
@@ -100,14 +94,11 @@ define([
loadImageFromTypedArray,
loadKTX,
CesiumMath,
- Matrix2,
Matrix3,
Matrix4,
PixelFormat,
- Plane,
PrimitiveType,
Quaternion,
- Queue,
Resource,
RuntimeError,
Transforms,
@@ -128,14 +119,11 @@ define([
addPipelineExtras,
ForEach,
getAccessorByteStride,
+ hasExtension,
numberOfComponentsForType,
- parseBinaryGltf,
- processModelMaterialsCommon,
- processPbrMetallicRoughness,
+ parseGlb,
updateVersion,
- Uri,
when,
- AttributeType,
Axis,
BlendingState,
ClippingPlaneCollection,
@@ -152,6 +140,8 @@ define([
ModelMesh,
ModelNode,
ModelUtility,
+ processModelMaterialsCommon,
+ processPbrMetallicRoughness,
SceneMode,
ShadowMode) {
'use strict';
@@ -249,6 +239,10 @@ define([
* {@link https://github.com/KhronosGroup/glTF/blob/master/extensions/1.0/Vendor/WEB3D_quantized_attributes/README.md|WEB3D_quantized_attributes}
*
* {@link https://github.com/KhronosGroup/glTF/blob/master/extensions/2.0/Khronos/KHR_draco_mesh_compression/README.md|KHR_draco_mesh_compression}
+ *
+ * {@link https://github.com/KhronosGroup/glTF/blob/master/extensions/2.0/Khronos/KHR_techniques_webgl/README.md|KHR_techniques_webgl}
+ *
+ * {@link https://github.com/KhronosGroup/glTF/blob/master/extensions/2.0/Khronos/KHR_blend/README.md|KHR_blend}
*
*
*
@@ -319,7 +313,7 @@ define([
if (gltf instanceof Uint8Array) {
// Binary glTF
- var parsedGltf = parseBinaryGltf(gltf);
+ var parsedGltf = parseGlb(gltf);
cachedGltf = new CachedGltf({
gltf : parsedGltf,
@@ -644,10 +638,10 @@ define([
this._texturesByteLength = 0;
this._trianglesLength = 0;
- // Hold references to programs and shaders for shader reconstruction.
+ // Hold references for shader reconstruction.
// Hold these separately because _cachedGltf may get released (this.releaseGltfJson)
- this._sourcePrograms = undefined;
- this._sourceShaders = undefined;
+ this._sourceTechniques = {};
+ this._sourceShaders = {};
this._quantizedVertexShaders = {};
this._nodeCommands = [];
@@ -1123,6 +1117,10 @@ define([
* {@link https://github.com/KhronosGroup/glTF/blob/master/extensions/1.0/Vendor/WEB3D_quantized_attributes/README.md|WEB3D_quantized_attributes}
*
* {@link https://github.com/KhronosGroup/glTF/blob/master/extensions/2.0/Khronos/KHR_draco_mesh_compression/README.md|KHR_draco_mesh_compression}
+ *
+ * {@link https://github.com/KhronosGroup/glTF/blob/master/extensions/2.0/Khronos/KHR_techniques_webgl/README.md|KHR_techniques_webgl}
+ *
+ * {@link https://github.com/KhronosGroup/glTF/blob/master/extensions/2.0/Khronos/KHR_blend/README.md|KHR_blend}
*
*
*
@@ -1239,7 +1237,7 @@ define([
var array = new Uint8Array(arrayBuffer);
if (containsGltfMagic(array)) {
// Load binary glTF
- var parsedGltf = parseBinaryGltf(array);
+ var parsedGltf = parseGlb(array);
// KHR_binary_glTF is from the beginning of the binary section
cachedGltf.makeReady(parsedGltf, array);
} else {
@@ -1370,27 +1368,29 @@ define([
}
var children = n.children;
- var childrenLength = children.length;
- for (var k = 0; k < childrenLength; ++k) {
- var child = gltfNodes[children[k]];
- child._transformToRoot = ModelUtility.getTransform(child);
- Matrix4.multiplyTransformation(transformToRoot, child._transformToRoot, child._transformToRoot);
- nodeStack.push(child);
+ if (defined(children)) {
+ var childrenLength = children.length;
+ for (var k = 0; k < childrenLength; ++k) {
+ var child = gltfNodes[children[k]];
+ child._transformToRoot = ModelUtility.getTransform(child);
+ Matrix4.multiplyTransformation(transformToRoot, child._transformToRoot, child._transformToRoot);
+ nodeStack.push(child);
+ }
}
delete n._transformToRoot;
}
}
var boundingSphere = BoundingSphere.fromCornerPoints(min, max);
+ if (model._forwardAxis === Axis.Z) {
+ // glTF 2.0 has a Z-forward convention that must be adapted here to X-forward.
+ BoundingSphere.transformWithoutScale(boundingSphere, Axis.Z_UP_TO_X_UP, boundingSphere);
+ }
if (model._upAxis === Axis.Y) {
BoundingSphere.transformWithoutScale(boundingSphere, Axis.Y_UP_TO_Z_UP, boundingSphere);
} else if (model._upAxis === Axis.X) {
BoundingSphere.transformWithoutScale(boundingSphere, Axis.X_UP_TO_Z_UP, boundingSphere);
}
- if (model._forwardAxis === Axis.Z) {
- // glTF 2.0 has a Z-forward convention that must be adapted here to X-forward.
- BoundingSphere.transformWithoutScale(boundingSphere, Axis.Z_UP_TO_X_UP, boundingSphere);
- }
return boundingSphere;
}
@@ -1490,7 +1490,7 @@ define([
bufferView : undefined
};
--loadResources.pendingShaderLoads;
- model.gltf.shaders[id].extras._pipeline.source = source;
+ model._shaders[id].extras._pipeline.source = source;
};
}
@@ -1523,14 +1523,34 @@ define([
url : shader.uri
});
- shaderResource.fetchText().then(shaderLoad(model, shader.type, id)).otherwise(getFailedLoadFunction(model, 'shader', shaderResource.url));
+ shaderResource.fetchText()
+ .then(shaderLoad(model, shader.type, id))
+ .otherwise(getFailedLoadFunction(model, 'shader', shaderResource.url));
}
+
+ // retain reference to source shader
+ model._sourceShaders[id] = clone(shader);
});
}
function parsePrograms(model) {
- ForEach.program(model.gltf, function(program, id) {
- model._loadResources.programsToCreate.enqueue(id);
+ var sourcePrograms = model._sourcePrograms = {};
+ var gltf = model.gltf;
+
+ if (!hasExtension(gltf, 'KHR_techniques_webgl')) {
+ return;
+ }
+
+ var programs = gltf.extensions.KHR_techniques_webgl.programs;
+ ForEach.technique(model.gltf, function(technique, techniqueId) {
+ var programId = technique.program;
+ if (!defined(sourcePrograms[programId])) {
+ sourcePrograms[programId] = clone(programs[programId]);
+ model._loadResources.programsToCreate.enqueue({
+ id: programId,
+ technique: techniqueId
+ });
+ }
});
}
@@ -1694,22 +1714,47 @@ define([
}
function parseMaterials(model) {
+ var gltf = model.gltf;
+ var techniques = model._sourceTechniques = {};
+
+ ForEach.technique(model.gltf, function(technique, index) {
+ techniques[index] = clone(technique);
+ });
+
var runtimeMaterialsByName = {};
var runtimeMaterialsById = {};
var uniformMaps = model._uniformMaps;
- ForEach.material(model.gltf, function(material, id) {
+ ForEach.material(gltf, function(material, materialId) {
// Allocated now so ModelMaterial can keep a reference to it.
- uniformMaps[id] = {
+ uniformMaps[materialId] = {
uniformMap : undefined,
values : undefined,
jointMatrixUniformName : undefined,
morphWeightsUniformName : undefined
};
- var modelMaterial = new ModelMaterial(model, material, id);
+ var modelMaterial = new ModelMaterial(model, material, materialId);
+
+ if (defined(material.extensions) && defined(material.extensions.KHR_techniques_webgl)) {
+ var techniqueId = material.extensions.KHR_techniques_webgl.technique;
+ modelMaterial._technique = techniqueId;
+ modelMaterial._program = techniques[techniqueId].program;
+
+ var values = material.extensions.KHR_techniques_webgl.values;
+ for (var uniformName in values) {
+ if (values.hasOwnProperty(uniformName)) {
+ if (!defined(modelMaterial._values)) {
+ modelMaterial._values = {};
+ }
+
+ modelMaterial._values[uniformName] = clone(values[uniformName]);
+ }
+ }
+ }
+
runtimeMaterialsByName[material.name] = modelMaterial;
- runtimeMaterialsById[id] = modelMaterial;
+ runtimeMaterialsById[materialId] = modelMaterial;
});
model._runtime.materialsByName = runtimeMaterialsByName;
@@ -1869,38 +1914,13 @@ define([
}
}
- function createAttributeLocations(model, attributes) {
- var attributeLocations = {};
- var length = attributes.length;
- var i;
-
- // Set the position attribute to the 0th index. In some WebGL implementations the shader
- // will not work correctly if the 0th attribute is not active. For example, some glTF models
- // list the normal attribute first but derived shaders like the cast-shadows shader do not use
- // the normal attribute.
- for (i = 1; i < length; ++i) {
- var attribute = attributes[i];
- if (/pos/i.test(attribute)) {
- attributes[i] = attributes[0];
- attributes[0] = attribute;
- break;
- }
- }
-
- for (i = 0; i < length; ++i) {
- attributeLocations[attributes[i]] = i;
+ function getProgramForPrimitive(model, primitive) {
+ var material = model._runtime.materialsById[primitive.material];
+ if (!defined(material)) {
+ return;
}
- return attributeLocations;
- }
-
- function getProgramForPrimitive(model, primitive) {
- var gltf = model.gltf;
- var materialId = primitive.material;
- var material = gltf.materials[materialId];
- var techniqueId = material.technique;
- var technique = gltf.techniques[techniqueId];
- return technique.program;
+ return material._program;
}
function modifyShaderForQuantizedAttributes(shader, programName, model) {
@@ -2004,26 +2024,29 @@ define([
// When building programs for the first time, do not include modifiers for clipping planes and color
// since this is the version of the program that will be cached for use with other Models.
- function createProgram(id, model, context) {
- var program = model._sourcePrograms[id];
+ function createProgram(programToCreate, model, context) {
+ var programId = programToCreate.id;
+ var techniqueId = programToCreate.technique;
+ var program = model._sourcePrograms[programId];
var shaders = model._sourceShaders;
- var quantizedVertexShaders = model._quantizedVertexShaders;
- var toClipCoordinatesGLSL = model._toClipCoordinatesGLSL[id];
var vs = shaders[program.vertexShader].extras._pipeline.source;
var fs = shaders[program.fragmentShader].extras._pipeline.source;
+ var quantizedVertexShaders = model._quantizedVertexShaders;
+ var toClipCoordinatesGLSL = model._toClipCoordinatesGLSL[programId];
+
if (model.extensionsUsed.WEB3D_quantized_attributes || model._dequantizeInShader) {
- var quantizedVS = quantizedVertexShaders[id];
+ var quantizedVS = quantizedVertexShaders[programId];
if (!defined(quantizedVS)) {
- quantizedVS = modifyShaderForQuantizedAttributes(vs, id, model);
- quantizedVertexShaders[id] = quantizedVS;
+ quantizedVS = modifyShaderForQuantizedAttributes(vs, programId, model);
+ quantizedVertexShaders[programId] = quantizedVS;
}
vs = quantizedVS;
}
- var drawVS = modifyShader(vs, id, model._vertexShaderLoaded);
- var drawFS = modifyShader(fs, id, model._fragmentShaderLoaded);
+ var drawVS = modifyShader(vs, programId, model._vertexShaderLoaded);
+ var drawFS = modifyShader(fs, programId, model._fragmentShaderLoaded);
// Internet Explorer seems to have problems with discard (for clipping planes) after too many levels of indirection:
// https://github.com/AnalyticalGraphicsInc/cesium/issues/6575.
@@ -2037,14 +2060,17 @@ define([
drawFS = 'uniform vec4 czm_pickColor;\n' + drawFS;
}
- createAttributesAndProgram(id, drawFS, drawVS, model, context);
+ createAttributesAndProgram(programId, techniqueId, drawFS, drawVS, model, context);
}
- function recreateProgram(id, model, context) {
- var program = model._sourcePrograms[id];
+ function recreateProgram(programToCreate, model, context) {
+ var programId = programToCreate.id;
+ var techniqueId = programToCreate.technique;
+ var program = model._sourcePrograms[programId];
var shaders = model._sourceShaders;
+
var quantizedVertexShaders = model._quantizedVertexShaders;
- var toClipCoordinatesGLSL = model._toClipCoordinatesGLSL[id];
+ var toClipCoordinatesGLSL = model._toClipCoordinatesGLSL[programId];
var clippingPlaneCollection = model.clippingPlanes;
var addClippingPlaneCode = isClippingEnabled(model);
@@ -2053,7 +2079,7 @@ define([
var fs = shaders[program.fragmentShader].extras._pipeline.source;
if (model.extensionsUsed.WEB3D_quantized_attributes || model._dequantizeInShader) {
- vs = quantizedVertexShaders[id];
+ vs = quantizedVertexShaders[programId];
}
var finalFS = fs;
@@ -2064,8 +2090,8 @@ define([
finalFS = modifyShaderForClippingPlanes(finalFS, clippingPlaneCollection, context);
}
- var drawVS = modifyShader(vs, id, model._vertexShaderLoaded);
- var drawFS = modifyShader(finalFS, id, model._fragmentShaderLoaded);
+ var drawVS = modifyShader(vs, programId, model._vertexShaderLoaded);
+ var drawFS = modifyShader(finalFS, programId, model._fragmentShaderLoaded);
if (!FeatureDetection.isInternetExplorer()) {
drawVS = ModelUtility.modifyVertexShaderForLogDepth(drawVS, toClipCoordinatesGLSL);
@@ -2076,25 +2102,14 @@ define([
drawFS = 'uniform vec4 czm_pickColor;\n' + drawFS;
}
- createAttributesAndProgram(id, drawFS, drawVS, model, context);
+ createAttributesAndProgram(programId, techniqueId, drawFS, drawVS, model, context);
}
- function createAttributesAndProgram(id, drawFS, drawVS, model, context) {
- var program = model._sourcePrograms[id];
- var attributeLocations = createAttributeLocations(model, program.attributes);
-
- // Add pre-created attributes to attributeLocations
- var attributesLength = program.attributes.length;
- var precreatedAttributes = model._precreatedAttributes;
- if (defined(precreatedAttributes)) {
- for (var attrName in precreatedAttributes) {
- if (precreatedAttributes.hasOwnProperty(attrName)) {
- attributeLocations[attrName] = attributesLength++;
- }
- }
- }
+ function createAttributesAndProgram(programId, techniqueId, drawFS, drawVS, model, context) {
+ var technique = model._sourceTechniques[techniqueId];
+ var attributeLocations = ModelUtility.createAttributeLocations(technique, model._precreatedAttributes);
- model._rendererResources.programs[id] = ShaderProgram.fromCache({
+ model._rendererResources.programs[programId] = ShaderProgram.fromCache({
context : context,
vertexShaderSource : drawVS,
fragmentShaderSource : drawFS,
@@ -2250,7 +2265,7 @@ define([
var tx;
var source = gltfTexture.image;
- if (defined(internalFormat) && texture.target === WebGLConstants.TEXTURE_2D) {
+ if (defined(internalFormat)) {
tx = new Texture({
context : context,
source : {
@@ -2274,19 +2289,17 @@ define([
source = canvas;
}
- if (texture.target === WebGLConstants.TEXTURE_2D) {
- tx = new Texture({
- context : context,
- source : source,
- pixelFormat : texture.internalFormat,
- pixelDatatype : texture.type,
- sampler : sampler,
- flipY : false
- });
- // GLTF_SPEC: Support TEXTURE_CUBE_MAP. https://github.com/KhronosGroup/glTF/issues/40
- if (mipmap) {
- tx.generateMipmap();
- }
+ tx = new Texture({
+ context : context,
+ source : source,
+ pixelFormat : texture.internalFormat,
+ pixelDatatype : texture.type,
+ sampler : sampler,
+ flipY : false
+ });
+ // GLTF_SPEC: Support TEXTURE_CUBE_MAP. https://github.com/KhronosGroup/glTF/issues/40
+ if (mipmap) {
+ tx.generateMipmap();
}
}
if (defined(tx)) {
@@ -2318,17 +2331,22 @@ define([
}
function getAttributeLocations(model, primitive) {
- var gltf = model.gltf;
- var techniques = gltf.techniques;
- var materials = gltf.materials;
+ var techniques = model._sourceTechniques;
// Retrieve the compiled shader program to assign index values to attributes
var attributeLocations = {};
var location;
var index;
- var technique = techniques[materials[primitive.material].technique];
- var parameters = technique.parameters;
+ var material = model._runtime.materialsById[primitive.material];
+ if (!defined(material)) {
+ return attributeLocations;
+ }
+ var technique = techniques[material._technique];
+ if (!defined(technique)) {
+ return;
+ }
+
var attributes = technique.attributes;
var program = model._rendererResources.programs[technique.program];
var programVertexAttributes = program.vertexAttributes;
@@ -2338,10 +2356,9 @@ define([
for (location in programVertexAttributes) {
if (programVertexAttributes.hasOwnProperty(location)) {
var attribute = attributes[location];
- index = programVertexAttributes[location].index;
if (defined(attribute)) {
- var parameter = parameters[attribute];
- attributeLocations[parameter.semantic] = index;
+ index = programAttributeLocations[location];
+ attributeLocations[attribute.semantic] = index;
}
}
}
@@ -2379,9 +2396,11 @@ define([
}
var children = n.children;
- var childrenLength = children.length;
- for (var k = 0; k < childrenLength; ++k) {
- stack.push(children[k]);
+ if (defined(children)) {
+ var childrenLength = children.length;
+ for (var k = 0; k < childrenLength; ++k) {
+ stack.push(children[k]);
+ }
}
}
}
@@ -2489,12 +2508,9 @@ define([
model._runtime.animations = [];
var runtimeNodes = model._runtime.nodes;
- var animations = model.gltf.animations;
var accessors = model.gltf.accessors;
- var length = animations.length;
- for (var i = 0; i < length; ++i) {
- var animation = animations[i];
+ ForEach.animation(model.gltf, function (animation, i) {
var channels = animation.channels;
var samplers = animation.samplers;
@@ -2528,7 +2544,7 @@ define([
stopTime : stopTime,
channelEvaluators : channelEvaluators
};
- }
+ });
}
function createVertexArrays(model, context) {
@@ -2565,6 +2581,7 @@ define([
// https://github.com/KhronosGroup/glTF/issues/258
var attributeLocations = getAttributeLocations(model, primitive);
+
var attributeName;
var attributeLocation;
var attribute;
@@ -2652,59 +2669,55 @@ define([
}
}
- function getBooleanStates(states) {
- // GLTF_SPEC: SAMPLE_ALPHA_TO_COVERAGE not used by Cesium
+ function getBooleanStates(material) {
var booleanStates = {};
- booleanStates[WebGLConstants.BLEND] = false;
- booleanStates[WebGLConstants.CULL_FACE] = false;
- booleanStates[WebGLConstants.DEPTH_TEST] = false;
+ booleanStates[WebGLConstants.BLEND] = (defined(material.alphaMode) && material.alphaMode !== 'OPAQUE');
+ booleanStates[WebGLConstants.CULL_FACE] = !material.doubleSided;
+ booleanStates[WebGLConstants.DEPTH_TEST] = true;
booleanStates[WebGLConstants.POLYGON_OFFSET_FILL] = false;
- var enable = states.enable;
- var length = enable.length;
- var i;
- for (i = 0; i < length; ++i) {
- booleanStates[enable[i]] = true;
- }
-
return booleanStates;
}
function createRenderStates(model, context) {
var loadResources = model._loadResources;
- var techniques = model.gltf.techniques;
if (loadResources.createRenderStates) {
loadResources.createRenderStates = false;
- for (var id in techniques) {
- if (techniques.hasOwnProperty(id)) {
- createRenderStateForTechnique(model, id, context);
- }
- }
+
+ ForEach.material(model.gltf, function (material, materialId) {
+ createRenderStateForMaterial(model, material, materialId, context);
+ });
}
}
- function createRenderStateForTechnique(model, id, context) {
+ function createRenderStateForMaterial(model, material, materialId, context) {
var rendererRenderStates = model._rendererResources.renderStates;
- var techniques = model.gltf.techniques;
- var technique = techniques[id];
- var states = technique.states;
-
- var booleanStates = getBooleanStates(states);
- var statesFunctions = defaultValue(states.functions, defaultValue.EMPTY_OBJECT);
- var blendColor = defaultValue(statesFunctions.blendColor, [0.0, 0.0, 0.0, 0.0]);
- var blendEquationSeparate = defaultValue(statesFunctions.blendEquationSeparate, [
+
+ var blendEquationSeparate = [
WebGLConstants.FUNC_ADD,
- WebGLConstants.FUNC_ADD]);
- var blendFuncSeparate = defaultValue(statesFunctions.blendFuncSeparate, [
+ WebGLConstants.FUNC_ADD
+ ];
+ var blendFuncSeparate = [
WebGLConstants.ONE,
- WebGLConstants.ZERO,
+ WebGLConstants.ONE_MINUS_SRC_ALPHA,
WebGLConstants.ONE,
- WebGLConstants.ZERO]);
- var colorMask = defaultValue(statesFunctions.colorMask, [true, true, true, true]);
- var depthRange = defaultValue(statesFunctions.depthRange, [0.0, 1.0]);
- var polygonOffset = defaultValue(statesFunctions.polygonOffset, [0.0, 0.0]);
+ WebGLConstants.ONE_MINUS_SRC_ALPHA
+ ];
+ if (defined(material.extensions) && defined(material.extensions.KHR_blend)) {
+ blendEquationSeparate = material.extensions.KHR_blend.blendEquation;
+ blendFuncSeparate = material.extensions.KHR_blend.blendFactors;
+ }
+
+ var statesFunctions = {
+ blendColor : [0.0, 0.0, 0.0, 0.0],
+ colorMask : [true, true, true, true],
+ depthRange : [0.0, 1.0],
+ polygonOffset : [0.0, 0.0]
+ };
+
+ var booleanStates = getBooleanStates(material);
// Change the render state to use traditional alpha blending instead of premultiplied alpha blending
if (booleanStates[WebGLConstants.BLEND] && model._hasPremultipliedAlpha) {
if ((blendFuncSeparate[0] === WebGLConstants.ONE) && (blendFuncSeparate[1] === WebGLConstants.ONE_MINUS_SRC_ALPHA)) {
@@ -2715,7 +2728,7 @@ define([
}
}
- rendererRenderStates[id] = RenderState.fromCache({
+ rendererRenderStates[materialId] = RenderState.fromCache({
frontFace : defined(statesFunctions.frontFace) ? statesFunctions.frontFace[0] : WebGLConstants.CCW,
cull : {
enabled : booleanStates[WebGLConstants.CULL_FACE],
@@ -2724,31 +2737,31 @@ define([
lineWidth : defined(statesFunctions.lineWidth) ? statesFunctions.lineWidth[0] : 1.0,
polygonOffset : {
enabled : booleanStates[WebGLConstants.POLYGON_OFFSET_FILL],
- factor : polygonOffset[0],
- units : polygonOffset[1]
+ factor: statesFunctions.polygonOffset[0],
+ units: statesFunctions.polygonOffset[1]
},
depthRange : {
- near : depthRange[0],
- far : depthRange[1]
+ near: statesFunctions.depthRange[0],
+ far: statesFunctions.depthRange[1]
},
depthTest : {
enabled : booleanStates[WebGLConstants.DEPTH_TEST],
func : defined(statesFunctions.depthFunc) ? statesFunctions.depthFunc[0] : WebGLConstants.LESS
},
colorMask : {
- red : colorMask[0],
- green : colorMask[1],
- blue : colorMask[2],
- alpha : colorMask[3]
+ red: statesFunctions.colorMask[0],
+ green: statesFunctions.colorMask[1],
+ blue: statesFunctions.colorMask[2],
+ alpha: statesFunctions.colorMask[3]
},
depthMask : defined(statesFunctions.depthMask) ? statesFunctions.depthMask[0] : true,
blending : {
enabled : booleanStates[WebGLConstants.BLEND],
color : {
- red : blendColor[0],
- green : blendColor[1],
- blue : blendColor[2],
- alpha : blendColor[3]
+ red: statesFunctions.blendColor[0],
+ green: statesFunctions.blendColor[1],
+ blue: statesFunctions.blendColor[2],
+ alpha: statesFunctions.blendColor[3]
},
equationRgb : blendEquationSeparate[0],
equationAlpha : blendEquationSeparate[1],
@@ -2864,6 +2877,56 @@ define([
return gltfUniformsFromNode[semantic](uniformState, model, runtimeNode);
}
+ function createUniformsForMaterial(model, technique, instanceValues, context, textures, defaultTexture) {
+ var uniformMap = {};
+ var uniformValues = {};
+ var jointMatrixUniformName;
+ var morphWeightsUniformName;
+
+ ForEach.techniqueUniform(technique, function(uniform, uniformName) {
+ // GLTF_SPEC: This does not take into account uniform arrays,
+ // indicated by uniforms with a count property.
+ //
+ // https://github.com/KhronosGroup/glTF/issues/258
+
+ // GLTF_SPEC: In this implementation, material parameters with a
+ // semantic or targeted via a source (for animation) are not
+ // targetable for material animations. Is this too strict?
+ //
+ // https://github.com/KhronosGroup/glTF/issues/142
+
+ if (defined(instanceValues[uniformName])) {
+ // Parameter overrides by the instance technique
+ var uv = ModelUtility.createUniformFunction(uniform.type, instanceValues[uniformName], textures, defaultTexture);
+ uniformMap[uniformName] = uv.func;
+ uniformValues[uniformName] = uv;
+ } else if (defined(uniform.node)) {
+ uniformMap[uniformName] = getUniformFunctionFromSource(uniform.node, model, uniform.semantic, context.uniformState);
+ } else if (defined(uniform.semantic)) {
+ if (uniform.semantic === 'JOINTMATRIX') {
+ jointMatrixUniformName = uniformName;
+ } else if (uniform.semantic === 'MORPHWEIGHTS') {
+ morphWeightsUniformName = uniformName;
+ } else {
+ // Map glTF semantic to Cesium automatic uniform
+ uniformMap[uniformName] = ModelUtility.getGltfSemanticUniforms()[uniform.semantic](context.uniformState, model);
+ }
+ } else if (defined(uniform.value)) {
+ // Technique value that isn't overridden by a material
+ var uv2 = ModelUtility.createUniformFunction(uniform.type, uniform.value, textures, defaultTexture);
+ uniformMap[uniformName] = uv2.func;
+ uniformValues[uniformName] = uv2;
+ }
+ });
+
+ return {
+ map : uniformMap, // uniform name -> function for the renderer
+ values : uniformValues, // material parameter name -> ModelMaterial for modifying the parameter at runtime
+ jointMatrixUniformName : jointMatrixUniformName,
+ morphWeightsUniformName : morphWeightsUniformName
+ };
+ }
+
function createUniformMaps(model, context) {
var loadResources = model._loadResources;
@@ -2877,76 +2940,25 @@ define([
loadResources.createUniformMaps = false;
var gltf = model.gltf;
- var materials = gltf.materials;
- var techniques = gltf.techniques;
+ var techniques = model._sourceTechniques;
var uniformMaps = model._uniformMaps;
var textures = model._rendererResources.textures;
var defaultTexture = model._defaultTexture;
- for (var materialId in materials) {
- if (materials.hasOwnProperty(materialId)) {
- var material = materials[materialId];
- var instanceParameters;
- instanceParameters = material.values;
- var technique = techniques[material.technique];
- var parameters = technique.parameters;
- var uniforms = technique.uniforms;
-
- var uniformMap = {};
- var uniformValues = {};
- var jointMatrixUniformName;
- var morphWeightsUniformName;
-
- // Uniform parameters
- for (var name in uniforms) {
- if (uniforms.hasOwnProperty(name) && name !== 'extras') {
- var parameterName = uniforms[name];
- var parameter = parameters[parameterName];
-
- // GLTF_SPEC: This does not take into account uniform arrays,
- // indicated by parameters with a count property.
- //
- // https://github.com/KhronosGroup/glTF/issues/258
-
- // GLTF_SPEC: In this implementation, material parameters with a
- // semantic or targeted via a source (for animation) are not
- // targetable for material animations. Is this too strict?
- //
- // https://github.com/KhronosGroup/glTF/issues/142
-
- if (defined(instanceParameters[parameterName])) {
- // Parameter overrides by the instance technique
- var uv = ModelUtility.createUniformFunction(parameter.type, instanceParameters[parameterName], textures, defaultTexture);
- uniformMap[name] = uv.func;
- uniformValues[parameterName] = uv;
- } else if (defined(parameter.node)) {
- uniformMap[name] = getUniformFunctionFromSource(parameter.node, model, parameter.semantic, context.uniformState);
- } else if (defined(parameter.semantic)) {
- if (parameter.semantic === 'JOINTMATRIX') {
- jointMatrixUniformName = name;
- } else if (parameter.semantic === 'MORPHWEIGHTS') {
- morphWeightsUniformName = name;
- } else {
- // Map glTF semantic to Cesium automatic uniform
- uniformMap[name] = ModelUtility.getGltfSemanticUniforms()[parameter.semantic](context.uniformState, model);
- }
- } else if (defined(parameter.value)) {
- // Technique value that isn't overridden by a material
- var uv2 = ModelUtility.createUniformFunction(parameter.type, parameter.value, textures, defaultTexture);
- uniformMap[name] = uv2.func;
- uniformValues[parameterName] = uv2;
- }
- }
- }
+ ForEach.material(gltf, function (material, materialId) {
+ var modelMaterial = model._runtime.materialsById[materialId];
+ var technique = techniques[modelMaterial._technique];
+ var instanceValues = modelMaterial._values;
- var u = uniformMaps[materialId];
- u.uniformMap = uniformMap; // uniform name -> function for the renderer
- u.values = uniformValues; // material parameter name -> ModelMaterial for modifying the parameter at runtime
- u.jointMatrixUniformName = jointMatrixUniformName;
- u.morphWeightsUniformName = morphWeightsUniformName;
- }
- }
+ var uniforms = createUniformsForMaterial(model, technique, instanceValues, context, textures, defaultTexture);
+
+ var u = uniformMaps[materialId];
+ u.uniformMap = uniforms.map; // uniform name -> function for the renderer
+ u.values = uniforms.values; // material parameter name -> ModelMaterial for modifying the parameter at runtime
+ u.jointMatrixUniformName = uniforms.jointMatrixUniformName;
+ u.morphWeightsUniformName = uniforms.morphWeightsUniformName;
+ });
}
function createUniformsForDracoQuantizedAttributes(decodedData) {
@@ -3059,8 +3071,6 @@ define([
var gltf = model.gltf;
var accessors = gltf.accessors;
var gltfMeshes = gltf.meshes;
- var techniques = gltf.techniques;
- var materials = gltf.materials;
var id = gltfNode.mesh;
var mesh = gltfMeshes[id];
@@ -3075,9 +3085,8 @@ define([
for (var i = 0; i < length; ++i) {
var primitive = primitives[i];
var ix = accessors[primitive.indices];
- var material = materials[primitive.material];
- var technique = techniques[material.technique];
- var programId = technique.program;
+ var material = model._runtime.materialsById[primitive.material];
+ var programId = material._program;
var decodedData = model._decodedData[id + '.primitive.' + i];
var boundingSphere;
@@ -3146,9 +3155,9 @@ define([
}
uniformMap = combine(uniformMap, quantizedUniformMap);
- var rs = rendererRenderStates[material.technique];
+ var rs = rendererRenderStates[primitive.material];
- // GLTF_SPEC: Offical means to determine translucency. https://github.com/KhronosGroup/glTF/issues/105
+ // GLTF_SPEC: Official means to determine translucency. https://github.com/KhronosGroup/glTF/issues/105
var isTranslucent = rs.blending.enabled;
var owner = model._pickObject;
@@ -3294,15 +3303,17 @@ define([
}
var children = gltfNode.children;
- var childrenLength = children.length;
- for (var j = 0; j < childrenLength; j++) {
- var childId = children[j];
- if (!seen[childId]) {
- stack.push({
- parentRuntimeNode : runtimeNode,
- gltfNode : nodes[childId],
- id : children[j]
- });
+ if (defined(children)) {
+ var childrenLength = children.length;
+ for (var j = 0; j < childrenLength; j++) {
+ var childId = children[j];
+ if (!seen[childId]) {
+ stack.push({
+ parentRuntimeNode : runtimeNode,
+ gltfNode : nodes[childId],
+ id : children[j]
+ });
+ }
}
}
@@ -3354,28 +3365,28 @@ define([
var context = frameState.context;
var scene3DOnly = frameState.scene3DOnly;
- // Retain references to updated source shaders and programs for rebuilding as needed
- var programs = model._sourcePrograms = model.gltf.programs;
- var shaders = model._sourceShaders = model.gltf.shaders;
+ // Retain references to updated source shaders for rebuilding as needed
+ var shaders = model._sourceShaders;
model._hasPremultipliedAlpha = hasPremultipliedAlpha(model);
var quantizedVertexShaders = model._quantizedVertexShaders;
var toClipCoordinates = model._toClipCoordinatesGLSL = {};
- for (var id in programs) {
- if (programs.hasOwnProperty(id)) {
- var program = programs[id];
+ var programs = model._sourcePrograms;
+ for (var programId in programs) {
+ if (programs.hasOwnProperty(programId)) {
+ var program = programs[programId];
var shader = shaders[program.vertexShader].extras._pipeline.source;
if (model.extensionsUsed.WEB3D_quantized_attributes || model._dequantizeInShader) {
- var quantizedVS = quantizedVertexShaders[id];
+ var quantizedVS = quantizedVertexShaders[programId];
if (!defined(quantizedVS)) {
- quantizedVS = modifyShaderForQuantizedAttributes(shader, id, model);
- quantizedVertexShaders[id] = quantizedVS;
+ quantizedVS = modifyShaderForQuantizedAttributes(shader, programId, model);
+ quantizedVertexShaders[programId] = quantizedVS;
}
shader = quantizedVS;
}
- shader = modifyShader(shader, id, model._vertexShaderLoaded);
- toClipCoordinates[id] = ModelUtility.toClipCoordinatesGLSL(model.gltf, shader);
+ shader = modifyShader(shader, programId, model._vertexShaderLoaded);
+ toClipCoordinates[programId] = ModelUtility.toClipCoordinatesGLSL(model.gltf, shader);
}
}
@@ -3429,7 +3440,7 @@ define([
var publicMatrix = publicNode.matrix;
if (publicNode.useMatrix && defined(publicMatrix)) {
- // Public matrix overrides orginial glTF matrix and glTF animations
+ // Public matrix overrides original glTF matrix and glTF animations
Matrix4.clone(publicMatrix, result);
} else if (defined(node.matrix)) {
Matrix4.clone(node.matrix, result);
@@ -3513,28 +3524,30 @@ define([
}
var children = n.children;
- var childrenLength = children.length;
- for (var k = 0; k < childrenLength; ++k) {
- var child = children[k];
-
- // A node's transform needs to be updated if
- // - It was targeted for animation this frame, or
- // - Any of its ancestors were targeted for animation this frame
-
- // PERFORMANCE_IDEA: if a child has multiple parents and only one of the parents
- // is dirty, all the subtrees for each child instance will be dirty; we probably
- // won't see this in the wild often.
- child.dirtyNumber = Math.max(child.dirtyNumber, n.dirtyNumber);
-
- if ((child.dirtyNumber === maxDirtyNumber) || justLoaded) {
- // Don't check for modelTransformChanged since if only the model's model matrix changed,
- // we do not need to rebuild the local transform-to-root, only the final
- // [model's-model-matrix][transform-to-root] above.
- getNodeMatrix(child, child.transformToRoot);
- Matrix4.multiplyTransformation(transformToRoot, child.transformToRoot, child.transformToRoot);
- }
+ if (defined(children)) {
+ var childrenLength = children.length;
+ for (var k = 0; k < childrenLength; ++k) {
+ var child = children[k];
+
+ // A node's transform needs to be updated if
+ // - It was targeted for animation this frame, or
+ // - Any of its ancestors were targeted for animation this frame
+
+ // PERFORMANCE_IDEA: if a child has multiple parents and only one of the parents
+ // is dirty, all the subtrees for each child instance will be dirty; we probably
+ // won't see this in the wild often.
+ child.dirtyNumber = Math.max(child.dirtyNumber, n.dirtyNumber);
+
+ if ((child.dirtyNumber === maxDirtyNumber) || justLoaded) {
+ // Don't check for modelTransformChanged since if only the model's model matrix changed,
+ // we do not need to rebuild the local transform-to-root, only the final
+ // [model's-model-matrix][transform-to-root] above.
+ getNodeMatrix(child, child.transformToRoot);
+ Matrix4.multiplyTransformation(transformToRoot, child.transformToRoot, child.transformToRoot);
+ }
- nodeStack.push(child);
+ nodeStack.push(child);
+ }
}
}
}
@@ -3600,12 +3613,14 @@ define([
// if commandsLength is zero, the node has a light or camera
var children = n.children;
- var childrenLength = children.length;
- for (var k = 0; k < childrenLength; ++k) {
- var child = children[k];
- // Parent needs to be shown for child to be shown.
- child.computedShow = show && child.publicNode.show;
- nodeStack.push(child);
+ if (defined(children)) {
+ var childrenLength = children.length;
+ for (var k = 0; k < childrenLength; ++k) {
+ var child = children[k];
+ // Parent needs to be shown for child to be shown.
+ child.computedShow = show && child.publicNode.show;
+ nodeStack.push(child);
+ }
}
}
}
@@ -4242,20 +4257,24 @@ define([
// Textures may continue to stream in while in the LOADED state.
if (loadResources.pendingBufferLoads === 0) {
if (!loadResources.initialized) {
- // glTF pipeline updates
- var options = {
- optimizeForCesium: true,
- addBatchIdToGeneratedShaders : this._addBatchIdToGeneratedShaders
- };
frameState.brdfLutGenerator.update(frameState);
+
+ ModelUtility.checkSupportedExtensions(this.extensionsRequired);
+
+ // glTF pipeline updates
+ addPipelineExtras(this.gltf);
+
updateVersion(this.gltf);
if (defined(this.gltf.asset) && defined(this.gltf.asset.extras) &&
this.gltf.asset.extras.gltf_pipeline_upgrade_10to20) {
- this._forwardAxis = Axis.X;
+ this._forwardAxis = Axis.X;
}
- ModelUtility.checkSupportedExtensions(this.extensionsRequired);
- addPipelineExtras(this.gltf);
+
addDefaults(this.gltf);
+
+ var options = {
+ addBatchIdToGeneratedShaders: this._addBatchIdToGeneratedShaders
+ };
processModelMaterialsCommon(this.gltf, options);
processPbrMetallicRoughness(this.gltf, options);
@@ -4314,6 +4333,8 @@ define([
}
if (loadResources.finished()) {
+ ModelUtility.removePipelineExtras(this.gltf);
+
this._loadResources = undefined; // Clear CPU memory since WebGL resources were created.
var resources = this._rendererResources;
@@ -4415,7 +4436,7 @@ define([
updateShadows(this);
updateClippingPlanes(this, frameState);
- // Regnerate shaders if ClippingPlaneCollection state changed or it was removed
+ // Regenerate shaders if ClippingPlaneCollection state changed or it was removed
var clippingPlanes = this._clippingPlanes;
var currentClippingPlanesState = 0;
if (defined(clippingPlanes) && clippingPlanes.enabled) {
@@ -4531,15 +4552,28 @@ define([
var cachedRendererResources = model._cachedRendererResources;
destroyIfNotCached(rendererResources, cachedRendererResources);
+ var programId;
if (isClippingEnabled(model) || isColorShadingEnabled(model)) {
rendererResources.programs = {};
rendererResources.silhouettePrograms = {};
- var sourcePrograms = model._sourcePrograms;
-
- ForEach.object(sourcePrograms, function(program, id) {
- recreateProgram(id, model, frameState.context);
- });
+ var visitedPrograms = {};
+ var techniques = model._sourceTechniques;
+ var technique;
+
+ for (var techniqueId in techniques) {
+ if (techniques.hasOwnProperty(techniqueId)) {
+ technique = techniques[techniqueId];
+ programId = technique.program;
+ if (!visitedPrograms[programId]) {
+ visitedPrograms[programId] = true;
+ recreateProgram({
+ id: programId,
+ technique: techniqueId
+ }, model, frameState.context);
+ }
+ }
+ }
} else {
rendererResources.programs = cachedRendererResources.programs;
rendererResources.silhouettePrograms = cachedRendererResources.silhouettePrograms;
@@ -4552,7 +4586,7 @@ define([
var commandCount = nodeCommands.length;
for (var i = 0; i < commandCount; ++i) {
var nodeCommand = nodeCommands[i];
- var programId = nodeCommand.programId;
+ programId = nodeCommand.programId;
var renderProgram = rendererPrograms[programId];
nodeCommand.command.shaderProgram = renderProgram;
@@ -4628,7 +4662,6 @@ define([
}
releaseCachedGltf(this);
- this._sourcePrograms = undefined;
this._sourceShaders = undefined;
this._quantizedVertexShaders = undefined;
diff --git a/Source/Scene/ModelInstanceCollection.js b/Source/Scene/ModelInstanceCollection.js
index d79691f689bb..678dd4c0251b 100644
--- a/Source/Scene/ModelInstanceCollection.js
+++ b/Source/Scene/ModelInstanceCollection.js
@@ -19,6 +19,7 @@ define([
'../Renderer/DrawCommand',
'../Renderer/Pass',
'../Renderer/ShaderSource',
+ '../ThirdParty/GltfPipeline/ForEach',
'../ThirdParty/when',
'./Model',
'./ModelInstance',
@@ -46,6 +47,7 @@ define([
DrawCommand,
Pass,
ShaderSource,
+ ForEach,
when,
Model,
ModelInstance,
@@ -225,6 +227,22 @@ define([
BoundingSphere.expand(this._boundingSphere, translation, this._boundingSphere);
};
+ function getCheckUniformSemanticFunction(modelSemantics, supportedSemantics, programId, uniformMap) {
+ return function(uniform, uniformName) {
+ var semantic = uniform.semantic;
+ if (defined(semantic) && (modelSemantics.indexOf(semantic) > -1)) {
+ if (supportedSemantics.indexOf(semantic) > -1) {
+ uniformMap[uniformName] = semantic;
+ } else {
+ throw new RuntimeError('Shader program cannot be optimized for instancing. ' +
+ 'Uniform "' + uniformName + '" in program "' + programId +
+ '" uses unsupported semantic "' + semantic + '"'
+ );
+ }
+ }
+ };
+ }
+
function getInstancedUniforms(collection, programId) {
if (defined(collection._instancedUniformsByProgram)) {
return collection._instancedUniformsByProgram[programId];
@@ -237,13 +255,10 @@ define([
var modelSemantics = ['MODEL', 'MODELVIEW', 'CESIUM_RTC_MODELVIEW', 'MODELVIEWPROJECTION', 'MODELINVERSE', 'MODELVIEWINVERSE', 'MODELVIEWPROJECTIONINVERSE', 'MODELINVERSETRANSPOSE', 'MODELVIEWINVERSETRANSPOSE'];
var supportedSemantics = ['MODELVIEW', 'CESIUM_RTC_MODELVIEW', 'MODELVIEWPROJECTION', 'MODELVIEWINVERSETRANSPOSE'];
- var gltf = collection._model.gltf;
- var techniques = gltf.techniques;
+ var techniques = collection._model._sourceTechniques;
for (var techniqueName in techniques) {
if (techniques.hasOwnProperty(techniqueName)) {
var technique = techniques[techniqueName];
- var parameters = technique.parameters;
- var uniforms = technique.uniforms;
var program = technique.program;
// Different techniques may share the same program, skip if already processed.
@@ -251,23 +266,7 @@ define([
if (!defined(instancedUniformsByProgram[program])) {
var uniformMap = {};
instancedUniformsByProgram[program] = uniformMap;
- for (var uniformName in uniforms) {
- if (uniforms.hasOwnProperty(uniformName)) {
- var parameterName = uniforms[uniformName];
- var parameter = parameters[parameterName];
- var semantic = parameter.semantic;
- if (defined(semantic) && (modelSemantics.indexOf(semantic) > -1)) {
- if (supportedSemantics.indexOf(semantic) > -1) {
- uniformMap[uniformName] = semantic;
- } else {
- throw new RuntimeError('Shader program cannot be optimized for instancing. ' +
- 'Parameter "' + parameter + '" in program "' + programId +
- '" uses unsupported semantic "' + semantic + '"'
- );
- }
- }
- }
- }
+ ForEach.techniqueUniform(technique, getCheckUniformSemanticFunction(modelSemantics, supportedSemantics, programId, uniformMap));
}
}
}
diff --git a/Source/Scene/ModelMaterial.js b/Source/Scene/ModelMaterial.js
index cc149d1be3dd..5726a532ef14 100644
--- a/Source/Scene/ModelMaterial.js
+++ b/Source/Scene/ModelMaterial.js
@@ -26,6 +26,10 @@ define([
this._name = material.name;
this._id = id;
this._uniformMap = model._uniformMaps[id];
+
+ this._technique = undefined;
+ this._program = undefined;
+ this._values = undefined;
}
defineProperties(ModelMaterial.prototype, {
diff --git a/Source/Scene/ModelUtility.js b/Source/Scene/ModelUtility.js
index 9e7524ef3f05..d1cdd8cb83c4 100644
--- a/Source/Scene/ModelUtility.js
+++ b/Source/Scene/ModelUtility.js
@@ -2,6 +2,7 @@ define([
'../Core/Cartesian2',
'../Core/Cartesian3',
'../Core/Cartesian4',
+ '../Core/clone',
'../Core/defined',
'../Core/defineProperties',
'../Core/Matrix2',
@@ -11,11 +12,15 @@ define([
'../Core/RuntimeError',
'../Core/WebGLConstants',
'../Renderer/ShaderSource',
+ '../ThirdParty/GltfPipeline/addToArray',
+ '../ThirdParty/GltfPipeline/ForEach',
+ '../ThirdParty/GltfPipeline/hasExtension',
'./AttributeType'
], function(
Cartesian2,
Cartesian3,
Cartesian4,
+ clone,
defined,
defineProperties,
Matrix2,
@@ -25,6 +30,9 @@ define([
RuntimeError,
WebGLConstants,
ShaderSource,
+ addToArray,
+ ForEach,
+ hasExtension,
AttributeType) {
'use strict';
@@ -33,6 +41,245 @@ define([
*/
var ModelUtility = {};
+ function removeExtrasIfEmpty(object) {
+ if (!defined(object.extras)) {
+ return;
+ }
+
+ var pipeline = object.extras._pipeline;
+ if (!defined(pipeline)) {
+ return;
+ }
+
+ if (Object.keys(pipeline).length === 0) {
+ delete object.extras;
+ }
+ }
+
+ /**
+ * Removes empty extra._pipeline object from each object that can have extras in the glTF asset.
+ *
+ * @param {Object} gltf A javascript object containing a glTF asset.
+ * @returns {Object} The glTF asset with the added pipeline extras.
+ */
+ ModelUtility.removePipelineExtras = function(gltf) {
+ ForEach.shader(gltf, function(shader) {
+ removeExtrasIfEmpty(shader);
+ });
+ ForEach.buffer(gltf, function(buffer) {
+ removeExtrasIfEmpty(buffer);
+ });
+ ForEach.image(gltf, function(image) {
+ removeExtrasIfEmpty(image);
+ ForEach.compressedImage(image, function(compressedImage) {
+ removeExtrasIfEmpty(compressedImage);
+ });
+ });
+
+ removeExtrasIfEmpty(gltf);
+
+ return gltf;
+ };
+
+ /**
+ * Splits primitive materials with values incompatible for generating techniques.
+ *
+ * @param {Object} gltf A javascript object containing a glTF asset.
+ * @returns {Object} The glTF asset with modified materials.
+ */
+ ModelUtility.splitIncompatibleMaterials = function(gltf) {
+ var accessors = gltf.accessors;
+ var materials = gltf.materials;
+ ForEach.mesh(gltf, function(mesh) {
+ ForEach.meshPrimitive(mesh, function(primitive) {
+ var materialId = primitive.material;
+ var material = materials[materialId];
+
+ var jointAccessorId = primitive.attributes.JOINTS_0;
+ var componentType;
+ var type;
+ if (defined(jointAccessorId)) {
+ var jointAccessor = accessors[jointAccessorId];
+ componentType = jointAccessor.componentType;
+ type = jointAccessor.type;
+ }
+ var isSkinned = defined(jointAccessorId);
+ var hasVertexColors = defined(primitive.attributes.COLOR_0);
+ var hasMorphTargets = defined(primitive.targets);
+ var hasNormals = defined(primitive.attributes.NORMAL);
+ var hasTangents = defined(primitive.attributes.TANGENT);
+ var hasTexCoords = defined(primitive.attributes.TEXCOORD_0);
+
+ if (!defined(material.extras) || !defined(material.extras._pipeline)) {
+ material.extras = {
+ _pipeline: {}
+ };
+ }
+
+ var primitiveInfo = material.extras._pipeline.primitive;
+ if (!defined(primitiveInfo)) {
+ material.extras._pipeline.primitive = {
+ skinning: {
+ skinned: isSkinned,
+ componentType: componentType,
+ type: type
+ },
+ hasVertexColors: hasVertexColors,
+ hasMorphTargets: hasMorphTargets,
+ hasNormals: hasNormals,
+ hasTangents: hasTangents,
+ hasTexCoords: hasTexCoords
+ };
+ } else if ((primitiveInfo.skinning.skinned !== isSkinned) ||
+ (primitiveInfo.skinning.type !== type) ||
+ (primitiveInfo.hasVertexColors !== hasVertexColors) ||
+ (primitiveInfo.hasMorphTargets !== hasMorphTargets) ||
+ (primitiveInfo.hasNormals !== hasNormals) ||
+ (primitiveInfo.hasTangents !== hasTangents) ||
+ (primitiveInfo.hasTexCoords !== hasTexCoords)) {
+ // This primitive uses the same material as another one that either:
+ // * Isn't skinned
+ // * Uses a different type to store joints and weights
+ // * Doesn't have vertex colors, morph targets, normals, tangents, or texCoords
+ var clonedMaterial = clone(material, true);
+ clonedMaterial.extras._pipeline.primitive = {
+ skinning: {
+ skinned: isSkinned,
+ componentType: componentType,
+ type: type
+ },
+ hasVertexColors: hasVertexColors,
+ hasMorphTargets: hasMorphTargets,
+ hasNormals: hasNormals,
+ hasTangents: hasTangents,
+ hasTexCoords: hasTexCoords
+ };
+ // Split this off as a separate material
+ materialId = addToArray(materials, clonedMaterial);
+ primitive.material = materialId;
+ }
+ });
+ });
+
+ return gltf;
+ };
+
+ ModelUtility.getShaderVariable = function(type) {
+ if (type === 'SCALAR') {
+ return 'float';
+ }
+ return type.toLowerCase();
+ };
+
+ function techniqueAttributeForSemantic(technique, semantic) {
+ return ForEach.techniqueAttribute(technique, function(attribute, attributeName) {
+ if (attribute.semantic === semantic) {
+ return attributeName;
+ }
+ });
+ }
+
+ function ensureSemanticExistenceForPrimitive(gltf, primitive) {
+ var accessors = gltf.accessors;
+ var materials = gltf.materials;
+ var techniquesWebgl = gltf.extensions.KHR_techniques_webgl;
+
+ var techniques = techniquesWebgl.techniques;
+ var programs = techniquesWebgl.programs;
+ var shaders = techniquesWebgl.shaders;
+ var targets = primitive.targets;
+
+ var attributes = primitive.attributes;
+ for (var target in targets) {
+ if (targets.hasOwnProperty(target)) {
+ var targetAttributes = targets[target];
+ for (var attribute in targetAttributes) {
+ if (attribute !== 'extras') {
+ attributes[attribute + '_' + target] = targetAttributes[attribute];
+ }
+ }
+ }
+ }
+
+ var material = materials[primitive.material];
+ var technique = techniques[material.extensions.KHR_techniques_webgl.technique];
+ var program = programs[technique.program];
+ var vertexShader = shaders[program.vertexShader];
+
+ for (var semantic in attributes) {
+ if (attributes.hasOwnProperty(semantic)) {
+ if (!defined(techniqueAttributeForSemantic(technique, semantic))) {
+ var accessorId = attributes[semantic];
+ var accessor = accessors[accessorId];
+ var lowerCase = semantic.toLowerCase();
+ if (lowerCase.charAt(0) === '_') {
+ lowerCase = lowerCase.slice(1);
+ }
+ var attributeName = 'a_' + lowerCase;
+ technique.attributes[attributeName] = {
+ semantic: semantic,
+ type: accessor.componentType
+ };
+ var pipelineExtras = vertexShader.extras._pipeline;
+ var shaderText = pipelineExtras.source;
+ shaderText = 'attribute ' + ModelUtility.getShaderVariable(accessor.type) + ' ' + attributeName + ';\n' + shaderText;
+ pipelineExtras.source = shaderText;
+ }
+ }
+ }
+ }
+
+ /**
+ * Ensures all attributes present on the primitive are present in the technique and
+ * vertex shader.
+ *
+ * @param {Object} gltf A javascript object containing a glTF asset.
+ * @returns {Object} The glTF asset, including any additional attributes.
+ */
+ ModelUtility.ensureSemanticExistence = function (gltf) {
+ ForEach.mesh(gltf, function(mesh) {
+ ForEach.meshPrimitive(mesh, function(primitive) {
+ ensureSemanticExistenceForPrimitive(gltf, primitive);
+ });
+ });
+
+ return gltf;
+ };
+
+ /**
+ * Creates attribute location for all attributes required by a technique.
+ *
+ * @param {Object} technique A glTF KHR_techniques_webgl technique object.
+ * @param {Object} precreatedAttributes A dictionary object of pre-created attributes for which to also create locations.
+ * @returns {Object} A dictionary object containing attribute names and their locations.
+ */
+ ModelUtility.createAttributeLocations = function(technique, precreatedAttributes) {
+ var attributeLocations = {};
+ var i = 1;
+
+ ForEach.techniqueAttribute(technique, function (attribute, attributeName) {
+ // Set the position attribute to the 0th index. In some WebGL implementations the shader
+ // will not work correctly if the 0th attribute is not active. For example, some glTF models
+ // list the normal attribute first but derived shaders like the cast-shadows shader do not use
+ // the normal attribute.
+ if (/pos/i.test(attributeName)) {
+ attributeLocations[attributeName] = 0;
+ } else {
+ attributeLocations[attributeName] = i++;
+ }
+ });
+
+ if (defined(precreatedAttributes)) {
+ for (var attributeName in precreatedAttributes) {
+ if (precreatedAttributes.hasOwnProperty(attributeName)) {
+ attributeLocations[attributeName] = i++;
+ }
+ }
+ }
+
+ return attributeLocations;
+ };
+
ModelUtility.getAccessorMinMax = function(gltf, accessorId) {
var accessor = gltf.accessors[accessorId];
var extensions = accessor.extensions;
@@ -52,37 +299,37 @@ define([
};
};
- ModelUtility.getAttributeOrUniformBySemantic = function(gltf, semantic, programId, ignoreNodes) {
- var techniques = gltf.techniques;
- var parameter;
- for (var techniqueName in techniques) {
- if (techniques.hasOwnProperty(techniqueName)) {
- var technique = techniques[techniqueName];
- if (defined(programId) && (technique.program !== programId)) {
- continue;
- }
- var parameters = technique.parameters;
- var attributes = technique.attributes;
- var uniforms = technique.uniforms;
- for (var attributeName in attributes) {
- if (attributes.hasOwnProperty(attributeName)) {
- parameter = parameters[attributes[attributeName]];
- if (defined(parameter) && parameter.semantic === semantic && (!ignoreNodes || !defined(parameter.node))) {
- return attributeName;
- }
- }
- }
- for (var uniformName in uniforms) {
- if (uniforms.hasOwnProperty(uniformName)) {
- parameter = parameters[uniforms[uniformName]];
- if (defined(parameter) && parameter.semantic === semantic && (!ignoreNodes || !defined(parameter.node))) {
- return uniformName;
- }
- }
+ function getTechniqueAttributeOrUniformFunction(gltf, technique, semantic, ignoreNodes) {
+ if (hasExtension(gltf, 'KHR_techniques_webgl')) {
+ return function(attributeOrUniform, attributeOrUniformName) {
+ if (attributeOrUniform.semantic === semantic && (!ignoreNodes || !defined(attributeOrUniform.node))) {
+ return attributeOrUniformName;
}
- }
+ };
}
- return undefined;
+
+ return function(parameterName, attributeOrUniformName) {
+ var attributeOrUniform = technique.parameters[parameterName];
+ if (attributeOrUniform.semantic === semantic && (!ignoreNodes || !defined(attributeOrUniform.node))) {
+ return attributeOrUniformName;
+ }
+ };
+ }
+
+ ModelUtility.getAttributeOrUniformBySemantic = function(gltf, semantic, programId, ignoreNodes) {
+ return ForEach.technique(gltf, function(technique) {
+ if (defined(programId) && (technique.program !== programId)) {
+ return;
+ }
+
+ var value = ForEach.techniqueAttribute(technique, getTechniqueAttributeOrUniformFunction(gltf, technique, semantic, ignoreNodes));
+
+ if (defined(value)) {
+ return value;
+ }
+
+ return ForEach.techniqueUniform(technique, getTechniqueAttributeOrUniformFunction(gltf, technique, semantic, ignoreNodes));
+ });
};
ModelUtility.getDiffuseAttributeOrUniform = function(gltf, programId) {
@@ -138,15 +385,20 @@ define([
return cachedExtensionsRequired;
};
+ ModelUtility.supportedExtensions = {
+ 'CESIUM_RTC' : true,
+ 'EXT_blend' : true,
+ 'KHR_binary_glTF' : true,
+ 'KHR_draco_mesh_compression' : true,
+ 'KHR_materials_common' : true,
+ 'KHR_techniques_webgl': true,
+ 'WEB3D_quantized_attributes' : true
+ };
+
ModelUtility.checkSupportedExtensions = function(extensionsRequired) {
for (var extension in extensionsRequired) {
if (extensionsRequired.hasOwnProperty(extension)) {
- if (extension !== 'CESIUM_RTC' &&
- extension !== 'KHR_technique_webgl' &&
- extension !== 'KHR_binary_glTF' &&
- extension !== 'KHR_materials_common' &&
- extension !== 'WEB3D_quantized_attributes' &&
- extension !== 'KHR_draco_mesh_compression') {
+ if (!ModelUtility.supportedExtensions[extension]) {
throw new RuntimeError('Unsupported glTF Extension: ' + extension);
}
}
@@ -190,25 +442,22 @@ define([
function getAttributeVariableName(gltf, primitive, attributeSemantic) {
var materialId = primitive.material;
var material = gltf.materials[materialId];
- var techniqueId = material.technique;
- var technique = gltf.techniques[techniqueId];
- for (var parameter in technique.parameters) {
- if (technique.parameters.hasOwnProperty(parameter)) {
- var semantic = technique.parameters[parameter].semantic;
- if (semantic === attributeSemantic) {
- var attributes = technique.attributes;
- for (var attributeVarName in attributes) {
- if (attributes.hasOwnProperty(attributeVarName)) {
- var name = attributes[attributeVarName];
- if (name === parameter) {
- return attributeVarName;
- }
- }
- }
- }
- }
+
+ if (!hasExtension(gltf, 'KHR_techniques_webgl')
+ || !defined(material.extensions)
+ || !defined(material.extensions.KHR_techniques_webgl)) {
+ return;
}
- return undefined;
+
+ var techniqueId = material.extensions.KHR_techniques_webgl.technique;
+ var techniquesWebgl = gltf.extensions.KHR_techniques_webgl;
+ var technique = techniquesWebgl.techniques[techniqueId];
+ return ForEach.techniqueAttribute(technique, function(attribute, attributeName) {
+ var semantic = attribute.semantic;
+ if (semantic === attributeSemantic) {
+ return attributeName;
+ }
+ });
}
ModelUtility.modifyShaderForDracoQuantizedAttributes = function(gltf, primitive, shader, decodedAttributes) {
@@ -516,8 +765,8 @@ define([
///////////////////////////////////////////////////////////////////////////
- function getTextureUniformFunction(value, texture, defaultTexture) {
- var uniform = new DelayLoadedTextureUniform(value, texture, defaultTexture);
+ function getTextureUniformFunction(value, textures, defaultTexture) {
+ var uniform = new DelayLoadedTextureUniform(value, textures, defaultTexture);
// Define function here to access closure since 'this' can't be
// used when the Renderer sets uniforms.
uniform.func = function() {
diff --git a/Source/ThirdParty/GltfPipeline/processModelMaterialsCommon.js b/Source/Scene/processModelMaterialsCommon.js
similarity index 62%
rename from Source/ThirdParty/GltfPipeline/processModelMaterialsCommon.js
rename to Source/Scene/processModelMaterialsCommon.js
index bcf942379723..c8fd54254680 100644
--- a/Source/ThirdParty/GltfPipeline/processModelMaterialsCommon.js
+++ b/Source/Scene/processModelMaterialsCommon.js
@@ -1,25 +1,24 @@
define([
- './addToArray',
- './ForEach',
- './numberOfComponentsForType',
- './techniqueParameterForSemantic',
- './webGLConstantToGlslType',
- './glslTypeToWebGLConstant',
- '../../Core/clone',
- '../../Core/defined',
- '../../Core/defaultValue',
- '../../Core/WebGLConstants'
+ './ModelUtility',
+ '../Core/defined',
+ '../Core/defaultValue',
+ '../Core/WebGLConstants',
+ '../Core/webGLConstantToGlslType',
+ '../ThirdParty/GltfPipeline/addToArray',
+ '../ThirdParty/GltfPipeline/ForEach',
+ '../ThirdParty/GltfPipeline/hasExtension',
+ '../ThirdParty/GltfPipeline/numberOfComponentsForType'
], function(
- addToArray,
- ForEach,
- numberOfComponentsForType,
- techniqueParameterForSemantic,
- webGLConstantToGlslType,
- glslTypeToWebGLConstant,
- clone,
+ ModelUtility,
defined,
defaultValue,
- WebGLConstants) {
+ WebGLConstants,
+ webGLConstantToGlslType,
+ addToArray,
+ ForEach,
+ hasExtension,
+ numberOfComponentsForType
+ ) {
'use strict';
/**
@@ -29,85 +28,81 @@ define([
options = defaultValue(options, {});
if (!defined(gltf)) {
- return undefined;
+ return;
}
- var hasExtension = false;
- var extensionsRequired = gltf.extensionsRequired;
- var extensionsUsed = gltf.extensionsUsed;
- if (defined(extensionsUsed)) {
- var index = extensionsUsed.indexOf('KHR_materials_common');
- if (index >= 0) {
- extensionsUsed.splice(index, 1);
- hasExtension = true;
- }
- if (defined(extensionsRequired)) {
- index = extensionsRequired.indexOf('KHR_materials_common');
- if (index >= 0) {
- extensionsRequired.splice(index, 1);
- }
- }
+ if (!hasExtension(gltf, 'KHR_materials_common')) {
+ return;
}
- if (hasExtension) {
- if (!defined(gltf.programs)) {
- gltf.programs = [];
- }
- if (!defined(gltf.shaders)) {
- gltf.shaders = [];
- }
- if (!defined(gltf.techniques)) {
- gltf.techniques = [];
- }
- lightDefaults(gltf);
-
- var lightParameters = generateLightParameters(gltf);
-
- // Pre-processing to address incompatibilities between primitives using the same materials. Handles skinning and vertex color incompatibilities.
- splitIncompatibleMaterials(gltf);
-
- var techniques = {};
- ForEach.material(gltf, function(material) {
- if (defined(material.extensions) && defined(material.extensions.KHR_materials_common)) {
- var khrMaterialsCommon = material.extensions.KHR_materials_common;
- var techniqueKey = getTechniqueKey(khrMaterialsCommon);
- var technique = techniques[techniqueKey];
- if (!defined(technique)) {
- technique = generateTechnique(gltf, khrMaterialsCommon, lightParameters, options);
- techniques[techniqueKey] = technique;
- }
+ if (!hasExtension('KHR_techniques_webgl')) {
+ gltf.extensions.KHR_techniques_webgl = {
+ programs : [],
+ shaders : [],
+ techniques : []
+ };
+ gltf.extensionsUsed.push('KHR_techniques_webgl');
+ gltf.extensionsRequired.push('KHR_techniques_webgl');
+ }
- // Take advantage of the fact that we generate techniques that use the
- // same parameter names as the extension values.
- material.values = {};
- var values = khrMaterialsCommon.values;
- for (var valueName in values) {
- if (values.hasOwnProperty(valueName)) {
- var value = values[valueName];
- material.values[valueName] = value;
- }
- }
+ var techniquesWebgl = gltf.extensions.KHR_techniques_webgl;
+
+ lightDefaults(gltf);
- material.technique = technique;
+ var lightParameters = generateLightParameters(gltf);
- delete material.extensions.KHR_materials_common;
- if (Object.keys(material.extensions).length === 0) {
- delete material.extensions;
+ ModelUtility.splitIncompatibleMaterials (gltf);
+
+ var techniques = {};
+ ForEach.material(gltf, function(material) {
+ if (defined(material.extensions) && defined(material.extensions.KHR_materials_common)) {
+ var khrMaterialsCommon = material.extensions.KHR_materials_common;
+ var techniqueKey = getTechniqueKey(material, khrMaterialsCommon);
+ var technique = techniques[techniqueKey];
+ var primitiveInfo = material.extras._pipeline.primitive;
+
+ if (!defined(technique)) {
+ technique = generateTechnique(gltf, techniquesWebgl, primitiveInfo, khrMaterialsCommon, lightParameters, options.addBatchIdToGeneratedShaders);
+ techniques[techniqueKey] = technique;
+ }
+
+ var materialValues = {};
+ var values = khrMaterialsCommon.values;
+ var uniformName;
+ for (var valueName in values) {
+ if (values.hasOwnProperty(valueName) && (valueName !== 'transparent') && (valueName !== 'doubleSided')) {
+ uniformName = 'u_' + valueName.toLowerCase();
+ materialValues[uniformName] = values[valueName];
}
}
- });
- if (defined(gltf.extensions)) {
- delete gltf.extensions.KHR_materials_common;
- if (Object.keys(gltf.extensions).length === 0) {
- delete gltf.extensions;
+ material.extensions.KHR_techniques_webgl = {
+ technique: technique,
+ values: materialValues
+ };
+
+ if (khrMaterialsCommon.transparent) {
+ material.alphaMode = 'BLEND';
+ material.extensions.KHR_blend = {
+ blendFactors: [
+ WebGLConstants.ONE,
+ WebGLConstants.ONE_MINUS_SRC_ALPHA,
+ WebGLConstants.ONE,
+ WebGLConstants.ONE_MINUS_SRC_ALPHA
+ ]
+ };
+ if (!hasExtension(gltf, 'KHR_blend')) {
+ gltf.extensions.push('KHR_blend');
+ }
+ } else if (khrMaterialsCommon.doubleSided) {
+ material.doubleSided = true;
}
}
+ });
- // If any primitives have semantics that aren't declared in the generated
- // shaders, we want to preserve them.
- ensureSemanticExistence(gltf);
- }
+ // If any primitives have semantics that aren't declared in the generated
+ // shaders, we want to preserve them.
+ ModelUtility.ensureSemanticExistence(gltf);
return gltf;
}
@@ -226,28 +221,17 @@ define([
return result;
}
- function generateTechnique(gltf, khrMaterialsCommon, lightParameters, options) {
- var optimizeForCesium = defaultValue(options.optimizeForCesium, false);
- var hasCesiumRTCExtension = defined(gltf.extensions) && defined(gltf.extensions.CESIUM_RTC);
- var addBatchIdToGeneratedShaders = defaultValue(options.addBatchIdToGeneratedShaders, false);
+ function generateTechnique(gltf, techniquesWebgl, primitiveInfo, khrMaterialsCommon, lightParameters, addBatchIdToGeneratedShaders) {
+ addBatchIdToGeneratedShaders = defaultValue(addBatchIdToGeneratedShaders, false);
- var techniques = gltf.techniques;
- var shaders = gltf.shaders;
- var programs = gltf.programs;
+ var techniques = techniquesWebgl.techniques;
+ var shaders = techniquesWebgl.shaders;
+ var programs = techniquesWebgl.programs;
var lightingModel = khrMaterialsCommon.technique.toUpperCase();
- var lights;
- if (defined(gltf.extensions) && defined(gltf.extensions.KHR_materials_common)) {
- lights = gltf.extensions.KHR_materials_common.lights;
- }
+ var lights = gltf.extensions.KHR_materials_common.lights;
+
var parameterValues = khrMaterialsCommon.values;
- if (defined(khrMaterialsCommon.transparent)) {
- parameterValues.transparent = khrMaterialsCommon.transparent;
- }
- if (defined(khrMaterialsCommon.doubleSided)) {
- parameterValues.doubleSided = khrMaterialsCommon.doubleSided;
- }
var jointCount = defaultValue(khrMaterialsCommon.jointCount, 0);
- var primitiveInfo = khrMaterialsCommon.extras._pipeline.primitive;
var skinningInfo;
var hasSkinning = false;
@@ -265,78 +249,77 @@ define([
var hasNormals = (lightingModel !== 'CONSTANT');
// Add techniques
- var techniqueParameters = {
- // Add matrices
- modelViewMatrix: {
- semantic: hasCesiumRTCExtension ? 'CESIUM_RTC_MODELVIEW' : 'MODELVIEW',
+ var techniqueUniforms = {
+ u_modelViewMatrix: {
+ semantic: hasExtension(gltf, 'CESIUM_RTC') ? 'CESIUM_RTC_MODELVIEW' : 'MODELVIEW',
type: WebGLConstants.FLOAT_MAT4
},
- projectionMatrix: {
+ u_projectionMatrix: {
semantic: 'PROJECTION',
type: WebGLConstants.FLOAT_MAT4
}
};
if (hasNormals) {
- techniqueParameters.normalMatrix = {
+ techniqueUniforms.u_normalMatrix = {
semantic: 'MODELVIEWINVERSETRANSPOSE',
type: WebGLConstants.FLOAT_MAT3
};
}
if (hasSkinning) {
- techniqueParameters.jointMatrix = {
+ techniqueUniforms.u_jointMatrix = {
count: jointCount,
semantic: 'JOINTMATRIX',
type: WebGLConstants.FLOAT_MAT4
};
}
- // Add material parameters
- var lowerCase;
+ // Add material values
+ var uniformName;
var hasTexCoords = false;
for (var name in parameterValues) {
//generate shader parameters for KHR_materials_common attributes
//(including a check, because some boolean flags should not be used as shader parameters)
if (parameterValues.hasOwnProperty(name) && (name !== 'transparent') && (name !== 'doubleSided')) {
- var valType = getKHRMaterialsCommonValueType(name, parameterValues[name]);
- lowerCase = name.toLowerCase();
- if (!hasTexCoords && (valType === WebGLConstants.SAMPLER_2D)) {
+ var uniformType = getKHRMaterialsCommonValueType(name, parameterValues[name]);
+ uniformName = 'u_' + name.toLowerCase();
+ if (!hasTexCoords && (uniformType === WebGLConstants.SAMPLER_2D)) {
hasTexCoords = true;
}
- techniqueParameters[lowerCase] = {
- type: valType
+
+ techniqueUniforms[uniformName] = {
+ type : uniformType
};
}
}
// Give the diffuse uniform a semantic to support color replacement in 3D Tiles
- if (defined(techniqueParameters.diffuse) && optimizeForCesium) {
- techniqueParameters.diffuse.semantic = '_3DTILESDIFFUSE';
+ if (defined(techniqueUniforms.u_diffuse)) {
+ techniqueUniforms.u_diffuse.semantic = '_3DTILESDIFFUSE';
}
// Copy light parameters into technique parameters
if (defined(lightParameters)) {
for (var lightParamName in lightParameters) {
if (lightParameters.hasOwnProperty(lightParamName)) {
- techniqueParameters[lightParamName] = lightParameters[lightParamName];
+ uniformName = 'u_' + lightParamName;
+ techniqueUniforms[uniformName] = lightParameters[lightParamName];
}
}
}
- // Generate uniforms object before attributes are added
- var techniqueUniforms = {};
- for (var paramName in techniqueParameters) {
- if (techniqueParameters.hasOwnProperty(paramName) && paramName !== 'extras') {
- var param = techniqueParameters[paramName];
- techniqueUniforms['u_' + paramName] = paramName;
- var arraySize = defined(param.count) ? '[' + param.count + ']' : '';
- if (((param.type !== WebGLConstants.FLOAT_MAT3) && (param.type !== WebGLConstants.FLOAT_MAT4)) ||
- param.useInFragment) {
- fragmentShader += 'uniform ' + webGLConstantToGlslType(param.type) + ' u_' + paramName + arraySize + ';\n';
- delete param.useInFragment;
+ // Add uniforms to shaders
+ for (uniformName in techniqueUniforms) {
+ if (techniqueUniforms.hasOwnProperty(uniformName)) {
+ var uniform = techniqueUniforms[uniformName];
+ var arraySize = defined(uniform.count) ? '[' + uniform.count + ']' : '';
+ if (((uniform.type !== WebGLConstants.FLOAT_MAT3) && (uniform.type !== WebGLConstants.FLOAT_MAT4)) ||
+ uniform.useInFragment) {
+ fragmentShader += 'uniform ' + webGLConstantToGlslType(uniform.type) + ' ' + uniformName + arraySize + ';\n';
+ delete uniform.useInFragment;
} else {
- vertexShader += 'uniform ' + webGLConstantToGlslType(param.type) + ' u_' + paramName + arraySize + ';\n';
+ vertexShader += 'uniform ' + webGLConstantToGlslType(uniform.type) + ' ' + uniformName + arraySize + ';\n';
}
}
}
@@ -376,11 +359,9 @@ define([
// Add position always
var techniqueAttributes = {
- a_position: 'position'
- };
- techniqueParameters.position = {
- semantic: 'POSITION',
- type: WebGLConstants.FLOAT_VEC3
+ a_position: {
+ semantic : 'POSITION'
+ }
};
vertexShader += 'attribute vec3 a_position;\n';
vertexShader += 'varying vec3 v_positionEC;\n';
@@ -395,10 +376,8 @@ define([
// Add normal if we don't have constant lighting
if (hasNormals) {
- techniqueAttributes.a_normal = 'normal';
- techniqueParameters.normal = {
- semantic: 'NORMAL',
- type: WebGLConstants.FLOAT_VEC3
+ techniqueAttributes.a_normal = {
+ semantic: 'NORMAL'
};
vertexShader += 'attribute vec3 a_normal;\n';
vertexShader += 'varying vec3 v_normal;\n';
@@ -414,10 +393,8 @@ define([
// Add texture coordinates if the material uses them
var v_texcoord;
if (hasTexCoords) {
- techniqueAttributes.a_texcoord_0 = 'texcoord_0';
- techniqueParameters.texcoord_0 = {
- semantic: 'TEXCOORD_0',
- type: WebGLConstants.FLOAT_VEC2
+ techniqueAttributes.a_texcoord_0 = {
+ semantic: 'TEXCOORD_0'
};
v_texcoord = 'v_texcoord_0';
@@ -429,18 +406,12 @@ define([
}
if (hasSkinning) {
- techniqueAttributes.a_joint = 'joint';
- var attributeType = getShaderVariable(skinningInfo.type);
- var webGLConstant = glslTypeToWebGLConstant(attributeType);
-
- techniqueParameters.joint = {
- semantic: 'JOINT',
- type: webGLConstant
+ var attributeType = ModelUtility.getShaderVariable(skinningInfo.type);
+ techniqueAttributes.a_joint = {
+ semantic: 'JOINT'
};
- techniqueAttributes.a_weight = 'weight';
- techniqueParameters.weight = {
- semantic: 'WEIGHT',
- type: webGLConstant
+ techniqueAttributes.a_weight = {
+ semantic: 'WEIGHT'
};
vertexShader += 'attribute ' + attributeType + ' a_joint;\n';
@@ -448,10 +419,8 @@ define([
}
if (hasVertexColors) {
- techniqueAttributes.a_vertexColor = 'vertexColor';
- techniqueParameters.vertexColor = {
- semantic: 'COLOR_0',
- type: WebGLConstants.FLOAT_VEC4
+ techniqueAttributes.a_vertexColor = {
+ semantic: 'COLOR_0'
};
vertexShader += 'attribute vec4 a_vertexColor;\n';
vertexShader += 'varying vec4 v_vertexColor;\n';
@@ -460,17 +429,15 @@ define([
}
if (addBatchIdToGeneratedShaders) {
- techniqueAttributes.a_batchId = 'batchId';
- techniqueParameters.batchId = {
- semantic: '_BATCHID',
- type: WebGLConstants.FLOAT
+ techniqueAttributes.a_batchId = {
+ semantic: '_BATCHID'
};
vertexShader += 'attribute float a_batchId;\n';
}
var hasSpecular = hasNormals && ((lightingModel === 'BLINN') || (lightingModel === 'PHONG')) &&
- defined(techniqueParameters.specular) && defined(techniqueParameters.shininess) &&
- (techniqueParameters.shininess > 0.0);
+ defined(techniqueUniforms.u_specular) && defined(techniqueUniforms.u_shininess) &&
+ (techniqueUniforms.u_shininess > 0.0);
// Generate lighting code blocks
var hasNonAmbientLights = false;
@@ -553,12 +520,8 @@ define([
}
if (!hasNonAmbientLights && (lightingModel !== 'CONSTANT')) {
- if (optimizeForCesium) {
- fragmentLightingBlock += ' vec3 l = normalize(czm_sunDirectionEC);\n';
- } else {
- fragmentLightingBlock += ' vec3 l = vec3(0.0, 0.0, 1.0);\n';
- }
- var minimumLighting = optimizeForCesium ? '0.2' : '0.0'; // Use strings instead of values as 0.0 -> 0 when stringified
+ fragmentLightingBlock += ' vec3 l = normalize(czm_sunDirectionEC);\n';
+ var minimumLighting = '0.2'; // Use strings instead of values as 0.0 -> 0 when stringified
fragmentLightingBlock += ' diffuseLight += vec3(1.0, 1.0, 1.0) * max(dot(normal,l), ' + minimumLighting + ');\n';
if (hasSpecular) {
@@ -592,8 +555,8 @@ define([
var finalColorComputation;
if (lightingModel !== 'CONSTANT') {
- if (defined(techniqueParameters.diffuse)) {
- if (techniqueParameters.diffuse.type === WebGLConstants.SAMPLER_2D) {
+ if (defined(techniqueUniforms.u_diffuse)) {
+ if (techniqueUniforms.u_diffuse.type === WebGLConstants.SAMPLER_2D) {
fragmentShader += ' vec4 diffuse = texture2D(u_diffuse, ' + v_texcoord + ');\n';
} else {
fragmentShader += ' vec4 diffuse = u_diffuse;\n';
@@ -603,7 +566,7 @@ define([
}
if (hasSpecular) {
- if (techniqueParameters.specular.type === WebGLConstants.SAMPLER_2D) {
+ if (techniqueUniforms.u_specular.type === WebGLConstants.SAMPLER_2D) {
fragmentShader += ' vec3 specular = texture2D(u_specular, ' + v_texcoord + ').rgb;\n';
} else {
fragmentShader += ' vec3 specular = u_specular.rgb;\n';
@@ -612,25 +575,23 @@ define([
colorCreationBlock += ' color += specular * specularLight;\n';
}
- if (defined(techniqueParameters.transparency)) {
+ if (defined(techniqueUniforms.u_transparency)) {
finalColorComputation = ' gl_FragColor = vec4(color * diffuse.a * u_transparency, diffuse.a * u_transparency);\n';
} else {
finalColorComputation = ' gl_FragColor = vec4(color * diffuse.a, diffuse.a);\n';
}
- } else {
- if (defined(techniqueParameters.transparency)) {
+ } else if (defined(techniqueUniforms.u_transparency)) {
finalColorComputation = ' gl_FragColor = vec4(color * u_transparency, u_transparency);\n';
} else {
finalColorComputation = ' gl_FragColor = vec4(color, 1.0);\n';
}
- }
if (hasVertexColors) {
colorCreationBlock += ' color *= v_vertexColor.rgb;\n';
}
- if (defined(techniqueParameters.emission)) {
- if (techniqueParameters.emission.type === WebGLConstants.SAMPLER_2D) {
+ if (defined(techniqueUniforms.u_emission)) {
+ if (techniqueUniforms.u_emission.type === WebGLConstants.SAMPLER_2D) {
fragmentShader += ' vec3 emission = texture2D(u_emission, ' + v_texcoord + ').rgb;\n';
} else {
fragmentShader += ' vec3 emission = u_emission.rgb;\n';
@@ -638,9 +599,9 @@ define([
colorCreationBlock += ' color += emission;\n';
}
- if (defined(techniqueParameters.ambient) || (lightingModel !== 'CONSTANT')) {
- if (defined(techniqueParameters.ambient)) {
- if (techniqueParameters.ambient.type === WebGLConstants.SAMPLER_2D) {
+ if (defined(techniqueUniforms.u_ambient) || (lightingModel !== 'CONSTANT')) {
+ if (defined(techniqueUniforms.u_ambient)) {
+ if (techniqueUniforms.u_ambient.type === WebGLConstants.SAMPLER_2D) {
fragmentShader += ' vec3 ambient = texture2D(u_ambient, ' + v_texcoord + ').rgb;\n';
} else {
fragmentShader += ' vec3 ambient = u_ambient.rgb;\n';
@@ -660,49 +621,13 @@ define([
fragmentShader += finalColorComputation;
fragmentShader += '}\n';
- var techniqueStates;
- if (parameterValues.transparent) {
- techniqueStates = {
- enable: [
- WebGLConstants.DEPTH_TEST,
- WebGLConstants.BLEND
- ],
- functions: {
- depthMask : [false],
- blendEquationSeparate: [
- WebGLConstants.FUNC_ADD,
- WebGLConstants.FUNC_ADD
- ],
- blendFuncSeparate: [
- WebGLConstants.ONE,
- WebGLConstants.ONE_MINUS_SRC_ALPHA,
- WebGLConstants.ONE,
- WebGLConstants.ONE_MINUS_SRC_ALPHA
- ]
- }
- };
- } else if (khrMaterialsCommon.doubleSided) {
- techniqueStates = {
- enable: [
- WebGLConstants.DEPTH_TEST
- ]
- };
- } else { // Not transparent or double sided
- techniqueStates = {
- enable: [
- WebGLConstants.CULL_FACE,
- WebGLConstants.DEPTH_TEST
- ]
- };
- }
-
// Add shaders
var vertexShaderId = addToArray(shaders, {
type: WebGLConstants.VERTEX_SHADER,
- extras: {
- _pipeline: {
- source: vertexShader,
- extension: '.glsl'
+ extras: {
+ _pipeline: {
+ source: vertexShader,
+ extension: '.glsl'
}
}
});
@@ -718,18 +643,14 @@ define([
});
// Add program
- var programAttributes = Object.keys(techniqueAttributes);
var programId = addToArray(programs, {
- attributes: programAttributes,
fragmentShader: fragmentShaderId,
vertexShader: vertexShaderId
});
var techniqueId = addToArray(techniques, {
attributes: techniqueAttributes,
- parameters: techniqueParameters,
program: programId,
- states: techniqueStates,
uniforms: techniqueUniforms
});
@@ -772,7 +693,7 @@ define([
}
}
- function getTechniqueKey(khrMaterialsCommon) {
+ function getTechniqueKey(material, khrMaterialsCommon) {
var techniqueKey = '';
techniqueKey += 'technique:' + khrMaterialsCommon.technique + ';';
@@ -787,13 +708,9 @@ define([
}
}
- var doubleSided = defaultValue(khrMaterialsCommon.doubleSided, defaultValue(khrMaterialsCommon.values.doubleSided, false));
- techniqueKey += doubleSided.toString() + ';';
- var transparent = defaultValue(khrMaterialsCommon.transparent, defaultValue(khrMaterialsCommon.values.transparent, false));
- techniqueKey += transparent.toString() + ';';
var jointCount = defaultValue(khrMaterialsCommon.jointCount, 0);
techniqueKey += jointCount.toString() + ';';
- var primitiveInfo = khrMaterialsCommon.extras._pipeline.primitive;
+ var primitiveInfo = material.extras._pipeline.primitive;
if (defined(primitiveInfo)) {
var skinningInfo = primitiveInfo.skinning;
if (jointCount > 0) {
@@ -806,15 +723,7 @@ define([
}
function lightDefaults(gltf) {
- if (!defined(gltf.extensions)) {
- gltf.extensions = {};
- }
- var extensions = gltf.extensions;
-
- if (!defined(extensions.KHR_materials_common)) {
- extensions.KHR_materials_common = {};
- }
- var khrMaterialsCommon = extensions.KHR_materials_common;
+ var khrMaterialsCommon = gltf.extensions.KHR_materials_common;
if (!defined(khrMaterialsCommon.lights)) {
khrMaterialsCommon.lights = {};
@@ -874,112 +783,5 @@ define([
}
}
- function getShaderVariable(type) {
- if (type === 'SCALAR') {
- return 'float';
- }
- return type.toLowerCase();
- }
-
- function ensureSemanticExistenceForPrimitive(gltf, primitive) {
- var accessors = gltf.accessors;
- var materials = gltf.materials;
- var techniques = gltf.techniques;
- var programs = gltf.programs;
- var shaders = gltf.shaders;
-
- var attributes = primitive.attributes;
- var material = materials[primitive.material];
- var technique = techniques[material.technique];
- var program = programs[technique.program];
- var vertexShader = shaders[program.vertexShader];
-
- for (var semantic in attributes) {
- if (attributes.hasOwnProperty(semantic)) {
- if (!defined(techniqueParameterForSemantic(technique, semantic))) {
- var accessorId = attributes[semantic];
- var accessor = accessors[accessorId];
- var lowerCase = semantic.toLowerCase();
- if (lowerCase.charAt(0) === '_') {
- lowerCase = lowerCase.slice(1);
- }
- var attributeName = 'a_' + lowerCase;
- technique.parameters[lowerCase] = {
- semantic: semantic,
- type: accessor.componentType
- };
- technique.attributes[attributeName] = lowerCase;
- program.attributes.push(attributeName);
- var pipelineExtras = vertexShader.extras._pipeline;
- var shaderText = pipelineExtras.source;
- shaderText = 'attribute ' + getShaderVariable(accessor.type) + ' ' + attributeName + ';\n' + shaderText;
- pipelineExtras.source = shaderText;
- }
- }
- }
- }
-
- function ensureSemanticExistence(gltf) {
- ForEach.mesh(gltf, function(mesh) {
- ForEach.meshPrimitive(mesh, function(primitive) {
- ensureSemanticExistenceForPrimitive(gltf, primitive);
- });
- });
- }
-
- function splitIncompatibleMaterials(gltf) {
- var accessors = gltf.accessors;
- var materials = gltf.materials;
- ForEach.mesh(gltf, function(mesh) {
- ForEach.meshPrimitive(mesh, function(primitive) {
- var materialId = primitive.material;
- var material = materials[materialId];
-
- if (defined(material.extensions) && defined(material.extensions.KHR_materials_common)) {
- var khrMaterialsCommon = material.extensions.KHR_materials_common;
- var jointAccessorId = primitive.attributes.JOINT;
- var componentType;
- var type;
- if (defined(jointAccessorId)) {
- var jointAccessor = accessors[jointAccessorId];
- componentType = jointAccessor.componentType;
- type = jointAccessor.type;
- }
- var isSkinned = defined(jointAccessorId);
- var hasVertexColors = defined(primitive.attributes.COLOR_0);
-
- var primitiveInfo = khrMaterialsCommon.extras._pipeline.primitive;
- if (!defined(primitiveInfo)) {
- khrMaterialsCommon.extras._pipeline.primitive = {
- skinning : {
- skinned: isSkinned,
- componentType: componentType,
- type: type
- },
- hasVertexColors : hasVertexColors
- };
- } else if ((primitiveInfo.skinning.skinned !== isSkinned) || (primitiveInfo.skinning.type !== type) || (primitiveInfo.hasVertexColors !== hasVertexColors)) {
- // This primitive uses the same material as another one that either:
- // * Isn't skinned
- // * Uses a different type to store joints and weights
- // * Doesn't have vertex colors
- var clonedMaterial = clone(material, true);
- clonedMaterial.extensions.KHR_materials_common.extras._pipeline.primitive = {
- skinning : {
- skinned: isSkinned,
- componentType: componentType,
- type: type
- },
- hasVertexColors : hasVertexColors
- };
- // Split this off as a separate material
- materialId = addToArray(materials, clonedMaterial);
- primitive.material = materialId;
- }
- }
- });
- });
- }
-
return processModelMaterialsCommon;
});
diff --git a/Source/ThirdParty/GltfPipeline/processPbrMetallicRoughness.js b/Source/Scene/processPbrMetallicRoughness.js
similarity index 52%
rename from Source/ThirdParty/GltfPipeline/processPbrMetallicRoughness.js
rename to Source/Scene/processPbrMetallicRoughness.js
index 54383682051f..17458246ab48 100644
--- a/Source/ThirdParty/GltfPipeline/processPbrMetallicRoughness.js
+++ b/Source/Scene/processPbrMetallicRoughness.js
@@ -1,25 +1,24 @@
define([
- './addToArray',
- './ForEach',
- './numberOfComponentsForType',
- './techniqueParameterForSemantic',
- './webGLConstantToGlslType',
- './glslTypeToWebGLConstant',
- '../../Core/clone',
- '../../Core/defined',
- '../../Core/defaultValue',
- '../../Core/WebGLConstants'
+ './ModelUtility',
+ '../Core/defined',
+ '../Core/defaultValue',
+ '../Core/WebGLConstants',
+ '../Core/webGLConstantToGlslType',
+ '../ThirdParty/GltfPipeline/addToArray',
+ '../ThirdParty/GltfPipeline/ForEach',
+ '../ThirdParty/GltfPipeline/hasExtension',
+ '../ThirdParty/GltfPipeline/numberOfComponentsForType'
], function(
- addToArray,
- ForEach,
- numberOfComponentsForType,
- techniqueParameterForSemantic,
- webGLConstantToGlslType,
- glslTypeToWebGLConstant,
- clone,
+ ModelUtility,
defined,
defaultValue,
- WebGLConstants) {
+ WebGLConstants,
+ webGLConstantToGlslType,
+ addToArray,
+ ForEach,
+ hasExtension,
+ numberOfComponentsForType
+) {
'use strict';
/**
@@ -35,36 +34,53 @@ define([
}
});
- if (hasPbrMetallicRoughness) {
- if (!defined(gltf.programs)) {
- gltf.programs = [];
- }
- if (!defined(gltf.shaders)) {
- gltf.shaders = [];
- }
- if (!defined(gltf.techniques)) {
- gltf.techniques = [];
- }
+ if (!hasPbrMetallicRoughness) {
+ return gltf;
+ }
- // Pre-processing to address incompatibilities between primitives using the same materials.
- splitIncompatibleMaterials(gltf);
-
- ForEach.material(gltf, function(material, materialIndex) {
- if (isPbrMaterial(material)) {
- var values = {};
- var technique = generateTechnique(gltf, material, materialIndex, values, options);
- gltf.materials[materialIndex] = {
- values : values,
- technique : technique
- };
- }
- });
+ // No need to create new techniques if they already exist,
+ // the shader should handle these values
+ if (hasExtension(gltf, 'KHR_techniques_webgl')) {
+ // TODO: Modify shader values for alphaMode or doubleSided?
+ return gltf;
+ }
- // If any primitives have semantics that aren't declared in the generated
- // shaders, we want to preserve them.
- ensureSemanticExistence(gltf);
+ if (!defined(gltf.extensions)) {
+ gltf.extensions = {};
+ gltf.extensionsUsed = [];
+ gltf.extensionsRequired = [];
}
+ gltf.extensions.KHR_techniques_webgl = {
+ programs: [],
+ shaders: [],
+ techniques: []
+ };
+ gltf.extensionsUsed.push('KHR_techniques_webgl');
+ gltf.extensionsRequired.push('KHR_techniques_webgl');
+
+ ModelUtility.splitIncompatibleMaterials(gltf);
+
+ ForEach.material(gltf, function(material, materialIndex) {
+ if (isPbrMaterial(material)) {
+ var values = {};
+ var technique = generateTechnique(gltf, material, materialIndex, values, options);
+
+ if (!defined(material.extensions)) {
+ material.extensions = {};
+ }
+
+ material.extensions.KHR_techniques_webgl = {
+ values : values,
+ technique : technique
+ };
+ }
+ });
+
+ // If any primitives have semantics that aren't declared in the generated
+ // shaders, we want to preserve them.
+ ModelUtility.ensureSemanticExistence(gltf);
+
return gltf;
}
@@ -80,26 +96,28 @@ define([
}
function generateTechnique(gltf, material, materialIndex, values, options) {
- var optimizeForCesium = defaultValue(options.optimizeForCesium, false);
- var hasCesiumRTCExtension = defined(gltf.extensions) && defined(gltf.extensions.CESIUM_RTC);
var addBatchIdToGeneratedShaders = defaultValue(options.addBatchIdToGeneratedShaders, false);
- var techniques = gltf.techniques;
- var shaders = gltf.shaders;
- var programs = gltf.programs;
+ var techniquesWebgl = gltf.extensions.KHR_techniques_webgl;
+ var techniques = techniquesWebgl.techniques;
+ var shaders = techniquesWebgl.shaders;
+ var programs = techniquesWebgl.programs;
var parameterValues = values;
+ var uniformName;
var pbrMetallicRoughness = material.pbrMetallicRoughness;
if (defined(pbrMetallicRoughness)) {
for (var parameterName in pbrMetallicRoughness) {
if (pbrMetallicRoughness.hasOwnProperty(parameterName)) {
- parameterValues[parameterName] = pbrMetallicRoughness[parameterName];
+ uniformName = 'u_' + parameterName;
+ parameterValues[uniformName] = pbrMetallicRoughness[parameterName];
}
}
}
for (var additional in material) {
- if (material.hasOwnProperty(additional) && ((additional.indexOf('Texture') >= 0) || additional.indexOf('Factor') >= 0) || additional === 'doubleSided') {
- parameterValues[additional] = material[additional];
+ if (material.hasOwnProperty(additional) && ((additional.indexOf('Texture') >= 0) || additional.indexOf('Factor') >= 0)) {
+ uniformName = 'u_' + additional;
+ parameterValues[uniformName] = material[additional];
}
}
@@ -147,27 +165,27 @@ define([
}
// Add techniques
- var techniqueParameters = {
+ var techniqueUniforms = {
// Add matrices
- modelViewMatrix : {
- semantic : hasCesiumRTCExtension ? 'CESIUM_RTC_MODELVIEW' : 'MODELVIEW',
+ u_modelViewMatrix : {
+ semantic : hasExtension(gltf, 'CESIUM_RTC') ? 'CESIUM_RTC_MODELVIEW' : 'MODELVIEW',
type : WebGLConstants.FLOAT_MAT4
},
- projectionMatrix : {
+ u_projectionMatrix : {
semantic : 'PROJECTION',
type : WebGLConstants.FLOAT_MAT4
}
};
if (hasNormals) {
- techniqueParameters.normalMatrix = {
+ techniqueUniforms.u_normalMatrix = {
semantic : 'MODELVIEWINVERSETRANSPOSE',
type : WebGLConstants.FLOAT_MAT3
};
}
if (hasSkinning) {
- techniqueParameters.jointMatrix = {
+ techniqueUniforms.u_jointMatrix = {
count : jointCount,
semantic : 'JOINTMATRIX',
type : WebGLConstants.FLOAT_MAT4
@@ -175,7 +193,7 @@ define([
}
if (hasMorphTargets) {
- techniqueParameters.morphWeights = {
+ techniqueUniforms.u_morphWeights = {
count : morphTargets.length,
semantic : 'MORPHWEIGHTS',
type : WebGLConstants.FLOAT
@@ -183,27 +201,25 @@ define([
}
// Add material parameters
- for (var name in parameterValues) {
- if (parameterValues.hasOwnProperty(name)) {
- techniqueParameters[name] = {
- type : getPBRValueType(name)
+ for (uniformName in parameterValues) {
+ if (parameterValues.hasOwnProperty(uniformName)) {
+ techniqueUniforms[uniformName] = {
+ type : getPBRValueType(uniformName)
};
}
}
- // Generate uniforms object before attributes are added
- var techniqueUniforms = {};
- for (var paramName in techniqueParameters) {
- if (techniqueParameters.hasOwnProperty(paramName) && paramName !== 'extras') {
- var param = techniqueParameters[paramName];
- techniqueUniforms['u_' + paramName] = paramName;
- var arraySize = defined(param.count) ? '[' + param.count + ']' : '';
- if (((param.type !== WebGLConstants.FLOAT_MAT3) && (param.type !== WebGLConstants.FLOAT_MAT4) && (paramName !== 'morphWeights')) ||
- param.useInFragment) {
- fragmentShader += 'uniform ' + webGLConstantToGlslType(param.type) + ' u_' + paramName + arraySize + ';\n';
- delete param.useInFragment;
+ // Add uniforms to shaders
+ for (uniformName in techniqueUniforms) {
+ if (techniqueUniforms.hasOwnProperty(uniformName)) {
+ var uniform = techniqueUniforms[uniformName];
+ var arraySize = defined(uniform.count) ? '[' + uniform.count + ']' : '';
+ if (((uniform.type !== WebGLConstants.FLOAT_MAT3) && (uniform.type !== WebGLConstants.FLOAT_MAT4) && (uniformName !== 'u_morphWeights')) ||
+ uniform.useInFragment) {
+ fragmentShader += 'uniform ' + webGLConstantToGlslType(uniform.type) + ' ' + uniformName + arraySize + ';\n';
+ delete uniform.useInFragment;
} else {
- vertexShader += 'uniform ' + webGLConstantToGlslType(param.type) + ' u_' + paramName + arraySize + ';\n';
+ vertexShader += 'uniform ' + webGLConstantToGlslType(uniform.type) + ' ' + uniformName + arraySize + ';\n';
}
}
}
@@ -243,18 +259,14 @@ define([
// Add position always
var techniqueAttributes = {
- a_position : 'position'
- };
- techniqueParameters.position = {
- semantic : 'POSITION',
- type : WebGLConstants.FLOAT_VEC3
+ a_position : {
+ semantic : 'POSITION'
+ }
};
vertexShader += 'attribute vec3 a_position;\n';
if (hasNormals) {
vertexShader += 'varying vec3 v_positionEC;\n';
- if (optimizeForCesium) {
- vertexShader += 'varying vec3 v_positionWC;\n';
- }
+ vertexShader += 'varying vec3 v_positionWC;\n';
}
// Morph Target Weighting
@@ -270,19 +282,17 @@ define([
var targetAttributes = morphTargets[k];
for (var targetAttribute in targetAttributes) {
if (targetAttributes.hasOwnProperty(targetAttribute) && targetAttribute !== 'extras') {
- var attributeLower = targetAttribute.toLowerCase() + '_' + k;
- techniqueAttributes['a_' + attributeLower] = attributeLower;
- techniqueParameters[attributeLower] = {
- semantic : targetAttribute + '_' + k,
- type : WebGLConstants.FLOAT_VEC3
+ var attributeName = 'a_' + targetAttribute + '_' + k;
+ techniqueAttributes[attributeName] = {
+ semantic : targetAttribute + '_' + k
};
- vertexShader += 'attribute vec3 a_' + attributeLower + ';\n';
+ vertexShader += 'attribute vec3 ' + attributeName + ';\n';
if (targetAttribute === 'POSITION') {
- vertexShaderMain += ' weightedPosition += u_morphWeights[' + k + '] * a_' + attributeLower + ';\n';
+ vertexShaderMain += ' weightedPosition += u_morphWeights[' + k + '] * a_' + attributeName + ';\n';
} else if (targetAttribute === 'NORMAL') {
- vertexShaderMain += ' weightedNormal += u_morphWeights[' + k + '] * a_' + attributeLower + ';\n';
+ vertexShaderMain += ' weightedNormal += u_morphWeights[' + k + '] * a_' + attributeName + ';\n';
} else if (hasTangents && targetAttribute === 'TANGENT') {
- vertexShaderMain += ' weightedTangent.xyz += u_morphWeights[' + k + '] * a_' + attributeLower + ';\n';
+ vertexShaderMain += ' weightedTangent.xyz += u_morphWeights[' + k + '] * a_' + attributeName + ';\n';
}
}
}
@@ -295,7 +305,7 @@ define([
} else {
vertexShaderMain += ' vec4 position = vec4(weightedPosition, 1.0);\n';
}
- if (hasNormals && optimizeForCesium) {
+ if (hasNormals) {
vertexShaderMain += ' v_positionWC = (czm_model * position).xyz;\n';
}
vertexShaderMain += ' position = u_modelViewMatrix * position;\n';
@@ -306,10 +316,8 @@ define([
// Final normal computation
if (hasNormals) {
- techniqueAttributes.a_normal = 'normal';
- techniqueParameters.normal = {
- semantic : 'NORMAL',
- type : WebGLConstants.FLOAT_VEC3
+ techniqueAttributes.a_normal = {
+ semantic : 'NORMAL'
};
vertexShader += 'attribute vec3 a_normal;\n';
vertexShader += 'varying vec3 v_normal;\n';
@@ -321,18 +329,13 @@ define([
fragmentShader += 'varying vec3 v_normal;\n';
fragmentShader += 'varying vec3 v_positionEC;\n';
-
- if (optimizeForCesium) {
- fragmentShader += 'varying vec3 v_positionWC;\n';
- }
+ fragmentShader += 'varying vec3 v_positionWC;\n';
}
// Read tangents if available
if (hasTangents) {
- techniqueAttributes.a_tangent = 'tangent';
- techniqueParameters.tangent = {
- semantic : 'TANGENT',
- type : WebGLConstants.FLOAT_VEC4
+ techniqueAttributes.a_tangent = {
+ semantic : 'TANGENT'
};
vertexShader += 'attribute vec4 a_tangent;\n';
vertexShader += 'varying vec4 v_tangent;\n';
@@ -345,10 +348,8 @@ define([
// Add texture coordinates if the material uses them
var v_texcoord;
if (hasTexCoords) {
- techniqueAttributes.a_texcoord_0 = 'texcoord_0';
- techniqueParameters.texcoord_0 = {
- semantic : 'TEXCOORD_0',
- type : WebGLConstants.FLOAT_VEC2
+ techniqueAttributes.a_texcoord_0 = {
+ semantic : 'TEXCOORD_0'
};
v_texcoord = 'v_texcoord_0';
@@ -361,18 +362,12 @@ define([
// Add skinning information if available
if (hasSkinning) {
- techniqueAttributes.a_joint = 'joint';
- var attributeType = getShaderVariable(skinningInfo.type);
- var webGLConstant = glslTypeToWebGLConstant(attributeType);
-
- techniqueParameters.joint = {
- semantic : 'JOINTS_0',
- type : webGLConstant
+ var attributeType = ModelUtility.getShaderVariable(skinningInfo.type);
+ techniqueAttributes.a_joint = {
+ semantic : 'JOINTS_0'
};
- techniqueAttributes.a_weight = 'weight';
- techniqueParameters.weight = {
- semantic : 'WEIGHTS_0',
- type : webGLConstant
+ techniqueAttributes.a_weight ={
+ semantic : 'WEIGHTS_0'
};
vertexShader += 'attribute ' + attributeType + ' a_joint;\n';
@@ -380,10 +375,8 @@ define([
}
if (hasVertexColors) {
- techniqueAttributes.a_vertexColor = 'vertexColor';
- techniqueParameters.vertexColor = {
- semantic: 'COLOR_0',
- type: WebGLConstants.FLOAT_VEC4
+ techniqueAttributes.a_vertexColor = {
+ semantic: 'COLOR_0'
};
vertexShader += 'attribute vec4 a_vertexColor;\n';
vertexShader += 'varying vec4 v_vertexColor;\n';
@@ -392,10 +385,8 @@ define([
}
if (addBatchIdToGeneratedShaders) {
- techniqueAttributes.a_batchId = 'batchId';
- techniqueParameters.batchId = {
- semantic: '_BATCHID',
- type: WebGLConstants.FLOAT
+ techniqueAttributes.a_batchId = {
+ semantic: '_BATCHID'
};
vertexShader += 'attribute float a_batchId;\n';
}
@@ -463,7 +454,7 @@ define([
// Add normal mapping to fragment shader
if (hasNormals) {
fragmentShader += ' vec3 ng = normalize(v_normal);\n';
- if (defined(parameterValues.normalTexture)) {
+ if (defined(parameterValues.u_normalTexture)) {
if (hasTangents) {
// Read tangents from varying
fragmentShader += ' vec3 t = normalize(v_tangent.xyz);\n';
@@ -496,7 +487,7 @@ define([
} else {
fragmentShader += ' vec3 n = ng;\n';
}
- if (parameterValues.doubleSided) {
+ if (material.doubleSided) {
fragmentShader += ' if (!gl_FrontFacing)\n';
fragmentShader += ' {\n';
fragmentShader += ' n = -n;\n';
@@ -505,18 +496,16 @@ define([
}
// Add base color to fragment shader
- if (defined(parameterValues.baseColorTexture)) {
+ if (defined(parameterValues.u_baseColorTexture)) {
fragmentShader += ' vec4 baseColorWithAlpha = SRGBtoLINEAR4(texture2D(u_baseColorTexture, ' + v_texcoord + '));\n';
- if (defined(parameterValues.baseColorFactor)) {
+ if (defined(parameterValues.u_baseColorFactor)) {
fragmentShader += ' baseColorWithAlpha *= u_baseColorFactor;\n';
}
- } else {
- if (defined(parameterValues.baseColorFactor)) {
+ } else if (defined(parameterValues.u_baseColorFactor)) {
fragmentShader += ' vec4 baseColorWithAlpha = u_baseColorFactor;\n';
} else {
fragmentShader += ' vec4 baseColorWithAlpha = vec4(1.0);\n';
}
- }
if (hasVertexColors) {
fragmentShader += ' baseColorWithAlpha *= v_vertexColor;\n';
@@ -526,23 +515,23 @@ define([
if (hasNormals) {
// Add metallic-roughness to fragment shader
- if (defined(parameterValues.metallicRoughnessTexture)) {
+ if (defined(parameterValues.u_metallicRoughnessTexture)) {
fragmentShader += ' vec3 metallicRoughness = texture2D(u_metallicRoughnessTexture, ' + v_texcoord + ').rgb;\n';
fragmentShader += ' float metalness = clamp(metallicRoughness.b, 0.0, 1.0);\n';
fragmentShader += ' float roughness = clamp(metallicRoughness.g, 0.04, 1.0);\n';
- if (defined(parameterValues.metallicFactor)) {
+ if (defined(parameterValues.u_metallicFactor)) {
fragmentShader += ' metalness *= u_metallicFactor;\n';
}
- if (defined(parameterValues.roughnessFactor)) {
+ if (defined(parameterValues.u_roughnessFactor)) {
fragmentShader += ' roughness *= u_roughnessFactor;\n';
}
} else {
- if (defined(parameterValues.metallicFactor)) {
+ if (defined(parameterValues.u_metallicFactor)) {
fragmentShader += ' float metalness = clamp(u_metallicFactor, 0.0, 1.0);\n';
} else {
fragmentShader += ' float metalness = 1.0;\n';
}
- if (defined(parameterValues.roughnessFactor)) {
+ if (defined(parameterValues.u_roughnessFactor)) {
fragmentShader += ' float roughness = clamp(u_roughnessFactor, 0.04, 1.0);\n';
} else {
fragmentShader += ' float roughness = 1.0;\n';
@@ -551,29 +540,20 @@ define([
fragmentShader += ' vec3 v = -normalize(v_positionEC);\n';
// Generate fragment shader's lighting block
- if (optimizeForCesium) {
- // The Sun is brighter than your average light source, and has a yellowish tint balanced by the Earth's ambient blue.
- fragmentShader += ' vec3 lightColor = vec3(1.5, 1.4, 1.2);\n';
- fragmentShader += ' vec3 l = normalize(czm_sunDirectionEC);\n';
- } else {
- fragmentShader += ' vec3 lightColor = vec3(1.0, 1.0, 1.0);\n';
- fragmentShader += ' vec3 l = vec3(0.0, 0.0, 1.0);\n';
- }
+ // The Sun is brighter than your average light source, and has a yellowish tint balanced by the Earth's ambient blue.
+ fragmentShader += ' vec3 lightColor = vec3(1.5, 1.4, 1.2);\n';
+ fragmentShader += ' vec3 l = normalize(czm_sunDirectionEC);\n';
fragmentShader += ' vec3 h = normalize(v + l);\n';
- if (optimizeForCesium) {
- fragmentShader += ' vec3 r = normalize(czm_inverseViewRotation * normalize(reflect(v, n)));\n';
- // Figure out if the reflection vector hits the ellipsoid
- fragmentShader += ' czm_ellipsoid ellipsoid = czm_getWgs84EllipsoidEC();\n';
- fragmentShader += ' float vertexRadius = length(v_positionWC);\n';
- fragmentShader += ' float horizonDotNadir = 1.0 - min(1.0, ellipsoid.radii.x / vertexRadius);\n';
- fragmentShader += ' float reflectionDotNadir = dot(r, normalize(v_positionWC));\n';
- // Flipping the X vector is a cheap way to get the inverse of czm_temeToPseudoFixed, since that's a rotation about Z.
- fragmentShader += ' r.x = -r.x;\n';
- fragmentShader += ' r = -normalize(czm_temeToPseudoFixed * r);\n';
- fragmentShader += ' r.x = -r.x;\n';
- } else {
- fragmentShader += ' vec3 r = normalize(reflect(v, n));\n';
- }
+ fragmentShader += ' vec3 r = normalize(czm_inverseViewRotation * normalize(reflect(v, n)));\n';
+ // Figure out if the reflection vector hits the ellipsoid
+ fragmentShader += ' czm_ellipsoid ellipsoid = czm_getWgs84EllipsoidEC();\n';
+ fragmentShader += ' float vertexRadius = length(v_positionWC);\n';
+ fragmentShader += ' float horizonDotNadir = 1.0 - min(1.0, ellipsoid.radii.x / vertexRadius);\n';
+ fragmentShader += ' float reflectionDotNadir = dot(r, normalize(v_positionWC));\n';
+ // Flipping the X vector is a cheap way to get the inverse of czm_temeToPseudoFixed, since that's a rotation about Z.
+ fragmentShader += ' r.x = -r.x;\n';
+ fragmentShader += ' r = -normalize(czm_temeToPseudoFixed * r);\n';
+ fragmentShader += ' r.x = -r.x;\n';
fragmentShader += ' float NdotL = clamp(dot(n, l), 0.001, 1.0);\n';
fragmentShader += ' float NdotV = abs(dot(n, v)) + 0.001;\n';
fragmentShader += ' float NdotH = clamp(dot(n, h), 0.0, 1.0);\n';
@@ -596,58 +576,54 @@ define([
fragmentShader += ' vec3 specularContribution = F * G * D / (4.0 * NdotL * NdotV);\n';
fragmentShader += ' vec3 color = NdotL * lightColor * (diffuseContribution + specularContribution);\n';
- if (optimizeForCesium) {
- fragmentShader += ' float inverseRoughness = 1.04 - roughness;\n';
- fragmentShader += ' inverseRoughness *= inverseRoughness;\n';
- fragmentShader += ' vec3 sceneSkyBox = textureCube(czm_environmentMap, r).rgb * inverseRoughness;\n';
-
- fragmentShader += ' float atmosphereHeight = 0.05;\n';
- fragmentShader += ' float blendRegionSize = 0.1 * ((1.0 - inverseRoughness) * 8.0 + 1.1 - horizonDotNadir);\n';
- fragmentShader += ' float blendRegionOffset = roughness * -1.0;\n';
- fragmentShader += ' float farAboveHorizon = clamp(horizonDotNadir - blendRegionSize * 0.5 + blendRegionOffset, 1.0e-10 - blendRegionSize, 0.99999);\n';
- fragmentShader += ' float aroundHorizon = clamp(horizonDotNadir + blendRegionSize * 0.5, 1.0e-10 - blendRegionSize, 0.99999);\n';
- fragmentShader += ' float farBelowHorizon = clamp(horizonDotNadir + blendRegionSize * 1.5, 1.0e-10 - blendRegionSize, 0.99999);\n';
- fragmentShader += ' float smoothstepHeight = smoothstep(0.0, atmosphereHeight, horizonDotNadir);\n';
-
- fragmentShader += ' vec3 belowHorizonColor = mix(vec3(0.1, 0.15, 0.25), vec3(0.4, 0.7, 0.9), smoothstepHeight);\n';
- fragmentShader += ' vec3 nadirColor = belowHorizonColor * 0.5;\n';
- fragmentShader += ' vec3 aboveHorizonColor = mix(vec3(0.9, 1.0, 1.2), belowHorizonColor, roughness * 0.5);\n';
- fragmentShader += ' vec3 blueSkyColor = mix(vec3(0.18, 0.26, 0.48), aboveHorizonColor, reflectionDotNadir * inverseRoughness * 0.5 + 0.75);\n';
- fragmentShader += ' vec3 zenithColor = mix(blueSkyColor, sceneSkyBox, smoothstepHeight);\n';
-
- fragmentShader += ' vec3 blueSkyDiffuseColor = vec3(0.7, 0.85, 0.9);\n';
- fragmentShader += ' float diffuseIrradianceFromEarth = (1.0 - horizonDotNadir) * (reflectionDotNadir * 0.25 + 0.75) * smoothstepHeight;\n';
- fragmentShader += ' float diffuseIrradianceFromSky = (1.0 - smoothstepHeight) * (1.0 - (reflectionDotNadir * 0.25 + 0.25));\n';
- fragmentShader += ' vec3 diffuseIrradiance = blueSkyDiffuseColor * clamp(diffuseIrradianceFromEarth + diffuseIrradianceFromSky, 0.0, 1.0);\n';
-
- fragmentShader += ' float notDistantRough = (1.0 - horizonDotNadir * roughness * 0.8);\n';
- fragmentShader += ' vec3 specularIrradiance = mix(zenithColor, aboveHorizonColor, smoothstep(farAboveHorizon, aroundHorizon, reflectionDotNadir) * notDistantRough);\n';
- fragmentShader += ' specularIrradiance = mix(specularIrradiance, belowHorizonColor, smoothstep(aroundHorizon, farBelowHorizon, reflectionDotNadir) * inverseRoughness);\n';
- fragmentShader += ' specularIrradiance = mix(specularIrradiance, nadirColor, smoothstep(farBelowHorizon, 1.0, reflectionDotNadir) * inverseRoughness);\n';
-
- fragmentShader += ' vec2 brdfLut = texture2D(czm_brdfLut, vec2(NdotV, 1.0 - roughness)).rg;\n';
- fragmentShader += ' vec3 IBLColor = (diffuseIrradiance * diffuseColor) + (specularIrradiance * SRGBtoLINEAR3(specularColor * brdfLut.x + brdfLut.y));\n';
- fragmentShader += ' color += IBLColor;\n';
- }
+ fragmentShader += ' float inverseRoughness = 1.04 - roughness;\n';
+ fragmentShader += ' inverseRoughness *= inverseRoughness;\n';
+ fragmentShader += ' vec3 sceneSkyBox = textureCube(czm_environmentMap, r).rgb * inverseRoughness;\n';
+
+ fragmentShader += ' float atmosphereHeight = 0.05;\n';
+ fragmentShader += ' float blendRegionSize = 0.1 * ((1.0 - inverseRoughness) * 8.0 + 1.1 - horizonDotNadir);\n';
+ fragmentShader += ' float blendRegionOffset = roughness * -1.0;\n';
+ fragmentShader += ' float farAboveHorizon = clamp(horizonDotNadir - blendRegionSize * 0.5 + blendRegionOffset, 1.0e-10 - blendRegionSize, 0.99999);\n';
+ fragmentShader += ' float aroundHorizon = clamp(horizonDotNadir + blendRegionSize * 0.5, 1.0e-10 - blendRegionSize, 0.99999);\n';
+ fragmentShader += ' float farBelowHorizon = clamp(horizonDotNadir + blendRegionSize * 1.5, 1.0e-10 - blendRegionSize, 0.99999);\n';
+ fragmentShader += ' float smoothstepHeight = smoothstep(0.0, atmosphereHeight, horizonDotNadir);\n';
+
+ fragmentShader += ' vec3 belowHorizonColor = mix(vec3(0.1, 0.15, 0.25), vec3(0.4, 0.7, 0.9), smoothstepHeight);\n';
+ fragmentShader += ' vec3 nadirColor = belowHorizonColor * 0.5;\n';
+ fragmentShader += ' vec3 aboveHorizonColor = mix(vec3(0.9, 1.0, 1.2), belowHorizonColor, roughness * 0.5);\n';
+ fragmentShader += ' vec3 blueSkyColor = mix(vec3(0.18, 0.26, 0.48), aboveHorizonColor, reflectionDotNadir * inverseRoughness * 0.5 + 0.75);\n';
+ fragmentShader += ' vec3 zenithColor = mix(blueSkyColor, sceneSkyBox, smoothstepHeight);\n';
+
+ fragmentShader += ' vec3 blueSkyDiffuseColor = vec3(0.7, 0.85, 0.9);\n';
+ fragmentShader += ' float diffuseIrradianceFromEarth = (1.0 - horizonDotNadir) * (reflectionDotNadir * 0.25 + 0.75) * smoothstepHeight;\n';
+ fragmentShader += ' float diffuseIrradianceFromSky = (1.0 - smoothstepHeight) * (1.0 - (reflectionDotNadir * 0.25 + 0.25));\n';
+ fragmentShader += ' vec3 diffuseIrradiance = blueSkyDiffuseColor * clamp(diffuseIrradianceFromEarth + diffuseIrradianceFromSky, 0.0, 1.0);\n';
+
+ fragmentShader += ' float notDistantRough = (1.0 - horizonDotNadir * roughness * 0.8);\n';
+ fragmentShader += ' vec3 specularIrradiance = mix(zenithColor, aboveHorizonColor, smoothstep(farAboveHorizon, aroundHorizon, reflectionDotNadir) * notDistantRough);\n';
+ fragmentShader += ' specularIrradiance = mix(specularIrradiance, belowHorizonColor, smoothstep(aroundHorizon, farBelowHorizon, reflectionDotNadir) * inverseRoughness);\n';
+ fragmentShader += ' specularIrradiance = mix(specularIrradiance, nadirColor, smoothstep(farBelowHorizon, 1.0, reflectionDotNadir) * inverseRoughness);\n';
+
+ fragmentShader += ' vec2 brdfLut = texture2D(czm_brdfLut, vec2(NdotV, 1.0 - roughness)).rg;\n';
+ fragmentShader += ' vec3 IBLColor = (diffuseIrradiance * diffuseColor) + (specularIrradiance * SRGBtoLINEAR3(specularColor * brdfLut.x + brdfLut.y));\n';
+ fragmentShader += ' color += IBLColor;\n';
} else {
fragmentShader += ' vec3 color = baseColor;\n';
}
- if (defined(parameterValues.occlusionTexture)) {
+ if (defined(parameterValues.u_occlusionTexture)) {
fragmentShader += ' color *= texture2D(u_occlusionTexture, ' + v_texcoord + ').r;\n';
}
- if (defined(parameterValues.emissiveTexture)) {
+ if (defined(parameterValues.u_emissiveTexture)) {
fragmentShader += ' vec3 emissive = SRGBtoLINEAR3(texture2D(u_emissiveTexture, ' + v_texcoord + ').rgb);\n';
- if (defined(parameterValues.emissiveFactor)) {
+ if (defined(parameterValues.u_emissiveFactor)) {
fragmentShader += ' emissive *= u_emissiveFactor;\n';
}
fragmentShader += ' color += emissive;\n';
}
- else {
- if (defined(parameterValues.emissiveFactor)) {
+ else if (defined(parameterValues.u_emissiveFactor)) {
fragmentShader += ' color += u_emissiveFactor;\n';
}
- }
// Final color
fragmentShader += ' color = LINEARtoSRGB(color);\n';
@@ -666,46 +642,6 @@ define([
}
fragmentShader += '}\n';
- var techniqueStates;
- if (defined(alphaMode) && alphaMode !== 'OPAQUE') {
- techniqueStates = {
- enable: parameterValues.doubleSided ? [
- WebGLConstants.DEPTH_TEST,
- WebGLConstants.BLEND
- ]: [
- WebGLConstants.CULL_FACE,
- WebGLConstants.DEPTH_TEST,
- WebGLConstants.BLEND
- ],
- functions: {
- depthMask : [false],
- blendEquationSeparate: [
- WebGLConstants.FUNC_ADD,
- WebGLConstants.FUNC_ADD
- ],
- blendFuncSeparate: [
- WebGLConstants.ONE,
- WebGLConstants.ONE_MINUS_SRC_ALPHA,
- WebGLConstants.ONE,
- WebGLConstants.ONE_MINUS_SRC_ALPHA
- ]
- }
- };
- } else if (parameterValues.doubleSided) {
- techniqueStates = {
- enable : [
- WebGLConstants.DEPTH_TEST
- ]
- };
- } else {
- techniqueStates = {
- enable : [
- WebGLConstants.CULL_FACE,
- WebGLConstants.DEPTH_TEST
- ]
- };
- }
-
// Add shaders
var vertexShaderId = addToArray(shaders, {
type : WebGLConstants.VERTEX_SHADER,
@@ -728,18 +664,14 @@ define([
});
// Add program
- var programAttributes = Object.keys(techniqueAttributes);
var programId = addToArray(programs, {
- attributes : programAttributes,
fragmentShader : fragmentShaderId,
vertexShader : vertexShaderId
});
var techniqueId = addToArray(techniques, {
attributes : techniqueAttributes,
- parameters : techniqueParameters,
program : programId,
- states : techniqueStates,
uniforms : techniqueUniforms
});
@@ -748,161 +680,26 @@ define([
function getPBRValueType(paramName) {
switch (paramName) {
- case 'baseColorFactor':
+ case 'u_baseColorFactor':
return WebGLConstants.FLOAT_VEC4;
- case 'metallicFactor':
+ case 'u_metallicFactor':
return WebGLConstants.FLOAT;
- case 'roughnessFactor':
+ case 'u_roughnessFactor':
return WebGLConstants.FLOAT;
- case 'baseColorTexture':
+ case 'u_baseColorTexture':
return WebGLConstants.SAMPLER_2D;
- case 'metallicRoughnessTexture':
+ case 'u_metallicRoughnessTexture':
return WebGLConstants.SAMPLER_2D;
- case 'normalTexture':
+ case 'u_normalTexture':
return WebGLConstants.SAMPLER_2D;
- case 'occlusionTexture':
+ case 'u_occlusionTexture':
return WebGLConstants.SAMPLER_2D;
- case 'emissiveTexture':
+ case 'u_emissiveTexture':
return WebGLConstants.SAMPLER_2D;
- case 'emissiveFactor':
+ case 'u_emissiveFactor':
return WebGLConstants.FLOAT_VEC3;
- case 'doubleSided':
- return WebGLConstants.BOOL;
}
}
- function getShaderVariable(type) {
- if (type === 'SCALAR') {
- return 'float';
- }
- return type.toLowerCase();
- }
-
- function ensureSemanticExistenceForPrimitive(gltf, primitive) {
- var accessors = gltf.accessors;
- var materials = gltf.materials;
- var techniques = gltf.techniques;
- var programs = gltf.programs;
- var shaders = gltf.shaders;
- var targets = primitive.targets;
-
- var attributes = primitive.attributes;
- for (var target in targets) {
- if (targets.hasOwnProperty(target)) {
- var targetAttributes = targets[target];
- for (var attribute in targetAttributes) {
- if (attribute !== 'extras') {
- attributes[attribute + '_' + target] = targetAttributes[attribute];
- }
- }
- }
- }
- var material = materials[primitive.material];
- var technique = techniques[material.technique];
- var program = programs[technique.program];
- var vertexShader = shaders[program.vertexShader];
-
- for (var semantic in attributes) {
- if (attributes.hasOwnProperty(semantic)) {
- if (!defined(techniqueParameterForSemantic(technique, semantic))) {
- var accessorId = attributes[semantic];
- var accessor = accessors[accessorId];
- var lowerCase = semantic.toLowerCase();
- if (lowerCase.charAt(0) === '_') {
- lowerCase = lowerCase.slice(1);
- }
- var attributeName = 'a_' + lowerCase;
- technique.parameters[lowerCase] = {
- semantic: semantic,
- type: accessor.componentType
- };
- technique.attributes[attributeName] = lowerCase;
- program.attributes.push(attributeName);
- var pipelineExtras = vertexShader.extras._pipeline;
- var shaderText = pipelineExtras.source;
- shaderText = 'attribute ' + getShaderVariable(accessor.type) + ' ' + attributeName + ';\n' + shaderText;
- pipelineExtras.source = shaderText;
- }
- }
- }
- }
-
- function ensureSemanticExistence(gltf) {
- ForEach.mesh(gltf, function(mesh) {
- ForEach.meshPrimitive(mesh, function(primitive) {
- ensureSemanticExistenceForPrimitive(gltf, primitive);
- });
- });
- }
-
- function splitIncompatibleMaterials(gltf) {
- var accessors = gltf.accessors;
- var materials = gltf.materials;
- ForEach.mesh(gltf, function(mesh) {
- ForEach.meshPrimitive(mesh, function(primitive) {
- var materialId = primitive.material;
- var material = materials[materialId];
-
- var jointAccessorId = primitive.attributes.JOINTS_0;
- var componentType;
- var type;
- if (defined(jointAccessorId)) {
- var jointAccessor = accessors[jointAccessorId];
- componentType = jointAccessor.componentType;
- type = jointAccessor.type;
- }
- var isSkinned = defined(jointAccessorId);
- var hasVertexColors = defined(primitive.attributes.COLOR_0);
- var hasMorphTargets = defined(primitive.targets);
- var hasNormals = defined(primitive.attributes.NORMAL);
- var hasTangents = defined(primitive.attributes.TANGENT);
- var hasTexCoords = defined(primitive.attributes.TEXCOORD_0);
-
- var primitiveInfo = material.extras._pipeline.primitive;
- if (!defined(primitiveInfo)) {
- material.extras._pipeline.primitive = {
- skinning : {
- skinned : isSkinned,
- componentType : componentType,
- type : type
- },
- hasVertexColors : hasVertexColors,
- hasMorphTargets : hasMorphTargets,
- hasNormals : hasNormals,
- hasTangents : hasTangents,
- hasTexCoords : hasTexCoords
- };
- } else if ((primitiveInfo.skinning.skinned !== isSkinned) ||
- (primitiveInfo.skinning.type !== type) ||
- (primitiveInfo.hasVertexColors !== hasVertexColors) ||
- (primitiveInfo.hasMorphTargets !== hasMorphTargets) ||
- (primitiveInfo.hasNormals !== hasNormals) ||
- (primitiveInfo.hasTangents !== hasTangents) ||
- (primitiveInfo.hasTexCoords !== hasTexCoords)) {
- // This primitive uses the same material as another one that either:
- // * Isn't skinned
- // * Uses a different type to store joints and weights
- // * Doesn't have vertex colors, morph targets, normals, tangents, or texCoords
- var clonedMaterial = clone(material, true);
- clonedMaterial.extras._pipeline.primitive = {
- skinning : {
- skinned : isSkinned,
- componentType : componentType,
- type : type
- },
- hasVertexColors : hasVertexColors,
- hasMorphTargets : hasMorphTargets,
- hasNormals : hasNormals,
- hasTangents : hasTangents,
- hasTexCoords : hasTexCoords
- };
- // Split this off as a separate material
- materialId = addToArray(materials, clonedMaterial);
- primitive.material = materialId;
- }
- });
- });
- }
-
return processPbrMetallicRoughness;
});
diff --git a/Source/ThirdParty/GltfPipeline/ForEach.js b/Source/ThirdParty/GltfPipeline/ForEach.js
index 1894f5a896b1..dd5ce20378ad 100644
--- a/Source/ThirdParty/GltfPipeline/ForEach.js
+++ b/Source/ThirdParty/GltfPipeline/ForEach.js
@@ -1,99 +1,231 @@
define([
- '../../Core/defined'
+ './hasExtension',
+ '../../Core/defined',
+ '../../Core/isArray'
], function(
- defined) {
+ hasExtension,
+ defined,
+ isArray) {
'use strict';
/**
* Contains traversal functions for processing elements of the glTF hierarchy.
+ * @constructor
+ *
+ * @private
*/
- var ForEach = {};
+ function ForEach() {
+ }
+ /**
+ * Fallback for glTF 1.0
+ * @private
+ */
+ ForEach.objectLegacy = function(objects, handler) {
+ if (defined(objects)) {
+ for (var objectId in objects) {
+ if (objects.hasOwnProperty(objectId)) {
+ var object = objects[objectId];
+ var value = handler(object, objectId);
+
+ if (defined(value)) {
+ return value;
+ }
+ }
+ }
+ }
+ };
+
+ /**
+ * @private
+ */
ForEach.object = function(arrayOfObjects, handler) {
if (defined(arrayOfObjects)) {
- for (var i = 0; i < arrayOfObjects.length; i++) {
+ var length = arrayOfObjects.length;
+ for (var i = 0; i < length; i++) {
var object = arrayOfObjects[i];
- var returnValue = handler(object, i);
- if (typeof returnValue === 'number') {
- i += returnValue;
- }
- else if (returnValue) {
- break;
+ var value = handler(object, i);
+
+ if (defined(value)) {
+ return value;
}
}
}
};
+ /**
+ * Supports glTF 1.0 and 2.0
+ * @private
+ */
ForEach.topLevel = function(gltf, name, handler) {
- var arrayOfObjects = gltf[name];
- ForEach.object(arrayOfObjects, handler);
+ var gltfProperty = gltf[name];
+ if (defined(gltfProperty) && !isArray(gltfProperty)) {
+ return ForEach.objectLegacy(gltfProperty, handler);
+ }
+
+ return ForEach.object(gltfProperty, handler);
};
ForEach.accessor = function(gltf, handler) {
- ForEach.topLevel(gltf, 'accessors', handler);
+ return ForEach.topLevel(gltf, 'accessors', handler);
};
ForEach.accessorWithSemantic = function(gltf, semantic, handler) {
- ForEach.mesh(gltf, function(mesh) {
- ForEach.meshPrimitive(mesh, function(primitive) {
- ForEach.meshPrimitiveAttribute(primitive, function(accessorId, attributeSemantic) {
- if (attributeSemantic.indexOf(semantic) === 0) {
- handler(accessorId, attributeSemantic, primitive);
+ var visited = {};
+ return ForEach.mesh(gltf, function(mesh) {
+ return ForEach.meshPrimitive(mesh, function(primitive) {
+ var value = ForEach.meshPrimitiveAttribute(primitive, function(accessorId, attributeSemantic) {
+ if (attributeSemantic.indexOf(semantic) === 0 && !defined(visited[accessorId])) {
+ visited[accessorId] = true;
+ value = handler(accessorId);
+
+ if (defined(value)) {
+ return value;
+ }
}
});
+
+ if (defined(value)) {
+ return value;
+ }
+
+ return ForEach.meshPrimitiveTarget(primitive, function(target) {
+ return ForEach.meshPrimitiveTargetAttribute(target, function(accessorId, attributeSemantic) {
+ if (attributeSemantic.indexOf(semantic) === 0 && !defined(visited[accessorId])) {
+ visited[accessorId] = true;
+ value = handler(accessorId);
+
+ if (defined(value)) {
+ return value;
+ }
+ }
+ });
+ });
+ });
+ });
+ };
+
+ ForEach.accessorContainingVertexAttributeData = function(gltf, handler) {
+ var visited = {};
+ return ForEach.mesh(gltf, function(mesh) {
+ return ForEach.meshPrimitive(mesh, function(primitive) {
+ var value = ForEach.meshPrimitiveAttribute(primitive, function(accessorId) {
+ if (!defined(visited[accessorId])) {
+ visited[accessorId] = true;
+ value = handler(accessorId);
+
+ if (defined(value)) {
+ return value;
+ }
+ }
+ });
+
+ if (defined(value)) {
+ return value;
+ }
+
+ return ForEach.meshPrimitiveTarget(primitive, function(target) {
+ return ForEach.meshPrimitiveTargetAttribute(target, function(accessorId) {
+ if (!defined(visited[accessorId])) {
+ visited[accessorId] = true;
+ value = handler(accessorId);
+
+ if (defined(value)) {
+ return value;
+ }
+ }
+ });
+ });
+ });
+ });
+ };
+
+ ForEach.accessorContainingIndexData = function(gltf, handler) {
+ var visited = {};
+ return ForEach.mesh(gltf, function(mesh) {
+ return ForEach.meshPrimitive(mesh, function(primitive) {
+ var indices = primitive.indices;
+ if (defined(indices) && !defined(visited[indices])) {
+ visited[indices] = true;
+ var value = handler(indices);
+
+ if (defined(value)) {
+ return value;
+ }
+ }
});
});
};
ForEach.animation = function(gltf, handler) {
- ForEach.topLevel(gltf, 'animations', handler);
+ return ForEach.topLevel(gltf, 'animations', handler);
};
ForEach.animationChannel = function(animation, handler) {
var channels = animation.channels;
- ForEach.object(channels, handler);
+ return ForEach.object(channels, handler);
};
ForEach.animationSampler = function(animation, handler) {
var samplers = animation.samplers;
- if (defined(samplers)) {
- ForEach.object(samplers, handler);
- }
+ return ForEach.object(samplers, handler);
};
ForEach.buffer = function(gltf, handler) {
- ForEach.topLevel(gltf, 'buffers', handler);
+ return ForEach.topLevel(gltf, 'buffers', handler);
};
ForEach.bufferView = function(gltf, handler) {
- ForEach.topLevel(gltf, 'bufferViews', handler);
+ return ForEach.topLevel(gltf, 'bufferViews', handler);
};
ForEach.camera = function(gltf, handler) {
- ForEach.topLevel(gltf, 'cameras', handler);
+ return ForEach.topLevel(gltf, 'cameras', handler);
};
ForEach.image = function(gltf, handler) {
- ForEach.topLevel(gltf, 'images', handler);
+ return ForEach.topLevel(gltf, 'images', handler);
+ };
+
+ ForEach.compressedImage = function(image, handler) {
+ if (defined(image.extras)) {
+ var compressedImages = image.extras.compressedImage3DTiles;
+ for (var type in compressedImages) {
+ if (compressedImages.hasOwnProperty(type)) {
+ var compressedImage = compressedImages[type];
+ var value = handler(compressedImage, type);
+
+ if (defined(value)) {
+ return value;
+ }
+ }
+ }
+ }
};
ForEach.material = function(gltf, handler) {
- ForEach.topLevel(gltf, 'materials', handler);
+ return ForEach.topLevel(gltf, 'materials', handler);
};
ForEach.materialValue = function(material, handler) {
var values = material.values;
- if (defined(values)) {
- for (var name in values) {
- if (values.hasOwnProperty(name)) {
- handler(values[name], name);
+ if (defined(material.extensions) && defined(material.extensions.KHR_techniques_webgl)) {
+ values = material.extensions.KHR_techniques_webgl.values;
+ }
+
+ for (var name in values) {
+ if (values.hasOwnProperty(name)) {
+ var value = handler(values[name], name);
+
+ if (defined(value)) {
+ return value;
}
}
}
};
ForEach.mesh = function(gltf, handler) {
- ForEach.topLevel(gltf, 'meshes', handler);
+ return ForEach.topLevel(gltf, 'meshes', handler);
};
ForEach.meshPrimitive = function(mesh, handler) {
@@ -102,53 +234,80 @@ define([
var primitivesLength = primitives.length;
for (var i = 0; i < primitivesLength; i++) {
var primitive = primitives[i];
- handler(primitive, i);
+ var value = handler(primitive, i);
+
+ if (defined(value)) {
+ return value;
+ }
}
}
};
ForEach.meshPrimitiveAttribute = function(primitive, handler) {
var attributes = primitive.attributes;
- if (defined(attributes)) {
- for (var semantic in attributes) {
- if (attributes.hasOwnProperty(semantic)) {
- handler(attributes[semantic], semantic);
+ for (var semantic in attributes) {
+ if (attributes.hasOwnProperty(semantic)) {
+ var value = handler(attributes[semantic], semantic);
+
+ if (defined(value)) {
+ return value;
}
}
}
};
- ForEach.meshPrimitiveTargetAttribute = function(primitive, handler) {
+ ForEach.meshPrimitiveTarget = function(primitive, handler) {
var targets = primitive.targets;
if (defined(targets)) {
- for (var targetId in targets) {
- if (targets.hasOwnProperty(targetId)) {
- var target = targets[targetId];
- for (var attributeId in target) {
- if (target.hasOwnProperty(attributeId) && attributeId !== 'extras') {
- handler(target[attributeId], attributeId);
- }
- }
+ var length = targets.length;
+ for (var i = 0; i < length; ++i) {
+ var value = handler(targets[i], i);
+
+ if (defined(value)) {
+ return value;
+ }
+ }
+ }
+ };
+
+ ForEach.meshPrimitiveTargetAttribute = function(target, handler) {
+ for (var semantic in target) {
+ if (target.hasOwnProperty(semantic)) {
+ var accessorId = target[semantic];
+ var value = handler(accessorId, semantic);
+
+ if (defined(value)) {
+ return value;
}
}
}
};
ForEach.node = function(gltf, handler) {
- ForEach.topLevel(gltf, 'nodes', handler);
+ return ForEach.topLevel(gltf, 'nodes', handler);
};
ForEach.nodeInTree = function(gltf, nodeIds, handler) {
var nodes = gltf.nodes;
if (defined(nodes)) {
- for (var i = 0; i < nodeIds.length; i++) {
+ var length = nodeIds.length;
+ for (var i = 0; i < length; i++) {
var nodeId = nodeIds[i];
var node = nodes[nodeId];
if (defined(node)) {
- handler(node, nodeId);
+ var value = handler(node, nodeId);
+
+ if (defined(value)) {
+ return value;
+ }
+
var children = node.children;
if (defined(children)) {
- ForEach.nodeInTree(gltf, children, handler);
+ value = ForEach.nodeInTree(gltf, children, handler);
+
+ if (defined(value)) {
+ return value;
+ }
}
}
}
@@ -158,38 +317,59 @@ define([
ForEach.nodeInScene = function(gltf, scene, handler) {
var sceneNodeIds = scene.nodes;
if (defined(sceneNodeIds)) {
- ForEach.nodeInTree(gltf, sceneNodeIds, handler);
+ return ForEach.nodeInTree(gltf, sceneNodeIds, handler);
}
};
ForEach.program = function(gltf, handler) {
- ForEach.topLevel(gltf, 'programs', handler);
+ if (hasExtension(gltf, 'KHR_techniques_webgl')) {
+ return ForEach.object(gltf.extensions.KHR_techniques_webgl.programs, handler);
+ }
+
+ return ForEach.topLevel(gltf, 'programs', handler);
};
ForEach.sampler = function(gltf, handler) {
- ForEach.topLevel(gltf, 'samplers', handler);
+ return ForEach.topLevel(gltf, 'samplers', handler);
};
ForEach.scene = function(gltf, handler) {
- ForEach.topLevel(gltf, 'scenes', handler);
+ return ForEach.topLevel(gltf, 'scenes', handler);
};
ForEach.shader = function(gltf, handler) {
- ForEach.topLevel(gltf, 'shaders', handler);
+ if (hasExtension(gltf, 'KHR_techniques_webgl')) {
+ return ForEach.object(gltf.extensions.KHR_techniques_webgl.shaders, handler);
+ }
+
+ return ForEach.topLevel(gltf, 'shaders', handler);
};
ForEach.skin = function(gltf, handler) {
- ForEach.topLevel(gltf, 'skins', handler);
+ return ForEach.topLevel(gltf, 'skins', handler);
};
ForEach.techniqueAttribute = function(technique, handler) {
var attributes = technique.attributes;
- if (defined(attributes)) {
- for (var semantic in attributes) {
- if (attributes.hasOwnProperty(semantic)) {
- if (handler(attributes[semantic], semantic)) {
- break;
- }
+ for (var attributeName in attributes) {
+ if (attributes.hasOwnProperty(attributeName)) {
+ var value = handler(attributes[attributeName], attributeName);
+
+ if (defined(value)) {
+ return value;
+ }
+ }
+ }
+ };
+
+ ForEach.techniqueUniform = function(technique, handler) {
+ var uniforms = technique.uniforms;
+ for (var uniformName in uniforms) {
+ if (uniforms.hasOwnProperty(uniformName)) {
+ var value = handler(uniforms[uniformName], uniformName);
+
+ if (defined(value)) {
+ return value;
}
}
}
@@ -197,23 +377,27 @@ define([
ForEach.techniqueParameter = function(technique, handler) {
var parameters = technique.parameters;
- if (defined(parameters)) {
- for (var parameterName in parameters) {
- if (parameters.hasOwnProperty(parameterName)) {
- if (handler(parameters[parameterName], parameterName)) {
- break;
- }
+ for (var parameterName in parameters) {
+ if (parameters.hasOwnProperty(parameterName)) {
+ var value = handler(parameters[parameterName], parameterName);
+
+ if (defined(value)) {
+ return value;
}
}
}
};
ForEach.technique = function(gltf, handler) {
- ForEach.topLevel(gltf, 'techniques', handler);
+ if (hasExtension(gltf, 'KHR_techniques_webgl')) {
+ return ForEach.object(gltf.extensions.KHR_techniques_webgl.techniques, handler);
+ }
+
+ return ForEach.topLevel(gltf, 'techniques', handler);
};
ForEach.texture = function(gltf, handler) {
- ForEach.topLevel(gltf, 'textures', handler);
+ return ForEach.topLevel(gltf, 'textures', handler);
};
return ForEach;
diff --git a/Source/ThirdParty/GltfPipeline/addDefaults.js b/Source/ThirdParty/GltfPipeline/addDefaults.js
index 51f46acb4b54..503f3f91b7f7 100644
--- a/Source/ThirdParty/GltfPipeline/addDefaults.js
+++ b/Source/ThirdParty/GltfPipeline/addDefaults.js
@@ -1,522 +1,173 @@
define([
- './addToArray',
'./ForEach',
- '../../Core/clone',
+ './getAccessorByteStride',
'../../Core/defaultValue',
'../../Core/defined',
'../../Core/WebGLConstants'
], function(
- addToArray,
ForEach,
- clone,
+ getAccessorByteStride,
defaultValue,
defined,
WebGLConstants) {
'use strict';
- var gltfTemplate = {
- accessors: [],
- animations : [
- {
- channels : [],
- samplers : [
- {
- interpolation : 'LINEAR'
- }
- ]
- }
- ],
- asset : {},
- buffers : [
- {
- byteLength: 0,
- type: 'arraybuffer'
- }
- ],
- bufferViews: [
- {
- byteLength: 0
- }
- ],
- cameras: [],
- images: [],
- materials: [
- {
- values: function(material) {
- var extensions = defaultValue(material.extensions, {});
- var materialsCommon = extensions.KHR_materials_common;
- if (!defined(materialsCommon)) {
- return {};
- }
- },
- extensions: function(material) {
- var extensions = defaultValue(material.extensions, {});
- var materialsCommon = extensions.KHR_materials_common;
- if (defined(materialsCommon)) {
- var technique = materialsCommon.technique;
- var defaults = {
- ambient: [0.0, 0.0, 0.0, 1.0],
- emission: [0.0, 0.0, 0.0, 1.0],
- transparency: 1.0
- };
- if (technique !== 'CONSTANT') {
- defaults.diffuse = [0.0, 0.0, 0.0, 1.0];
- if (technique !== 'LAMBERT') {
- defaults.specular = [0.0, 0.0, 0.0, 1.0];
- defaults.shininess = 0.0;
- }
- }
- return {
- KHR_materials_common: {
- doubleSided: false,
- transparent: false,
- values: defaults
- }
- };
- }
- }
- }
- ],
- meshes : [
- {
- primitives : [
- {
- attributes : {},
- mode : WebGLConstants.TRIANGLES
- }
- ]
- }
- ],
- nodes : [
- {
- children : [],
- matrix : function(node) {
- if (!defined(node.translation) && !defined(node.rotation) && !defined(node.scale)) {
- return [
- 1.0, 0.0, 0.0, 0.0,
- 0.0, 1.0, 0.0, 0.0,
- 0.0, 0.0, 1.0, 0.0,
- 0.0, 0.0, 0.0, 1.0
- ];
- }
- },
- rotation : function(node) {
- if (defined(node.translation) || defined(node.scale)) {
- return [0.0, 0.0, 0.0, 1.0];
- }
- },
- scale : function(node) {
- if (defined(node.translation) || defined(node.rotation)) {
- return [1.0, 1.0, 1.0];
- }
- },
- translation : function(node) {
- if (defined(node.rotation) || defined(node.scale)) {
- return [0.0, 0.0, 0.0];
- }
- }
- }
- ],
- programs : [
- {
- attributes : []
- }
- ],
- samplers : [
- {
- magFilter: WebGLConstants.LINEAR,
- minFilter : WebGLConstants.NEAREST_MIPMAP_LINEAR,
- wrapS : WebGLConstants.REPEAT,
- wrapT : WebGLConstants.REPEAT
- }
- ],
- scenes : [
- {
- nodes : []
- }
- ],
- shaders : [],
- skins : [
- {
- bindShapeMatrix : [
- 1.0, 0.0, 0.0, 0.0,
- 0.0, 1.0, 0.0, 0.0,
- 0.0, 0.0, 1.0, 0.0,
- 0.0, 0.0, 0.0, 1.0
- ]
- }
- ],
- techniques : [
- {
- parameters: {},
- attributes: {},
- uniforms: {},
- states: {
- enable: []
- }
- }
- ],
- textures : [
- {
- format: WebGLConstants.RGBA,
- internalFormat: WebGLConstants.RGBA,
- target: WebGLConstants.TEXTURE_2D,
- type: WebGLConstants.UNSIGNED_BYTE
- }
- ],
- extensionsUsed : [],
- extensionsRequired : []
- };
+ /**
+ * Adds default glTF values if they don't exist.
+ *
+ * @param {Object} gltf A javascript object containing a glTF asset.
+ * @returns {Object} The modified glTF.
+ */
+ function addDefaults(gltf) {
+ ForEach.accessor(gltf, function(accessor) {
+ accessor.byteOffset = defaultValue(accessor.byteOffset, 0);
+ });
- function addDefaultsFromTemplate(object, template) {
- for (var id in template) {
- if (template.hasOwnProperty(id)) {
- var templateValue = template[id];
- if (typeof templateValue === 'function') {
- templateValue = templateValue(object);
- }
- if (defined(templateValue)) {
- if (typeof templateValue === 'object') {
- if (Array.isArray(templateValue)) {
- var arrayValue = defaultValue(object[id], []);
- if (templateValue.length > 0) {
- var arrayTemplate = templateValue[0];
- if (typeof arrayTemplate === 'object') {
- var arrayValueLength = arrayValue.length;
- for (var i = 0; i < arrayValueLength; i++) {
- addDefaultsFromTemplate(arrayValue[i], arrayTemplate);
- }
- } else {
- arrayValue = defaultValue(object[id], templateValue);
- }
- }
- object[id] = arrayValue;
- } else {
- var applyTemplate = templateValue['*'];
- object[id] = defaultValue(object[id], {});
- var objectValue = object[id];
- if (defined(applyTemplate)) {
- for (var subId in objectValue) {
- if (objectValue.hasOwnProperty(subId) && subId !== 'extras') {
- var subObject = objectValue[subId];
- addDefaultsFromTemplate(subObject, applyTemplate);
- }
- }
- } else {
- addDefaultsFromTemplate(objectValue, templateValue);
- }
- }
- } else {
- object[id] = defaultValue(object[id], templateValue);
- }
- }
- }
- }
- }
+ ForEach.bufferView(gltf, function(bufferView) {
+ bufferView.byteOffset = defaultValue(bufferView.byteOffset, 0);
+ });
- function getAnimatedNodes(gltf) {
- var nodes = {};
- ForEach.animation(gltf, function(animation) {
- ForEach.animationChannel(animation, function(channel) {
- var target = channel.target;
- var nodeId = target.node;
- var path = target.path;
- // Ignore animations that target 'weights'
- if (path === 'translation' || path === 'rotation' || path === 'scale') {
- nodes[nodeId] = true;
- }
+ ForEach.mesh(gltf, function(mesh) {
+ ForEach.meshPrimitive(mesh, function(primitive) {
+ primitive.mode = defaultValue(primitive.mode, WebGLConstants.TRIANGLES);
});
});
- return nodes;
- }
- function addDefaultTransformToAnimatedNodes(gltf) {
- var animatedNodes = getAnimatedNodes(gltf);
- ForEach.node(gltf, function(node, id) {
- if (defined(animatedNodes[id])) {
- delete node.matrix;
- node.translation = defaultValue(node.translation, [0.0, 0.0, 0.0]);
- node.rotation = defaultValue(node.rotation, [0.0, 0.0, 0.0, 1.0]);
- node.scale = defaultValue(node.scale, [1.0, 1.0, 1.0]);
+ ForEach.accessorContainingVertexAttributeData(gltf, function(accessorId) {
+ var accessor = gltf.accessors[accessorId];
+ var bufferViewId = accessor.bufferView;
+ accessor.normalized = defaultValue(accessor.normalized, false);
+ if (defined(bufferViewId)) {
+ var bufferView = gltf.bufferViews[bufferViewId];
+ bufferView.byteStride = getAccessorByteStride(gltf, accessor);
+ bufferView.target = WebGLConstants.ARRAY_BUFFER;
}
});
- }
- var defaultMaterial = {
- values : {
- emission : [
- 0.5, 0.5, 0.5, 1.0
- ]
- },
- extras : {
- _pipeline: {}
- }
- };
-
- var defaultTechnique = {
- attributes : {
- a_position : 'position'
- },
- parameters : {
- modelViewMatrix : {
- semantic : 'MODELVIEW',
- type : WebGLConstants.FLOAT_MAT4
- },
- projectionMatrix : {
- semantic : 'PROJECTION',
- type : WebGLConstants.FLOAT_MAT4
- },
- emission : {
- type : WebGLConstants.FLOAT_VEC4,
- value : [
- 0.5, 0.5, 0.5, 1.0
- ]
- },
- position : {
- semantic: 'POSITION',
- type: WebGLConstants.FLOAT_VEC3
- }
- },
- states : {
- enable : [
- WebGLConstants.CULL_FACE,
- WebGLConstants.DEPTH_TEST
- ]
- },
- uniforms : {
- u_modelViewMatrix : 'modelViewMatrix',
- u_projectionMatrix : 'projectionMatrix',
- u_emission : 'emission'
- }
- };
-
- var defaultProgram = {
- attributes : [
- 'a_position'
- ]
- };
-
- var defaultVertexShader = {
- type : WebGLConstants.VERTEX_SHADER,
- extras : {
- _pipeline : {
- extension : '.vert',
- source : '' +
- 'precision highp float;\n' +
- '\n' +
- 'uniform mat4 u_modelViewMatrix;\n' +
- 'uniform mat4 u_projectionMatrix;\n' +
- '\n' +
- 'attribute vec3 a_position;\n' +
- '\n' +
- 'void main (void)\n' +
- '{\n' +
- ' gl_Position = u_projectionMatrix * u_modelViewMatrix * vec4(a_position, 1.0);\n' +
- '}\n'
+ ForEach.accessorContainingIndexData(gltf, function(accessorId) {
+ var accessor = gltf.accessors[accessorId];
+ var bufferViewId = accessor.bufferView;
+ if (defined(bufferViewId)) {
+ var bufferView = gltf.bufferViews[bufferViewId];
+ bufferView.target = WebGLConstants.ELEMENT_ARRAY_BUFFER;
}
- }
- };
-
- var defaultFragmentShader = {
- type : WebGLConstants.FRAGMENT_SHADER,
- extras : {
- _pipeline : {
- extension: '.frag',
- source : '' +
- 'precision highp float;\n' +
- '\n' +
- 'uniform vec4 u_emission;\n' +
- '\n' +
- 'void main(void)\n' +
- '{\n' +
- ' gl_FragColor = u_emission;\n' +
- '}\n'
- }
- }
- };
-
- function addDefaultMaterial(gltf) {
- var materials = gltf.materials;
- var meshes = gltf.meshes;
-
- var defaultMaterialId;
+ });
- var meshesLength = meshes.length;
- for (var meshId = 0; meshId < meshesLength; meshId++) {
- var mesh = meshes[meshId];
- var primitives = mesh.primitives;
- var primitivesLength = primitives.length;
- for (var j = 0; j < primitivesLength; j++) {
- var primitive = primitives[j];
- if (!defined(primitive.material)) {
- if (!defined(defaultMaterialId)) {
- defaultMaterialId = addToArray(materials, clone(defaultMaterial, true));
+ ForEach.material(gltf, function(material) {
+ var extensions = defaultValue(material.extensions, defaultValue.EMPTY_OBJECT);
+ var materialsCommon = extensions.KHR_materials_common;
+ if (defined(materialsCommon)) {
+ var technique = materialsCommon.technique;
+ var values = defined(materialsCommon.values) ? materialsCommon.values : {};
+ materialsCommon.values = values;
+
+ values.ambient = defined(values.ambient) ? values.ambient : [0.0, 0.0, 0.0, 1.0];
+ values.emission = defined(values.emission) ? values.emission : [0.0, 0.0, 0.0, 1.0];
+
+ values.transparency = defaultValue(values.transparency, 1.0);
+ values.transparent = defaultValue(values.transparent, false);
+ values.doubleSided = defaultValue(values.doubleSided, false);
+
+ if (technique !== 'CONSTANT') {
+ values.diffuse = defined(values.diffuse) ? values.diffuse : [0.0, 0.0, 0.0, 1.0];
+ if (technique !== 'LAMBERT') {
+ values.specular = defined(values.specular) ? values.specular : [0.0, 0.0, 0.0, 1.0];
+ values.shininess = defaultValue(values.shininess, 0.0);
}
- primitive.material = defaultMaterialId;
}
+ return;
}
- }
- }
- function addDefaultTechnique(gltf) {
- var materials = gltf.materials;
- var techniques = gltf.techniques;
- var programs = gltf.programs;
- var shaders = gltf.shaders;
+ material.emissiveFactor = defaultValue(material.emissiveFactor, [0.0, 0.0, 0.0]);
+ material.alphaMode = defaultValue(material.alphaMode, 'OPAQUE');
+ material.doubleSided = defaultValue(material.doubleSided, false);
- var defaultTechniqueId;
-
- var materialsLength = materials.length;
- for (var materialId = 0; materialId < materialsLength; materialId++) {
- var material = materials[materialId];
- var techniqueId = material.technique;
- var extensions = defaultValue(material.extensions, {});
- var materialsCommon = extensions.KHR_materials_common;
- if (!defined(techniqueId)) {
- if (!defined(defaultTechniqueId) && !defined(materialsCommon)) {
- var technique = clone(defaultTechnique, true);
- defaultTechniqueId = addToArray(techniques, technique);
+ if (material.alphaMode === 'MASK') {
+ material.alphaCutoff = defaultValue(material.alphaCutoff, 0.5);
+ }
- var program = clone(defaultProgram, true);
- technique.program = addToArray(programs, program);
+ var techniquesExtension = extensions.KHR_techniques_webgl;
+ if (defined(techniquesExtension)) {
+ ForEach.materialValue(material, function (materialValue) {
+ // Check if material value is a TextureInfo object
+ if (defined(materialValue.index)) {
+ addTextureDefaults(materialValue);
+ }
+ });
+ }
- var vertexShader = clone(defaultVertexShader, true);
- program.vertexShader = addToArray(shaders, vertexShader);
+ addTextureDefaults(material.emissiveTexture);
+ addTextureDefaults(material.normalTexture);
+ addTextureDefaults(material.occlusionTexture);
- var fragmentShader = clone(defaultFragmentShader, true);
- program.fragmentShader = addToArray(shaders, fragmentShader);
- }
- material.technique = defaultTechniqueId;
+ var pbrMetallicRoughness = material.pbrMetallicRoughness;
+ if (defined(pbrMetallicRoughness)) {
+ pbrMetallicRoughness.baseColorFactor = defaultValue(pbrMetallicRoughness.baseColorFactor, [1.0, 1.0, 1.0, 1.0]);
+ pbrMetallicRoughness.metallicFactor = defaultValue(pbrMetallicRoughness.metallicFactor, 1.0);
+ pbrMetallicRoughness.roughnessFactor = defaultValue(pbrMetallicRoughness.roughnessFactor, 1.0);
+ addTextureDefaults(pbrMetallicRoughness.baseColorTexture);
+ addTextureDefaults(pbrMetallicRoughness.metallicRoughnessTexture);
}
- }
- }
-
- function addDefaultByteOffsets(gltf) {
- var accessors = gltf.accessors;
- var accessorLength = accessors.length;
- for (var i = 0; i < accessorLength; i++) {
- var accessor = accessors[i];
- if (!defined(accessor.byteOffset)) {
- accessor.byteOffset = 0;
+ var pbrSpecularGlossiness = extensions.pbrSpecularGlossiness;
+ if (defined(pbrSpecularGlossiness)) {
+ pbrSpecularGlossiness.diffuseFactor = defaultValue(pbrSpecularGlossiness.diffuseFactor, [1.0, 1.0, 1.0, 1.0]);
+ pbrSpecularGlossiness.specularFactor = defaultValue(pbrSpecularGlossiness.specularFactor, [1.0, 1.0, 1.0]);
+ pbrSpecularGlossiness.glossinessFactor = defaultValue(pbrSpecularGlossiness.glossinessFactor, 1.0);
+ addTextureDefaults(pbrSpecularGlossiness.specularGlossinessTexture);
}
- }
+ });
- var bufferViews = gltf.bufferViews;
+ ForEach.animation(gltf, function(animation) {
+ ForEach.animationSampler(animation, function(sampler) {
+ sampler.interpolation = defaultValue(sampler.interpolation, 'LINEAR');
+ });
+ });
- var bufferViewsLength = bufferViews.length;
- for (var j = 0; j < bufferViewsLength; j++) {
- var bufferView = bufferViews[j];
- if (!defined(bufferView.byteOffset)) {
- bufferView.byteOffset = 0;
+ var animatedNodes = getAnimatedNodes(gltf);
+ ForEach.node(gltf, function(node, id) {
+ var animated = defined(animatedNodes[id]);
+ if (animated || defined(node.translation) || defined(node.rotation) || defined(node.scale)) {
+ node.translation = defaultValue(node.translation, [0.0, 0.0, 0.0]);
+ node.rotation = defaultValue(node.rotation, [0.0, 0.0, 0.0, 1.0]);
+ node.scale = defaultValue(node.scale, [1.0, 1.0, 1.0]);
+ } else {
+ node.matrix = defaultValue(node.matrix, [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0]);
}
- }
- }
+ });
+
+ ForEach.sampler(gltf, function(sampler) {
+ sampler.wrapS = defaultValue(sampler.wrapS, WebGLConstants.REPEAT);
+ sampler.wrapT = defaultValue(sampler.wrapT, WebGLConstants.REPEAT);
+ });
- function selectDefaultScene(gltf) {
if (defined(gltf.scenes) && !defined(gltf.scene)) {
gltf.scene = 0;
}
- }
- function optimizeForCesium(gltf) {
- // Give the diffuse uniform a semantic to support color replacement in 3D Tiles
- var techniques = gltf.techniques;
- var techniquesLength = techniques.length;
- for (var techniqueId = 0; techniqueId < techniquesLength; techniqueId++) {
- var technique = techniques[techniqueId];
- var parameters = technique.parameters;
- if (defined(parameters.diffuse)) {
- parameters.diffuse.semantic = '_3DTILESDIFFUSE';
- }
- }
+ return gltf;
}
- function inferBufferViewTargets(gltf) {
- // If bufferView elements are missing targets, we can infer their type from their use
- var needsTarget = {};
- var shouldTraverse = 0;
- ForEach.bufferView(gltf, function(bufferView, bufferViewId) {
- if (!defined(bufferView.target)) {
- needsTarget[bufferViewId] = true;
- shouldTraverse++;
- }
- });
- if (shouldTraverse > 0) {
- var accessors = gltf.accessors;
- var bufferViews = gltf.bufferViews;
- ForEach.mesh(gltf, function (mesh) {
- ForEach.meshPrimitive(mesh, function (primitive) {
- var indices = primitive.indices;
- if (defined(indices)) {
- var accessor = accessors[indices];
- var bufferViewId = accessor.bufferView;
- if (needsTarget[bufferViewId]) {
- var bufferView = bufferViews[bufferViewId];
- if (defined(bufferView)) {
- bufferView.target = WebGLConstants.ELEMENT_ARRAY_BUFFER;
- needsTarget[bufferViewId] = false;
- shouldTraverse--;
- }
- }
- }
- ForEach.meshPrimitiveAttribute(primitive, function (accessorId) {
- var accessor = accessors[accessorId];
- var bufferViewId = accessor.bufferView;
- if (needsTarget[bufferViewId]) {
- var bufferView = bufferViews[bufferViewId];
- if (defined(bufferView)) {
- bufferView.target = WebGLConstants.ARRAY_BUFFER;
- needsTarget[bufferViewId] = false;
- shouldTraverse--;
- }
- }
- });
- ForEach.meshPrimitiveTargetAttribute(primitive, function (targetAttribute) {
- var bufferViewId = accessors[targetAttribute].bufferView;
- if (needsTarget[bufferViewId]) {
- var bufferView = bufferViews[bufferViewId];
- if (defined(bufferView)) {
- bufferView.target = WebGLConstants.ARRAY_BUFFER;
- needsTarget[bufferViewId] = false;
- shouldTraverse--;
- }
- }
- });
- });
- if (shouldTraverse === 0) {
- return true;
+ function getAnimatedNodes(gltf) {
+ var nodes = {};
+ ForEach.animation(gltf, function(animation) {
+ ForEach.animationChannel(animation, function(channel) {
+ var target = channel.target;
+ var nodeId = target.node;
+ var path = target.path;
+ // Ignore animations that target 'weights'
+ if (path === 'translation' || path === 'rotation' || path === 'scale') {
+ nodes[nodeId] = true;
}
});
- }
+ });
+ return nodes;
}
- /**
- * Adds default glTF values if they don't exist.
- *
- * The glTF asset must be initialized for the pipeline.
- *
- * @param {Object} gltf A javascript object containing a glTF asset.
- * @param {Object} [options] An object with the following properties:
- * @param {Boolean} [options.optimizeForCesium] Optimize the defaults for Cesium. Uses the Cesium sun as the default light source.
- * @returns {Object} The modified glTF.
- *
- * @see addPipelineExtras
- * @see loadGltfUris
- */
- function addDefaults(gltf, options) {
- options = defaultValue(options, {});
- addDefaultsFromTemplate(gltf, gltfTemplate);
- addDefaultTransformToAnimatedNodes(gltf);
- addDefaultMaterial(gltf);
- addDefaultTechnique(gltf);
- addDefaultByteOffsets(gltf);
- selectDefaultScene(gltf);
- inferBufferViewTargets(gltf);
- if (options.optimizeForCesium) {
- optimizeForCesium(gltf);
+ function addTextureDefaults(texture) {
+ if (defined(texture)) {
+ texture.texCoord = defaultValue(texture.texCoord, 0);
}
- return gltf;
}
return addDefaults;
diff --git a/Source/ThirdParty/GltfPipeline/addExtensionsRequired.js b/Source/ThirdParty/GltfPipeline/addExtensionsRequired.js
index 49ec2de50fa6..2affd1d2b842 100644
--- a/Source/ThirdParty/GltfPipeline/addExtensionsRequired.js
+++ b/Source/ThirdParty/GltfPipeline/addExtensionsRequired.js
@@ -12,6 +12,8 @@ define([
*
* @param {Object} gltf A javascript object containing a glTF asset.
* @param {String} extension The extension to add.
+ *
+ * @private
*/
function addExtensionsRequired(gltf, extension) {
var extensionsRequired = gltf.extensionsRequired;
@@ -19,10 +21,11 @@ define([
extensionsRequired = [];
gltf.extensionsRequired = extensionsRequired;
}
- if (extensionsRequired.indexOf(extension) < 0) {
+ if (extensionsRequired.indexOf(extension) === -1) {
extensionsRequired.push(extension);
}
addExtensionsUsed(gltf, extension);
}
+
return addExtensionsRequired;
});
diff --git a/Source/ThirdParty/GltfPipeline/addExtensionsUsed.js b/Source/ThirdParty/GltfPipeline/addExtensionsUsed.js
index 6d8bed56db03..a008069cf114 100644
--- a/Source/ThirdParty/GltfPipeline/addExtensionsUsed.js
+++ b/Source/ThirdParty/GltfPipeline/addExtensionsUsed.js
@@ -10,6 +10,8 @@ define([
*
* @param {Object} gltf A javascript object containing a glTF asset.
* @param {String} extension The extension to add.
+ *
+ * @private
*/
function addExtensionsUsed(gltf, extension) {
var extensionsUsed = gltf.extensionsUsed;
@@ -17,9 +19,10 @@ define([
extensionsUsed = [];
gltf.extensionsUsed = extensionsUsed;
}
- if (extensionsUsed.indexOf(extension) < 0) {
+ if (extensionsUsed.indexOf(extension) === -1) {
extensionsUsed.push(extension);
}
}
+
return addExtensionsUsed;
});
diff --git a/Source/ThirdParty/GltfPipeline/addPipelineExtras.js b/Source/ThirdParty/GltfPipeline/addPipelineExtras.js
index 5f5dc2b54656..4f4b3db8162f 100644
--- a/Source/ThirdParty/GltfPipeline/addPipelineExtras.js
+++ b/Source/ThirdParty/GltfPipeline/addPipelineExtras.js
@@ -1,68 +1,43 @@
define([
- '../../Core/defaultValue',
+ './ForEach',
'../../Core/defined'
], function(
- defaultValue,
+ ForEach,
defined) {
'use strict';
- // Objects with these ids should not have extras added
- var exceptions = {
- attributes: true,
- uniforms: true,
- extensions: true,
- values: true,
- samplers: true
- };
-
/**
* Adds extras._pipeline to each object that can have extras in the glTF asset.
+ * This stage runs before updateVersion and handles both glTF 1.0 and glTF 2.0 assets.
*
* @param {Object} gltf A javascript object containing a glTF asset.
* @returns {Object} The glTF asset with the added pipeline extras.
+ *
+ * @private
*/
function addPipelineExtras(gltf) {
- var objectStack = [];
- for (var rootArrayId in gltf) {
- if (gltf.hasOwnProperty(rootArrayId)) {
- var rootArray = gltf[rootArrayId];
- var rootArrayLength = rootArray.length;
- for (var i = 0; i < rootArrayLength; i++) {
- var rootObject = rootArray[i];
- if (defined(rootObject) && typeof rootObject === 'object') {
- rootObject.extras = defaultValue(rootObject.extras, {});
- rootObject.extras._pipeline = defaultValue(rootObject.extras._pipeline, {});
- objectStack.push(rootObject);
- }
- }
- }
- }
- while (objectStack.length > 0) {
- var object = objectStack.pop();
- for (var propertyId in object) {
- if (object.hasOwnProperty(propertyId)) {
- var property = object[propertyId];
- if (defined(property) && typeof property === 'object' && propertyId !== 'extras') {
- objectStack.push(property);
- if (!exceptions[propertyId] && !Array.isArray(property)) {
- property.extras = defaultValue(property.extras, {});
- property.extras._pipeline = defaultValue(property.extras._pipeline, {});
- }
- }
- }
- }
- }
- gltf.extras = defaultValue(gltf.extras, {});
- gltf.extras._pipeline = defaultValue(gltf.extras._pipeline, {});
- gltf.asset = defaultValue(gltf.asset, {});
- gltf.asset.extras = defaultValue(gltf.asset.extras, {});
- if (defined(gltf.asset.extras) && typeof(gltf.asset.extras) !== 'object') {
- gltf.asset.extras = {
- extras : gltf.asset.extras
- };
- }
- gltf.asset.extras._pipeline = defaultValue(gltf.asset.extras._pipeline, {});
+ ForEach.shader(gltf, function(shader) {
+ addExtras(shader);
+ });
+ ForEach.buffer(gltf, function(buffer) {
+ addExtras(buffer);
+ });
+ ForEach.image(gltf, function (image) {
+ addExtras(image);
+ ForEach.compressedImage(image, function(compressedImage) {
+ addExtras(compressedImage);
+ });
+ });
+
+ addExtras(gltf);
+
return gltf;
}
+
+ function addExtras(object) {
+ object.extras = defined(object.extras) ? object.extras : {};
+ object.extras._pipeline = defined(object.extras._pipeline) ? object.extras._pipeline : {};
+ }
+
return addPipelineExtras;
});
diff --git a/Source/ThirdParty/GltfPipeline/addToArray.js b/Source/ThirdParty/GltfPipeline/addToArray.js
index 8559cb54288b..78e347799ba6 100644
--- a/Source/ThirdParty/GltfPipeline/addToArray.js
+++ b/Source/ThirdParty/GltfPipeline/addToArray.js
@@ -1,9 +1,18 @@
define([], function() {
'use strict';
+ /**
+ * Adds an element to an array and returns the element's index.
+ *
+ * @param {Array} array The array to add to.
+ * @param {Object} element The element to add.
+ *
+ * @private
+ */
function addToArray(array, element) {
array.push(element);
return array.length - 1;
}
+
return addToArray;
});
diff --git a/Source/ThirdParty/GltfPipeline/byteLengthForComponentType.js b/Source/ThirdParty/GltfPipeline/byteLengthForComponentType.js
deleted file mode 100644
index 409bc740ad48..000000000000
--- a/Source/ThirdParty/GltfPipeline/byteLengthForComponentType.js
+++ /dev/null
@@ -1,34 +0,0 @@
-define([
- '../../Core/WebGLConstants'
- ], function(
- WebGLConstants) {
- 'use strict';
-
- /**
- * Utility function for retrieving the byte length of a component type.
- * As per the spec:
- * 5120 (BYTE) : 1
- * 5121 (UNSIGNED_BYTE) : 1
- * 5122 (SHORT) : 2
- * 5123 (UNSIGNED_SHORT) : 2
- * 5126 (FLOAT) : 4
- * 5125 (UNSIGNED_INT) : 4
- *
- * @param {Number} [componentType]
- * @returns {Number} The byte length of the component type.
- */
- function byteLengthForComponentType(componentType) {
- switch (componentType) {
- case WebGLConstants.BYTE:
- case WebGLConstants.UNSIGNED_BYTE:
- return 1;
- case WebGLConstants.SHORT:
- case WebGLConstants.UNSIGNED_SHORT:
- return 2;
- case WebGLConstants.FLOAT:
- case WebGLConstants.UNSIGNED_INT:
- return 4;
- }
- }
- return byteLengthForComponentType;
-});
diff --git a/Source/ThirdParty/GltfPipeline/findAccessorMinMax.js b/Source/ThirdParty/GltfPipeline/findAccessorMinMax.js
index 3ebf53b24eb1..cb2a46810e40 100644
--- a/Source/ThirdParty/GltfPipeline/findAccessorMinMax.js
+++ b/Source/ThirdParty/GltfPipeline/findAccessorMinMax.js
@@ -1,11 +1,13 @@
define([
'./getAccessorByteStride',
+ './getComponentReader',
'./numberOfComponentsForType',
'../../Core/arrayFill',
'../../Core/ComponentDatatype',
'../../Core/defined'
], function(
getAccessorByteStride,
+ getComponentReader,
numberOfComponentsForType,
arrayFill,
ComponentDatatype,
@@ -13,51 +15,60 @@ define([
'use strict';
/**
- * Finds the min and max for an accessor in gltf.
- *
- * The glTF asset must be initialized for the pipeline.
+ * Finds the min and max values of the accessor.
*
* @param {Object} gltf A javascript object containing a glTF asset.
* @param {Object} accessor The accessor object from the glTF asset to read.
* @returns {{min: Array, max: Array}} min holding the array of minimum values and max holding the array of maximum values.
*
- * @see addPipelineExtras
- * @see loadGltfUris
+ * @private
*/
function findAccessorMinMax(gltf, accessor) {
var bufferViews = gltf.bufferViews;
var buffers = gltf.buffers;
var bufferViewId = accessor.bufferView;
var numberOfComponents = numberOfComponentsForType(accessor.type);
+
+ // According to the spec, when bufferView is not defined, accessor must be initialized with zeros
+ if (!defined(accessor.bufferView)) {
+ return {
+ min: arrayFill(new Array(numberOfComponents), 0.0),
+ max: arrayFill(new Array(numberOfComponents), 0.0)
+ };
+ }
+
var min = arrayFill(new Array(numberOfComponents), Number.POSITIVE_INFINITY);
var max = arrayFill(new Array(numberOfComponents), Number.NEGATIVE_INFINITY);
- if (defined(bufferViewId) && defined(bufferViews) && bufferViews.hasOwnProperty(bufferViewId)) {
- var bufferView = bufferViews[bufferViewId];
- var bufferId = bufferView.buffer;
- if (defined(bufferId) && defined(buffers) && buffers.hasOwnProperty(bufferId)) {
- var buffer = buffers[bufferId];
- var source = buffer.extras._pipeline.source;
-
- var count = accessor.count;
- var byteStride = getAccessorByteStride(gltf, accessor);
- var byteOffset = accessor.byteOffset + bufferView.byteOffset;
- var componentType = accessor.componentType;
-
- for (var i = 0; i < count; i++) {
- var typedArray = ComponentDatatype.createArrayBufferView(componentType, source.buffer, byteOffset + source.byteOffset, numberOfComponents);
- for (var j = 0; j < numberOfComponents; j++) {
- var value = typedArray[j];
- min[j] = Math.min(min[j], value);
- max[j] = Math.max(max[j], value);
- }
- byteOffset += byteStride;
- }
+
+ var bufferView = bufferViews[bufferViewId];
+ var bufferId = bufferView.buffer;
+ var buffer = buffers[bufferId];
+ var source = buffer.extras._pipeline.source;
+
+ var count = accessor.count;
+ var byteStride = getAccessorByteStride(gltf, accessor);
+ var byteOffset = accessor.byteOffset + bufferView.byteOffset + source.byteOffset;
+ var componentType = accessor.componentType;
+ var componentTypeByteLength = ComponentDatatype.getSizeInBytes(componentType);
+ var dataView = new DataView(source.buffer);
+ var components = new Array(numberOfComponents);
+ var componentReader = getComponentReader(componentType);
+
+ for (var i = 0; i < count; i++) {
+ componentReader(dataView, byteOffset, numberOfComponents, componentTypeByteLength, components);
+ for (var j = 0; j < numberOfComponents; j++) {
+ var value = components[j];
+ min[j] = Math.min(min[j], value);
+ max[j] = Math.max(max[j], value);
}
+ byteOffset += byteStride;
}
+
return {
- min : min,
- max : max
+ min: min,
+ max: max
};
}
+
return findAccessorMinMax;
});
diff --git a/Source/ThirdParty/GltfPipeline/getAccessorByteStride.js b/Source/ThirdParty/GltfPipeline/getAccessorByteStride.js
index c9dbfe0f9fb4..5de99d59fe34 100644
--- a/Source/ThirdParty/GltfPipeline/getAccessorByteStride.js
+++ b/Source/ThirdParty/GltfPipeline/getAccessorByteStride.js
@@ -1,10 +1,10 @@
define([
- './byteLengthForComponentType',
'./numberOfComponentsForType',
+ '../../Core/ComponentDatatype',
'../../Core/defined'
], function(
- byteLengthForComponentType,
numberOfComponentsForType,
+ ComponentDatatype,
defined) {
'use strict';
@@ -15,13 +15,19 @@ define([
* @param {Object} gltf A javascript object containing a glTF asset.
* @param {Object} accessor The accessor.
* @returns {Number} The byte stride of the accessor.
+ *
+ * @private
*/
function getAccessorByteStride(gltf, accessor) {
- var bufferView = gltf.bufferViews[accessor.bufferView];
- if (defined(bufferView.byteStride) && bufferView.byteStride > 0) {
- return bufferView.byteStride;
+ var bufferViewId = accessor.bufferView;
+ if (defined(bufferViewId)) {
+ var bufferView = gltf.bufferViews[bufferViewId];
+ if (defined(bufferView.byteStride) && bufferView.byteStride > 0) {
+ return bufferView.byteStride;
+ }
}
- return byteLengthForComponentType(accessor.componentType) * numberOfComponentsForType(accessor.type);
+ return ComponentDatatype.getSizeInBytes(accessor.componentType) * numberOfComponentsForType(accessor.type);
}
+
return getAccessorByteStride;
});
diff --git a/Source/ThirdParty/GltfPipeline/getComponentReader.js b/Source/ThirdParty/GltfPipeline/getComponentReader.js
new file mode 100644
index 000000000000..c6fbf048a35a
--- /dev/null
+++ b/Source/ThirdParty/GltfPipeline/getComponentReader.js
@@ -0,0 +1,80 @@
+define([
+ '../../Core/ComponentDatatype'
+ ], function(
+ ComponentDatatype) {
+ 'use strict';
+
+ /**
+ * Returns a function to read and convert data from a DataView into an array.
+ *
+ * @param {Number} componentType Type to convert the data to.
+ * @returns {ComponentReader} Function that reads and converts data.
+ *
+ * @private
+ */
+ function getComponentReader(componentType) {
+ switch (componentType) {
+ case ComponentDatatype.BYTE:
+ return function (dataView, byteOffset, numberOfComponents, componentTypeByteLength, result) {
+ for (var i = 0; i < numberOfComponents; ++i) {
+ result[i] = dataView.getInt8(byteOffset + i * componentTypeByteLength);
+ }
+ };
+ case ComponentDatatype.UNSIGNED_BYTE:
+ return function (dataView, byteOffset, numberOfComponents, componentTypeByteLength, result) {
+ for (var i = 0; i < numberOfComponents; ++i) {
+ result[i] = dataView.getUint8(byteOffset + i * componentTypeByteLength);
+ }
+ };
+ case ComponentDatatype.SHORT:
+ return function (dataView, byteOffset, numberOfComponents, componentTypeByteLength, result) {
+ for (var i = 0; i < numberOfComponents; ++i) {
+ result[i] = dataView.getInt16(byteOffset + i * componentTypeByteLength, true);
+ }
+ };
+ case ComponentDatatype.UNSIGNED_SHORT:
+ return function (dataView, byteOffset, numberOfComponents, componentTypeByteLength, result) {
+ for (var i = 0; i < numberOfComponents; ++i) {
+ result[i] = dataView.getUint16(byteOffset + i * componentTypeByteLength, true);
+ }
+ };
+ case ComponentDatatype.INT:
+ return function (dataView, byteOffset, numberOfComponents, componentTypeByteLength, result) {
+ for (var i = 0; i < numberOfComponents; ++i) {
+ result[i] = dataView.getInt32(byteOffset + i * componentTypeByteLength, true);
+ }
+ };
+ case ComponentDatatype.UNSIGNED_INT:
+ return function (dataView, byteOffset, numberOfComponents, componentTypeByteLength, result) {
+ for (var i = 0; i < numberOfComponents; ++i) {
+ result[i] = dataView.getUint32(byteOffset + i * componentTypeByteLength, true);
+ }
+ };
+ case ComponentDatatype.FLOAT:
+ return function (dataView, byteOffset, numberOfComponents, componentTypeByteLength, result) {
+ for (var i = 0; i < numberOfComponents; ++i) {
+ result[i] = dataView.getFloat32(byteOffset + i * componentTypeByteLength, true);
+ }
+ };
+ case ComponentDatatype.DOUBLE:
+ return function (dataView, byteOffset, numberOfComponents, componentTypeByteLength, result) {
+ for (var i = 0; i < numberOfComponents; ++i) {
+ result[i] = dataView.getFloat64(byteOffset + i * componentTypeByteLength, true);
+ }
+ };
+ }
+ }
+
+ /**
+ * A callback function that logs messages.
+ * @callback ComponentReader
+ *
+ * @param {DataView} dataView The data view to read from.
+ * @param {Number} byteOffset The byte offset applied when reading from the data view.
+ * @param {Number} numberOfComponents The number of components to read.
+ * @param {Number} componentTypeByteLength The byte length of each component.
+ * @param {Number} result An array storing the components that are read.
+ */
+
+ return getComponentReader;
+});
diff --git a/Source/ThirdParty/GltfPipeline/getJointCountForMaterials.js b/Source/ThirdParty/GltfPipeline/getJointCountForMaterials.js
deleted file mode 100644
index ba299be639e7..000000000000
--- a/Source/ThirdParty/GltfPipeline/getJointCountForMaterials.js
+++ /dev/null
@@ -1,44 +0,0 @@
-define([
- './ForEach',
- '../../Core/defined'
- ], function(
- ForEach,
- defined) {
- 'use strict';
-
- function getJointCountForMaterials(gltf) {
- var meshes = gltf.meshes;
- var jointCountForMaterialId = {};
-
- var nodesForSkinId = {};
- ForEach.node(gltf, function(node) {
- if (defined(node.skin)) {
- if (!defined(nodesForSkinId[node.skin])) {
- nodesForSkinId[node.skin] = [];
- }
- nodesForSkinId[node.skin].push(node);
- }
- });
-
- ForEach.skin(gltf, function(skin, skinId) {
- var jointCount = skin.joints.length;
- var meshPrimitiveFunction = function(primitive) {
- jointCountForMaterialId[primitive.material] = jointCount;
- };
- var skinnedNodes = nodesForSkinId[skinId];
- var skinnedNodesLength = skinnedNodes.length;
- for (var i = 0; i < skinnedNodesLength; i++) {
- var skinnedNode = skinnedNodes[i];
- var meshId = skinnedNode.mesh;
- if (defined(meshId)) {
- var mesh = meshes[meshId];
- ForEach.meshPrimitive(mesh, meshPrimitiveFunction);
- }
- }
- });
-
- return jointCountForMaterialId;
- }
-
- return getJointCountForMaterials;
-});
diff --git a/Source/ThirdParty/GltfPipeline/glslTypeToWebGLConstant.js b/Source/ThirdParty/GltfPipeline/glslTypeToWebGLConstant.js
deleted file mode 100644
index f05c65a0c871..000000000000
--- a/Source/ThirdParty/GltfPipeline/glslTypeToWebGLConstant.js
+++ /dev/null
@@ -1,28 +0,0 @@
-define([
- '../../Core/WebGLConstants'
- ], function(
- WebGLConstants) {
- 'use strict';
-
- function glslTypeToWebGLConstant(glslType) {
- switch (glslType) {
- case 'float':
- return WebGLConstants.FLOAT;
- case 'vec2':
- return WebGLConstants.FLOAT_VEC2;
- case 'vec3':
- return WebGLConstants.FLOAT_VEC3;
- case 'vec4':
- return WebGLConstants.FLOAT_VEC4;
- case 'mat2':
- return WebGLConstants.FLOAT_MAT2;
- case 'mat3':
- return WebGLConstants.FLOAT_MAT3;
- case 'mat4':
- return WebGLConstants.FLOAT_MAT4;
- case 'sampler2D':
- return WebGLConstants.SAMPLER_2D;
- }
- }
- return glslTypeToWebGLConstant;
-});
diff --git a/Source/ThirdParty/GltfPipeline/hasExtension.js b/Source/ThirdParty/GltfPipeline/hasExtension.js
new file mode 100644
index 000000000000..84308f8a7618
--- /dev/null
+++ b/Source/ThirdParty/GltfPipeline/hasExtension.js
@@ -0,0 +1,21 @@
+define([
+ '../../Core/defined'
+ ], function(
+ defined) {
+ 'use strict';
+
+ /**
+ * Checks whether the glTF has the given extension.
+ *
+ * @param {Object} gltf A javascript object containing a glTF asset.
+ * @param {String} extension The name of the extension.
+ * @returns {Boolean} Whether the glTF has the given extension.
+ *
+ * @private
+ */
+ function hasExtension(gltf, extension) {
+ return defined(gltf.extensionsUsed) && (gltf.extensionsUsed.indexOf(extension) >= 0);
+ }
+
+ return hasExtension;
+});
diff --git a/Source/ThirdParty/GltfPipeline/moveTechniqueRenderStates.js b/Source/ThirdParty/GltfPipeline/moveTechniqueRenderStates.js
new file mode 100644
index 000000000000..4c2da1660bab
--- /dev/null
+++ b/Source/ThirdParty/GltfPipeline/moveTechniqueRenderStates.js
@@ -0,0 +1,138 @@
+define([
+ './addExtensionsUsed',
+ './ForEach',
+ '../../Core/defaultValue',
+ '../../Core/defined',
+ '../../Core/WebGLConstants'
+ ], function(
+ addExtensionsUsed,
+ ForEach,
+ defaultValue,
+ defined,
+ WebGLConstants) {
+ 'use strict';
+
+ var defaultBlendEquation = [
+ WebGLConstants.FUNC_ADD,
+ WebGLConstants.FUNC_ADD
+ ];
+
+ var defaultBlendFactors = [
+ WebGLConstants.ONE,
+ WebGLConstants.ZERO,
+ WebGLConstants.ONE,
+ WebGLConstants.ZERO
+ ];
+
+ function isStateEnabled(renderStates, state) {
+ var enabled = renderStates.enable;
+ if (!defined(enabled)) {
+ return false;
+ }
+
+ return (enabled.indexOf(state) > -1);
+ }
+
+ var supportedBlendFactors = [
+ WebGLConstants.ZERO,
+ WebGLConstants.ONE,
+ WebGLConstants.SRC_COLOR,
+ WebGLConstants.ONE_MINUS_SRC_COLOR,
+ WebGLConstants.SRC_ALPHA,
+ WebGLConstants.ONE_MINUS_SRC_ALPHA,
+ WebGLConstants.DST_ALPHA,
+ WebGLConstants.ONE_MINUS_DST_ALPHA,
+ WebGLConstants.DST_COLOR,
+ WebGLConstants.ONE_MINUS_DST_COLOR
+ ];
+
+ // If any of the blend factors are not supported, return the default
+ function getSupportedBlendFactors(value, defaultValue) {
+ if (!defined(value)) {
+ return defaultValue;
+ }
+
+ for (var i = 0; i < 4; i++) {
+ if (supportedBlendFactors.indexOf(value[i]) === -1) {
+ return defaultValue;
+ }
+ }
+
+ return value;
+ }
+
+ /**
+ * Move glTF 1.0 technique render states to glTF 2.0 materials properties and KHR_blend extension.
+ *
+ * @param {Object} gltf A javascript object containing a glTF asset.
+ * @returns {Object} The updated glTF asset.
+ *
+ * @private
+ */
+ function moveTechniqueRenderStates(gltf) {
+ var blendingForTechnique = {};
+ var materialPropertiesForTechnique = {};
+ var techniquesLegacy = gltf.techniques;
+ if (!defined(techniquesLegacy)) {
+ return gltf;
+ }
+
+ ForEach.technique(gltf, function (techniqueLegacy, techniqueIndex) {
+ var renderStates = techniqueLegacy.states;
+ if (defined(renderStates)) {
+ var materialProperties = materialPropertiesForTechnique[techniqueIndex] = {};
+
+ // If BLEND is enabled, the material should have alpha mode BLEND
+ if (isStateEnabled(renderStates, WebGLConstants.BLEND)) {
+ materialProperties.alphaMode = 'BLEND';
+
+ var blendFunctions = renderStates.functions;
+ if (defined(blendFunctions) && (defined(blendFunctions.blendEquationSeparate)
+ || defined(blendFunctions.blendFuncSeparate))) {
+ blendingForTechnique[techniqueIndex] = {
+ blendEquation: defaultValue(blendFunctions.blendEquationSeparate, defaultBlendEquation),
+ blendFactors: getSupportedBlendFactors(blendFunctions.blendFuncSeparate, defaultBlendFactors)
+ };
+ }
+ }
+
+ // If CULL_FACE is not enabled, the material should be doubleSided
+ if (!isStateEnabled(renderStates, WebGLConstants.CULL_FACE)) {
+ materialProperties.doubleSided = true;
+ }
+
+ delete techniqueLegacy.states;
+ }
+ });
+
+ if (Object.keys(blendingForTechnique).length > 0) {
+ if (!defined(gltf.extensions)) {
+ gltf.extensions = {};
+ }
+
+ addExtensionsUsed(gltf, 'KHR_blend');
+ }
+
+ ForEach.material(gltf, function (material) {
+ if (defined(material.technique)) {
+ var materialProperties = materialPropertiesForTechnique[material.technique];
+ ForEach.objectLegacy(materialProperties, function (value, property) {
+ material[property] = value;
+ });
+
+ var blending = blendingForTechnique[material.technique];
+ if (defined(blending)) {
+ if (!defined(material.extensions)) {
+ material.extensions = {};
+ }
+
+ material.extensions.KHR_blend = blending;
+ }
+ }
+ });
+
+ return gltf;
+ }
+
+ return moveTechniqueRenderStates;
+});
diff --git a/Source/ThirdParty/GltfPipeline/moveTechniquesToExtension.js b/Source/ThirdParty/GltfPipeline/moveTechniquesToExtension.js
new file mode 100644
index 000000000000..35b4ff1124dd
--- /dev/null
+++ b/Source/ThirdParty/GltfPipeline/moveTechniquesToExtension.js
@@ -0,0 +1,128 @@
+define([
+ './addExtensionsUsed',
+ './addExtensionsRequired',
+ './addToArray',
+ './ForEach',
+ '../../Core/defined'
+ ], function(
+ addExtensionsUsed,
+ addExtensionsRequired,
+ addToArray,
+ ForEach,
+ defined) {
+ 'use strict';
+
+ /**
+ * Move glTF 1.0 material techniques to glTF 2.0 KHR_techniques_webgl extension.
+ *
+ * @param {Object} gltf A javascript object containing a glTF asset.
+ * @returns {Object} The updated glTF asset.
+ *
+ * @private
+ */
+ function moveTechniquesToExtension(gltf) {
+ var techniquesLegacy = gltf.techniques;
+ var mappedUniforms = {};
+ var updatedTechniqueIndices = {};
+ if (defined(techniquesLegacy)) {
+ var extension = {
+ programs: [],
+ shaders: [],
+ techniques: []
+ };
+
+ ForEach.technique(gltf, function (techniqueLegacy, techniqueIndex) {
+ var technique = {
+ name: techniqueLegacy.name,
+ program: undefined,
+ attributes: {},
+ uniforms: {}
+ };
+
+ var parameterLegacy;
+ ForEach.techniqueAttribute(techniqueLegacy, function (parameterName, attributeName) {
+ parameterLegacy = techniqueLegacy.parameters[parameterName];
+ technique.attributes[attributeName] = {
+ semantic: parameterLegacy.semantic
+ };
+ });
+
+ ForEach.techniqueUniform(techniqueLegacy, function (parameterName, uniformName) {
+ parameterLegacy = techniqueLegacy.parameters[parameterName];
+ technique.uniforms[uniformName] = {
+ count: parameterLegacy.count,
+ node: parameterLegacy.node,
+ type: parameterLegacy.type,
+ semantic: parameterLegacy.semantic,
+ value: parameterLegacy.value
+ };
+
+ // Store the name of the uniform to update material values.
+ mappedUniforms[parameterName] = uniformName;
+ });
+
+ var programLegacy = gltf.programs[techniqueLegacy.program];
+ var program = {
+ name: programLegacy.name,
+ fragmentShader: undefined,
+ vertexShader: undefined
+ };
+
+ var fs = gltf.shaders[programLegacy.fragmentShader];
+ program.fragmentShader = addToArray(extension.shaders, fs);
+
+ var vs = gltf.shaders[programLegacy.vertexShader];
+ program.vertexShader = addToArray(extension.shaders, vs);
+
+ technique.program = addToArray(extension.programs, program);
+
+ // Store the index of the new technique to reference instead.
+ updatedTechniqueIndices[techniqueIndex] = addToArray(extension.techniques, technique);
+ });
+
+ if (extension.techniques.length > 0) {
+ if (!defined(gltf.extensions)) {
+ gltf.extensions = {};
+ }
+
+ gltf.extensions.KHR_techniques_webgl = extension;
+ addExtensionsUsed(gltf, 'KHR_techniques_webgl');
+ addExtensionsRequired(gltf, 'KHR_techniques_webgl');
+ }
+ }
+
+ ForEach.material(gltf, function (material) {
+ if (defined(material.technique)) {
+ var materialExtension = {
+ technique: updatedTechniqueIndices[material.technique]
+ };
+
+ ForEach.objectLegacy(material.values, function (value, parameterName) {
+ if (!defined(materialExtension.values)) {
+ materialExtension.values = {};
+ }
+
+ var uniformName = mappedUniforms[parameterName];
+ materialExtension.values[uniformName] = value;
+ });
+
+ if (!defined(material.extensions)) {
+ material.extensions = {};
+ }
+
+ material.extensions.KHR_techniques_webgl = materialExtension;
+ }
+
+ delete material.technique;
+ delete material.values;
+ });
+
+ delete gltf.techniques;
+ delete gltf.programs;
+ delete gltf.shaders;
+
+ return gltf;
+ }
+
+ return moveTechniquesToExtension;
+});
diff --git a/Source/ThirdParty/GltfPipeline/numberOfComponentsForType.js b/Source/ThirdParty/GltfPipeline/numberOfComponentsForType.js
index f87c62123c3b..9329ca1b8ebb 100644
--- a/Source/ThirdParty/GltfPipeline/numberOfComponentsForType.js
+++ b/Source/ThirdParty/GltfPipeline/numberOfComponentsForType.js
@@ -3,17 +3,11 @@ define([], function() {
/**
* Utility function for retrieving the number of components in a given type.
- * As per the spec:
- * 'SCALAR' : 1
- * 'VEC2' : 2
- * 'VEC3' : 3
- * 'VEC4' : 4
- * 'MAT2' : 4
- * 'MAT3' : 9
- * 'MAT4' : 16
*
* @param {String} type glTF type
* @returns {Number} The number of components in that type.
+ *
+ * @private
*/
function numberOfComponentsForType(type) {
switch (type) {
@@ -32,5 +26,6 @@ define([], function() {
return 16;
}
}
+
return numberOfComponentsForType;
});
diff --git a/Source/ThirdParty/GltfPipeline/parseBinaryGltf.js b/Source/ThirdParty/GltfPipeline/parseBinaryGltf.js
deleted file mode 100644
index fd2000d6c8f9..000000000000
--- a/Source/ThirdParty/GltfPipeline/parseBinaryGltf.js
+++ /dev/null
@@ -1,122 +0,0 @@
-define([
- './addPipelineExtras',
- './removeExtensionsUsed',
- './updateVersion',
- '../../Core/ComponentDatatype',
- '../../Core/defined',
- '../../Core/DeveloperError',
- '../../Core/getMagic',
- '../../Core/getStringFromTypedArray',
- '../../Core/WebGLConstants'
- ], function(
- addPipelineExtras,
- removeExtensionsUsed,
- updateVersion,
- ComponentDatatype,
- defined,
- DeveloperError,
- getMagic,
- getStringFromTypedArray,
- WebGLConstants) {
- 'use strict';
-
- /**
- * Parses a binary glTF buffer into glTF JSON.
- *
- * @param {Uint8Array} data The binary glTF data to parse.
- * @returns {Object} The parsed binary glTF.
- */
- function parseBinaryGltf(data) {
- var headerView = ComponentDatatype.createArrayBufferView(WebGLConstants.INT, data.buffer, data.byteOffset, 5);
-
- // Check that the magic string is present
- var magic = getMagic(data);
- if (magic !== 'glTF') {
- throw new DeveloperError('File is not valid binary glTF');
- }
-
- // Check that the version is 1 or 2
- var version = headerView[1];
- if (version !== 1 && version !== 2) {
- throw new DeveloperError('Binary glTF version is not 1 or 2');
- }
-
- var gltf;
- var buffers;
- var length;
- // Load binary glTF version 1
- if (version === 1) {
- length = headerView[2];
- var contentLength = headerView[3];
- var contentFormat = headerView[4];
-
- // Check that the content format is 0, indicating that it is JSON
- if (contentFormat !== 0) {
- throw new DeveloperError('Binary glTF scene format is not JSON');
- }
-
- var jsonStart = 20;
- var binaryStart = jsonStart + contentLength;
-
- var contentString = getStringFromTypedArray(data, jsonStart, contentLength);
- gltf = JSON.parse(contentString);
-
- var binaryData = data.subarray(binaryStart, length);
-
- buffers = gltf.buffers;
- if (defined(buffers) && Object.keys(buffers).length > 0) {
- var binaryGltfBuffer = buffers.binary_glTF;
- // In some older models, the binary glTF buffer is named KHR_binary_glTF
- if (!defined(binaryGltfBuffer)) {
- binaryGltfBuffer = buffers.KHR_binary_glTF;
- }
- if (defined(binaryGltfBuffer)) {
- binaryGltfBuffer.extras = {
- _pipeline: {
- source: binaryData
- }
- };
- }
- }
- // Update to glTF 2.0
- updateVersion(gltf);
- // Remove the KHR_binary_glTF extension
- removeExtensionsUsed(gltf, 'KHR_binary_glTF');
- addPipelineExtras(gltf);
- }
-
- // Load binary glTF version 2
- if (version === 2) {
- length = headerView[2];
- var byteOffset = 12;
- var binaryBuffer;
- while (byteOffset < length) {
- var chunkHeaderView = ComponentDatatype.createArrayBufferView(WebGLConstants.INT, data.buffer, data.byteOffset + byteOffset, 2);
- var chunkLength = chunkHeaderView[0];
- var chunkType = chunkHeaderView[1];
- byteOffset += 8;
- var chunkBuffer = data.subarray(byteOffset, byteOffset + chunkLength);
- byteOffset += chunkLength;
- // Load JSON chunk
- if (chunkType === 0x4E4F534A) {
- var jsonString = getStringFromTypedArray(chunkBuffer);
- gltf = JSON.parse(jsonString);
- addPipelineExtras(gltf);
- }
- // Load Binary chunk
- else if (chunkType === 0x004E4942) {
- binaryBuffer = chunkBuffer;
- }
- }
- if (defined(gltf) && defined(binaryBuffer)) {
- buffers = gltf.buffers;
- if (defined(buffers) && buffers.length > 0) {
- var buffer = buffers[0];
- buffer.extras._pipeline.source = binaryBuffer;
- }
- }
- }
- return gltf;
- }
- return parseBinaryGltf;
-});
diff --git a/Source/ThirdParty/GltfPipeline/parseGlb.js b/Source/ThirdParty/GltfPipeline/parseGlb.js
new file mode 100644
index 000000000000..07c8c979fbda
--- /dev/null
+++ b/Source/ThirdParty/GltfPipeline/parseGlb.js
@@ -0,0 +1,126 @@
+define([
+ './addPipelineExtras',
+ './removeExtensionsUsed',
+ '../../Core/defaultValue',
+ '../../Core/defined',
+ '../../Core/getMagic',
+ '../../Core/getStringFromTypedArray',
+ '../../Core/RuntimeError'
+ ], function(
+ addPipelineExtras,
+ removeExtensionsUsed,
+ defaultValue,
+ defined,
+ getMagic,
+ getStringFromTypedArray,
+ RuntimeError) {
+ 'use strict';
+
+ var sizeOfUint32 = 4;
+
+ /**
+ * Convert a binary glTF to glTF.
+ *
+ * The returned glTF has pipeline extras included. The binary data is stored in gltf.buffers[0].extras._pipeline.source.
+ *
+ * @param {Buffer} glb The glb data to parse.
+ * @returns {Object} A javascript object containing a glTF asset with pipeline extras included.
+ *
+ * @private
+ */
+ function parseGlb(glb) {
+ // Check that the magic string is present
+ var magic = getMagic(glb);
+ if (magic !== 'glTF') {
+ throw new RuntimeError('File is not valid binary glTF');
+ }
+
+ var header = readHeader(glb, 0, 5);
+ var version = header[1];
+ if (version !== 1 && version !== 2) {
+ throw new RuntimeError('Binary glTF version is not 1 or 2');
+ }
+
+ if (version === 1) {
+ return parseGlbVersion1(glb, header);
+ }
+
+ return parseGlbVersion2(glb, header);
+ }
+
+ function readHeader(glb, byteOffset, count) {
+ var dataView = new DataView(glb.buffer);
+ var header = new Array(count);
+ for (var i = 0; i < count; ++i) {
+ header[i] = dataView.getUint32(glb.byteOffset + byteOffset + i * sizeOfUint32, true);
+ }
+ return header;
+ }
+
+ function parseGlbVersion1(glb, header) {
+ var length = header[2];
+ var contentLength = header[3];
+ var contentFormat = header[4];
+
+ // Check that the content format is 0, indicating that it is JSON
+ if (contentFormat !== 0) {
+ throw new RuntimeError('Binary glTF scene format is not JSON');
+ }
+
+ var jsonStart = 20;
+ var binaryStart = jsonStart + contentLength;
+
+ var contentString = getStringFromTypedArray(glb, jsonStart, contentLength);
+ var gltf = JSON.parse(contentString);
+ addPipelineExtras(gltf);
+
+ var binaryBuffer = glb.subarray(binaryStart, length);
+
+ var buffers = gltf.buffers;
+ if (defined(buffers) && Object.keys(buffers).length > 0) {
+ // In some older models, the binary glTF buffer is named KHR_binary_glTF
+ var binaryGltfBuffer = defaultValue(buffers.binary_glTF, buffers.KHR_binary_glTF);
+ if (defined(binaryGltfBuffer)) {
+ binaryGltfBuffer.extras._pipeline.source = binaryBuffer;
+ }
+ }
+ // Remove the KHR_binary_glTF extension
+ removeExtensionsUsed(gltf, 'KHR_binary_glTF');
+ return gltf;
+ }
+
+ function parseGlbVersion2(glb, header) {
+ var length = header[2];
+ var byteOffset = 12;
+ var gltf;
+ var binaryBuffer;
+ while (byteOffset < length) {
+ var chunkHeader = readHeader(glb, byteOffset, 2);
+ var chunkLength = chunkHeader[0];
+ var chunkType = chunkHeader[1];
+ byteOffset += 8;
+ var chunkBuffer = glb.subarray(byteOffset, byteOffset + chunkLength);
+ byteOffset += chunkLength;
+ // Load JSON chunk
+ if (chunkType === 0x4E4F534A) {
+ var jsonString = getStringFromTypedArray(chunkBuffer);
+ gltf = JSON.parse(jsonString);
+ addPipelineExtras(gltf);
+ }
+ // Load Binary chunk
+ else if (chunkType === 0x004E4942) {
+ binaryBuffer = chunkBuffer;
+ }
+ }
+ if (defined(gltf) && defined(binaryBuffer)) {
+ var buffers = gltf.buffers;
+ if (defined(buffers) && buffers.length > 0) {
+ var buffer = buffers[0];
+ buffer.extras._pipeline.source = binaryBuffer;
+ }
+ }
+ return gltf;
+ }
+
+ return parseGlb;
+});
diff --git a/Source/ThirdParty/GltfPipeline/removeExtensionsRequired.js b/Source/ThirdParty/GltfPipeline/removeExtensionsRequired.js
index 54d8002887bb..c77cf1ff9e07 100644
--- a/Source/ThirdParty/GltfPipeline/removeExtensionsRequired.js
+++ b/Source/ThirdParty/GltfPipeline/removeExtensionsRequired.js
@@ -9,6 +9,8 @@ define([
*
* @param {Object} gltf A javascript object containing a glTF asset.
* @param {String} extension The extension to remove.
+ *
+ * @private
*/
function removeExtensionsRequired(gltf, extension) {
var extensionsRequired = gltf.extensionsRequired;
diff --git a/Source/ThirdParty/GltfPipeline/removeExtensionsUsed.js b/Source/ThirdParty/GltfPipeline/removeExtensionsUsed.js
index f3fc28de7bca..7ded30174af7 100644
--- a/Source/ThirdParty/GltfPipeline/removeExtensionsUsed.js
+++ b/Source/ThirdParty/GltfPipeline/removeExtensionsUsed.js
@@ -11,6 +11,8 @@ define([
*
* @param {Object} gltf A javascript object containing a glTF asset.
* @param {String} extension The extension to remove.
+ *
+ * @private
*/
function removeExtensionsUsed(gltf, extension) {
var extensionsUsed = gltf.extensionsUsed;
@@ -25,5 +27,6 @@ define([
}
}
}
+
return removeExtensionsUsed;
});
diff --git a/Source/ThirdParty/GltfPipeline/removePipelineExtras.js b/Source/ThirdParty/GltfPipeline/removePipelineExtras.js
deleted file mode 100644
index abe075ca8a75..000000000000
--- a/Source/ThirdParty/GltfPipeline/removePipelineExtras.js
+++ /dev/null
@@ -1,34 +0,0 @@
-define([
- '../../Core/defined'
- ], function(
- defined) {
- 'use strict';
-
- /**
- * Iterate through the objects within each glTF object and delete their pipeline extras object.
- *
- * @param {Object} object Root object to remove pipeline extras.
- * @returns {Object} glTF with no pipeline extras.
- */
- function removePipelineExtras(object) {
- if (defined(object) && typeof object === 'object') {
- if (defined(object.extras) && defined(object.extras._pipeline)) {
- delete object.extras._pipeline;
- // Also delete extras if extras._pipeline is the only extras object
- if (Object.keys(object.extras).length === 0) {
- delete object.extras;
- }
- }
-
- //Recursively check subproperties for extras
- for (var propertyId in object) {
- if (object.hasOwnProperty(propertyId)) {
- removePipelineExtras(object[propertyId]);
- }
- }
- }
-
- return object;
- }
- return removePipelineExtras;
-});
diff --git a/Source/ThirdParty/GltfPipeline/removeUnusedElements.js b/Source/ThirdParty/GltfPipeline/removeUnusedElements.js
new file mode 100644
index 000000000000..c906e386ef52
--- /dev/null
+++ b/Source/ThirdParty/GltfPipeline/removeUnusedElements.js
@@ -0,0 +1,266 @@
+define([
+ './ForEach',
+ './hasExtension',
+ '../../Core/defined'
+ ], function(
+ ForEach,
+ hasExtension,
+ defined) {
+ 'use strict';
+
+ /**
+ * Removes unused elements from gltf.
+ * This function currently only works for accessors, buffers, and bufferViews.
+ *
+ * @param {Object} gltf A javascript object containing a glTF asset.
+ *
+ * @private
+ */
+ function removeUnusedElements(gltf) {
+ removeUnusedElementsByType(gltf, 'accessor');
+ removeUnusedElementsByType(gltf, 'bufferView');
+ removeUnusedElementsByType(gltf, 'buffer');
+ return gltf;
+ }
+
+ var TypeToGltfElementName = {
+ accessor: 'accessors',
+ buffer: 'buffers',
+ bufferView: 'bufferViews'
+ };
+
+ function removeUnusedElementsByType(gltf, type) {
+ var name = TypeToGltfElementName[type];
+ var arrayOfObjects = gltf[name];
+
+ if (defined(arrayOfObjects)) {
+ var removed = 0;
+ var usedIds = getListOfElementsIdsInUse[type](gltf);
+ var length = arrayOfObjects.length;
+
+ for (var i = 0; i < length; ++i) {
+ if (!usedIds[i]) {
+ Remove[type](gltf, i - removed);
+ removed++;
+ }
+ }
+ }
+ }
+
+ /**
+ * Contains functions for removing elements from a glTF hierarchy.
+ * Since top-level glTF elements are arrays, when something is removed, referring
+ * indices need to be updated.
+ * @constructor
+ *
+ * @private
+ */
+ function Remove() {}
+
+ Remove.accessor = function(gltf, accessorId) {
+ var accessors = gltf.accessors;
+
+ accessors.splice(accessorId, 1);
+
+ ForEach.mesh(gltf, function(mesh) {
+ ForEach.meshPrimitive(mesh, function(primitive) {
+ // Update accessor ids for the primitives.
+ ForEach.meshPrimitiveAttribute(primitive, function(attributeAccessorId, semantic) {
+ if (attributeAccessorId > accessorId) {
+ primitive.attributes[semantic]--;
+ }
+ });
+
+ // Update accessor ids for the targets.
+ ForEach.meshPrimitiveTarget(primitive, function(target) {
+ ForEach.meshPrimitiveTargetAttribute(target, function(attributeAccessorId, semantic) {
+ if (attributeAccessorId > accessorId) {
+ target[semantic]--;
+ }
+ });
+ });
+ var indices = primitive.indices;
+ if (defined(indices) && indices > accessorId) {
+ primitive.indices--;
+ }
+ });
+ });
+
+ ForEach.skin(gltf, function(skin) {
+ if (defined(skin.inverseBindMatrices) && skin.inverseBindMatrices > accessorId) {
+ skin.inverseBindMatrices--;
+ }
+ });
+
+ ForEach.animation(gltf, function(animation) {
+ ForEach.animationSampler(animation, function(sampler) {
+ if (defined(sampler.input) && sampler.input > accessorId) {
+ sampler.input--;
+ }
+ if (defined(sampler.output) && sampler.output > accessorId) {
+ sampler.output--;
+ }
+ });
+ });
+ };
+
+ Remove.buffer = function(gltf, bufferId) {
+ var buffers = gltf.buffers;
+
+ buffers.splice(bufferId, 1);
+
+ ForEach.bufferView(gltf, function(bufferView) {
+ if (defined(bufferView.buffer) && bufferView.buffer > bufferId) {
+ bufferView.buffer--;
+ }
+ });
+ };
+
+ Remove.bufferView = function(gltf, bufferViewId) {
+ var bufferViews = gltf.bufferViews;
+
+ bufferViews.splice(bufferViewId, 1);
+
+ ForEach.accessor(gltf, function(accessor) {
+ if (defined(accessor.bufferView) && accessor.bufferView > bufferViewId) {
+ accessor.bufferView--;
+ }
+ });
+
+ ForEach.shader(gltf, function(shader) {
+ if (defined(shader.bufferView) && shader.bufferView > bufferViewId) {
+ shader.bufferView--;
+ }
+ });
+
+ ForEach.image(gltf, function(image) {
+ if (defined(image.bufferView) && image.bufferView > bufferViewId) {
+ image.bufferView--;
+ }
+ ForEach.compressedImage(image, function(compressedImage) {
+ var compressedImageBufferView = compressedImage.bufferView;
+ if (defined(compressedImageBufferView) && compressedImageBufferView > bufferViewId) {
+ compressedImage.bufferView--;
+ }
+ });
+ });
+
+ if (hasExtension(gltf, 'KHR_draco_mesh_compression')) {
+ ForEach.mesh(gltf, function (mesh) {
+ ForEach.meshPrimitive(mesh, function (primitive) {
+ if (defined(primitive.extensions) &&
+ defined(primitive.extensions.KHR_draco_mesh_compression)) {
+ if (primitive.extensions.KHR_draco_mesh_compression.bufferView > bufferViewId) {
+ primitive.extensions.KHR_draco_mesh_compression.bufferView--;
+ }
+ }
+ });
+ });
+ }
+ };
+
+ /**
+ * Contains functions for getting a list of element ids in use by the glTF asset.
+ * @constructor
+ *
+ * @private
+ */
+ function getListOfElementsIdsInUse() {}
+
+ getListOfElementsIdsInUse.accessor = function(gltf) {
+ // Calculate accessor's that are currently in use.
+ var usedAccessorIds = {};
+
+ ForEach.mesh(gltf, function(mesh) {
+ ForEach.meshPrimitive(mesh, function(primitive) {
+ ForEach.meshPrimitiveAttribute(primitive, function(accessorId) {
+ usedAccessorIds[accessorId] = true;
+ });
+ ForEach.meshPrimitiveTarget(primitive, function(target) {
+ ForEach.meshPrimitiveTargetAttribute(target, function(accessorId) {
+ usedAccessorIds[accessorId] = true;
+ });
+ });
+ var indices = primitive.indices;
+ if (defined(indices)) {
+ usedAccessorIds[indices] = true;
+ }
+ });
+ });
+
+ ForEach.skin(gltf, function(skin) {
+ if (defined(skin.inverseBindMatrices)) {
+ usedAccessorIds[skin.inverseBindMatrices] = true;
+ }
+ });
+
+ ForEach.animation(gltf, function(animation) {
+ ForEach.animationSampler(animation, function(sampler) {
+ if (defined(sampler.input)) {
+ usedAccessorIds[sampler.input] = true;
+ }
+ if (defined(sampler.output)) {
+ usedAccessorIds[sampler.output] = true;
+ }
+ });
+ });
+
+ return usedAccessorIds;
+ };
+
+ getListOfElementsIdsInUse.buffer = function(gltf) {
+ // Calculate buffer's that are currently in use.
+ var usedBufferIds = {};
+
+ ForEach.bufferView(gltf, function(bufferView) {
+ if (defined(bufferView.buffer)) {
+ usedBufferIds[bufferView.buffer] = true;
+ }
+ });
+
+ return usedBufferIds;
+ };
+
+ getListOfElementsIdsInUse.bufferView = function(gltf) {
+ // Calculate bufferView's that are currently in use.
+ var usedBufferViewIds = {};
+
+ ForEach.accessor(gltf, function(accessor) {
+ if (defined(accessor.bufferView)) {
+ usedBufferViewIds[accessor.bufferView] = true;
+ }
+ });
+
+ ForEach.shader(gltf, function(shader) {
+ if (defined(shader.bufferView)) {
+ usedBufferViewIds[shader.bufferView] = true;
+ }
+ });
+
+ ForEach.image(gltf, function(image) {
+ if (defined(image.bufferView)) {
+ usedBufferViewIds[image.bufferView] = true;
+ }
+ ForEach.compressedImage(image, function(compressedImage) {
+ if (defined(compressedImage.bufferView)) {
+ usedBufferViewIds[compressedImage.bufferView] = true;
+ }
+ });
+ });
+
+ if (hasExtension(gltf, 'KHR_draco_mesh_compression')) {
+ ForEach.mesh(gltf, function(mesh) {
+ ForEach.meshPrimitive(mesh, function(primitive) {
+ if (defined(primitive.extensions) &&
+ defined(primitive.extensions.KHR_draco_mesh_compression)) {
+ usedBufferViewIds[primitive.extensions.KHR_draco_mesh_compression.bufferView] = true;
+ }
+ });
+ });
+ }
+
+ return usedBufferViewIds;
+ };
+
+ return removeUnusedElements;
+});
diff --git a/Source/ThirdParty/GltfPipeline/techniqueParameterForSemantic.js b/Source/ThirdParty/GltfPipeline/techniqueParameterForSemantic.js
deleted file mode 100644
index a0dc6adfe587..000000000000
--- a/Source/ThirdParty/GltfPipeline/techniqueParameterForSemantic.js
+++ /dev/null
@@ -1,29 +0,0 @@
-define([
- '../../Core/defined'
- ], function(
- defined) {
- 'use strict';
-
- /**
- * Retrieves the technique parameter that has a matching semantic.
- *
- * @param {Object} technique A javascript object containing a glTF technique.
- * @param {String} semantic The search string for semantics.
- * @returns {String} The technique parameter with matching semantic.
- *
- * @private
- */
- function techniqueParameterForSemantic(technique, semantic) {
- var parameters = technique.parameters;
- for (var parameterName in parameters) {
- if (parameters.hasOwnProperty(parameterName)) {
- var parameter = parameters[parameterName];
- var parameterSemantic = parameter.semantic;
- if (defined(parameterSemantic) && parameterSemantic === semantic) {
- return parameterName;
- }
- }
- }
- }
- return techniqueParameterForSemantic;
-});
diff --git a/Source/ThirdParty/GltfPipeline/updateVersion.js b/Source/ThirdParty/GltfPipeline/updateVersion.js
index 637af6603081..c083be681089 100644
--- a/Source/ThirdParty/GltfPipeline/updateVersion.js
+++ b/Source/ThirdParty/GltfPipeline/updateVersion.js
@@ -1,37 +1,45 @@
define([
- './addExtensionsRequired',
+ './addExtensionsUsed',
'./addToArray',
+ './findAccessorMinMax',
'./ForEach',
'./getAccessorByteStride',
'./numberOfComponentsForType',
+ './moveTechniqueRenderStates',
+ './moveTechniquesToExtension',
+ './removeUnusedElements',
'../../Core/Cartesian3',
- '../../Core/Math',
'../../Core/clone',
'../../Core/ComponentDatatype',
'../../Core/defaultValue',
'../../Core/defined',
+ '../../Core/isArray',
'../../Core/Quaternion',
'../../Core/WebGLConstants'
], function(
- addExtensionsRequired,
+ addExtensionsUsed,
addToArray,
+ findAccessorMinMax,
ForEach,
getAccessorByteStride,
numberOfComponentsForType,
+ moveTechniqueRenderStates,
+ moveTechniquesToExtension,
+ removeUnusedElements,
Cartesian3,
- CesiumMath,
clone,
ComponentDatatype,
defaultValue,
defined,
+ isArray,
Quaternion,
WebGLConstants) {
'use strict';
var updateFunctions = {
- '0.8' : glTF08to10,
- '1.0' : glTF10to20,
- '2.0' : undefined
+ '0.8': glTF08to10,
+ '1.0': glTF10to20,
+ '2.0': undefined
};
/**
@@ -43,9 +51,11 @@ define([
* @param {Object} [options] Options for updating the glTF.
* @param {String} [options.targetVersion] The glTF will be upgraded until it hits the specified version.
* @returns {Object} The updated glTF asset.
+ *
+ * @private
*/
function updateVersion(gltf, options) {
- options = defaultValue(options, {});
+ options = defaultValue(options, defaultValue.EMPTY_OBJECT);
var targetVersion = options.targetVersion;
var version = gltf.version;
@@ -53,14 +63,16 @@ define([
version: '1.0'
});
- version = defaultValue(version, gltf.asset.version);
- // invalid version
+ gltf.asset.version = defaultValue(gltf.asset.version, '1.0');
+ version = defaultValue(version, gltf.asset.version).toString();
+
+ // Invalid version
if (!updateFunctions.hasOwnProperty(version)) {
- // try truncating trailing version numbers, could be a number as well if it is 0.8
+ // Try truncating trailing version numbers, could be a number as well if it is 0.8
if (defined(version)) {
- version = ('' + version).substring(0, 3);
+ version = version.substring(0, 3);
}
- // default to 1.0 if it cannot be determined
+ // Default to 1.0 if it cannot be determined
if (!updateFunctions.hasOwnProperty(version)) {
version = '1.0';
}
@@ -72,7 +84,7 @@ define([
if (version === targetVersion) {
break;
}
- updateFunction(gltf);
+ updateFunction(gltf, options);
version = gltf.asset.version;
updateFunction = updateFunctions[version];
}
@@ -102,7 +114,7 @@ define([
var primitives = mesh.primitives;
if (defined(primitives)) {
var primitivesLength = primitives.length;
- for (var i = 0; i < primitivesLength; i++) {
+ for (var i = 0; i < primitivesLength; ++i) {
var primitive = primitives[i];
var defaultMode = defaultValue(primitive.primitive, WebGLConstants.TRIANGLES);
primitive.mode = defaultValue(primitive.mode, defaultMode);
@@ -215,11 +227,18 @@ define([
}
var asset = gltf.asset;
asset.version = '1.0';
- // profile should be an object, not a string
- if (!defined(asset.profile) || (typeof asset.profile === 'string')) {
+ // Profile should be an object, not a string
+ if (typeof asset.profile === 'string') {
+ var split = asset.profile.split(' ');
+ asset.profile = {
+ api: split[0],
+ version: split[1]
+ };
+ } else {
asset.profile = {};
}
- // version property should be in asset, not on the root element
+
+ // Version property should be in asset, not on the root element
if (defined(gltf.version)) {
delete gltf.version;
}
@@ -227,13 +246,18 @@ define([
updateInstanceTechniques(gltf);
// primitive.primitive should be primitive.mode
setPrimitiveModes(gltf);
- // node rotation should be quaternion, not axis-angle
+ // Node rotation should be quaternion, not axis-angle
// node.instanceSkin is deprecated
updateNodes(gltf);
- // animations that target rotations should be quaternion, not axis-angle
+ // Animations that target rotations should be quaternion, not axis-angle
updateAnimations(gltf);
// technique.pass and techniques.passes are deprecated
removeTechniquePasses(gltf);
+ // gltf.allExtensions -> extensionsUsed
+ if (defined(gltf.allExtensions)) {
+ gltf.extensionsUsed = gltf.allExtensions;
+ delete gltf.allExtensions;
+ }
// gltf.lights -> khrMaterialsCommon.lights
if (defined(gltf.lights)) {
var extensions = defaultValue(gltf.extensions, {});
@@ -242,11 +266,7 @@ define([
extensions.KHR_materials_common = materialsCommon;
materialsCommon.lights = gltf.lights;
delete gltf.lights;
- }
- // gltf.allExtensions -> extensionsUsed
- if (defined(gltf.allExtensions)) {
- gltf.extensionsUsed = gltf.allExtensions;
- gltf.allExtensions = undefined;
+ addExtensionsUsed(gltf, 'KHR_materials_common');
}
}
@@ -278,7 +298,7 @@ define([
var value = object[id];
mapping[id] = array.length;
array.push(value);
- if (!defined(value.name) && typeof(value) === 'object') {
+ if (!defined(value.name)) {
value.name = id;
}
}
@@ -291,15 +311,19 @@ define([
var globalMapping = {
accessors: {},
animations: {},
- bufferViews: {},
buffers: {},
+ bufferViews: {},
cameras: {},
+ images: {},
materials: {},
meshes: {},
nodes: {},
programs: {},
+ samplers: {},
+ scenes: {},
shaders: {},
skins: {},
+ textures: {},
techniques: {}
};
@@ -318,18 +342,11 @@ define([
// Convert top level objects to arrays
for (var topLevelId in gltf) {
- if (gltf.hasOwnProperty(topLevelId) && topLevelId !== 'extras' && topLevelId !== 'asset' && topLevelId !== 'extensions') {
+ if (gltf.hasOwnProperty(topLevelId) && defined(globalMapping[topLevelId])) {
var objectMapping = {};
var object = gltf[topLevelId];
- if (typeof(object) === 'object' && !Array.isArray(object)) {
- gltf[topLevelId] = objectToArray(object, objectMapping);
- globalMapping[topLevelId] = objectMapping;
- if (topLevelId === 'animations') {
- objectMapping = {};
- object.samplers = objectToArray(object.samplers, objectMapping);
- globalMapping[topLevelId].samplers = objectMapping;
- }
- }
+ gltf[topLevelId] = objectToArray(object, objectMapping);
+ globalMapping[topLevelId] = objectMapping;
}
}
@@ -384,18 +401,10 @@ define([
parameter.node = globalMapping.nodes[parameter.node];
}
var value = parameter.value;
- if (defined(value)) {
- if (Array.isArray(value)) {
- if (value.length === 1) {
- var textureId = value[0];
- if (typeof textureId === 'string') {
- value[0] = globalMapping.textures[textureId];
- }
- }
- }
- else if (typeof value === 'string') {
- parameter.value = [globalMapping.textures[value]];
- }
+ if (typeof value === 'string') {
+ parameter.value = {
+ index: globalMapping.textures[value]
+ };
}
});
});
@@ -416,7 +425,7 @@ define([
var children = node.children;
if (defined(children)) {
var childrenLength = children.length;
- for (i = 0; i < childrenLength; i++) {
+ for (i = 0; i < childrenLength; ++i) {
children[i] = globalMapping.nodes[children[i]];
}
}
@@ -426,12 +435,9 @@ define([
var meshesLength = meshes.length;
if (meshesLength > 0) {
node.mesh = globalMapping.meshes[meshes[0]];
- for (i = 1; i < meshesLength; i++) {
+ for (i = 1; i < meshesLength; ++i) {
var meshNode = {
- mesh: globalMapping.meshes[meshes[i]],
- extras: {
- _pipeline: {}
- }
+ mesh: globalMapping.meshes[meshes[i]]
};
var meshNodeId = addToArray(gltf.nodes, meshNode);
if (!defined(children)) {
@@ -446,31 +452,32 @@ define([
if (defined(node.camera)) {
node.camera = globalMapping.cameras[node.camera];
}
+ if (defined(node.skin)) {
+ node.skin = globalMapping.skins[node.skin];
+ }
if (defined(node.skeletons)) {
// Assign skeletons to skins
var skeletons = node.skeletons;
var skeletonsLength = skeletons.length;
if ((skeletonsLength > 0) && defined(node.skin)) {
- var skin = gltf.skins[globalMapping.skins[node.skin]];
+ var skin = gltf.skins[node.skin];
skin.skeleton = globalMapping.nodes[skeletons[0]];
}
delete node.skeletons;
}
- if (defined(node.skin)) {
- node.skin = globalMapping.skins[node.skin];
- }
if (defined(node.jointName)) {
- delete(node.jointName);
+ delete node.jointName;
}
});
ForEach.skin(gltf, function(skin) {
if (defined(skin.inverseBindMatrices)) {
skin.inverseBindMatrices = globalMapping.accessors[skin.inverseBindMatrices];
}
- var joints = [];
var jointNames = skin.jointNames;
if (defined(jointNames)) {
- for (i = 0; i < jointNames.length; i++) {
+ var joints = [];
+ var jointNamesLength = jointNames.length;
+ for (i = 0; i < jointNamesLength; ++i) {
joints[i] = jointNameToId[jointNames[i]];
}
skin.joints = joints;
@@ -481,7 +488,7 @@ define([
var sceneNodes = scene.nodes;
if (defined(sceneNodes)) {
var sceneNodesLength = sceneNodes.length;
- for (i = 0; i < sceneNodesLength; i++) {
+ for (i = 0; i < sceneNodesLength; ++i) {
sceneNodes[i] = globalMapping.nodes[sceneNodes[i]];
}
}
@@ -493,36 +500,23 @@ define([
sampler.input = globalMapping.accessors[sampler.input];
sampler.output = globalMapping.accessors[sampler.output];
});
- var channels = animation.channels;
- if (defined(channels)) {
- var channelsLength = channels.length;
- for (i = 0; i < channelsLength; i++) {
- var channel = channels[i];
- channel.sampler = samplerMapping[channel.sampler];
- var target = channel.target;
- if (defined(target)) {
- target.node = globalMapping.nodes[target.id];
- delete target.id;
- }
+ ForEach.animationChannel(animation, function(channel) {
+ channel.sampler = samplerMapping[channel.sampler];
+ var target = channel.target;
+ if (defined(target)) {
+ target.node = globalMapping.nodes[target.id];
+ delete target.id;
}
- }
+ });
});
ForEach.material(gltf, function(material) {
if (defined(material.technique)) {
material.technique = globalMapping.techniques[material.technique];
}
ForEach.materialValue(material, function(value, name) {
- if (Array.isArray(value)) {
- if (value.length === 1) {
- var textureId = value[0];
- if (typeof textureId === 'string') {
- value[0] = globalMapping.textures[textureId];
- }
- }
- }
- else if (typeof value === 'string') {
+ if (typeof value === 'string') {
material.values[name] = {
- index : globalMapping.textures[value]
+ index: globalMapping.textures[value]
};
}
});
@@ -531,15 +525,7 @@ define([
var materialsCommon = extensions.KHR_materials_common;
if (defined(materialsCommon)) {
ForEach.materialValue(materialsCommon, function(value, name) {
- if (Array.isArray(value)) {
- if (value.length === 1) {
- var textureId = value[0];
- if (typeof textureId === 'string') {
- value[0] = globalMapping.textures[textureId];
- }
- }
- }
- else if (typeof value === 'string') {
+ if (typeof value === 'string') {
materialsCommon.values[name] = {
index: globalMapping.textures[value]
};
@@ -561,26 +547,20 @@ define([
delete image.extensions;
}
}
- if (defined(image.extras)) {
- var compressedImages = image.extras.compressedImage3DTiles;
- for (var type in compressedImages) {
- if (compressedImages.hasOwnProperty(type)) {
- var compressedImage = compressedImages[type];
- var compressedExtensions = compressedImage.extensions;
- if (defined(compressedExtensions)) {
- var compressedBinaryGltf = compressedExtensions.KHR_binary_glTF;
- if (defined(compressedBinaryGltf)) {
- compressedImage.bufferView = globalMapping.bufferViews[compressedBinaryGltf.bufferView];
- compressedImage.mimeType = compressedBinaryGltf.mimeType;
- delete compressedExtensions.KHR_binary_glTF;
- }
- if (Object.keys(compressedExtensions).length === 0) {
- delete compressedImage.extensions;
- }
- }
+ ForEach.compressedImage(image, function(compressedImage) {
+ var compressedExtensions = compressedImage.extensions;
+ if (defined(compressedExtensions)) {
+ var compressedBinaryGltf = compressedExtensions.KHR_binary_glTF;
+ if (defined(compressedBinaryGltf)) {
+ compressedImage.bufferView = globalMapping.bufferViews[compressedBinaryGltf.bufferView];
+ compressedImage.mimeType = compressedBinaryGltf.mimeType;
+ delete compressedExtensions.KHR_binary_glTF;
+ }
+ if (Object.keys(extensions).length === 0) {
+ delete compressedImage.extensions;
}
}
- }
+ });
});
ForEach.texture(gltf, function(texture) {
if (defined(texture.sampler)) {
@@ -592,22 +572,39 @@ define([
});
}
- function stripProfile(gltf) {
+ function removeEmptyArrays(gltf) {
+ for (var topLevelId in gltf) {
+ if (gltf.hasOwnProperty(topLevelId)) {
+ var array = gltf[topLevelId];
+ if (isArray(array) && array.length === 0) {
+ delete gltf[topLevelId];
+ }
+ }
+ }
+ ForEach.node(gltf, function(node) {
+ if (defined(node.children) && node.children.length === 0) {
+ delete node.children;
+ }
+ });
+ }
+
+ function stripAsset(gltf) {
var asset = gltf.asset;
delete asset.profile;
+ delete asset.premultipliedAlpha;
}
var knownExtensions = {
- CESIUM_RTC : true,
- KHR_materials_common : true,
- WEB3D_quantized_attributes : true
+ CESIUM_RTC: true,
+ KHR_materials_common: true,
+ WEB3D_quantized_attributes: true
};
function requireKnownExtensions(gltf) {
var extensionsUsed = gltf.extensionsUsed;
gltf.extensionsRequired = defaultValue(gltf.extensionsRequired, []);
if (defined(extensionsUsed)) {
var extensionsUsedLength = extensionsUsed.length;
- for (var i = 0; i < extensionsUsedLength; i++) {
+ for (var i = 0; i < extensionsUsedLength; ++i) {
var extension = extensionsUsed[i];
if (defined(knownExtensions[extension])) {
gltf.extensionsRequired.push(extension);
@@ -622,6 +619,15 @@ define([
});
}
+ function removeTextureProperties(gltf) {
+ ForEach.texture(gltf, function(texture) {
+ delete texture.format;
+ delete texture.internalFormat;
+ delete texture.target;
+ delete texture.type;
+ });
+ }
+
function requireAttributeSetIndex(gltf) {
ForEach.mesh(gltf, function(mesh) {
ForEach.meshPrimitive(mesh, function(primitive) {
@@ -653,25 +659,37 @@ define([
var knownSemantics = {
POSITION: true,
NORMAL: true,
- TEXCOORD: true,
- COLOR: true,
- JOINT: true,
- WEIGHT: true
+ TANGENT: true
+ };
+ var indexedSemantics = {
+ COLOR: 'COLOR',
+ JOINT : 'JOINTS',
+ JOINTS: 'JOINTS',
+ TEXCOORD: 'TEXCOORD',
+ WEIGHT: 'WEIGHTS',
+ WEIGHTS: 'WEIGHTS'
};
function underscoreApplicationSpecificSemantics(gltf) {
var mappedSemantics = {};
ForEach.mesh(gltf, function(mesh) {
ForEach.meshPrimitive(mesh, function(primitive) {
- /* jshint unused:vars */
+ /*eslint-disable no-unused-vars*/
ForEach.meshPrimitiveAttribute(primitive, function(accessorId, semantic) {
if (semantic.charAt(0) !== '_') {
var setIndex = semantic.search(/_[0-9]+/g);
var strippedSemantic = semantic;
+ var suffix = '_0';
if (setIndex >= 0) {
strippedSemantic = semantic.substring(0, setIndex);
+ suffix = semantic.substring(setIndex);
}
- if (!defined(knownSemantics[strippedSemantic])) {
- var newSemantic = '_' + semantic;
+ var newSemantic;
+ var indexedSemantic = indexedSemantics[strippedSemantic];
+ if (defined(indexedSemantic)) {
+ newSemantic = indexedSemantic + suffix;
+ mappedSemantics[semantic] = newSemantic;
+ } else if (!defined(knownSemantics[strippedSemantic])) {
+ newSemantic = '_' + semantic;
mappedSemantics[semantic] = newSemantic;
}
}
@@ -698,47 +716,6 @@ define([
});
}
- function removeScissorFromTechniques(gltf) {
- ForEach.technique(gltf, function(technique) {
- var techniqueStates = technique.states;
- if (defined(techniqueStates)) {
- var techniqueFunctions = techniqueStates.functions;
- if (defined(techniqueFunctions)) {
- delete techniqueFunctions.scissor;
- }
- var enableStates = techniqueStates.enable;
- if (defined(enableStates)) {
- var scissorIndex = enableStates.indexOf(WebGLConstants.SCISSOR_TEST);
- if (scissorIndex >= 0) {
- enableStates.splice(scissorIndex, 1);
- }
- }
- }
- });
- }
-
- function clampTechniqueFunctionStates(gltf) {
- ForEach.technique(gltf, function(technique) {
- var techniqueStates = technique.states;
- if (defined(techniqueStates)) {
- var functions = techniqueStates.functions;
- if (defined(functions)) {
- var blendColor = functions.blendColor;
- if (defined(blendColor)) {
- for (var i = 0; i < 4; i++) {
- blendColor[i] = CesiumMath.clamp(blendColor[i], 0.0, 1.0);
- }
- }
- var depthRange = functions.depthRange;
- if (defined(depthRange)) {
- depthRange[1] = CesiumMath.clamp(depthRange[1], 0.0, 1.0);
- depthRange[0] = CesiumMath.clamp(depthRange[0], 0.0, depthRange[1]);
- }
- }
- }
- });
- }
-
function clampCameraParameters(gltf) {
ForEach.camera(gltf, function(camera) {
var perspective = camera.perspective;
@@ -755,172 +732,140 @@ define([
});
}
+ function computeAccessorByteStride(gltf, accessor) {
+ return (defined(accessor.byteStride) && accessor.byteStride !== 0) ? accessor.byteStride : getAccessorByteStride(gltf, accessor);
+ }
+
function requireByteLength(gltf) {
ForEach.buffer(gltf, function(buffer) {
if (!defined(buffer.byteLength)) {
buffer.byteLength = buffer.extras._pipeline.source.length;
}
});
- ForEach.bufferView(gltf, function(bufferView) {
- if (!defined(bufferView.byteLength)) {
- var bufferViewBufferId = bufferView.buffer;
- var bufferViewBuffer = gltf.buffers[bufferViewBufferId];
- bufferView.byteLength = bufferViewBuffer.byteLength;
+ ForEach.accessor(gltf, function(accessor) {
+ var bufferViewId = accessor.bufferView;
+ if (defined(bufferViewId)) {
+ var bufferView = gltf.bufferViews[bufferViewId];
+ var accessorByteStride = computeAccessorByteStride(gltf, accessor);
+ var accessorByteEnd = accessor.byteOffset + accessor.count * accessorByteStride;
+ bufferView.byteLength = Math.max(defaultValue(bufferView.byteLength, 0), accessorByteEnd);
}
});
}
function moveByteStrideToBufferView(gltf) {
+ var i;
+ var j;
+ var bufferView;
var bufferViews = gltf.bufferViews;
- var bufferViewsToDelete = {};
- ForEach.accessor(gltf, function(accessor) {
- var oldBufferViewId = accessor.bufferView;
- if (defined(oldBufferViewId)) {
- if (!defined(bufferViewsToDelete[oldBufferViewId])) {
- bufferViewsToDelete[oldBufferViewId] = true;
- }
- var bufferView = clone(bufferViews[oldBufferViewId]);
- var accessorByteStride = (defined(accessor.byteStride) && accessor.byteStride !== 0) ? accessor.byteStride : getAccessorByteStride(gltf, accessor);
- if (defined(accessorByteStride)) {
- bufferView.byteStride = accessorByteStride;
- if (bufferView.byteStride !== 0) {
- bufferView.byteLength = accessor.count * accessorByteStride;
- }
- bufferView.byteOffset += accessor.byteOffset;
- accessor.byteOffset = 0;
- delete accessor.byteStride;
- }
- accessor.bufferView = addToArray(bufferViews, bufferView);
- }
- });
- var bufferViewShiftMap = {};
- var bufferViewRemovalCount = 0;
- /* jshint unused:vars */
- ForEach.bufferView(gltf, function(bufferView, bufferViewId) {
- if (defined(bufferViewsToDelete[bufferViewId])) {
- bufferViewRemovalCount++;
- } else {
- bufferViewShiftMap[bufferViewId] = bufferViewId - bufferViewRemovalCount;
+ var bufferViewHasVertexAttributes = {};
+ ForEach.accessorContainingVertexAttributeData(gltf, function(accessorId) {
+ var accessor = gltf.accessors[accessorId];
+ if (defined(accessor.bufferView)) {
+ bufferViewHasVertexAttributes[accessor.bufferView] = true;
}
});
- var removedCount = 0;
- for (var bufferViewId in bufferViewsToDelete) {
- if (defined(bufferViewId)) {
- var index = parseInt(bufferViewId) - removedCount;
- bufferViews.splice(index, 1);
- removedCount++;
- }
- }
-
+ // Map buffer views to a list of accessors
+ var bufferViewMap = {};
ForEach.accessor(gltf, function(accessor) {
- var accessorBufferView = accessor.bufferView;
- if (defined(accessorBufferView)) {
- accessor.bufferView = bufferViewShiftMap[accessorBufferView];
+ if (defined(accessor.bufferView)) {
+ bufferViewMap[accessor.bufferView] = defaultValue(bufferViewMap[accessor.bufferView], []);
+ bufferViewMap[accessor.bufferView].push(accessor);
}
});
- ForEach.shader(gltf, function(shader) {
- var shaderBufferView = shader.bufferView;
- if (defined(shaderBufferView)) {
- shader.bufferView = bufferViewShiftMap[shaderBufferView];
- }
- });
+ // Split accessors with different byte strides
+ for (var bufferViewId in bufferViewMap) {
+ if (bufferViewMap.hasOwnProperty(bufferViewId)) {
+ bufferView = bufferViews[bufferViewId];
+ var accessors = bufferViewMap[bufferViewId];
+ accessors.sort(function(a, b) {
+ return a.byteOffset - b.byteOffset;
+ });
+ var currentByteOffset = 0;
+ var currentIndex = 0;
+ var accessorsLength = accessors.length;
+ for (i = 0; i < accessorsLength; ++i) {
+ var accessor = accessors[i];
+ var accessorByteStride = computeAccessorByteStride(gltf, accessor);
+ var accessorByteOffset = accessor.byteOffset;
+ var accessorByteLength = accessor.count * accessorByteStride;
+ delete accessor.byteStride;
- ForEach.image(gltf, function(image) {
- var imageBufferView = image.bufferView;
- if (defined(imageBufferView)) {
- image.bufferView = bufferViewShiftMap[imageBufferView];
- }
- if (defined(image.extras)) {
- var compressedImages = image.extras.compressedImage3DTiles;
- for (var type in compressedImages) {
- if (compressedImages.hasOwnProperty(type)) {
- var compressedImage = compressedImages[type];
- var compressedImageBufferView = compressedImage.bufferView;
- if (defined(compressedImageBufferView)) {
- compressedImage.bufferView = bufferViewShiftMap[compressedImageBufferView];
+ var nextAccessorByteStride = (i < accessorsLength - 1) ? computeAccessorByteStride(gltf, accessors[i + 1]) : undefined;
+ if (accessorByteStride !== nextAccessorByteStride) {
+ var newBufferView = clone(bufferView, true);
+ if (bufferViewHasVertexAttributes[bufferViewId]) {
+ newBufferView.byteStride = accessorByteStride;
}
+ newBufferView.byteOffset += currentByteOffset;
+ newBufferView.byteLength = accessorByteOffset + accessorByteLength - currentByteOffset;
+ var newBufferViewId = addToArray(bufferViews, newBufferView);
+ for (j = currentIndex; j <= i; ++j) {
+ accessor = accessors[j];
+ accessor.bufferView = newBufferViewId;
+ accessor.byteOffset = accessor.byteOffset - currentByteOffset;
+ }
+ currentByteOffset = accessorByteOffset + accessorByteLength;
+ currentIndex = i + 1;
}
}
}
- });
- }
+ }
- function stripTechniqueAttributeValues(gltf) {
- ForEach.technique(gltf, function(technique) {
- ForEach.techniqueAttribute(technique, function(attribute) {
- var parameter = technique.parameters[attribute];
- if (defined(parameter.value)) {
- delete parameter.value;
- }
- });
- });
+ // Remove unused buffer views
+ removeUnusedElements(gltf);
}
- function stripTechniqueParameterCount(gltf) {
- ForEach.technique(gltf, function(technique) {
- ForEach.techniqueParameter(technique, function(parameter) {
- if (defined(parameter.count)) {
- var semantic = parameter.semantic;
- if (!defined(semantic) || (semantic !== 'JOINTMATRIX' && semantic.indexOf('_') !== 0)) {
- delete parameter.count;
- }
- }
- });
+ function requirePositionAccessorMinMax(gltf) {
+ ForEach.accessorWithSemantic(gltf, 'POSITION', function(accessorId) {
+ var accessor = gltf.accessors[accessorId];
+ if (!defined(accessor.min) || !defined(accessor.max)) {
+ var minMax = findAccessorMinMax(gltf, accessor);
+ accessor.min = minMax.min;
+ accessor.max = minMax.max;
+ }
});
}
- function addKHRTechniqueExtension(gltf) {
- var techniques = gltf.techniques;
- if (defined(techniques) && techniques.length > 0) {
- addExtensionsRequired(gltf, 'KHR_technique_webgl');
- }
- }
-
function glTF10to20(gltf) {
- if (!defined(gltf.asset)) {
- gltf.asset = {};
- }
- if (!defined(gltf.asset.extras)) {
- gltf.asset.extras = {};
- }
- var asset = gltf.asset;
- asset.version = '2.0';
- asset.extras.gltf_pipeline_upgrade_10to20 = true;
+ gltf.asset = defaultValue(gltf.asset, {});
+ gltf.asset.version = '2.0';
// material.instanceTechnique properties should be directly on the material. instanceTechnique is a gltf 0.8 property but is seen in some 1.0 models.
updateInstanceTechniques(gltf);
// animation.samplers now refers directly to accessors and animation.parameters should be removed
removeAnimationSamplersIndirection(gltf);
- // top-level objects are now arrays referenced by index instead of id
+ // Top-level objects are now arrays referenced by index instead of id
objectsToArrays(gltf);
// asset.profile no longer exists
- stripProfile(gltf);
- // move known extensions from extensionsUsed to extensionsRequired
+ stripAsset(gltf);
+ // Move known extensions from extensionsUsed to extensionsRequired
requireKnownExtensions(gltf);
// bufferView.byteLength and buffer.byteLength are required
requireByteLength(gltf);
// byteStride moved from accessor to bufferView
moveByteStrideToBufferView(gltf);
+ // accessor.min and accessor.max must be defined for accessors containing POSITION attributes
+ requirePositionAccessorMinMax(gltf);
// buffer.type is unnecessary and should be removed
removeBufferType(gltf);
+ // Remove format, internalFormat, target, and type
+ removeTextureProperties(gltf);
// TEXCOORD and COLOR attributes must be written with a set index (TEXCOORD_#)
requireAttributeSetIndex(gltf);
// Add underscores to application-specific parameters
underscoreApplicationSpecificSemantics(gltf);
- // remove scissor from techniques
- removeScissorFromTechniques(gltf);
- // clamp technique function states to min/max
- clampTechniqueFunctionStates(gltf);
- // clamp camera parameters
+ // Clamp camera parameters
clampCameraParameters(gltf);
- // a technique parameter specified as an attribute cannot have a value
- stripTechniqueAttributeValues(gltf);
- // only techniques with a JOINTMATRIX or application specific semantic may have a defined count property
- stripTechniqueParameterCount(gltf);
- // add KHR_technique_webgl extension
- addKHRTechniqueExtension(gltf);
+ // Move legacy technique render states to material properties and add KHR_blend extension blending functions
+ moveTechniqueRenderStates(gltf);
+ // Add material techniques to KHR_techniques_webgl extension, removing shaders, programs, and techniques
+ moveTechniquesToExtension(gltf);
+ // Remove empty arrays
+ removeEmptyArrays(gltf);
}
+
return updateVersion;
});
From 9d907df8e65e75cc85eee2b50789057006910369 Mon Sep 17 00:00:00 2001
From: ggetz
Date: Mon, 16 Jul 2018 17:08:03 -0400
Subject: [PATCH 02/52] Cleanup
---
Source/Scene/ClassificationModel.js | 2 +-
Source/Scene/Model.js | 17 ++++++++---------
2 files changed, 9 insertions(+), 10 deletions(-)
diff --git a/Source/Scene/ClassificationModel.js b/Source/Scene/ClassificationModel.js
index e628df0e348e..3f2fb412a199 100644
--- a/Source/Scene/ClassificationModel.js
+++ b/Source/Scene/ClassificationModel.js
@@ -133,7 +133,7 @@ define([
var gltfMeshes = gltf.meshes;
var gltfNode = gltfNodes.rootNode;
- if (!defined(gltfNode)) {
+ if (!defined(gltfNode) || !defined(gltfNode.meshes)) {
throw new RuntimeError('Only one node is supported for classification and it must have a mesh.');
}
diff --git a/Source/Scene/Model.js b/Source/Scene/Model.js
index 63bd0356e635..71982b8d930d 100644
--- a/Source/Scene/Model.js
+++ b/Source/Scene/Model.js
@@ -2342,9 +2342,10 @@ define([
if (!defined(material)) {
return attributeLocations;
}
+
var technique = techniques[material._technique];
if (!defined(technique)) {
- return;
+ return attributeLocations;
}
var attributes = technique.attributes;
@@ -2920,8 +2921,8 @@ define([
});
return {
- map : uniformMap, // uniform name -> function for the renderer
- values : uniformValues, // material parameter name -> ModelMaterial for modifying the parameter at runtime
+ map : uniformMap,
+ values : uniformValues,
jointMatrixUniformName : jointMatrixUniformName,
morphWeightsUniformName : morphWeightsUniformName
};
@@ -3377,10 +3378,10 @@ define([
var program = programs[programId];
var shader = shaders[program.vertexShader].extras._pipeline.source;
if (model.extensionsUsed.WEB3D_quantized_attributes || model._dequantizeInShader) {
- var quantizedVS = quantizedVertexShaders[programId];
+ var quantizedVS = quantizedVertexShaders[programId];
if (!defined(quantizedVS)) {
- quantizedVS = modifyShaderForQuantizedAttributes(shader, programId, model);
- quantizedVertexShaders[programId] = quantizedVS;
+ quantizedVS = modifyShaderForQuantizedAttributes(shader, programId, model);
+ quantizedVertexShaders[programId] = quantizedVS;
}
shader = quantizedVS;
}
@@ -4263,13 +4264,11 @@ define([
// glTF pipeline updates
addPipelineExtras(this.gltf);
-
updateVersion(this.gltf);
if (defined(this.gltf.asset) && defined(this.gltf.asset.extras) &&
- this.gltf.asset.extras.gltf_pipeline_upgrade_10to20) {
+ this.gltf.asset.extras.gltf_pipeline_upgrade_10to20) {
this._forwardAxis = Axis.X;
}
-
addDefaults(this.gltf);
var options = {
From e82b4b6291db5472ed9fd589b72c36f1c76c2815 Mon Sep 17 00:00:00 2001
From: Sean Lilley
Date: Thu, 19 Jul 2018 18:30:21 -0400
Subject: [PATCH 03/52] Doc edits
---
Source/Scene/Model.js | 8 ++++----
Source/Scene/ModelMaterial.js | 12 +++---------
Source/Scene/ModelMesh.js | 10 ++--------
Source/Scene/ModelNode.js | 10 ++--------
4 files changed, 11 insertions(+), 29 deletions(-)
diff --git a/Source/Scene/Model.js b/Source/Scene/Model.js
index 71982b8d930d..28b152a59a2c 100644
--- a/Source/Scene/Model.js
+++ b/Source/Scene/Model.js
@@ -603,12 +603,12 @@ define([
this._runtime = {
animations : undefined,
rootNodes : undefined,
- nodes : undefined, // Indexed with the node property's name, i.e., glTF id
+ nodes : undefined, // Indexed with the node's index
nodesByName : undefined, // Indexed with name property in the node
skinnedNodes : undefined,
meshesByName : undefined, // Indexed with the name property in the mesh
materialsByName : undefined, // Indexed with the name property in the material
- materialsById : undefined // Indexed with the material's property name
+ materialsById : undefined // Indexed with the material's index
};
this._uniformMaps = {}; // Not cached since it can be targeted by glTF animation
@@ -1547,8 +1547,8 @@ define([
if (!defined(sourcePrograms[programId])) {
sourcePrograms[programId] = clone(programs[programId]);
model._loadResources.programsToCreate.enqueue({
- id: programId,
- technique: techniqueId
+ id : programId,
+ technique : techniqueId
});
}
});
diff --git a/Source/Scene/ModelMaterial.js b/Source/Scene/ModelMaterial.js
index 5726a532ef14..bebec280cfe3 100644
--- a/Source/Scene/ModelMaterial.js
+++ b/Source/Scene/ModelMaterial.js
@@ -34,10 +34,7 @@ define([
defineProperties(ModelMaterial.prototype, {
/**
- * The value of the name
property of this material. This is the
- * name assigned by the artist when the asset is created. This can be
- * different than the name of the material property ({@link ModelMaterial#id}),
- * which is internal to glTF.
+ * The value of the name
property of this material.
*
* @memberof ModelMaterial.prototype
*
@@ -51,10 +48,7 @@ define([
},
/**
- * The name of the glTF JSON property for this material. This is guaranteed
- * to be unique among all materials. It may not match the material's
- * name
property (@link ModelMaterial#name), which is assigned by
- * the artist when the asset is created.
+ * The index of the material.
*
* @memberof ModelMaterial.prototype
*
@@ -80,7 +74,7 @@ define([
*
* @example
* material.setValue('diffuse', new Cesium.Cartesian4(1.0, 0.0, 0.0, 1.0)); // vec4
- * material.setValue('shininess', 256.0); // scalar
+ * material.setValue('shininess', 256.0); // scalar
*/
ModelMaterial.prototype.setValue = function(name, value) {
//>>includeStart('debug', pragmas.debug);
diff --git a/Source/Scene/ModelMesh.js b/Source/Scene/ModelMesh.js
index 6b1363d3b83f..0acb1c546f64 100644
--- a/Source/Scene/ModelMesh.js
+++ b/Source/Scene/ModelMesh.js
@@ -31,10 +31,7 @@ define([
defineProperties(ModelMesh.prototype, {
/**
- * The value of the name
property of this mesh. This is the
- * name assigned by the artist when the asset is created. This can be
- * different than the name of the mesh property ({@link ModelMesh#id}),
- * which is internal to glTF.
+ * The value of the name
property of this mesh.
*
* @memberof ModelMesh.prototype
*
@@ -48,10 +45,7 @@ define([
},
/**
- * The name of the glTF JSON property for this mesh. This is guaranteed
- * to be unique among all meshes. It may not match the mesh's
- * name
property (@link ModelMesh#name), which is assigned by
- * the artist when the asset is created.
+ * The index of the mesh.
*
* @memberof ModelMesh.prototype
*
diff --git a/Source/Scene/ModelNode.js b/Source/Scene/ModelNode.js
index 619093d16196..051380ee4caf 100644
--- a/Source/Scene/ModelNode.js
+++ b/Source/Scene/ModelNode.js
@@ -42,10 +42,7 @@ define([
defineProperties(ModelNode.prototype, {
/**
- * The value of the name
property of this node. This is the
- * name assigned by the artist when the asset is created. This can be
- * different than the name of the node property ({@link ModelNode#id}),
- * which is internal to glTF.
+ * The value of the name
property of this node.
*
* @memberof ModelNode.prototype
*
@@ -59,10 +56,7 @@ define([
},
/**
- * The name of the glTF JSON property for this node. This is guaranteed
- * to be unique among all nodes. It may not match the node's
- * name
property (@link ModelNode#name), which is assigned by
- * the artist when the asset is created.
+ * The index of the node.
*
* @memberof ModelNode.prototype
*
From 395eb34ae79a540e00cccc9c22b8e30b5ebec4c0 Mon Sep 17 00:00:00 2001
From: Sean Lilley
Date: Mon, 23 Jul 2018 17:48:08 -0400
Subject: [PATCH 04/52] Minor cleanup
---
Source/Scene/Model.js | 2 +-
Source/Scene/ModelUtility.js | 2 +-
Source/Scene/processModelMaterialsCommon.js | 3 +--
Source/Scene/processPbrMetallicRoughness.js | 3 +--
4 files changed, 4 insertions(+), 6 deletions(-)
diff --git a/Source/Scene/Model.js b/Source/Scene/Model.js
index 28b152a59a2c..ae8dbc71f255 100644
--- a/Source/Scene/Model.js
+++ b/Source/Scene/Model.js
@@ -2194,7 +2194,7 @@ define([
}
}
- function createSamplers(model, context) {
+ function createSamplers(model) {
var loadResources = model._loadResources;
if (loadResources.createSamplers) {
diff --git a/Source/Scene/ModelUtility.js b/Source/Scene/ModelUtility.js
index d1cdd8cb83c4..d288f7e3e329 100644
--- a/Source/Scene/ModelUtility.js
+++ b/Source/Scene/ModelUtility.js
@@ -391,7 +391,7 @@ define([
'KHR_binary_glTF' : true,
'KHR_draco_mesh_compression' : true,
'KHR_materials_common' : true,
- 'KHR_techniques_webgl': true,
+ 'KHR_techniques_webgl' : true,
'WEB3D_quantized_attributes' : true
};
diff --git a/Source/Scene/processModelMaterialsCommon.js b/Source/Scene/processModelMaterialsCommon.js
index c8fd54254680..7a1a5cbcfb7c 100644
--- a/Source/Scene/processModelMaterialsCommon.js
+++ b/Source/Scene/processModelMaterialsCommon.js
@@ -17,8 +17,7 @@ define([
addToArray,
ForEach,
hasExtension,
- numberOfComponentsForType
- ) {
+ numberOfComponentsForType) {
'use strict';
/**
diff --git a/Source/Scene/processPbrMetallicRoughness.js b/Source/Scene/processPbrMetallicRoughness.js
index 17458246ab48..8facade5626a 100644
--- a/Source/Scene/processPbrMetallicRoughness.js
+++ b/Source/Scene/processPbrMetallicRoughness.js
@@ -17,8 +17,7 @@ define([
addToArray,
ForEach,
hasExtension,
- numberOfComponentsForType
-) {
+ numberOfComponentsForType) {
'use strict';
/**
From 173f4b5df5d9f4b030b925ef3400532a519c47d1 Mon Sep 17 00:00:00 2001
From: ggetz
Date: Wed, 25 Jul 2018 16:26:53 -0400
Subject: [PATCH 05/52] Cleanup model with new gltf-pipeline
---
Source/Scene/Model.js | 359 ++++++++++++++++--------------------------
1 file changed, 135 insertions(+), 224 deletions(-)
diff --git a/Source/Scene/Model.js b/Source/Scene/Model.js
index ae8dbc71f255..0536b0288e62 100644
--- a/Source/Scene/Model.js
+++ b/Source/Scene/Model.js
@@ -232,8 +232,6 @@ define([
* Cesium supports glTF assets with the following extensions:
*
* -
- * {@link https://github.com/KhronosGroup/glTF/blob/master/extensions/1.0/Khronos/KHR_binary_glTF/README.md|KHR_binary_glTF}
- *
-
* {@link https://github.com/KhronosGroup/glTF/blob/master/extensions/1.0/Khronos/KHR_materials_common/README.md|KHR_materials_common}
*
-
* {@link https://github.com/KhronosGroup/glTF/blob/master/extensions/1.0/Vendor/WEB3D_quantized_attributes/README.md|WEB3D_quantized_attributes}
@@ -256,7 +254,7 @@ define([
* @constructor
*
* @param {Object} [options] Object with the following properties:
- * @param {Object|ArrayBuffer|Uint8Array} [options.gltf] The object for the glTF JSON or an arraybuffer of Binary glTF defined by the KHR_binary_glTF extension.
+ * @param {Object|ArrayBuffer|Uint8Array} [options.gltf] A glTF JSON object, or a binary glTF buffer.
* @param {Resource|String} [options.basePath=''] The base path that paths in the glTF JSON are relative to.
* @param {Boolean} [options.show=true] Determines if the model primitive will be shown.
* @param {Matrix4} [options.modelMatrix=Matrix4.IDENTITY] The 4x4 transformation matrix that transforms the model from model to world coordinates.
@@ -282,9 +280,6 @@ define([
* @param {ClippingPlaneCollection} [options.clippingPlanes] The {@link ClippingPlaneCollection} used to selectively disable rendering the model.
* @param {Boolean} [options.dequantizeInShader=true] Determines if a {@link https://github.com/google/draco|Draco} encoded model is dequantized on the GPU. This decreases total memory usage for encoded models.
*
- * @exception {DeveloperError} bgltf is not a valid Binary glTF file.
- * @exception {DeveloperError} Only glTF Binary version 1 is supported.
- *
* @see Model.fromGltf
*
* @demo {@link https://cesiumjs.org/Cesium/Apps/Sandcastle/index.html?src=3D%20Models.html|Cesium Sandcastle Models Demo}
@@ -503,7 +498,6 @@ define([
this.color = defaultValue(options.color, Color.WHITE);
this._color = new Color();
this._colorPreviousAlpha = 1.0;
- this._hasPremultipliedAlpha = false;
/**
* Defines how the color blends with the model.
@@ -1103,15 +1097,12 @@ define([
* and shader files are downloaded and the WebGL resources are created, the {@link Model#readyPromise} is resolved.
*
*
- * The model can be a traditional glTF asset with a .gltf extension or a Binary glTF using the
- * KHR_binary_glTF extension with a .glb extension.
+ * The model can be a traditional glTF asset with a .gltf extension or a Binary glTF using the .glb extension.
*
*
* Cesium supports glTF assets with the following extensions:
*
* -
- * {@link https://github.com/KhronosGroup/glTF/blob/master/extensions/1.0/Khronos/KHR_binary_glTF/README.md|KHR_binary_glTF}
- *
-
* {@link https://github.com/KhronosGroup/glTF/blob/master/extensions/1.0/Khronos/KHR_materials_common/README.md|KHR_materials_common}
*
-
* {@link https://github.com/KhronosGroup/glTF/blob/master/extensions/1.0/Vendor/WEB3D_quantized_attributes/README.md|WEB3D_quantized_attributes}
@@ -1159,9 +1150,6 @@ define([
*
* @returns {Model} The newly created model.
*
- * @exception {DeveloperError} bgltf is not a valid Binary glTF file.
- * @exception {DeveloperError} Only glTF Binary version 1 is supported.
- *
* @example
* // Example 1. Create a model from a glTF asset
* var model = scene.primitives.add(Cesium.Model.fromGltf({
@@ -1426,29 +1414,25 @@ define([
function parseBuffers(model) {
var loadResources = model._loadResources;
- // Iterate this way for compatibility with objects and arrays
- var buffers = model.gltf.buffers;
- for (var id in buffers) {
- if (buffers.hasOwnProperty(id)) {
- var buffer = buffers[id];
- buffer.extras = defaultValue(buffer.extras, {});
- buffer.extras._pipeline = defaultValue(buffer.extras._pipeline, {});
- if (defined(buffer.extras._pipeline.source)) {
- loadResources.buffers[id] = buffer.extras._pipeline.source;
- } else {
- var bufferResource = model._resource.getDerivedResource({
- url : buffer.uri
- });
- ++loadResources.pendingBufferLoads;
- bufferResource.fetchArrayBuffer().then(bufferLoad(model, id)).otherwise(getFailedLoadFunction(model, 'buffer', bufferResource.url));
- }
+ ForEach.buffer(model.gltf, function(buffer, bufferViewId) {
+ buffer.extras = defaultValue(buffer.extras, {});
+ buffer.extras._pipeline = defaultValue(buffer.extras._pipeline, {});
+ if (defined(buffer.extras._pipeline.source)) {
+ loadResources.buffers[bufferViewId] = buffer.extras._pipeline.source;
+ } else {
+ var bufferResource = model._resource.getDerivedResource({
+ url: buffer.uri
+ });
+ ++loadResources.pendingBufferLoads;
+ bufferResource.fetchArrayBuffer()
+ .then(bufferLoad(model, bufferViewId))
+ .otherwise(getFailedLoadFunction(model, 'buffer', bufferResource.url));
}
- }
+ });
}
function parseBufferViews(model) {
var bufferViews = model.gltf.bufferViews;
-
var vertexBuffersToCreate = model._loadResources.vertexBuffersToCreate;
// Only ARRAY_BUFFER here. ELEMENT_ARRAY_BUFFER created below.
@@ -1490,7 +1474,7 @@ define([
bufferView : undefined
};
--loadResources.pendingShaderLoads;
- model._shaders[id].extras._pipeline.source = source;
+ model._sourceShaders[id].extras._pipeline.source = source;
};
}
@@ -1498,7 +1482,10 @@ define([
var gltf = model.gltf;
var buffers = gltf.buffers;
var bufferViews = gltf.bufferViews;
- ForEach.shader(gltf, function(shader, id) {
+ ForEach.shader(gltf, function(sourceShader, id) {
+ // retain reference to source shader
+ var shader = model._sourceShaders[id] = clone(sourceShader);
+
// Shader references either uri (external or base64-encoded) or bufferView
if (defined(shader.bufferView)) {
var bufferViewId = shader.bufferView;
@@ -1527,14 +1514,11 @@ define([
.then(shaderLoad(model, shader.type, id))
.otherwise(getFailedLoadFunction(model, 'shader', shaderResource.url));
}
-
- // retain reference to source shader
- model._sourceShaders[id] = clone(shader);
});
}
function parsePrograms(model) {
- var sourcePrograms = model._sourcePrograms = {};
+ var sourcePrograms = model._sourcePrograms;
var gltf = model.gltf;
if (!hasExtension(gltf, 'KHR_techniques_webgl')) {
@@ -1547,8 +1531,8 @@ define([
if (!defined(sourcePrograms[programId])) {
sourcePrograms[programId] = clone(programs[programId]);
model._loadResources.programsToCreate.enqueue({
- id : programId,
- technique : techniqueId
+ programId : programId,
+ techniqueId : techniqueId
});
}
});
@@ -1715,7 +1699,7 @@ define([
function parseMaterials(model) {
var gltf = model.gltf;
- var techniques = model._sourceTechniques = {};
+ var techniques = model._sourceTechniques;
ForEach.technique(model.gltf, function(technique, index) {
techniques[index] = clone(technique);
@@ -1741,16 +1725,13 @@ define([
modelMaterial._technique = techniqueId;
modelMaterial._program = techniques[techniqueId].program;
- var values = material.extensions.KHR_techniques_webgl.values;
- for (var uniformName in values) {
- if (values.hasOwnProperty(uniformName)) {
- if (!defined(modelMaterial._values)) {
- modelMaterial._values = {};
- }
-
- modelMaterial._values[uniformName] = clone(values[uniformName]);
+ ForEach.materialValue(material, function(value, uniformName) {
+ if (!defined(modelMaterial._values)) {
+ modelMaterial._values = {};
}
- }
+
+ modelMaterial._values[uniformName] = clone(value);
+ });
}
runtimeMaterialsByName[material.name] = modelMaterial;
@@ -1765,23 +1746,20 @@ define([
var runtimeMeshesByName = {};
var runtimeMaterialsById = model._runtime.materialsById;
- ForEach.mesh(model.gltf, function(mesh, id) {
- runtimeMeshesByName[mesh.name] = new ModelMesh(mesh, runtimeMaterialsById, id);
+ ForEach.mesh(model.gltf, function(mesh, meshId) {
+ runtimeMeshesByName[mesh.name] = new ModelMesh(mesh, runtimeMaterialsById, meshId);
if (defined(model.extensionsUsed.WEB3D_quantized_attributes) || model._dequantizeInShader) {
// Cache primitives according to their program
- var primitives = mesh.primitives;
- var primitivesLength = primitives.length;
- for (var i = 0; i < primitivesLength; i++) {
- var primitive = primitives[i];
+ ForEach.meshPrimitive(mesh, function(primitive, primitiveId) {
var programId = getProgramForPrimitive(model, primitive);
var programPrimitives = model._programPrimitives[programId];
if (!defined(programPrimitives)) {
programPrimitives = {};
model._programPrimitives[programId] = programPrimitives;
}
- programPrimitives[id + '.primitive.' + i] = primitive;
+ programPrimitives[meshId + '.primitive.' + primitiveId] = primitive;
+ });
}
- }
});
model._runtime.meshesByName = runtimeMeshesByName;
@@ -1959,35 +1937,14 @@ define([
return result.shader;
}
- function hasPremultipliedAlpha(model) {
- var gltf = model.gltf;
- return defined(gltf.asset) ? defaultValue(gltf.asset.premultipliedAlpha, false) : false;
- }
-
- function modifyShaderForColor(shader, premultipliedAlpha) {
+ function modifyShaderForColor(shader) {
shader = ShaderSource.replaceMain(shader, 'gltf_blend_main');
shader +=
'uniform vec4 gltf_color; \n' +
'uniform float gltf_colorBlend; \n' +
'void main() \n' +
'{ \n' +
- ' gltf_blend_main(); \n';
-
- // Un-premultiply the alpha so that blending is correct.
-
- // Avoid divide-by-zero. The code below is equivalent to:
- // if (gl_FragColor.a > 0.0)
- // {
- // gl_FragColor.rgb /= gl_FragColor.a;
- // }
-
- if (premultipliedAlpha) {
- shader +=
- ' float alpha = 1.0 - ceil(gl_FragColor.a) + gl_FragColor.a; \n' +
- ' gl_FragColor.rgb /= alpha; \n';
- }
-
- shader +=
+ ' gltf_blend_main(); \n' +
' gl_FragColor.rgb = mix(gl_FragColor.rgb, gltf_color.rgb, gltf_colorBlend); \n' +
' float highlight = ceil(gltf_colorBlend); \n' +
' gl_FragColor.rgb *= mix(gltf_color.rgb, vec3(1.0), highlight); \n' +
@@ -2005,19 +1962,19 @@ define([
}
var CreateProgramJob = function() {
- this.id = undefined;
+ this.programToCreate = undefined;
this.model = undefined;
this.context = undefined;
};
- CreateProgramJob.prototype.set = function(id, model, context) {
- this.id = id;
+ CreateProgramJob.prototype.set = function(programToCreate, model, context) {
+ this.programToCreate = programToCreate;
this.model = model;
this.context = context;
};
CreateProgramJob.prototype.execute = function() {
- createProgram(this.id, this.model, this.context);
+ createProgram(this.programToCreate, this.model, this.context);
};
///////////////////////////////////////////////////////////////////////////
@@ -2025,8 +1982,8 @@ define([
// When building programs for the first time, do not include modifiers for clipping planes and color
// since this is the version of the program that will be cached for use with other Models.
function createProgram(programToCreate, model, context) {
- var programId = programToCreate.id;
- var techniqueId = programToCreate.technique;
+ var programId = programToCreate.programId;
+ var techniqueId = programToCreate.techniqueId;
var program = model._sourcePrograms[programId];
var shaders = model._sourceShaders;
@@ -2064,8 +2021,8 @@ define([
}
function recreateProgram(programToCreate, model, context) {
- var programId = programToCreate.id;
- var techniqueId = programToCreate.technique;
+ var programId = programToCreate.programId;
+ var techniqueId = programToCreate.techniqueId;
var program = model._sourcePrograms[programId];
var shaders = model._sourceShaders;
@@ -2084,7 +2041,7 @@ define([
var finalFS = fs;
if (isColorShadingEnabled(model)) {
- finalFS = Model._modifyShaderForColor(finalFS, model._hasPremultipliedAlpha);
+ finalFS = Model._modifyShaderForColor(finalFS);
}
if (addClippingPlaneCode) {
finalFS = modifyShaderForClippingPlanes(finalFS, clippingPlaneCollection, context);
@@ -2196,24 +2153,18 @@ define([
function createSamplers(model) {
var loadResources = model._loadResources;
-
if (loadResources.createSamplers) {
loadResources.createSamplers = false;
var rendererSamplers = model._rendererResources.samplers;
- var samplers = model.gltf.samplers;
- for (var id in samplers) {
- if (samplers.hasOwnProperty(id)) {
- var sampler = samplers[id];
-
- rendererSamplers[id] = new Sampler({
- wrapS : sampler.wrapS,
- wrapT : sampler.wrapT,
- minificationFilter : sampler.minFilter,
- magnificationFilter : sampler.magFilter
- });
- }
- }
+ ForEach.sampler(model.gltf, function(sampler, samplerId) {
+ rendererSamplers[samplerId] = new Sampler({
+ wrapS: sampler.wrapS,
+ wrapT: sampler.wrapT,
+ minificationFilter: sampler.minFilter,
+ magnificationFilter: sampler.magFilter
+ });
+ });
}
}
@@ -2550,12 +2501,8 @@ define([
function createVertexArrays(model, context) {
var loadResources = model._loadResources;
-
- if (!loadResources.finishedBuffersCreation() || !loadResources.finishedProgramCreation()) {
- return;
- }
-
- if (!loadResources.createVertexArrays) {
+ if (!loadResources.finishedBuffersCreation() || !loadResources.finishedProgramCreation()
+ || !loadResources.createVertexArrays) {
return;
}
loadResources.createVertexArrays = false;
@@ -2564,115 +2511,91 @@ define([
var rendererVertexArrays = model._rendererResources.vertexArrays;
var gltf = model.gltf;
var accessors = gltf.accessors;
- var meshes = gltf.meshes;
-
- for (var meshId in meshes) {
- if (meshes.hasOwnProperty(meshId)) {
- var primitives = meshes[meshId].primitives;
- var primitivesLength = primitives.length;
-
- for (var i = 0; i < primitivesLength; ++i) {
- var primitive = primitives[i];
- var decodedData = model._decodedData[meshId + '.primitive.' + i];
-
- // GLTF_SPEC: This does not take into account attribute arrays,
- // indicated by when an attribute points to a parameter with a
- // count property.
- //
- // https://github.com/KhronosGroup/glTF/issues/258
-
- var attributeLocations = getAttributeLocations(model, primitive);
-
- var attributeName;
- var attributeLocation;
- var attribute;
- var attributes = [];
- var primitiveAttributes = primitive.attributes;
- for (attributeName in primitiveAttributes) {
- if (primitiveAttributes.hasOwnProperty(attributeName)) {
- attributeLocation = attributeLocations[attributeName];
- // Skip if the attribute is not used by the material, e.g., because the asset was exported
- // with an attribute that wasn't used and the asset wasn't optimized.
- if (defined(attributeLocation)) {
- // Use attributes of previously decoded draco geometry
- if (defined(decodedData)) {
- var decodedAttributes = decodedData.attributes;
- if (decodedAttributes.hasOwnProperty(attributeName)) {
- var decodedAttribute = decodedAttributes[attributeName];
- attributes.push({
- index : attributeLocation,
- vertexBuffer : rendererBuffers[decodedAttribute.bufferView],
- componentsPerAttribute : decodedAttribute.componentsPerAttribute,
- componentDatatype : decodedAttribute.componentDatatype,
- normalize: decodedAttribute.normalized,
- offsetInBytes : decodedAttribute.byteOffset,
- strideInBytes : decodedAttribute.byteStride
- });
-
- continue;
- }
- }
-
- var a = accessors[primitiveAttributes[attributeName]];
-
- var normalize = false;
- if (defined(a.normalized) && a.normalized) {
- normalize = true;
- }
-
+ ForEach.mesh(gltf, function(mesh, meshId) {
+ ForEach.meshPrimitive(mesh, function(primitive, primitiveId) {
+ var attributes = [];
+ var attributeLocation;
+ var attributeLocations = getAttributeLocations(model, primitive);
+ var decodedData = model._decodedData[meshId + '.primitive.' + primitiveId];
+ ForEach.meshPrimitiveAttribute(primitive, function(accessorId, attributeName) {
+ // Skip if the attribute is not used by the material, e.g., because the asset
+ // was exported with an attribute that wasn't used and the asset wasn't optimized.
+ attributeLocation = attributeLocations[attributeName];
+ if (defined(attributeLocation)) {
+ // Use attributes of previously decoded draco geometry
+ if (defined(decodedData)) {
+ var decodedAttributes = decodedData.attributes;
+ if (decodedAttributes.hasOwnProperty(attributeName)) {
+ var decodedAttribute = decodedAttributes[attributeName];
attributes.push({
- index : attributeLocation,
- vertexBuffer : rendererBuffers[a.bufferView],
- componentsPerAttribute : numberOfComponentsForType(a.type),
- componentDatatype : a.componentType,
- normalize : normalize,
- offsetInBytes : a.byteOffset,
- strideInBytes : getAccessorByteStride(gltf, a)
+ index: attributeLocation,
+ vertexBuffer: rendererBuffers[decodedAttribute.bufferView],
+ componentsPerAttribute: decodedAttribute.componentsPerAttribute,
+ componentDatatype: decodedAttribute.componentDatatype,
+ normalize: decodedAttribute.normalized,
+ offsetInBytes: decodedAttribute.byteOffset,
+ strideInBytes: decodedAttribute.byteStride
});
+
+ return;
}
}
+
+ var a = accessors[accessorId];
+ var normalize = defined(a.normalized) && a.normalized;
+ attributes.push({
+ index: attributeLocation,
+ vertexBuffer: rendererBuffers[a.bufferView],
+ componentsPerAttribute: numberOfComponentsForType(a.type),
+ componentDatatype: a.componentType,
+ normalize: normalize,
+ offsetInBytes: a.byteOffset,
+ strideInBytes: getAccessorByteStride(gltf, a)
+ });
}
+ });
- // Add pre-created attributes
- var precreatedAttributes = model._precreatedAttributes;
- if (defined(precreatedAttributes)) {
- for (attributeName in precreatedAttributes) {
- if (precreatedAttributes.hasOwnProperty(attributeName)) {
- attributeLocation = attributeLocations[attributeName];
- if (defined(attributeLocation)) {
- attribute = precreatedAttributes[attributeName];
- attribute.index = attributeLocation;
- attributes.push(attribute);
- }
+ // Add pre-created attributes
+ var attribute;
+ var attributeName;
+ var precreatedAttributes = model._precreatedAttributes;
+ if (defined(precreatedAttributes)) {
+ for (attributeName in precreatedAttributes) {
+ if (precreatedAttributes.hasOwnProperty(attributeName)) {
+ attributeLocation = attributeLocations[attributeName];
+ if (defined(attributeLocation)) {
+ attribute = precreatedAttributes[attributeName];
+ attribute.index = attributeLocation;
+ attributes.push(attribute);
}
}
}
+ }
- var indexBuffer;
- if (defined(primitive.indices)) {
- var accessor = accessors[primitive.indices];
- var bufferView = accessor.bufferView;
-
- // Use buffer of previously decoded draco geometry
- if (defined(decodedData)) {
- bufferView = decodedData.bufferView;
- }
+ var indexBuffer;
+ if (defined(primitive.indices)) {
+ var accessor = accessors[primitive.indices];
+ var bufferView = accessor.bufferView;
- indexBuffer = rendererBuffers[bufferView];
+ // Use buffer of previously decoded draco geometry
+ if (defined(decodedData)) {
+ bufferView = decodedData.bufferView;
}
- rendererVertexArrays[meshId + '.primitive.' + i] = new VertexArray({
- context : context,
- attributes : attributes,
- indexBuffer : indexBuffer
- });
+
+ indexBuffer = rendererBuffers[bufferView];
}
- }
- }
+ rendererVertexArrays[meshId + '.primitive.' + primitiveId] = new VertexArray({
+ context: context,
+ attributes: attributes,
+ indexBuffer: indexBuffer
+ });
+ });
+ });
}
function getBooleanStates(material) {
var booleanStates = {};
- booleanStates[WebGLConstants.BLEND] = (defined(material.alphaMode) && material.alphaMode !== 'OPAQUE');
+ booleanStates[WebGLConstants.BLEND] = (material.alphaMode === 'BLEND');
booleanStates[WebGLConstants.CULL_FACE] = !material.doubleSided;
booleanStates[WebGLConstants.DEPTH_TEST] = true;
booleanStates[WebGLConstants.POLYGON_OFFSET_FILL] = false;
@@ -2680,19 +2603,18 @@ define([
return booleanStates;
}
- function createRenderStates(model, context) {
+ function createRenderStates(model) {
var loadResources = model._loadResources;
-
if (loadResources.createRenderStates) {
loadResources.createRenderStates = false;
ForEach.material(model.gltf, function (material, materialId) {
- createRenderStateForMaterial(model, material, materialId, context);
+ createRenderStateForMaterial(model, material, materialId);
});
}
}
- function createRenderStateForMaterial(model, material, materialId, context) {
+ function createRenderStateForMaterial(model, material, materialId) {
var rendererRenderStates = model._rendererResources.renderStates;
var blendEquationSeparate = [
@@ -2719,15 +2641,6 @@ define([
};
var booleanStates = getBooleanStates(material);
- // Change the render state to use traditional alpha blending instead of premultiplied alpha blending
- if (booleanStates[WebGLConstants.BLEND] && model._hasPremultipliedAlpha) {
- if ((blendFuncSeparate[0] === WebGLConstants.ONE) && (blendFuncSeparate[1] === WebGLConstants.ONE_MINUS_SRC_ALPHA)) {
- blendFuncSeparate[0] = WebGLConstants.SRC_ALPHA;
- blendFuncSeparate[1] = WebGLConstants.ONE_MINUS_SRC_ALPHA;
- blendFuncSeparate[2] = WebGLConstants.SRC_ALPHA;
- blendFuncSeparate[3] = WebGLConstants.ONE_MINUS_SRC_ALPHA;
- }
- }
rendererRenderStates[materialId] = RenderState.fromCache({
frontFace : defined(statesFunctions.frontFace) ? statesFunctions.frontFace[0] : WebGLConstants.CCW,
@@ -3157,8 +3070,6 @@ define([
uniformMap = combine(uniformMap, quantizedUniformMap);
var rs = rendererRenderStates[primitive.material];
-
- // GLTF_SPEC: Official means to determine translucency. https://github.com/KhronosGroup/glTF/issues/105
var isTranslucent = rs.blending.enabled;
var owner = model._pickObject;
@@ -3368,7 +3279,6 @@ define([
// Retain references to updated source shaders for rebuilding as needed
var shaders = model._sourceShaders;
- model._hasPremultipliedAlpha = hasPremultipliedAlpha(model);
var quantizedVertexShaders = model._quantizedVertexShaders;
var toClipCoordinates = model._toClipCoordinatesGLSL = {};
@@ -3377,6 +3287,9 @@ define([
if (programs.hasOwnProperty(programId)) {
var program = programs[programId];
var shader = shaders[program.vertexShader].extras._pipeline.source;
+
+ ModelUtility.checkSupportedGlExtensions(program.glExtensions, context);
+
if (model.extensionsUsed.WEB3D_quantized_attributes || model._dequantizeInShader) {
var quantizedVS = quantizedVertexShaders[programId];
if (!defined(quantizedVS)) {
@@ -3391,7 +3304,6 @@ define([
}
}
- ModelUtility.checkSupportedGlExtensions(model.gltf.glExtensionsUsed, context);
if (model._loadRendererResourcesFromCache) {
var resources = model._rendererResources;
var cachedResources = model._cachedRendererResources;
@@ -3424,7 +3336,7 @@ define([
if (!model._loadRendererResourcesFromCache) {
createVertexArrays(model, context); // using glTF meshes
- createRenderStates(model, context); // using glTF materials/techniques/states
+ createRenderStates(model); // using glTF materials/techniques/states
// Long-term, we might not cache render states if they could change
// due to an animation, e.g., a uniform going from opaque to transparent.
// Could use copy-on-write if it is worth it. Probably overkill.
@@ -4265,8 +4177,7 @@ define([
// glTF pipeline updates
addPipelineExtras(this.gltf);
updateVersion(this.gltf);
- if (defined(this.gltf.asset) && defined(this.gltf.asset.extras) &&
- this.gltf.asset.extras.gltf_pipeline_upgrade_10to20) {
+ if (this.gltf.extras._pipeline.gltf_pipeline_upgrade_10to20) {
this._forwardAxis = Axis.X;
}
addDefaults(this.gltf);
@@ -4567,8 +4478,8 @@ define([
if (!visitedPrograms[programId]) {
visitedPrograms[programId] = true;
recreateProgram({
- id: programId,
- technique: techniqueId
+ programId: programId,
+ techniqueId: techniqueId
}, model, frameState.context);
}
}
From 923874b552995a7a8f8d1d481157306702d62dc3 Mon Sep 17 00:00:00 2001
From: ggetz
Date: Thu, 2 Aug 2018 16:50:30 -0400
Subject: [PATCH 06/52] Simplify render states
---
Source/Scene/Model.js | 55 +++++--------------------------------------
1 file changed, 6 insertions(+), 49 deletions(-)
diff --git a/Source/Scene/Model.js b/Source/Scene/Model.js
index 0536b0288e62..2970313ed889 100644
--- a/Source/Scene/Model.js
+++ b/Source/Scene/Model.js
@@ -1518,7 +1518,7 @@ define([
}
function parsePrograms(model) {
- var sourcePrograms = model._sourcePrograms;
+ var sourcePrograms = model._sourcePrograms = {};
var gltf = model.gltf;
if (!hasExtension(gltf, 'KHR_techniques_webgl')) {
@@ -2593,16 +2593,6 @@ define([
});
}
- function getBooleanStates(material) {
- var booleanStates = {};
- booleanStates[WebGLConstants.BLEND] = (material.alphaMode === 'BLEND');
- booleanStates[WebGLConstants.CULL_FACE] = !material.doubleSided;
- booleanStates[WebGLConstants.DEPTH_TEST] = true;
- booleanStates[WebGLConstants.POLYGON_OFFSET_FILL] = false;
-
- return booleanStates;
- }
-
function createRenderStates(model) {
var loadResources = model._loadResources;
if (loadResources.createRenderStates) {
@@ -2633,50 +2623,17 @@ define([
blendFuncSeparate = material.extensions.KHR_blend.blendFactors;
}
- var statesFunctions = {
- blendColor : [0.0, 0.0, 0.0, 0.0],
- colorMask : [true, true, true, true],
- depthRange : [0.0, 1.0],
- polygonOffset : [0.0, 0.0]
- };
-
- var booleanStates = getBooleanStates(material);
-
+ var enableCulling = !material.doubleSided;
+ var blendingEnabled = (material.alphaMode === 'BLEND');
rendererRenderStates[materialId] = RenderState.fromCache({
- frontFace : defined(statesFunctions.frontFace) ? statesFunctions.frontFace[0] : WebGLConstants.CCW,
cull : {
- enabled : booleanStates[WebGLConstants.CULL_FACE],
- face : defined(statesFunctions.cullFace) ? statesFunctions.cullFace[0] : WebGLConstants.BACK
- },
- lineWidth : defined(statesFunctions.lineWidth) ? statesFunctions.lineWidth[0] : 1.0,
- polygonOffset : {
- enabled : booleanStates[WebGLConstants.POLYGON_OFFSET_FILL],
- factor: statesFunctions.polygonOffset[0],
- units: statesFunctions.polygonOffset[1]
- },
- depthRange : {
- near: statesFunctions.depthRange[0],
- far: statesFunctions.depthRange[1]
+ enabled : enableCulling
},
depthTest : {
- enabled : booleanStates[WebGLConstants.DEPTH_TEST],
- func : defined(statesFunctions.depthFunc) ? statesFunctions.depthFunc[0] : WebGLConstants.LESS
+ enabled : true
},
- colorMask : {
- red: statesFunctions.colorMask[0],
- green: statesFunctions.colorMask[1],
- blue: statesFunctions.colorMask[2],
- alpha: statesFunctions.colorMask[3]
- },
- depthMask : defined(statesFunctions.depthMask) ? statesFunctions.depthMask[0] : true,
blending : {
- enabled : booleanStates[WebGLConstants.BLEND],
- color : {
- red: statesFunctions.blendColor[0],
- green: statesFunctions.blendColor[1],
- blue: statesFunctions.blendColor[2],
- alpha: statesFunctions.blendColor[3]
- },
+ enabled : blendingEnabled,
equationRgb : blendEquationSeparate[0],
equationAlpha : blendEquationSeparate[1],
functionSourceRgb : blendFuncSeparate[0],
From 7abc5c7a5ad7cc745f96a0ac56bf2139caacd577 Mon Sep 17 00:00:00 2001
From: ggetz
Date: Thu, 2 Aug 2018 17:35:56 -0400
Subject: [PATCH 07/52] Fix ClassificationModel, factor out duplicate code
---
Source/Scene/ClassificationModel.js | 129 ++++++++++------------------
Source/Scene/Model.js | 30 ++-----
Source/Scene/ModelUtility.js | 37 ++++++++
3 files changed, 89 insertions(+), 107 deletions(-)
diff --git a/Source/Scene/ClassificationModel.js b/Source/Scene/ClassificationModel.js
index 3f2fb412a199..55fd00a76503 100644
--- a/Source/Scene/ClassificationModel.js
+++ b/Source/Scene/ClassificationModel.js
@@ -3,7 +3,6 @@ define([
'../Core/BoundingSphere',
'../Core/Cartesian3',
'../Core/Cartesian4',
- '../Core/Cartographic',
'../Core/Color',
'../Core/combine',
'../Core/ComponentDatatype',
@@ -16,20 +15,23 @@ define([
'../Core/IndexDatatype',
'../Core/Matrix4',
'../Core/PrimitiveType',
- '../Core/Quaternion',
'../Core/Resource',
'../Core/RuntimeError',
'../Core/Transforms',
'../Core/WebGLConstants',
+ '../ThirdParty/GltfPipeline/addDefaults',
'../ThirdParty/GltfPipeline/ForEach',
'../ThirdParty/GltfPipeline/getAccessorByteStride',
'../ThirdParty/GltfPipeline/numberOfComponentsForType',
'../ThirdParty/GltfPipeline/parseGlb',
+ '../ThirdParty/GltfPipeline/updateVersion',
'../ThirdParty/when',
'./Axis',
'./ClassificationType',
'./ModelLoadResources',
'./ModelUtility',
+ './processModelMaterialsCommon',
+ './processPbrMetallicRoughness',
'./SceneMode',
'./Vector3DTileBatch',
'./Vector3DTilePrimitive'
@@ -38,7 +40,6 @@ define([
BoundingSphere,
Cartesian3,
Cartesian4,
- Cartographic,
Color,
combine,
ComponentDatatype,
@@ -51,20 +52,23 @@ define([
IndexDatatype,
Matrix4,
PrimitiveType,
- Quaternion,
Resource,
RuntimeError,
Transforms,
WebGLConstants,
+ addDefaults,
ForEach,
getAccessorByteStride,
numberOfComponentsForType,
parseGlb,
+ updateVersion,
when,
Axis,
ClassificationType,
ModelLoadResources,
ModelUtility,
+ processModelMaterialsCommon,
+ processPbrMetallicRoughness,
SceneMode,
Vector3DTileBatch,
Vector3DTilePrimitive) {
@@ -78,12 +82,7 @@ define([
var boundingSphereCartesian3Scratch = new Cartesian3();
- var ModelState = {
- NEEDS_LOAD : 0,
- LOADING : 1,
- LOADED : 2,
- FAILED : 3
- };
+ var ModelState = ModelUtility.ModelState;
///////////////////////////////////////////////////////////////////////////
@@ -125,6 +124,10 @@ define([
if (gltf instanceof Uint8Array) {
// Binary glTF
gltf = parseGlb(gltf);
+ updateVersion(gltf);
+ addDefaults(gltf);
+ processModelMaterialsCommon(gltf);
+ processPbrMetallicRoughness(gltf);
} else {
throw new RuntimeError('Only binary glTF is supported as a classifier.');
}
@@ -132,17 +135,17 @@ define([
var gltfNodes = gltf.nodes;
var gltfMeshes = gltf.meshes;
- var gltfNode = gltfNodes.rootNode;
- if (!defined(gltfNode) || !defined(gltfNode.meshes)) {
+ var gltfNode = gltfNodes[0];
+ var meshId = gltfNode.mesh;
+ if (gltfNodes.length !== 1 || !defined(meshId)) {
throw new RuntimeError('Only one node is supported for classification and it must have a mesh.');
}
- var nodeMesh = gltfNode.meshes[0];
- if (!defined(nodeMesh)) {
- throw new RuntimeError('Only one node is supported for classification and it must have a mesh.');
+ if (gltfMeshes.length !== 1) {
+ throw new RuntimeError('Only one mesh is supported when using b3dm for classification.');
}
- var gltfPrimitives = gltfMeshes[nodeMesh].primitives;
+ var gltfPrimitives = gltfMeshes[0].primitives;
if (gltfPrimitives.length !== 1) {
throw new RuntimeError('Only one primitive per mesh is supported when using b3dm for classification.');
}
@@ -499,8 +502,8 @@ define([
var min = new Cartesian3(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE);
var max = new Cartesian3(-Number.MAX_VALUE, -Number.MAX_VALUE, -Number.MAX_VALUE);
- var n = gltfNodes.rootNode;
- var meshId = n.meshes[0];
+ var n = gltfNodes[0];
+ var meshId = n.mesh;
var transformToRoot = ModelUtility.getTransform(n);
var mesh = gltfMeshes[meshId];
@@ -527,13 +530,6 @@ define([
///////////////////////////////////////////////////////////////////////////
- function getFailedLoadFunction(model, type, path) {
- return function() {
- model._state = ModelState.FAILED;
- model._readyPromise.reject(new RuntimeError('Failed to load ' + type + ': ' + path));
- };
- }
-
function addBuffersToLoadResources(model) {
var gltf = model.gltf;
var loadResources = model._loadResources;
@@ -551,27 +547,6 @@ define([
};
}
- function parseBuffers(model) {
- var loadResources = model._loadResources;
- // Iterate this way for compatibility with objects and arrays
- var buffers = model.gltf.buffers;
- var length = buffers.length;
- for (var i = 0; i < length; ++i) {
- var buffer = buffers[i];
- buffer.extras = defaultValue(buffer.extras, {});
- buffer.extras._pipeline = defaultValue(buffer.extras._pipeline, {});
- if (defined(buffer.extras._pipeline.source)) {
- loadResources.buffers[i] = buffer.extras._pipeline.source;
- } else {
- var bufferResource = model._resource.getDerivedResource({
- url : buffer.uri
- });
- ++loadResources.pendingBufferLoads;
- bufferResource.fetchArrayBuffer().then(bufferLoad(model, i)).otherwise(getFailedLoadFunction(model, 'buffer', bufferResource.uri));
- }
- }
- }
-
function parseBufferViews(model) {
var bufferViews = model.gltf.bufferViews;
@@ -646,9 +621,7 @@ define([
}
function modifyShaderForQuantizedAttributes(shader, model) {
- var gltfMeshes = model.gltf.meshes;
- var gltfRootNode = model.gltf.nodes.rootNode;
- var primitive = gltfMeshes[gltfRootNode.meshes[0]].primitives[0];
+ var primitive = model.gltf.meshes[0].primitives[0];
var result = ModelUtility.modifyShaderForQuantizedAttributes(model.gltf, primitive, shader);
model._quantizedUniforms = result.uniforms;
return result.shader;
@@ -738,11 +711,7 @@ define([
function createVertexArray(model) {
var loadResources = model._loadResources;
- if (!loadResources.finishedBuffersCreation()) {
- return;
- }
-
- if (defined(model._vertexArray)) {
+ if (!loadResources.finishedBuffersCreation() || defined(model._vertexArray)) {
return;
}
@@ -750,31 +719,27 @@ define([
var gltf = model.gltf;
var accessors = gltf.accessors;
var meshes = gltf.meshes;
- var rootNode = gltf.nodes.rootNode;
- var primitives = meshes[rootNode.meshes[0]].primitives;
+ var primitives = meshes[0].primitives;
var primitive = primitives[0];
var attributeLocations = getAttributeLocations();
var attributes = {};
- var primitiveAttributes = primitive.attributes;
- for (var attributeName in primitiveAttributes) {
- if (primitiveAttributes.hasOwnProperty(attributeName)) {
- var attributeLocation = attributeLocations[attributeName];
- // Skip if the attribute is not used by the material, e.g., because the asset was exported
- // with an attribute that wasn't used and the asset wasn't optimized.
- if (defined(attributeLocation)) {
- var a = accessors[primitiveAttributes[attributeName]];
- attributes[attributeName] = {
- index : attributeLocation,
- vertexBuffer : rendererBuffers[a.bufferView],
- componentsPerAttribute : numberOfComponentsForType(a.type),
- componentDatatype : a.componentType,
- offsetInBytes : a.byteOffset,
- strideInBytes : getAccessorByteStride(gltf, a)
- };
- }
+ ForEach.meshPrimitiveAttribute(primitive, function(accessorId, attributeName) {
+ // Skip if the attribute is not used by the material, e.g., because the asset
+ // was exported with an attribute that wasn't used and the asset wasn't optimized.
+ var attributeLocation = attributeLocations[attributeName];
+ if (defined(attributeLocation)) {
+ var a = accessors[accessorId];
+ attributes[attributeName] = {
+ index: attributeLocation,
+ vertexBuffer: rendererBuffers[a.bufferView],
+ componentsPerAttribute: numberOfComponentsForType(a.type),
+ componentDatatype: a.componentType,
+ offsetInBytes: a.byteOffset,
+ strideInBytes: getAccessorByteStride(gltf, a)
+ };
}
- }
+ });
var indexBuffer;
if (defined(primitive.indices)) {
@@ -809,15 +774,12 @@ define([
var uniformMap = {};
ForEach.technique(model.gltf, function(technique) {
- var parameters = technique.parameters;
- ForEach.techniqueUniform(technique, function(parameterName, uniformName) {
- var parameter = parameters[parameterName];
-
- if (!defined(parameter.semantic) || !defined(gltfSemanticUniforms[parameter.semantic])) {
+ ForEach.techniqueUniform(technique, function(uniform, uniformName) {
+ if (!defined(uniform.semantic) || !defined(gltfSemanticUniforms[uniform.semantic])) {
return;
}
- uniformMap[uniformName] = gltfSemanticUniforms[parameter.semantic](context.uniformState, model);
+ uniformMap[uniformName] = gltfSemanticUniforms[uniform.semantic](context.uniformState, model);
});
});
@@ -849,8 +811,7 @@ define([
var gltf = model.gltf;
var accessors = gltf.accessors;
var gltfMeshes = gltf.meshes;
- var gltfRootNode = gltf.nodes.rootNode;
- var primitive = gltfMeshes[gltfRootNode.meshes[0]].primitives[0];
+ var primitive = gltfMeshes[0].primitives[0];
var ix = accessors[primitive.indices];
var positionAccessor = primitive.attributes.POSITION;
@@ -999,7 +960,7 @@ define([
var gltf = model.gltf;
var nodes = gltf.nodes;
- var gltfNode = nodes.rootNode;
+ var gltfNode = nodes[0];
model._nodeMatrix = ModelUtility.getTransform(gltfNode, model._nodeMatrix);
createPrimitive(model);
@@ -1086,7 +1047,7 @@ define([
}
this._loadResources = new ModelLoadResources();
- parseBuffers(this);
+ ModelUtility.parseBuffers(this, bufferLoad);
}
}
diff --git a/Source/Scene/Model.js b/Source/Scene/Model.js
index 2970313ed889..6cc8b8ef9339 100644
--- a/Source/Scene/Model.js
+++ b/Source/Scene/Model.js
@@ -154,12 +154,7 @@ define([
var boundingSphereCartesian3Scratch = new Cartesian3();
- var ModelState = {
- NEEDS_LOAD : 0,
- LOADING : 1,
- LOADED : 2, // Renderable, but textures can still be pending when incrementallyLoadTextures is true.
- FAILED : 3
- };
+ var ModelState = ModelUtility.ModelState;
// glTF MIME types discussed in https://github.com/KhronosGroup/glTF/issues/412 and https://github.com/KhronosGroup/glTF/issues/943
var defaultModelAccept = 'model/gltf-binary,model/gltf+json;q=0.8,application/json;q=0.2,*/*;q=0.01';
@@ -1233,7 +1228,7 @@ define([
var json = getStringFromTypedArray(array);
cachedGltf.makeReady(JSON.parse(json));
}
- }).otherwise(getFailedLoadFunction(model, 'model', url));
+ }).otherwise(ModelUtility.getFailedLoadFunction(model, 'model', url));
} else if (!cachedGltf.ready) {
// Cache hit but the fetchArrayBuffer() or fetchText() request is still pending
++cachedGltf.count;
@@ -1384,17 +1379,6 @@ define([
///////////////////////////////////////////////////////////////////////////
- function getFailedLoadFunction(model, type, path) {
- return function(error) {
- model._state = ModelState.FAILED;
- var message = 'Failed to load ' + type + ': ' + path;
- if (defined(error)) {
- message += '\n' + error.message;
- }
- model._readyPromise.reject(new RuntimeError(message));
- };
- }
-
function addBuffersToLoadResources(model) {
var gltf = model.gltf;
var loadResources = model._loadResources;
@@ -1426,7 +1410,7 @@ define([
++loadResources.pendingBufferLoads;
bufferResource.fetchArrayBuffer()
.then(bufferLoad(model, bufferViewId))
- .otherwise(getFailedLoadFunction(model, 'buffer', bufferResource.url));
+ .otherwise(ModelUtility.getFailedLoadFunction(model, 'buffer', bufferResource.url));
}
});
}
@@ -1512,7 +1496,7 @@ define([
shaderResource.fetchText()
.then(shaderLoad(model, shader.type, id))
- .otherwise(getFailedLoadFunction(model, 'shader', shaderResource.url));
+ .otherwise(ModelUtility.getFailedLoadFunction(model, 'shader', shaderResource.url));
}
});
}
@@ -1632,7 +1616,7 @@ define([
} else {
promise = imageResource.fetchImage();
}
- promise.then(imageLoad(model, id, imageId)).otherwise(getFailedLoadFunction(model, 'image', imageResource.url));
+ promise.then(imageLoad(model, id, imageId)).otherwise(ModelUtility.getFailedLoadFunction(model, 'image', imageResource.url));
}
});
}
@@ -2134,7 +2118,7 @@ define([
var bufferView = gltf.bufferViews[gltfTexture.bufferView];
var imageId = gltf.textures[gltfTexture.id].source;
- var onerror = getFailedLoadFunction(model, 'image', 'id: ' + gltfTexture.id + ', bufferView: ' + gltfTexture.bufferView);
+ var onerror = ModelUtility.getFailedLoadFunction(model, 'image', 'id: ' + gltfTexture.id + ', bufferView: ' + gltfTexture.bufferView);
if (gltfTexture.mimeType === 'image/ktx') {
loadKTX(loadResources.getBuffer(bufferView)).then(imageLoad(model, gltfTexture.id, imageId)).otherwise(onerror);
@@ -4168,7 +4152,7 @@ define([
if (!loadResources.finishedDecoding()) {
DracoLoader.decodeModel(this, context)
- .otherwise(getFailedLoadFunction(this, 'model', this.basePath));
+ .otherwise(ModelUtility.getFailedLoadFunction(this, 'model', this.basePath));
}
if (loadResources.finishedDecoding() && !loadResources.resourcesParsed) {
diff --git a/Source/Scene/ModelUtility.js b/Source/Scene/ModelUtility.js
index d288f7e3e329..fdaf779935a4 100644
--- a/Source/Scene/ModelUtility.js
+++ b/Source/Scene/ModelUtility.js
@@ -3,6 +3,7 @@ define([
'../Core/Cartesian3',
'../Core/Cartesian4',
'../Core/clone',
+ '../Core/defaultValue',
'../Core/defined',
'../Core/defineProperties',
'../Core/Matrix2',
@@ -21,6 +22,7 @@ define([
Cartesian3,
Cartesian4,
clone,
+ defaultValue,
defined,
defineProperties,
Matrix2,
@@ -171,6 +173,41 @@ define([
return type.toLowerCase();
};
+ ModelUtility.ModelState = {
+ NEEDS_LOAD: 0,
+ LOADING: 1,
+ LOADED: 2, // Renderable, but textures can still be pending when incrementallyLoadTextures is true.
+ FAILED: 3
+ };
+
+ ModelUtility.getFailedLoadFunction = function(model, type, path) {
+ return function(error) {
+ model._state = ModelUtility.ModelState.FAILED;
+ var message = 'Failed to load ' + type + ': ' + path;
+ if (defined(error)) {
+ message += '\n' + error.message;
+ }
+ model._readyPromise.reject(new RuntimeError(message));
+ };
+ };
+
+ ModelUtility.parseBuffers = function(model, bufferLoad) {
+ var loadResources = model._loadResources;
+ ForEach.buffer(model.gltf, function(buffer, bufferViewId) {
+ if (defined(buffer.extras._pipeline.source)) {
+ loadResources.buffers[bufferViewId] = buffer.extras._pipeline.source;
+ } else {
+ var bufferResource = model._resource.getDerivedResource({
+ url: buffer.uri
+ });
+ ++loadResources.pendingBufferLoads;
+ bufferResource.fetchArrayBuffer()
+ .then(bufferLoad(model, bufferViewId))
+ .otherwise(ModelUtility.getFailedLoadFunction(model, 'buffer', bufferResource.url));
+ }
+ });
+ };
+
function techniqueAttributeForSemantic(technique, semantic) {
return ForEach.techniqueAttribute(technique, function(attribute, attributeName) {
if (attribute.semantic === semantic) {
From 1e5d67f8e0a13acaae44893aa0439c922fa62a3a Mon Sep 17 00:00:00 2001
From: ggetz
Date: Fri, 3 Aug 2018 10:20:09 -0400
Subject: [PATCH 08/52] Various gltf cleanup
---
Source/Scene/ClassificationModel.js | 89 +++----------------------
Source/Scene/Model.js | 77 +--------------------
Source/Scene/ModelInstanceCollection.js | 2 +-
Source/Scene/ModelUtility.js | 82 ++++++++++++++++++++++-
4 files changed, 93 insertions(+), 157 deletions(-)
diff --git a/Source/Scene/ClassificationModel.js b/Source/Scene/ClassificationModel.js
index 55fd00a76503..e901d252799e 100644
--- a/Source/Scene/ClassificationModel.js
+++ b/Source/Scene/ClassificationModel.js
@@ -15,7 +15,6 @@ define([
'../Core/IndexDatatype',
'../Core/Matrix4',
'../Core/PrimitiveType',
- '../Core/Resource',
'../Core/RuntimeError',
'../Core/Transforms',
'../Core/WebGLConstants',
@@ -52,7 +51,6 @@ define([
IndexDatatype,
Matrix4,
PrimitiveType,
- Resource,
RuntimeError,
Transforms,
WebGLConstants,
@@ -96,17 +94,15 @@ define([
* @private
*
* @param {Object} [options] Object with the following properties:
- * @param {Object|ArrayBuffer|Uint8Array} options.gltf The object for the glTF JSON or an arraybuffer of Binary glTF defined by the KHR_binary_glTF extension.
- * @param {Resource|String} [options.basePath=''] The base path that paths in the glTF JSON are relative to.
+ * @param {ArrayBuffer|Uint8Array} [options.gltf] A binary glTF buffer.
* @param {Boolean} [options.show=true] Determines if the model primitive will be shown.
* @param {Matrix4} [options.modelMatrix=Matrix4.IDENTITY] The 4x4 transformation matrix that transforms the model from model to world coordinates.
* @param {Boolean} [options.debugShowBoundingVolume=false] For debugging only. Draws the bounding sphere for each draw command in the model.
* @param {Boolean} [options.debugWireframe=false] For debugging only. Draws the model in wireframe.
* @param {ClassificationType} [options.classificationType] What this model will classify.
*
- * @exception {DeveloperError} bgltf is not a valid Binary glTF file.
- * @exception {DeveloperError} Only glTF Binary version 1 is supported.
* @exception {RuntimeError} Only binary glTF is supported.
+ * @exception {RuntimeError} Buffer data must be embedded in the binary glTF.
* @exception {RuntimeError} Only one node is supported for classification and it must have a mesh.
* @exception {RuntimeError} Only one mesh is supported when using b3dm for classification.
* @exception {RuntimeError} Only one primitive per mesh is supported when using b3dm for classification.
@@ -122,7 +118,7 @@ define([
}
if (gltf instanceof Uint8Array) {
- // Binary glTF
+ // Parse and update binary glTF
gltf = parseGlb(gltf);
updateVersion(gltf);
addDefaults(gltf);
@@ -132,6 +128,12 @@ define([
throw new RuntimeError('Only binary glTF is supported as a classifier.');
}
+ ForEach.buffer(gltf, function(buffer) {
+ if (!defined(buffer.extras._pipeline.source)) {
+ throw new RuntimeError('Buffer data must be embedded in the binary gltf.');
+ }
+ });
+
var gltfNodes = gltf.nodes;
var gltfMeshes = gltf.meshes;
@@ -162,9 +164,6 @@ define([
this._gltf = gltf;
- var basePath = defaultValue(options.basePath, '');
- this._resource = Resource.createIfNeeded(basePath);
-
/**
* Determines if the model primitive will be shown.
*
@@ -282,26 +281,6 @@ define([
}
},
- /**
- * The base path that paths in the glTF JSON are relative to. The base
- * path is the same path as the path containing the .gltf file
- * minus the .gltf file, when binary, image, and shader files are
- * in the same directory as the .gltf. When this is
''
,
- * the app's base path is used.
- *
- * @memberof ClassificationModel.prototype
- *
- * @type {String}
- * @readonly
- *
- * @default ''
- */
- basePath : {
- get : function() {
- return this._resource.url;
- }
- },
-
/**
* The model's bounding sphere in its local coordinate system.
*
@@ -491,43 +470,6 @@ define([
}
});
- var aMinScratch = new Cartesian3();
- var aMaxScratch = new Cartesian3();
-
- function computeBoundingSphere(model) {
- var gltf = model.gltf;
- var gltfNodes = gltf.nodes;
- var gltfMeshes = gltf.meshes;
-
- var min = new Cartesian3(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE);
- var max = new Cartesian3(-Number.MAX_VALUE, -Number.MAX_VALUE, -Number.MAX_VALUE);
-
- var n = gltfNodes[0];
- var meshId = n.mesh;
-
- var transformToRoot = ModelUtility.getTransform(n);
- var mesh = gltfMeshes[meshId];
- var primitive = mesh.primitives[0];
- var positionAccessor = primitive.attributes.POSITION;
- var minMax = ModelUtility.getAccessorMinMax(gltf, positionAccessor);
- var aMin = Cartesian3.fromArray(minMax.min, 0, aMinScratch);
- var aMax = Cartesian3.fromArray(minMax.max, 0, aMaxScratch);
- if (defined(min) && defined(max)) {
- Matrix4.multiplyByPoint(transformToRoot, aMin, aMin);
- Matrix4.multiplyByPoint(transformToRoot, aMax, aMax);
- Cartesian3.minimumByComponent(min, aMin, min);
- Cartesian3.maximumByComponent(max, aMax, max);
- }
-
- var boundingSphere = BoundingSphere.fromCornerPoints(min, max);
- if (model._upAxis === Axis.Y) {
- BoundingSphere.transformWithoutScale(boundingSphere, Axis.Y_UP_TO_Z_UP, boundingSphere);
- } else if (model._upAxis === Axis.X) {
- BoundingSphere.transformWithoutScale(boundingSphere, Axis.X_UP_TO_Z_UP, boundingSphere);
- }
- return boundingSphere;
- }
-
///////////////////////////////////////////////////////////////////////////
function addBuffersToLoadResources(model) {
@@ -538,15 +480,6 @@ define([
});
}
- function bufferLoad(model, id) {
- return function(arrayBuffer) {
- var loadResources = model._loadResources;
- var buffer = new Uint8Array(arrayBuffer);
- --loadResources.pendingBufferLoads;
- model.gltf.buffers[id].extras._pipeline.source = buffer;
- };
- }
-
function parseBufferViews(model) {
var bufferViews = model.gltf.bufferViews;
@@ -1047,7 +980,7 @@ define([
}
this._loadResources = new ModelLoadResources();
- ModelUtility.parseBuffers(this, bufferLoad);
+ ModelUtility.parseBuffers(this);
}
}
@@ -1063,7 +996,7 @@ define([
addBuffersToLoadResources(this);
parseBufferViews(this);
- this._boundingSphere = computeBoundingSphere(this);
+ this._boundingSphere = ModelUtility.computeBoundingSphere(this);
this._initialRadius = this._boundingSphere.radius;
createResources(this, frameState);
}
diff --git a/Source/Scene/Model.js b/Source/Scene/Model.js
index 6cc8b8ef9339..0b8fc1249a5f 100644
--- a/Source/Scene/Model.js
+++ b/Source/Scene/Model.js
@@ -1221,8 +1221,7 @@ define([
if (containsGltfMagic(array)) {
// Load binary glTF
var parsedGltf = parseGlb(array);
- // KHR_binary_glTF is from the beginning of the binary section
- cachedGltf.makeReady(parsedGltf, array);
+ cachedGltf.makeReady(parsedGltf);
} else {
// Load text (JSON) glTF
var json = getStringFromTypedArray(array);
@@ -1305,78 +1304,6 @@ define([
return getRuntime(this, 'materialsByName', name);
};
- var aMinScratch = new Cartesian3();
- var aMaxScratch = new Cartesian3();
-
- function computeBoundingSphere(model) {
- var gltf = model.gltf;
- var gltfNodes = gltf.nodes;
- var gltfMeshes = gltf.meshes;
- var rootNodes = gltf.scenes[gltf.scene].nodes;
- var rootNodesLength = rootNodes.length;
-
- var nodeStack = [];
-
- var min = new Cartesian3(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE);
- var max = new Cartesian3(-Number.MAX_VALUE, -Number.MAX_VALUE, -Number.MAX_VALUE);
-
- for (var i = 0; i < rootNodesLength; ++i) {
- var n = gltfNodes[rootNodes[i]];
- n._transformToRoot = ModelUtility.getTransform(n);
- nodeStack.push(n);
-
- while (nodeStack.length > 0) {
- n = nodeStack.pop();
- var transformToRoot = n._transformToRoot;
-
- var meshId = n.mesh;
- if (defined(meshId)) {
- var mesh = gltfMeshes[meshId];
- var primitives = mesh.primitives;
- var primitivesLength = primitives.length;
- for (var m = 0; m < primitivesLength; ++m) {
- var positionAccessor = primitives[m].attributes.POSITION;
- if (defined(positionAccessor)) {
- var minMax = ModelUtility.getAccessorMinMax(gltf, positionAccessor);
- var aMin = Cartesian3.fromArray(minMax.min, 0, aMinScratch);
- var aMax = Cartesian3.fromArray(minMax.max, 0, aMaxScratch);
- if (defined(min) && defined(max)) {
- Matrix4.multiplyByPoint(transformToRoot, aMin, aMin);
- Matrix4.multiplyByPoint(transformToRoot, aMax, aMax);
- Cartesian3.minimumByComponent(min, aMin, min);
- Cartesian3.maximumByComponent(max, aMax, max);
- }
- }
- }
- }
-
- var children = n.children;
- if (defined(children)) {
- var childrenLength = children.length;
- for (var k = 0; k < childrenLength; ++k) {
- var child = gltfNodes[children[k]];
- child._transformToRoot = ModelUtility.getTransform(child);
- Matrix4.multiplyTransformation(transformToRoot, child._transformToRoot, child._transformToRoot);
- nodeStack.push(child);
- }
- }
- delete n._transformToRoot;
- }
- }
-
- var boundingSphere = BoundingSphere.fromCornerPoints(min, max);
- if (model._forwardAxis === Axis.Z) {
- // glTF 2.0 has a Z-forward convention that must be adapted here to X-forward.
- BoundingSphere.transformWithoutScale(boundingSphere, Axis.Z_UP_TO_X_UP, boundingSphere);
- }
- if (model._upAxis === Axis.Y) {
- BoundingSphere.transformWithoutScale(boundingSphere, Axis.Y_UP_TO_Z_UP, boundingSphere);
- } else if (model._upAxis === Axis.X) {
- BoundingSphere.transformWithoutScale(boundingSphere, Axis.X_UP_TO_Z_UP, boundingSphere);
- }
- return boundingSphere;
- }
-
///////////////////////////////////////////////////////////////////////////
function addBuffersToLoadResources(model) {
@@ -4156,7 +4083,7 @@ define([
}
if (loadResources.finishedDecoding() && !loadResources.resourcesParsed) {
- this._boundingSphere = computeBoundingSphere(this);
+ this._boundingSphere = ModelUtility.computeBoundingSphere(this);
this._initialRadius = this._boundingSphere.radius;
DracoLoader.cacheDataForModel(this);
diff --git a/Source/Scene/ModelInstanceCollection.js b/Source/Scene/ModelInstanceCollection.js
index 678dd4c0251b..b22041fccdd2 100644
--- a/Source/Scene/ModelInstanceCollection.js
+++ b/Source/Scene/ModelInstanceCollection.js
@@ -78,7 +78,7 @@ define([
* @param {Cesium3DTileBatchTable} [options.batchTable] The batch table of the instanced 3D Tile.
* @param {Resource|String} [options.url] The url to the .gltf file.
* @param {Object} [options.requestType] The request type, used for request prioritization
- * @param {Object|ArrayBuffer|Uint8Array} [options.gltf] The object for the glTF JSON or an arraybuffer of Binary glTF defined by the CESIUM_binary_glTF extension.
+ * @param {Object|ArrayBuffer|Uint8Array} [options.gltf] A glTF JSON object, or a binary glTF buffer.
* @param {Resource|String} [options.basePath=''] The base path that paths in the glTF JSON are relative to.
* @param {Boolean} [options.dynamic=false] Hint if instance model matrices will be updated frequently.
* @param {Boolean} [options.show=true] Determines if the collection will be shown.
diff --git a/Source/Scene/ModelUtility.js b/Source/Scene/ModelUtility.js
index fdaf779935a4..fad33f2fa3c2 100644
--- a/Source/Scene/ModelUtility.js
+++ b/Source/Scene/ModelUtility.js
@@ -1,4 +1,5 @@
define([
+ '../Core/BoundingSphere',
'../Core/Cartesian2',
'../Core/Cartesian3',
'../Core/Cartesian4',
@@ -16,8 +17,10 @@ define([
'../ThirdParty/GltfPipeline/addToArray',
'../ThirdParty/GltfPipeline/ForEach',
'../ThirdParty/GltfPipeline/hasExtension',
- './AttributeType'
+ './AttributeType',
+ './Axis'
], function(
+ BoundingSphere,
Cartesian2,
Cartesian3,
Cartesian4,
@@ -35,7 +38,8 @@ define([
addToArray,
ForEach,
hasExtension,
- AttributeType) {
+ AttributeType,
+ Axis) {
'use strict';
/**
@@ -196,7 +200,7 @@ define([
ForEach.buffer(model.gltf, function(buffer, bufferViewId) {
if (defined(buffer.extras._pipeline.source)) {
loadResources.buffers[bufferViewId] = buffer.extras._pipeline.source;
- } else {
+ } else if (defined(bufferLoad)) {
var bufferResource = model._resource.getDerivedResource({
url: buffer.uri
});
@@ -208,6 +212,78 @@ define([
});
};
+ var aMinScratch = new Cartesian3();
+ var aMaxScratch = new Cartesian3();
+
+ ModelUtility.computeBoundingSphere = function(model) {
+ var gltf = model.gltf;
+ var gltfNodes = gltf.nodes;
+ var gltfMeshes = gltf.meshes;
+ var rootNodes = gltf.scenes[gltf.scene].nodes;
+ var rootNodesLength = rootNodes.length;
+
+ var nodeStack = [];
+
+ var min = new Cartesian3(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE);
+ var max = new Cartesian3(-Number.MAX_VALUE, -Number.MAX_VALUE, -Number.MAX_VALUE);
+
+ for (var i = 0; i < rootNodesLength; ++i) {
+ var n = gltfNodes[rootNodes[i]];
+ n._transformToRoot = ModelUtility.getTransform(n);
+ nodeStack.push(n);
+
+ while (nodeStack.length > 0) {
+ n = nodeStack.pop();
+ var transformToRoot = n._transformToRoot;
+
+ var meshId = n.mesh;
+ if (defined(meshId)) {
+ var mesh = gltfMeshes[meshId];
+ var primitives = mesh.primitives;
+ var primitivesLength = primitives.length;
+ for (var m = 0; m < primitivesLength; ++m) {
+ var positionAccessor = primitives[m].attributes.POSITION;
+ if (defined(positionAccessor)) {
+ var minMax = ModelUtility.getAccessorMinMax(gltf, positionAccessor);
+ var aMin = Cartesian3.fromArray(minMax.min, 0, aMinScratch);
+ var aMax = Cartesian3.fromArray(minMax.max, 0, aMaxScratch);
+ if (defined(min) && defined(max)) {
+ Matrix4.multiplyByPoint(transformToRoot, aMin, aMin);
+ Matrix4.multiplyByPoint(transformToRoot, aMax, aMax);
+ Cartesian3.minimumByComponent(min, aMin, min);
+ Cartesian3.maximumByComponent(max, aMax, max);
+ }
+ }
+ }
+ }
+
+ var children = n.children;
+ if (defined(children)) {
+ var childrenLength = children.length;
+ for (var k = 0; k < childrenLength; ++k) {
+ var child = gltfNodes[children[k]];
+ child._transformToRoot = ModelUtility.getTransform(child);
+ Matrix4.multiplyTransformation(transformToRoot, child._transformToRoot, child._transformToRoot);
+ nodeStack.push(child);
+ }
+ }
+ delete n._transformToRoot;
+ }
+ }
+
+ var boundingSphere = BoundingSphere.fromCornerPoints(min, max);
+ if (model._forwardAxis === Axis.Z) {
+ // glTF 2.0 has a Z-forward convention that must be adapted here to X-forward.
+ BoundingSphere.transformWithoutScale(boundingSphere, Axis.Z_UP_TO_X_UP, boundingSphere);
+ }
+ if (model._upAxis === Axis.Y) {
+ BoundingSphere.transformWithoutScale(boundingSphere, Axis.Y_UP_TO_Z_UP, boundingSphere);
+ } else if (model._upAxis === Axis.X) {
+ BoundingSphere.transformWithoutScale(boundingSphere, Axis.X_UP_TO_Z_UP, boundingSphere);
+ }
+ return boundingSphere;
+ };
+
function techniqueAttributeForSemantic(technique, semantic) {
return ForEach.techniqueAttribute(technique, function(attribute, attributeName) {
if (attribute.semantic === semantic) {
From 6de38fe6a2e3a017ed5c99797ad08e6636dcc4ed Mon Sep 17 00:00:00 2001
From: ggetz
Date: Fri, 3 Aug 2018 14:30:30 -0400
Subject: [PATCH 09/52] alphaCutoff uniform, attribute location fix
---
Source/Scene/Model.js | 21 +++++++++++++++------
Source/Scene/ModelUtility.js | 4 +++-
Source/Scene/processPbrMetallicRoughness.js | 19 ++++++++++++-------
3 files changed, 30 insertions(+), 14 deletions(-)
diff --git a/Source/Scene/Model.js b/Source/Scene/Model.js
index 0b8fc1249a5f..5193b32388a3 100644
--- a/Source/Scene/Model.js
+++ b/Source/Scene/Model.js
@@ -27,7 +27,6 @@ define([
'../Core/PrimitiveType',
'../Core/Quaternion',
'../Core/Resource',
- '../Core/RuntimeError',
'../Core/Transforms',
'../Core/WebGLConstants',
'../Renderer/Buffer',
@@ -100,7 +99,6 @@ define([
PrimitiveType,
Quaternion,
Resource,
- RuntimeError,
Transforms,
WebGLConstants,
Buffer,
@@ -2535,7 +2533,7 @@ define([
}
var enableCulling = !material.doubleSided;
- var blendingEnabled = (material.alphaMode === 'BLEND');
+ var blendingEnabled = (material.alphaMode !== 'OPAQUE');
rendererRenderStates[materialId] = RenderState.fromCache({
cull : {
enabled : enableCulling
@@ -2659,7 +2657,7 @@ define([
return gltfUniformsFromNode[semantic](uniformState, model, runtimeNode);
}
- function createUniformsForMaterial(model, technique, instanceValues, context, textures, defaultTexture) {
+ function createUniformsForMaterial(model, material, technique, instanceValues, context, textures, defaultTexture) {
var uniformMap = {};
var uniformValues = {};
var jointMatrixUniformName;
@@ -2677,9 +2675,10 @@ define([
//
// https://github.com/KhronosGroup/glTF/issues/142
+ var uv;
if (defined(instanceValues[uniformName])) {
// Parameter overrides by the instance technique
- var uv = ModelUtility.createUniformFunction(uniform.type, instanceValues[uniformName], textures, defaultTexture);
+ uv = ModelUtility.createUniformFunction(uniform.type, instanceValues[uniformName], textures, defaultTexture);
uniformMap[uniformName] = uv.func;
uniformValues[uniformName] = uv;
} else if (defined(uniform.node)) {
@@ -2689,6 +2688,16 @@ define([
jointMatrixUniformName = uniformName;
} else if (uniform.semantic === 'MORPHWEIGHTS') {
morphWeightsUniformName = uniformName;
+ } else if (uniform.semantic === 'ALPHACUTOFF') {
+ // The material's alphaCutoff value uses a uniform with semantic ALPHACUTOFF.
+ // A uniform with this semantic will ignore the instance or default values.
+ var alphaMode = material.alphaMode;
+ if (defined(alphaMode) && alphaMode === 'MASK') {
+ var alphaCutoffValue = defaultValue(material.alphaCutoff, 0.5);
+ uv = ModelUtility.createUniformFunction(uniform.type, alphaCutoffValue, textures, defaultTexture);
+ uniformMap[uniformName] = uv.func;
+ uniformValues[uniformName] = uv;
+ }
} else {
// Map glTF semantic to Cesium automatic uniform
uniformMap[uniformName] = ModelUtility.getGltfSemanticUniforms()[uniform.semantic](context.uniformState, model);
@@ -2733,7 +2742,7 @@ define([
var technique = techniques[modelMaterial._technique];
var instanceValues = modelMaterial._values;
- var uniforms = createUniformsForMaterial(model, technique, instanceValues, context, textures, defaultTexture);
+ var uniforms = createUniformsForMaterial(model, material, technique, instanceValues, context, textures, defaultTexture);
var u = uniformMaps[materialId];
u.uniformMap = uniforms.map; // uniform name -> function for the renderer
diff --git a/Source/Scene/ModelUtility.js b/Source/Scene/ModelUtility.js
index fad33f2fa3c2..bb72b9e76f16 100644
--- a/Source/Scene/ModelUtility.js
+++ b/Source/Scene/ModelUtility.js
@@ -368,6 +368,7 @@ define([
*/
ModelUtility.createAttributeLocations = function(technique, precreatedAttributes) {
var attributeLocations = {};
+ var hasIndex0 = false;
var i = 1;
ForEach.techniqueAttribute(technique, function (attribute, attributeName) {
@@ -375,8 +376,9 @@ define([
// will not work correctly if the 0th attribute is not active. For example, some glTF models
// list the normal attribute first but derived shaders like the cast-shadows shader do not use
// the normal attribute.
- if (/pos/i.test(attributeName)) {
+ if (/pos/i.test(attributeName) && !hasIndex0) {
attributeLocations[attributeName] = 0;
+ hasIndex0 = true;
} else {
attributeLocations[attributeName] = i++;
}
diff --git a/Source/Scene/processPbrMetallicRoughness.js b/Source/Scene/processPbrMetallicRoughness.js
index 9da12afe2f3a..eededb54be8f 100644
--- a/Source/Scene/processPbrMetallicRoughness.js
+++ b/Source/Scene/processPbrMetallicRoughness.js
@@ -40,7 +40,6 @@ define([
// No need to create new techniques if they already exist,
// the shader should handle these values
if (hasExtension(gltf, 'KHR_techniques_webgl')) {
- // TODO: Modify shader values for alphaMode or doubleSided?
return gltf;
}
@@ -198,6 +197,14 @@ define([
};
}
+ var alphaMode = material.alphaMode;
+ if (defined(alphaMode) && alphaMode === 'MASK') {
+ techniqueUniforms.u_alphaCutoff = {
+ semantic: 'ALPHACUTOFF',
+ type: WebGLConstants.FLOAT
+ };
+ }
+
// Add material values
for (uniformName in generatedMaterialValues) {
if (generatedMaterialValues.hasOwnProperty(uniformName)) {
@@ -291,11 +298,11 @@ define([
};
vertexShader += 'attribute vec3 ' + attributeName + ';\n';
if (targetAttribute === 'POSITION') {
- vertexShaderMain += ' weightedPosition += u_morphWeights[' + k + '] * a_' + attributeName + ';\n';
+ vertexShaderMain += ' weightedPosition += u_morphWeights[' + k + '] * ' + attributeName + ';\n';
} else if (targetAttribute === 'NORMAL') {
- vertexShaderMain += ' weightedNormal += u_morphWeights[' + k + '] * a_' + attributeName + ';\n';
+ vertexShaderMain += ' weightedNormal += u_morphWeights[' + k + '] * ' + attributeName + ';\n';
} else if (hasTangents && targetAttribute === 'TANGENT') {
- vertexShaderMain += ' weightedTangent.xyz += u_morphWeights[' + k + '] * a_' + attributeName + ';\n';
+ vertexShaderMain += ' weightedTangent.xyz += u_morphWeights[' + k + '] * ' + attributeName + ';\n';
}
}
}
@@ -630,11 +637,9 @@ define([
// Final color
fragmentShader += ' color = LINEARtoSRGB(color);\n';
- var alphaMode = material.alphaMode;
if (defined(alphaMode)) {
if (alphaMode === 'MASK') {
- var alphaCutoff = defaultValue(material.alphaCutoff, 0.5);
- fragmentShader += ' gl_FragColor = vec4(color, int(baseColorWithAlpha.a >= ' + alphaCutoff + '));\n';
+ fragmentShader += ' gl_FragColor = vec4(color, int(baseColorWithAlpha.a >= u_alphaCutoff));\n';
} else if (alphaMode === 'BLEND') {
fragmentShader += ' gl_FragColor = vec4(color, baseColorWithAlpha.a);\n';
} else {
From 5651d796cf47033a9ecbd33af9d0ab92d045aac5 Mon Sep 17 00:00:00 2001
From: ggetz
Date: Fri, 3 Aug 2018 15:17:48 -0400
Subject: [PATCH 10/52] Update gltf-pipeline
---
Source/ThirdParty/GltfPipeline/addDefaults.js | 8 +-
.../GltfPipeline/addExtensionsRequired.js | 6 +-
.../GltfPipeline/addExtensionsUsed.js | 6 +-
Source/ThirdParty/GltfPipeline/addToArray.js | 16 +++-
.../GltfPipeline/moveTechniquesToExtension.js | 11 ++-
Source/ThirdParty/GltfPipeline/parseGlb.js | 2 +-
.../GltfPipeline/readAccessorPacked.js | 57 ++++++++++++
.../updateAccessorComponentTypes.js | 70 +++++++++++++++
.../ThirdParty/GltfPipeline/updateVersion.js | 87 +++++++++++++++++++
9 files changed, 249 insertions(+), 14 deletions(-)
create mode 100644 Source/ThirdParty/GltfPipeline/readAccessorPacked.js
create mode 100644 Source/ThirdParty/GltfPipeline/updateAccessorComponentTypes.js
diff --git a/Source/ThirdParty/GltfPipeline/addDefaults.js b/Source/ThirdParty/GltfPipeline/addDefaults.js
index 503f3f91b7f7..59063696602c 100644
--- a/Source/ThirdParty/GltfPipeline/addDefaults.js
+++ b/Source/ThirdParty/GltfPipeline/addDefaults.js
@@ -20,11 +20,15 @@ define([
*/
function addDefaults(gltf) {
ForEach.accessor(gltf, function(accessor) {
- accessor.byteOffset = defaultValue(accessor.byteOffset, 0);
+ if (defined(accessor.bufferView)) {
+ accessor.byteOffset = defaultValue(accessor.byteOffset, 0);
+ }
});
ForEach.bufferView(gltf, function(bufferView) {
- bufferView.byteOffset = defaultValue(bufferView.byteOffset, 0);
+ if (defined(bufferView.buffer)) {
+ bufferView.byteOffset = defaultValue(bufferView.byteOffset, 0);
+ }
});
ForEach.mesh(gltf, function(mesh) {
diff --git a/Source/ThirdParty/GltfPipeline/addExtensionsRequired.js b/Source/ThirdParty/GltfPipeline/addExtensionsRequired.js
index 2affd1d2b842..0a01c1197589 100644
--- a/Source/ThirdParty/GltfPipeline/addExtensionsRequired.js
+++ b/Source/ThirdParty/GltfPipeline/addExtensionsRequired.js
@@ -1,8 +1,10 @@
define([
'./addExtensionsUsed',
+ './addToArray',
'../../Core/defined'
], function(
addExtensionsUsed,
+ addToArray,
defined) {
'use strict';
@@ -21,9 +23,7 @@ define([
extensionsRequired = [];
gltf.extensionsRequired = extensionsRequired;
}
- if (extensionsRequired.indexOf(extension) === -1) {
- extensionsRequired.push(extension);
- }
+ addToArray(extensionsRequired, extension, true);
addExtensionsUsed(gltf, extension);
}
diff --git a/Source/ThirdParty/GltfPipeline/addExtensionsUsed.js b/Source/ThirdParty/GltfPipeline/addExtensionsUsed.js
index a008069cf114..9e7289223e32 100644
--- a/Source/ThirdParty/GltfPipeline/addExtensionsUsed.js
+++ b/Source/ThirdParty/GltfPipeline/addExtensionsUsed.js
@@ -1,6 +1,8 @@
define([
+ './addToArray',
'../../Core/defined'
], function(
+ addToArray,
defined) {
'use strict';
@@ -19,9 +21,7 @@ define([
extensionsUsed = [];
gltf.extensionsUsed = extensionsUsed;
}
- if (extensionsUsed.indexOf(extension) === -1) {
- extensionsUsed.push(extension);
- }
+ addToArray(extensionsUsed, extension, true);
}
return addExtensionsUsed;
diff --git a/Source/ThirdParty/GltfPipeline/addToArray.js b/Source/ThirdParty/GltfPipeline/addToArray.js
index 78e347799ba6..26d677311328 100644
--- a/Source/ThirdParty/GltfPipeline/addToArray.js
+++ b/Source/ThirdParty/GltfPipeline/addToArray.js
@@ -1,4 +1,7 @@
-define([], function() {
+define([
+ '../../Core/defaultValue'
+ ], function(
+ defaultValue) {
'use strict';
/**
@@ -6,10 +9,19 @@ define([], function() {
*
* @param {Array} array The array to add to.
* @param {Object} element The element to add.
+ * @param {Boolean} [checkDuplicates=false] When true
, if a duplicate element is found its index is returned and element
is not added to the array.
*
* @private
*/
- function addToArray(array, element) {
+ function addToArray(array, element, checkDuplicates) {
+ checkDuplicates = defaultValue(checkDuplicates, false);
+ if (checkDuplicates) {
+ var index = array.indexOf(element);
+ if (index > -1) {
+ return index;
+ }
+ }
+
array.push(element);
return array.length - 1;
}
diff --git a/Source/ThirdParty/GltfPipeline/moveTechniquesToExtension.js b/Source/ThirdParty/GltfPipeline/moveTechniquesToExtension.js
index 35b4ff1124dd..cdb2eb81b676 100644
--- a/Source/ThirdParty/GltfPipeline/moveTechniquesToExtension.js
+++ b/Source/ThirdParty/GltfPipeline/moveTechniquesToExtension.js
@@ -31,6 +31,10 @@ define([
techniques: []
};
+ // Some 1.1 models have a glExtensionsUsed property that can be transferred to program.glExtensions
+ var glExtensions = gltf.glExtensionsUsed;
+ delete gltf.glExtensionsUsed;
+
ForEach.technique(gltf, function (techniqueLegacy, techniqueIndex) {
var technique = {
name: techniqueLegacy.name,
@@ -65,14 +69,15 @@ define([
var program = {
name: programLegacy.name,
fragmentShader: undefined,
- vertexShader: undefined
+ vertexShader: undefined,
+ glExtensions: glExtensions
};
var fs = gltf.shaders[programLegacy.fragmentShader];
- program.fragmentShader = addToArray(extension.shaders, fs);
+ program.fragmentShader = addToArray(extension.shaders, fs, true);
var vs = gltf.shaders[programLegacy.vertexShader];
- program.vertexShader = addToArray(extension.shaders, vs);
+ program.vertexShader = addToArray(extension.shaders, vs, true);
technique.program = addToArray(extension.programs, program);
diff --git a/Source/ThirdParty/GltfPipeline/parseGlb.js b/Source/ThirdParty/GltfPipeline/parseGlb.js
index 07c8c979fbda..530c3c4d10ae 100644
--- a/Source/ThirdParty/GltfPipeline/parseGlb.js
+++ b/Source/ThirdParty/GltfPipeline/parseGlb.js
@@ -21,7 +21,7 @@ define([
/**
* Convert a binary glTF to glTF.
*
- * The returned glTF has pipeline extras included. The binary data is stored in gltf.buffers[0].extras._pipeline.source.
+ * The returned glTF has pipeline extras included. The embedded binary data is stored in gltf.buffers[0].extras._pipeline.source.
*
* @param {Buffer} glb The glb data to parse.
* @returns {Object} A javascript object containing a glTF asset with pipeline extras included.
diff --git a/Source/ThirdParty/GltfPipeline/readAccessorPacked.js b/Source/ThirdParty/GltfPipeline/readAccessorPacked.js
new file mode 100644
index 000000000000..4aec00204a50
--- /dev/null
+++ b/Source/ThirdParty/GltfPipeline/readAccessorPacked.js
@@ -0,0 +1,57 @@
+define([
+ './getAccessorByteStride',
+ './getComponentReader',
+ './numberOfComponentsForType',
+ '../../Core/arrayFill',
+ '../../Core/ComponentDatatype',
+ '../../Core/defined'
+ ], function(
+ getAccessorByteStride,
+ getComponentReader,
+ numberOfComponentsForType,
+ arrayFill,
+ ComponentDatatype,
+ defined) {
+ 'use strict';
+
+ /**
+ * Returns the accessor data in a contiguous array.
+ *
+ * @param {Object} gltf A javascript object containing a glTF asset.
+ * @param {Object} accessor The accessor.
+ * @returns {Array} The accessor values in a contiguous array.
+ *
+ * @private
+ */
+ function readAccessorPacked(gltf, accessor) {
+ var byteStride = getAccessorByteStride(gltf, accessor);
+ var componentTypeByteLength = ComponentDatatype.getSizeInBytes(accessor.componentType);
+ var numberOfComponents = numberOfComponentsForType(accessor.type);
+ var count = accessor.count;
+ var values = new Array(numberOfComponents * count);
+
+ if (!defined(accessor.bufferView)) {
+ arrayFill(values, 0);
+ return values;
+ }
+
+ var bufferView = gltf.bufferViews[accessor.bufferView];
+ var source = gltf.buffers[bufferView.buffer].extras._pipeline.source;
+ var byteOffset = accessor.byteOffset + bufferView.byteOffset + source.byteOffset;
+
+ var dataView = new DataView(source.buffer);
+ var components = new Array(numberOfComponents);
+ var componentReader = getComponentReader(accessor.componentType);
+
+ for (var i = 0; i < count; ++i) {
+ componentReader(dataView, byteOffset, numberOfComponents, componentTypeByteLength, components);
+ for (var j = 0; j < numberOfComponents; ++j) {
+ values[i * numberOfComponents + j] = components[j];
+ }
+ byteOffset += byteStride;
+ }
+ return values;
+ }
+
+ return readAccessorPacked;
+});
diff --git a/Source/ThirdParty/GltfPipeline/updateAccessorComponentTypes.js b/Source/ThirdParty/GltfPipeline/updateAccessorComponentTypes.js
new file mode 100644
index 000000000000..9278a3b15963
--- /dev/null
+++ b/Source/ThirdParty/GltfPipeline/updateAccessorComponentTypes.js
@@ -0,0 +1,70 @@
+define([
+ './addToArray',
+ './ForEach',
+ './readAccessorPacked',
+ '../../Core/ComponentDatatype',
+ '../../Core/WebGLConstants'
+ ], function(
+ addToArray,
+ ForEach,
+ readAccessorPacked,
+ ComponentDatatype,
+ WebGLConstants) {
+ 'use strict';
+
+ /**
+ * Update accessors referenced by JOINTS_0 and WEIGHTS_0 attributes to use correct component types.
+ *
+ * @param {Object} gltf A javascript object containing a glTF asset.
+ * @returns {Object} The glTF asset with compressed meshes.
+ *
+ * @private
+ */
+ function updateAccessorComponentTypes(gltf) {
+ var componentType;
+ ForEach.accessorWithSemantic(gltf, 'JOINTS_0', function(accessorId) {
+ var accessor = gltf.accessors[accessorId];
+ componentType = accessor.componentType;
+ if (componentType === WebGLConstants.BYTE) {
+ convertType(gltf, accessor, ComponentDatatype.UNSIGNED_BYTE);
+ } else if (componentType !== WebGLConstants.UNSIGNED_BYTE
+ && componentType !== WebGLConstants.UNSIGNED_SHORT) {
+ convertType(gltf, accessor, ComponentDatatype.UNSIGNED_SHORT);
+ }
+ });
+ ForEach.accessorWithSemantic(gltf, 'WEIGHTS_0', function(accessorId) {
+ var accessor = gltf.accessors[accessorId];
+ componentType = accessor.componentType;
+ if (componentType === WebGLConstants.BYTE) {
+ convertType(gltf, accessor, ComponentDatatype.UNSIGNED_BYTE);
+ } else if (componentType === WebGLConstants.SHORT) {
+ convertType(gltf, accessor, ComponentDatatype.UNSIGNED_SHORT);
+ }
+ });
+
+ return gltf;
+ }
+
+ function convertType(gltf, accessor, updatedComponentType) {
+ var typedArray = ComponentDatatype.createTypedArray(updatedComponentType, readAccessorPacked(gltf, accessor));
+ var newBuffer = new Uint8Array(typedArray.buffer);
+ var newBufferLength = newBuffer.length;
+ var buffer = {
+ byteLength: newBufferLength,
+ extras: {
+ _pipeline: {
+ source: newBuffer
+ }
+ }
+ };
+
+ var bufferId = addToArray(gltf.buffers, buffer);
+ accessor.componentType = updatedComponentType;
+ accessor.bufferView = addToArray(gltf.bufferViews, {
+ buffer: bufferId,
+ byteLength: newBufferLength
+ });
+ }
+
+ return updateAccessorComponentTypes;
+});
diff --git a/Source/ThirdParty/GltfPipeline/updateVersion.js b/Source/ThirdParty/GltfPipeline/updateVersion.js
index c083be681089..569e3d3f8136 100644
--- a/Source/ThirdParty/GltfPipeline/updateVersion.js
+++ b/Source/ThirdParty/GltfPipeline/updateVersion.js
@@ -8,12 +8,15 @@ define([
'./moveTechniqueRenderStates',
'./moveTechniquesToExtension',
'./removeUnusedElements',
+ './updateAccessorComponentTypes',
'../../Core/Cartesian3',
+ '../../Core/Cartesian4',
'../../Core/clone',
'../../Core/ComponentDatatype',
'../../Core/defaultValue',
'../../Core/defined',
'../../Core/isArray',
+ '../../Core/Matrix4',
'../../Core/Quaternion',
'../../Core/WebGLConstants'
], function(
@@ -26,12 +29,15 @@ define([
moveTechniqueRenderStates,
moveTechniquesToExtension,
removeUnusedElements,
+ updateAccessorComponentTypes,
Cartesian3,
+ Cartesian4,
clone,
ComponentDatatype,
defaultValue,
defined,
isArray,
+ Matrix4,
Quaternion,
WebGLConstants) {
'use strict';
@@ -572,6 +578,14 @@ define([
});
}
+ function removeAnimationSamplerNames(gltf) {
+ ForEach.animation(gltf, function(animation) {
+ ForEach.animationSampler(animation, function(sampler) {
+ delete sampler.name;
+ });
+ });
+ }
+
function removeEmptyArrays(gltf) {
for (var topLevelId in gltf) {
if (gltf.hasOwnProperty(topLevelId)) {
@@ -830,6 +844,71 @@ define([
});
}
+ function isNodeEmpty(node) {
+ return (!defined(node.children) || node.children.length === 0) &&
+ (!defined(node.meshes) || node.meshes.length === 0) &&
+ !defined(node.camera) && !defined(node.skin) && !defined(node.skeletons) && !defined(node.jointName) &&
+ (!defined(node.translation) || Cartesian3.fromArray(node.translation).equals(Cartesian3.ZERO)) &&
+ (!defined(node.scale) || Cartesian3.fromArray(node.scale).equals(new Cartesian3(1.0, 1.0, 1.0))) &&
+ (!defined(node.rotation) || Cartesian4.fromArray(node.rotation).equals(new Cartesian4(0.0, 0.0, 0.0, 1.0))) &&
+ (!defined(node.matrix) || Matrix4.fromColumnMajorArray(node.matrix).equals(Matrix4.IDENTITY));
+ }
+
+ function deleteNode(gltf, nodeId) {
+ // Remove from list of nodes in scene
+ ForEach.scene(gltf, function(scene) {
+ var sceneNodes = scene.nodes;
+ if (defined(sceneNodes)) {
+ var sceneNodesLength = sceneNodes.length;
+ for (var i = sceneNodesLength; i >= 0; --i) {
+ if (sceneNodes[i] === nodeId) {
+ sceneNodes.splice(i, 1);
+ return;
+ }
+ }
+ }
+ });
+
+ // Remove parent node's reference to this node, and delete the parent if also empty
+ ForEach.node(gltf, function(parentNode, parentNodeId) {
+ if (defined(parentNode.children)) {
+ var index = parentNode.children.indexOf(nodeId);
+ if (index > -1) {
+ parentNode.children.splice(index, 1);
+
+ if (isNodeEmpty(parentNode)) {
+ deleteNode(gltf, parentNodeId);
+ }
+ }
+ }
+ });
+
+ delete gltf.nodes[nodeId];
+ }
+
+ function removeEmptyNodes(gltf) {
+ ForEach.node(gltf, function(node, nodeId) {
+ if (isNodeEmpty(node)) {
+ deleteNode(gltf, nodeId);
+ }
+ });
+
+ return gltf;
+ }
+
+ function requireAnimationAccessorMinMax(gltf) {
+ ForEach.animation(gltf, function(animation) {
+ ForEach.animationSampler(animation, function(sampler) {
+ var accessor = gltf.accessors[sampler.input];
+ if (!defined(accessor.min) || !defined(accessor.max)) {
+ var minMax = findAccessorMinMax(gltf, accessor);
+ accessor.min = minMax.min;
+ accessor.max = minMax.max;
+ }
+ });
+ });
+ }
+
function glTF10to20(gltf) {
gltf.asset = defaultValue(gltf.asset, {});
gltf.asset.version = '2.0';
@@ -837,8 +916,12 @@ define([
updateInstanceTechniques(gltf);
// animation.samplers now refers directly to accessors and animation.parameters should be removed
removeAnimationSamplersIndirection(gltf);
+ // Remove empty nodes and re-assign referencing indices
+ removeEmptyNodes(gltf);
// Top-level objects are now arrays referenced by index instead of id
objectsToArrays(gltf);
+ // Animation.sampler objects cannot have names
+ removeAnimationSamplerNames(gltf);
// asset.profile no longer exists
stripAsset(gltf);
// Move known extensions from extensionsUsed to extensionsRequired
@@ -849,6 +932,8 @@ define([
moveByteStrideToBufferView(gltf);
// accessor.min and accessor.max must be defined for accessors containing POSITION attributes
requirePositionAccessorMinMax(gltf);
+ // An animation sampler's input accessor must have min and max properties defined
+ requireAnimationAccessorMinMax(gltf);
// buffer.type is unnecessary and should be removed
removeBufferType(gltf);
// Remove format, internalFormat, target, and type
@@ -857,6 +942,8 @@ define([
requireAttributeSetIndex(gltf);
// Add underscores to application-specific parameters
underscoreApplicationSpecificSemantics(gltf);
+ // Accessors referenced by JOINTS_0 and WEIGHTS_0 attributes must have correct component types
+ updateAccessorComponentTypes(gltf);
// Clamp camera parameters
clampCameraParameters(gltf);
// Move legacy technique render states to material properties and add KHR_blend extension blending functions
From c098115a5370a29b8db78761400bc29995c124ed Mon Sep 17 00:00:00 2001
From: ggetz
Date: Mon, 20 Aug 2018 14:59:17 -0400
Subject: [PATCH 11/52] Update pipeline, resolve material errors
---
Source/Scene/Model.js | 1 +
Source/Scene/ModelUtility.js | 27 ++++++--------
Source/Scene/processModelMaterialsCommon.js | 36 ++++++++-----------
Source/Scene/processPbrMetallicRoughness.js | 9 ++---
Source/ThirdParty/GltfPipeline/addBuffer.js | 35 ++++++++++++++++++
Source/ThirdParty/GltfPipeline/addDefaults.js | 13 +++++++
.../updateAccessorComponentTypes.js | 21 +++--------
7 files changed, 83 insertions(+), 59 deletions(-)
create mode 100644 Source/ThirdParty/GltfPipeline/addBuffer.js
diff --git a/Source/Scene/Model.js b/Source/Scene/Model.js
index 5193b32388a3..1ff3111d3525 100644
--- a/Source/Scene/Model.js
+++ b/Source/Scene/Model.js
@@ -2541,6 +2541,7 @@ define([
depthTest : {
enabled : true
},
+ depthMask : !blendingEnabled,
blending : {
enabled : blendingEnabled,
equationRgb : blendEquationSeparate[0],
diff --git a/Source/Scene/ModelUtility.js b/Source/Scene/ModelUtility.js
index bb72b9e76f16..822581f4c345 100644
--- a/Source/Scene/ModelUtility.js
+++ b/Source/Scene/ModelUtility.js
@@ -96,10 +96,11 @@ define([
ModelUtility.splitIncompatibleMaterials = function(gltf) {
var accessors = gltf.accessors;
var materials = gltf.materials;
+ var primitiveInfoByMaterial = {};
ForEach.mesh(gltf, function(mesh) {
ForEach.meshPrimitive(mesh, function(primitive) {
- var materialId = primitive.material;
- var material = materials[materialId];
+ var materialIndex = primitive.material;
+ var material = materials[materialIndex];
var jointAccessorId = primitive.attributes.JOINTS_0;
var componentType;
@@ -116,15 +117,9 @@ define([
var hasTangents = defined(primitive.attributes.TANGENT);
var hasTexCoords = defined(primitive.attributes.TEXCOORD_0);
- if (!defined(material.extras) || !defined(material.extras._pipeline)) {
- material.extras = {
- _pipeline: {}
- };
- }
-
- var primitiveInfo = material.extras._pipeline.primitive;
+ var primitiveInfo = primitiveInfoByMaterial[materialIndex];
if (!defined(primitiveInfo)) {
- material.extras._pipeline.primitive = {
+ primitiveInfoByMaterial[materialIndex] = {
skinning: {
skinned: isSkinned,
componentType: componentType,
@@ -148,7 +143,10 @@ define([
// * Uses a different type to store joints and weights
// * Doesn't have vertex colors, morph targets, normals, tangents, or texCoords
var clonedMaterial = clone(material, true);
- clonedMaterial.extras._pipeline.primitive = {
+ // Split this off as a separate material
+ materialIndex = addToArray(materials, clonedMaterial);
+ primitive.material = materialIndex;
+ primitiveInfoByMaterial[materialIndex] = {
skinning: {
skinned: isSkinned,
componentType: componentType,
@@ -160,14 +158,11 @@ define([
hasTangents: hasTangents,
hasTexCoords: hasTexCoords
};
- // Split this off as a separate material
- materialId = addToArray(materials, clonedMaterial);
- primitive.material = materialId;
}
});
});
- return gltf;
+ return primitiveInfoByMaterial;
};
ModelUtility.getShaderVariable = function(type) {
@@ -502,7 +497,7 @@ define([
ModelUtility.supportedExtensions = {
'CESIUM_RTC' : true,
- 'EXT_blend' : true,
+ 'KHR_blend' : true,
'KHR_binary_glTF' : true,
'KHR_draco_mesh_compression' : true,
'KHR_materials_common' : true,
diff --git a/Source/Scene/processModelMaterialsCommon.js b/Source/Scene/processModelMaterialsCommon.js
index 7a1a5cbcfb7c..8212ee78f6fa 100644
--- a/Source/Scene/processModelMaterialsCommon.js
+++ b/Source/Scene/processModelMaterialsCommon.js
@@ -50,15 +50,16 @@ define([
var lightParameters = generateLightParameters(gltf);
- ModelUtility.splitIncompatibleMaterials (gltf);
+ var primitiveByMaterial = ModelUtility.splitIncompatibleMaterials(gltf);
var techniques = {};
- ForEach.material(gltf, function(material) {
+ ForEach.material(gltf, function(material, materialIndex) {
if (defined(material.extensions) && defined(material.extensions.KHR_materials_common)) {
var khrMaterialsCommon = material.extensions.KHR_materials_common;
- var techniqueKey = getTechniqueKey(material, khrMaterialsCommon);
+ var primitiveInfo = primitiveByMaterial[materialIndex];
+
+ var techniqueKey = getTechniqueKey(khrMaterialsCommon, primitiveInfo);
var technique = techniques[techniqueKey];
- var primitiveInfo = material.extras._pipeline.primitive;
if (!defined(technique)) {
technique = generateTechnique(gltf, techniquesWebgl, primitiveInfo, khrMaterialsCommon, lightParameters, options.addBatchIdToGeneratedShaders);
@@ -80,20 +81,12 @@ define([
values: materialValues
};
+ material.alphaMode = 'OPAQUE';
if (khrMaterialsCommon.transparent) {
material.alphaMode = 'BLEND';
- material.extensions.KHR_blend = {
- blendFactors: [
- WebGLConstants.ONE,
- WebGLConstants.ONE_MINUS_SRC_ALPHA,
- WebGLConstants.ONE,
- WebGLConstants.ONE_MINUS_SRC_ALPHA
- ]
- };
- if (!hasExtension(gltf, 'KHR_blend')) {
- gltf.extensions.push('KHR_blend');
- }
- } else if (khrMaterialsCommon.doubleSided) {
+ }
+
+ if (khrMaterialsCommon.doubleSided) {
material.doubleSided = true;
}
}
@@ -580,10 +573,10 @@ define([
finalColorComputation = ' gl_FragColor = vec4(color * diffuse.a, diffuse.a);\n';
}
} else if (defined(techniqueUniforms.u_transparency)) {
- finalColorComputation = ' gl_FragColor = vec4(color * u_transparency, u_transparency);\n';
- } else {
- finalColorComputation = ' gl_FragColor = vec4(color, 1.0);\n';
- }
+ finalColorComputation = ' gl_FragColor = vec4(color * u_transparency, u_transparency);\n';
+ } else {
+ finalColorComputation = ' gl_FragColor = vec4(color, 1.0);\n';
+ }
if (hasVertexColors) {
colorCreationBlock += ' color *= v_vertexColor.rgb;\n';
@@ -692,7 +685,7 @@ define([
}
}
- function getTechniqueKey(material, khrMaterialsCommon) {
+ function getTechniqueKey(khrMaterialsCommon, primitiveInfo) {
var techniqueKey = '';
techniqueKey += 'technique:' + khrMaterialsCommon.technique + ';';
@@ -709,7 +702,6 @@ define([
var jointCount = defaultValue(khrMaterialsCommon.jointCount, 0);
techniqueKey += jointCount.toString() + ';';
- var primitiveInfo = material.extras._pipeline.primitive;
if (defined(primitiveInfo)) {
var skinningInfo = primitiveInfo.skinning;
if (jointCount > 0) {
diff --git a/Source/Scene/processPbrMetallicRoughness.js b/Source/Scene/processPbrMetallicRoughness.js
index eededb54be8f..dd351cd40fc3 100644
--- a/Source/Scene/processPbrMetallicRoughness.js
+++ b/Source/Scene/processPbrMetallicRoughness.js
@@ -57,12 +57,12 @@ define([
gltf.extensionsUsed.push('KHR_techniques_webgl');
gltf.extensionsRequired.push('KHR_techniques_webgl');
- ModelUtility.splitIncompatibleMaterials(gltf);
+ var primitiveByMaterial = ModelUtility.splitIncompatibleMaterials(gltf);
ForEach.material(gltf, function(material, materialIndex) {
if (isPbrMaterial(material)) {
var generatedMaterialValues = {};
- var technique = generateTechnique(gltf, material, materialIndex, generatedMaterialValues, options);
+ var technique = generateTechnique(gltf, material, materialIndex, generatedMaterialValues, primitiveByMaterial, options);
if (!defined(material.extensions)) {
material.extensions = {};
@@ -93,7 +93,7 @@ define([
defined(material.doubleSided);
}
- function generateTechnique(gltf, material, materialIndex, generatedMaterialValues, options) {
+ function generateTechnique(gltf, material, materialIndex, generatedMaterialValues, primitiveByMaterial, options) {
var addBatchIdToGeneratedShaders = defaultValue(options.addBatchIdToGeneratedShaders, false);
var techniquesWebgl = gltf.extensions.KHR_techniques_webgl;
@@ -127,7 +127,8 @@ define([
}
var joints = (defined(skin)) ? skin.joints : [];
var jointCount = joints.length;
- var primitiveInfo = material.extras._pipeline.primitive;
+
+ var primitiveInfo = primitiveByMaterial[materialIndex];
var skinningInfo;
var hasSkinning = false;
diff --git a/Source/ThirdParty/GltfPipeline/addBuffer.js b/Source/ThirdParty/GltfPipeline/addBuffer.js
new file mode 100644
index 000000000000..1903f4704258
--- /dev/null
+++ b/Source/ThirdParty/GltfPipeline/addBuffer.js
@@ -0,0 +1,35 @@
+define([
+ './addToArray'
+ ], function(
+ addToArray) {
+ 'use strict';
+
+ /**
+ * Adds buffer to gltf.
+ *
+ * @param {Object} gltf A javascript object containing a glTF asset.
+ * @param {Buffer} buffer A Buffer object which will be added to gltf.buffers.
+ * @returns {Number} The bufferView id of the newly added bufferView.
+ *
+ * @private
+ */
+ function addBuffer(gltf, buffer) {
+ var newBuffer = {
+ byteLength: buffer.length,
+ extras: {
+ _pipeline: {
+ source: buffer
+ }
+ }
+ };
+ var bufferId = addToArray(gltf.buffers, newBuffer);
+ var bufferView = {
+ buffer: bufferId,
+ byteOffset: 0,
+ byteLength: buffer.length
+ };
+ return addToArray(gltf.bufferViews, bufferView);
+ }
+
+ return addBuffer;
+});
diff --git a/Source/ThirdParty/GltfPipeline/addDefaults.js b/Source/ThirdParty/GltfPipeline/addDefaults.js
index 59063696602c..42ba95e83181 100644
--- a/Source/ThirdParty/GltfPipeline/addDefaults.js
+++ b/Source/ThirdParty/GltfPipeline/addDefaults.js
@@ -1,10 +1,12 @@
define([
+ './addToArray',
'./ForEach',
'./getAccessorByteStride',
'../../Core/defaultValue',
'../../Core/defined',
'../../Core/WebGLConstants'
], function(
+ addToArray,
ForEach,
getAccessorByteStride,
defaultValue,
@@ -17,6 +19,8 @@ define([
*
* @param {Object} gltf A javascript object containing a glTF asset.
* @returns {Object} The modified glTF.
+ *
+ * @private
*/
function addDefaults(gltf) {
ForEach.accessor(gltf, function(accessor) {
@@ -34,6 +38,15 @@ define([
ForEach.mesh(gltf, function(mesh) {
ForEach.meshPrimitive(mesh, function(primitive) {
primitive.mode = defaultValue(primitive.mode, WebGLConstants.TRIANGLES);
+ if (!defined(primitive.material)) {
+ if (!defined(gltf.materials)) {
+ gltf.materials = [];
+ }
+ var defaultMaterial = {
+ name: 'default'
+ };
+ primitive.material = addToArray(gltf.materials, defaultMaterial);
+ }
});
});
diff --git a/Source/ThirdParty/GltfPipeline/updateAccessorComponentTypes.js b/Source/ThirdParty/GltfPipeline/updateAccessorComponentTypes.js
index 9278a3b15963..0071dc4bb1a0 100644
--- a/Source/ThirdParty/GltfPipeline/updateAccessorComponentTypes.js
+++ b/Source/ThirdParty/GltfPipeline/updateAccessorComponentTypes.js
@@ -1,11 +1,11 @@
define([
- './addToArray',
+ './addBuffer',
'./ForEach',
'./readAccessorPacked',
'../../Core/ComponentDatatype',
'../../Core/WebGLConstants'
], function(
- addToArray,
+ addBuffer,
ForEach,
readAccessorPacked,
ComponentDatatype,
@@ -48,22 +48,9 @@ define([
function convertType(gltf, accessor, updatedComponentType) {
var typedArray = ComponentDatatype.createTypedArray(updatedComponentType, readAccessorPacked(gltf, accessor));
var newBuffer = new Uint8Array(typedArray.buffer);
- var newBufferLength = newBuffer.length;
- var buffer = {
- byteLength: newBufferLength,
- extras: {
- _pipeline: {
- source: newBuffer
- }
- }
- };
-
- var bufferId = addToArray(gltf.buffers, buffer);
+ accessor.bufferView = addBuffer(gltf, newBuffer);
accessor.componentType = updatedComponentType;
- accessor.bufferView = addToArray(gltf.bufferViews, {
- buffer: bufferId,
- byteLength: newBufferLength
- });
+ accessor.byteOffset = 0;
}
return updateAccessorComponentTypes;
From be83cc2cff733404fbb16a624035b2e10210dedd Mon Sep 17 00:00:00 2001
From: ggetz
Date: Mon, 20 Aug 2018 16:27:08 -0400
Subject: [PATCH 12/52] Remove pipeline extras where possible
---
Source/Scene/Model.js | 54 ++++++++++++++-----------------------------
1 file changed, 17 insertions(+), 37 deletions(-)
diff --git a/Source/Scene/Model.js b/Source/Scene/Model.js
index 1ff3111d3525..037fc93c3e70 100644
--- a/Source/Scene/Model.js
+++ b/Source/Scene/Model.js
@@ -1321,25 +1321,6 @@ define([
};
}
- function parseBuffers(model) {
- var loadResources = model._loadResources;
- ForEach.buffer(model.gltf, function(buffer, bufferViewId) {
- buffer.extras = defaultValue(buffer.extras, {});
- buffer.extras._pipeline = defaultValue(buffer.extras._pipeline, {});
- if (defined(buffer.extras._pipeline.source)) {
- loadResources.buffers[bufferViewId] = buffer.extras._pipeline.source;
- } else {
- var bufferResource = model._resource.getDerivedResource({
- url: buffer.uri
- });
- ++loadResources.pendingBufferLoads;
- bufferResource.fetchArrayBuffer()
- .then(bufferLoad(model, bufferViewId))
- .otherwise(ModelUtility.getFailedLoadFunction(model, 'buffer', bufferResource.url));
- }
- });
- }
-
function parseBufferViews(model) {
var bufferViews = model.gltf.bufferViews;
var vertexBuffersToCreate = model._loadResources.vertexBuffersToCreate;
@@ -1383,7 +1364,7 @@ define([
bufferView : undefined
};
--loadResources.pendingShaderLoads;
- model._sourceShaders[id].extras._pipeline.source = source;
+ model._sourceShaders[id] = source;
};
}
@@ -1391,9 +1372,9 @@ define([
var gltf = model.gltf;
var buffers = gltf.buffers;
var bufferViews = gltf.bufferViews;
- ForEach.shader(gltf, function(sourceShader, id) {
- // retain reference to source shader
- var shader = model._sourceShaders[id] = clone(sourceShader);
+ ForEach.shader(gltf, function(shader, id) {
+ // retain reference to source shader text
+ var sourceShader = model._sourceShaders[id] = clone(shader.extras._pipeline.source);
// Shader references either uri (external or base64-encoded) or bufferView
if (defined(shader.bufferView)) {
@@ -1406,17 +1387,17 @@ define([
source : source,
bufferView : undefined
};
- shader.extras._pipeline.source = source;
- } else if (defined(shader.extras._pipeline.source)) {
+ model._sourceShaders[id] = source;
+ } else if (defined(sourceShader)) {
model._loadResources.shaders[id] = {
- source : shader.extras._pipeline.source,
+ source: sourceShader,
bufferView : undefined
};
} else {
++model._loadResources.pendingShaderLoads;
var shaderResource = model._resource.getDerivedResource({
- url : shader.uri
+ url: shader.uri
});
shaderResource.fetchText()
@@ -1447,9 +1428,8 @@ define([
});
}
- function imageLoad(model, textureId, imageId) {
+ function imageLoad(model, textureId) {
return function(image) {
- var gltf = model.gltf;
var loadResources = model._loadResources;
--loadResources.pendingTextureLoads;
loadResources.texturesToCreate.enqueue({
@@ -1460,7 +1440,6 @@ define([
height : image.height,
internalFormat : image.internalFormat
});
- gltf.images[imageId].extras._pipeline.source = image;
};
}
@@ -1896,8 +1875,8 @@ define([
var program = model._sourcePrograms[programId];
var shaders = model._sourceShaders;
- var vs = shaders[program.vertexShader].extras._pipeline.source;
- var fs = shaders[program.fragmentShader].extras._pipeline.source;
+ var vs = shaders[program.vertexShader];
+ var fs = shaders[program.fragmentShader];
var quantizedVertexShaders = model._quantizedVertexShaders;
var toClipCoordinatesGLSL = model._toClipCoordinatesGLSL[programId];
@@ -1941,8 +1920,8 @@ define([
var clippingPlaneCollection = model.clippingPlanes;
var addClippingPlaneCode = isClippingEnabled(model);
- var vs = shaders[program.vertexShader].extras._pipeline.source;
- var fs = shaders[program.fragmentShader].extras._pipeline.source;
+ var vs = shaders[program.vertexShader];
+ var fs = shaders[program.fragmentShader];
if (model.extensionsUsed.WEB3D_quantized_attributes || model._dequantizeInShader) {
vs = quantizedVertexShaders[programId];
@@ -3164,7 +3143,7 @@ define([
for (var programId in programs) {
if (programs.hasOwnProperty(programId)) {
var program = programs[programId];
- var shader = shaders[program.vertexShader].extras._pipeline.source;
+ var shader = shaders[program.vertexShader];
ModelUtility.checkSupportedGlExtensions(program.glExtensions, context);
@@ -4031,10 +4010,12 @@ define([
}
}
+ addPipelineExtras(this.gltf);
+
this._loadResources = new ModelLoadResources();
if (!this._loadRendererResourcesFromCache) {
// Buffers are required to updateVersion
- parseBuffers(this);
+ ModelUtility.parseBuffers(this, bufferLoad);
}
}
}
@@ -4053,7 +4034,6 @@ define([
ModelUtility.checkSupportedExtensions(this.extensionsRequired);
// glTF pipeline updates
- addPipelineExtras(this.gltf);
updateVersion(this.gltf);
if (this.gltf.extras._pipeline.gltf_pipeline_upgrade_10to20) {
this._forwardAxis = Axis.X;
From 681aa2414d06b5c6564a7ff88acadada7709fe59 Mon Sep 17 00:00:00 2001
From: ggetz
Date: Mon, 27 Aug 2018 13:19:24 -0400
Subject: [PATCH 13/52] Fix model caching, cleanup forward axis, cleanup specs
---
Source/Scene/Model.js | 127 ++++++++-------
Source/Scene/ModelMaterial.js | 6 +-
Source/Scene/ModelUtility.js | 11 ++
Source/Scene/processModelMaterialsCommon.js | 29 +++-
Source/Scene/processPbrMetallicRoughness.js | 6 +
.../Models/BoxWithUnusedMaterial/Box.gltf | 154 ++++++++++++++++++
Specs/Scene/ClassificationModelSpec.js | 42 +++--
Specs/Scene/ModelSpec.js | 55 +++----
8 files changed, 312 insertions(+), 118 deletions(-)
create mode 100644 Specs/Data/Models/BoxWithUnusedMaterial/Box.gltf
diff --git a/Source/Scene/Model.js b/Source/Scene/Model.js
index 037fc93c3e70..40df9e669fee 100644
--- a/Source/Scene/Model.js
+++ b/Source/Scene/Model.js
@@ -607,6 +607,7 @@ define([
buffers : {},
vertexArrays : {},
programs : {},
+ sourceShaders : {},
silhouettePrograms : {},
textures : {},
samplers : {},
@@ -628,7 +629,7 @@ define([
// Hold references for shader reconstruction.
// Hold these separately because _cachedGltf may get released (this.releaseGltfJson)
this._sourceTechniques = {};
- this._sourceShaders = {};
+ this._sourcePrograms = {};
this._quantizedVertexShaders = {};
this._nodeCommands = [];
@@ -1355,6 +1356,27 @@ define([
});
}
+ function parseTechniques(model) {
+ // retain references to gltf techniques
+ var gltf = model.gltf;
+ if (!hasExtension(gltf, 'KHR_techniques_webgl')) {
+ return;
+ }
+
+ var sourcePrograms = model._sourcePrograms;
+ var sourceTechniques = model._sourceTechniques;
+ var programs = gltf.extensions.KHR_techniques_webgl.programs;
+
+ ForEach.technique(gltf, function(technique, techniqueId) {
+ sourceTechniques[techniqueId] = clone(technique);
+
+ var programId = technique.program;
+ if (!defined(sourcePrograms[programId])) {
+ sourcePrograms[programId] = clone(programs[programId]);
+ }
+ });
+ }
+
function shaderLoad(model, type, id) {
return function(source) {
var loadResources = model._loadResources;
@@ -1364,7 +1386,7 @@ define([
bufferView : undefined
};
--loadResources.pendingShaderLoads;
- model._sourceShaders[id] = source;
+ model._rendererResources.sourceShaders[id] = source;
};
}
@@ -1372,10 +1394,8 @@ define([
var gltf = model.gltf;
var buffers = gltf.buffers;
var bufferViews = gltf.bufferViews;
+ var sourceShaders = model._rendererResources.sourceShaders;
ForEach.shader(gltf, function(shader, id) {
- // retain reference to source shader text
- var sourceShader = model._sourceShaders[id] = clone(shader.extras._pipeline.source);
-
// Shader references either uri (external or base64-encoded) or bufferView
if (defined(shader.bufferView)) {
var bufferViewId = shader.bufferView;
@@ -1383,16 +1403,17 @@ define([
var bufferId = bufferView.buffer;
var buffer = buffers[bufferId];
var source = getStringFromTypedArray(buffer.extras._pipeline.source, bufferView.byteOffset, bufferView.byteLength);
- model._loadResources.shaders[id] = {
- source : source,
- bufferView : undefined
- };
- model._sourceShaders[id] = source;
- } else if (defined(sourceShader)) {
- model._loadResources.shaders[id] = {
- source: sourceShader,
- bufferView : undefined
- };
+ // model._loadResources.shaders[id] = {
+ // source : source,
+ // bufferView : undefined
+ // };
+ sourceShaders[id] = source;
+ } else if (defined(shader.extras._pipeline.source)) {
+ // model._loadResources.shaders[id] = {
+ // source: shader.extras._pipeline.source,
+ // bufferView : undefined
+ // };
+ sourceShaders[id] = shader.extras._pipeline.source;
} else {
++model._loadResources.pendingShaderLoads;
@@ -1408,24 +1429,16 @@ define([
}
function parsePrograms(model) {
- var sourcePrograms = model._sourcePrograms = {};
- var gltf = model.gltf;
-
- if (!hasExtension(gltf, 'KHR_techniques_webgl')) {
- return;
- }
-
- var programs = gltf.extensions.KHR_techniques_webgl.programs;
- ForEach.technique(model.gltf, function(technique, techniqueId) {
- var programId = technique.program;
- if (!defined(sourcePrograms[programId])) {
- sourcePrograms[programId] = clone(programs[programId]);
+ var sourceTechniques = model._sourceTechniques;
+ for (var techniqueId in sourceTechniques) {
+ if (sourceTechniques.hasOwnProperty(techniqueId)) {
+ var technique = sourceTechniques[techniqueId];
model._loadResources.programsToCreate.enqueue({
- programId : programId,
- techniqueId : techniqueId
+ programId: technique.program,
+ techniqueId: techniqueId
});
}
- });
+ }
}
function imageLoad(model, textureId) {
@@ -1589,10 +1602,6 @@ define([
var gltf = model.gltf;
var techniques = model._sourceTechniques;
- ForEach.technique(model.gltf, function(technique, index) {
- techniques[index] = clone(technique);
- });
-
var runtimeMaterialsByName = {};
var runtimeMaterialsById = {};
var uniformMaps = model._uniformMaps;
@@ -1873,7 +1882,7 @@ define([
var programId = programToCreate.programId;
var techniqueId = programToCreate.techniqueId;
var program = model._sourcePrograms[programId];
- var shaders = model._sourceShaders;
+ var shaders = model._rendererResources.sourceShaders;
var vs = shaders[program.vertexShader];
var fs = shaders[program.fragmentShader];
@@ -1912,7 +1921,7 @@ define([
var programId = programToCreate.programId;
var techniqueId = programToCreate.techniqueId;
var program = model._sourcePrograms[programId];
- var shaders = model._sourceShaders;
+ var shaders = model._rendererResources.sourceShaders;
var quantizedVertexShaders = model._quantizedVertexShaders;
var toClipCoordinatesGLSL = model._toClipCoordinatesGLSL[programId];
@@ -2656,7 +2665,7 @@ define([
// https://github.com/KhronosGroup/glTF/issues/142
var uv;
- if (defined(instanceValues[uniformName])) {
+ if (defined(instanceValues) && defined(instanceValues[uniformName])) {
// Parameter overrides by the instance technique
uv = ModelUtility.createUniformFunction(uniform.type, instanceValues[uniformName], textures, defaultTexture);
uniformMap[uniformName] = uv.func;
@@ -3133,15 +3142,20 @@ define([
function createResources(model, frameState) {
var context = frameState.context;
var scene3DOnly = frameState.scene3DOnly;
-
- // Retain references to updated source shaders for rebuilding as needed
- var shaders = model._sourceShaders;
-
var quantizedVertexShaders = model._quantizedVertexShaders;
var toClipCoordinates = model._toClipCoordinatesGLSL = {};
+ var techniques = model._sourceTechniques;
var programs = model._sourcePrograms;
- for (var programId in programs) {
- if (programs.hasOwnProperty(programId)) {
+
+ var resources = model._rendererResources;
+ var shaders = resources.sourceShaders;
+ if (model._loadRendererResourcesFromCache) {
+ shaders = resources.sourceShaders = model._cachedRendererResources.sourceShaders;
+ }
+
+ for (var techniqueId in techniques) {
+ if (techniques.hasOwnProperty(techniqueId)) {
+ var programId = techniques[techniqueId].program;
var program = programs[programId];
var shader = shaders[program.vertexShader];
@@ -3162,7 +3176,6 @@ define([
}
if (model._loadRendererResourcesFromCache) {
- var resources = model._rendererResources;
var cachedResources = model._cachedRendererResources;
resources.buffers = cachedResources.buffers;
@@ -3802,6 +3815,7 @@ define([
this.buffers = undefined;
this.vertexArrays = undefined;
this.programs = undefined;
+ this.sourceShaders = undefined;
this.silhouettePrograms = undefined;
this.textures = undefined;
this.samplers = undefined;
@@ -4032,25 +4046,26 @@ define([
frameState.brdfLutGenerator.update(frameState);
ModelUtility.checkSupportedExtensions(this.extensionsRequired);
+ ModelUtility.updateForwardAxis(this);
- // glTF pipeline updates
- updateVersion(this.gltf);
- if (this.gltf.extras._pipeline.gltf_pipeline_upgrade_10to20) {
- this._forwardAxis = Axis.X;
+ // glTF pipeline updates, not needed if loading from cache
+ if (!this._loadRendererResourcesFromCache) {
+ updateVersion(this.gltf);
+ addDefaults(this.gltf);
+
+ var options = {
+ addBatchIdToGeneratedShaders: this._addBatchIdToGeneratedShaders
+ };
+ processModelMaterialsCommon(this.gltf, options);
+ processPbrMetallicRoughness(this.gltf, options);
}
- addDefaults(this.gltf);
-
- var options = {
- addBatchIdToGeneratedShaders: this._addBatchIdToGeneratedShaders
- };
- processModelMaterialsCommon(this.gltf, options);
- processPbrMetallicRoughness(this.gltf, options);
// Skip dequantizing in the shader if not encoded
this._dequantizeInShader = this._dequantizeInShader && DracoLoader.hasExtension(this);
// We do this after to make sure that the ids don't change
addBuffersToLoadResources(this);
+ parseTechniques(this);
if (!this._loadRendererResourcesFromCache) {
parseBufferViews(this);
parseShaders(this);
@@ -4111,6 +4126,7 @@ define([
cachedResources.buffers = resources.buffers;
cachedResources.vertexArrays = resources.vertexArrays;
cachedResources.programs = resources.programs;
+ cachedResources.sourceShaders = resources.sourceShaders;
cachedResources.silhouettePrograms = resources.silhouettePrograms;
cachedResources.textures = resources.textures;
cachedResources.samplers = resources.samplers;
@@ -4430,7 +4446,6 @@ define([
}
releaseCachedGltf(this);
- this._sourceShaders = undefined;
this._quantizedVertexShaders = undefined;
// Only destroy the ClippingPlaneCollection if this is the owner - if this model is part of a Cesium3DTileset,
diff --git a/Source/Scene/ModelMaterial.js b/Source/Scene/ModelMaterial.js
index 4c6fdd81c5b1..5b261a2220c9 100644
--- a/Source/Scene/ModelMaterial.js
+++ b/Source/Scene/ModelMaterial.js
@@ -84,7 +84,8 @@ define([
}
//>>includeEnd('debug');
- var v = this._uniformMap.values[name];
+ var uniformName = 'u_' + name;
+ var v = this._uniformMap.values[uniformName];
//>>includeStart('debug', pragmas.debug);
if (!defined(v)) {
@@ -110,7 +111,8 @@ define([
}
//>>includeEnd('debug');
- var v = this._uniformMap.values[name];
+ var uniformName = 'u_' + name;
+ var v = this._uniformMap.values[uniformName];
if (!defined(v)) {
return undefined;
diff --git a/Source/Scene/ModelUtility.js b/Source/Scene/ModelUtility.js
index 822581f4c345..db5414426975 100644
--- a/Source/Scene/ModelUtility.js
+++ b/Source/Scene/ModelUtility.js
@@ -87,6 +87,17 @@ define([
return gltf;
};
+ /**
+ * Updates the model's forward axis if the model is not a 2.0 model.
+ *
+ * @param {Object} model The model to update.
+ */
+ ModelUtility.updateForwardAxis = function(model) {
+ if (model.gltf.asset.version !== '2.0') {
+ model._forwardAxis = Axis.X;
+ }
+ };
+
/**
* Splits primitive materials with values incompatible for generating techniques.
*
diff --git a/Source/Scene/processModelMaterialsCommon.js b/Source/Scene/processModelMaterialsCommon.js
index 8212ee78f6fa..f27ae921cdc1 100644
--- a/Source/Scene/processModelMaterialsCommon.js
+++ b/Source/Scene/processModelMaterialsCommon.js
@@ -34,7 +34,11 @@ define([
return;
}
- if (!hasExtension('KHR_techniques_webgl')) {
+ if (!hasExtension(gltf, 'KHR_techniques_webgl')) {
+ if (!defined(gltf.extensions)) {
+ gltf.extensions = {};
+ }
+
gltf.extensions.KHR_techniques_webgl = {
programs : [],
shaders : [],
@@ -50,9 +54,10 @@ define([
var lightParameters = generateLightParameters(gltf);
- var primitiveByMaterial = ModelUtility.splitIncompatibleMaterials(gltf);
+ var primitiveByMaterial = ModelUtility.splitIncompatibleMaterials(gltf);
var techniques = {};
+ var generatedTechniques = false;
ForEach.material(gltf, function(material, materialIndex) {
if (defined(material.extensions) && defined(material.extensions.KHR_materials_common)) {
var khrMaterialsCommon = material.extensions.KHR_materials_common;
@@ -64,6 +69,7 @@ define([
if (!defined(technique)) {
technique = generateTechnique(gltf, techniquesWebgl, primitiveInfo, khrMaterialsCommon, lightParameters, options.addBatchIdToGeneratedShaders);
techniques[techniqueKey] = technique;
+ generatedTechniques = true;
}
var materialValues = {};
@@ -92,6 +98,10 @@ define([
}
});
+ if (!generatedTechniques) {
+ return gltf;
+ }
+
// If any primitives have semantics that aren't declared in the generated
// shaders, we want to preserve them.
ModelUtility.ensureSemanticExistence(gltf);
@@ -214,13 +224,20 @@ define([
}
function generateTechnique(gltf, techniquesWebgl, primitiveInfo, khrMaterialsCommon, lightParameters, addBatchIdToGeneratedShaders) {
+ if (!defined(khrMaterialsCommon)) {
+ khrMaterialsCommon = {};
+ }
+
addBatchIdToGeneratedShaders = defaultValue(addBatchIdToGeneratedShaders, false);
var techniques = techniquesWebgl.techniques;
var shaders = techniquesWebgl.shaders;
var programs = techniquesWebgl.programs;
var lightingModel = khrMaterialsCommon.technique.toUpperCase();
- var lights = gltf.extensions.KHR_materials_common.lights;
+ var lights;
+ if (defined(gltf.extensions) && defined(gltf.extensions.KHR_materials_common)) {
+ lights = gltf.extensions.KHR_materials_common.lights;
+ }
var parameterValues = khrMaterialsCommon.values;
var jointCount = defaultValue(khrMaterialsCommon.jointCount, 0);
@@ -715,10 +732,10 @@ define([
function lightDefaults(gltf) {
var khrMaterialsCommon = gltf.extensions.KHR_materials_common;
-
- if (!defined(khrMaterialsCommon.lights)) {
- khrMaterialsCommon.lights = {};
+ if (!defined(khrMaterialsCommon) || !defined(khrMaterialsCommon.lights)) {
+ return;
}
+
var lights = khrMaterialsCommon.lights;
var lightsLength = lights.length;
diff --git a/Source/Scene/processPbrMetallicRoughness.js b/Source/Scene/processPbrMetallicRoughness.js
index dd351cd40fc3..782cd24129e2 100644
--- a/Source/Scene/processPbrMetallicRoughness.js
+++ b/Source/Scene/processPbrMetallicRoughness.js
@@ -45,7 +45,13 @@ define([
if (!defined(gltf.extensions)) {
gltf.extensions = {};
+ }
+
+ if (!defined(gltf.extensionsUsed)) {
gltf.extensionsUsed = [];
+ }
+
+ if (!defined(gltf.extensionsRequired)) {
gltf.extensionsRequired = [];
}
diff --git a/Specs/Data/Models/BoxWithUnusedMaterial/Box.gltf b/Specs/Data/Models/BoxWithUnusedMaterial/Box.gltf
new file mode 100644
index 000000000000..1efe7c0a4d93
--- /dev/null
+++ b/Specs/Data/Models/BoxWithUnusedMaterial/Box.gltf
@@ -0,0 +1,154 @@
+{
+ "asset": {
+ "generator": "COLLADA2GLTF",
+ "version": "2.0"
+ },
+ "scene": 0,
+ "scenes": [
+ {
+ "nodes": [
+ 0
+ ]
+ }
+ ],
+ "nodes": [
+ {
+ "children": [
+ 1
+ ],
+ "matrix": [
+ 1.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ -1.0,
+ 0.0,
+ 0.0,
+ 1.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 1.0
+ ]
+ },
+ {
+ "mesh": 0
+ }
+ ],
+ "meshes": [
+ {
+ "primitives": [
+ {
+ "attributes": {
+ "NORMAL": 1,
+ "POSITION": 2
+ },
+ "indices": 0,
+ "mode": 4,
+ "material": 0
+ }
+ ],
+ "name": "Mesh"
+ }
+ ],
+ "accessors": [
+ {
+ "bufferView": 0,
+ "byteOffset": 0,
+ "componentType": 5123,
+ "count": 36,
+ "max": [
+ 23
+ ],
+ "min": [
+ 0
+ ],
+ "type": "SCALAR"
+ },
+ {
+ "bufferView": 1,
+ "byteOffset": 0,
+ "componentType": 5126,
+ "count": 24,
+ "max": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "min": [
+ -1.0,
+ -1.0,
+ -1.0
+ ],
+ "type": "VEC3"
+ },
+ {
+ "bufferView": 1,
+ "byteOffset": 288,
+ "componentType": 5126,
+ "count": 24,
+ "max": [
+ 0.5,
+ 0.5,
+ 0.5
+ ],
+ "min": [
+ -0.5,
+ -0.5,
+ -0.5
+ ],
+ "type": "VEC3"
+ }
+ ],
+ "materials": [
+ {
+ "pbrMetallicRoughness": {
+ "baseColorFactor": [
+ 0.800000011920929,
+ 0.0,
+ 0.0,
+ 1.0
+ ],
+ "metallicFactor": 0.0
+ },
+ "name": "Red"
+ },
+ {
+ "pbrMetallicRoughness": {
+ "baseColorFactor": [
+ 0.800000011920929,
+ 0.0,
+ 0.0,
+ 1.0
+ ],
+ "metallicFactor": 0.0
+ },
+ "name": "Red"
+ }
+ ],
+ "bufferViews": [
+ {
+ "buffer": 0,
+ "byteOffset": 576,
+ "byteLength": 72,
+ "target": 34963
+ },
+ {
+ "buffer": 0,
+ "byteOffset": 0,
+ "byteLength": 576,
+ "byteStride": 12,
+ "target": 34962
+ }
+ ],
+ "buffers": [
+ {
+ "byteLength": 648,
+ "uri": "data:application/octet-stream;base64,AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAvwAAAL8AAAA/AAAAPwAAAL8AAAA/AAAAvwAAAD8AAAA/AAAAPwAAAD8AAAA/AAAAPwAAAL8AAAA/AAAAvwAAAL8AAAA/AAAAPwAAAL8AAAC/AAAAvwAAAL8AAAC/AAAAPwAAAD8AAAA/AAAAPwAAAL8AAAA/AAAAPwAAAD8AAAC/AAAAPwAAAL8AAAC/AAAAvwAAAD8AAAA/AAAAPwAAAD8AAAA/AAAAvwAAAD8AAAC/AAAAPwAAAD8AAAC/AAAAvwAAAL8AAAA/AAAAvwAAAD8AAAA/AAAAvwAAAL8AAAC/AAAAvwAAAD8AAAC/AAAAvwAAAL8AAAC/AAAAvwAAAD8AAAC/AAAAPwAAAL8AAAC/AAAAPwAAAD8AAAC/AAABAAIAAwACAAEABAAFAAYABwAGAAUACAAJAAoACwAKAAkADAANAA4ADwAOAA0AEAARABIAEwASABEAFAAVABYAFwAWABUA"
+ }
+ ]
+}
diff --git a/Specs/Scene/ClassificationModelSpec.js b/Specs/Scene/ClassificationModelSpec.js
index 019ccb253803..e763546cff76 100644
--- a/Specs/Scene/ClassificationModelSpec.js
+++ b/Specs/Scene/ClassificationModelSpec.js
@@ -20,7 +20,9 @@ defineSuite([
'Scene/Primitive',
'Specs/createScene',
'Specs/pollToPromise',
- 'ThirdParty/GltfPipeline/parseBinaryGltf'
+ 'ThirdParty/GltfPipeline/addDefaults',
+ 'ThirdParty/GltfPipeline/parseGlb',
+ 'ThirdParty/GltfPipeline/updateVersion'
], function(
ClassificationModel,
Cartesian3,
@@ -43,7 +45,9 @@ defineSuite([
Primitive,
createScene,
pollToPromise,
- parseBinaryGltf) {
+ addDefaults,
+ parseGlb,
+ updateVersion) {
'use strict';
var scene;
@@ -59,8 +63,20 @@ defineSuite([
scene.camera.lookAt(center, new HeadingPitchRange(0.0, -1.57, 15.0));
}
+ function loadModel(model) {
+ return Resource.fetchArrayBuffer(model).then(function(arrayBuffer) {
+ var gltf = new Uint8Array(arrayBuffer);
+ gltf = parseGlb(gltf);
+ updateVersion(gltf);
+ addDefaults(gltf);
+ return gltf;
+ });
+ }
+
beforeAll(function() {
scene = createScene();
+
+
});
afterAll(function() {
@@ -186,22 +202,18 @@ defineSuite([
});
it('throws with invalid number of nodes', function() {
- return Resource.fetchArrayBuffer(batchedModel).then(function(arrayBuffer) {
- var gltf = new Uint8Array(arrayBuffer);
- gltf = parseBinaryGltf(gltf);
+ return loadModel(batchedModel).then(function(gltf) {
gltf.nodes.push({});
expect(function() {
return new ClassificationModel({
- gltf : gltf
+ gltf: gltf
});
}).toThrowRuntimeError();
});
});
it('throws with invalid number of meshes', function() {
- return Resource.fetchArrayBuffer(batchedModel).then(function(arrayBuffer) {
- var gltf = new Uint8Array(arrayBuffer);
- gltf = parseBinaryGltf(gltf);
+ return loadModel(batchedModel).then(function(gltf) {
gltf.meshes.push({});
expect(function() {
return new ClassificationModel({
@@ -212,9 +224,7 @@ defineSuite([
});
it('throws with invalid number of primitives', function() {
- return Resource.fetchArrayBuffer(batchedModel).then(function(arrayBuffer) {
- var gltf = new Uint8Array(arrayBuffer);
- gltf = parseBinaryGltf(gltf);
+ return loadModel(batchedModel).then(function(gltf) {
gltf.meshes[0].primitives.push({});
expect(function() {
return new ClassificationModel({
@@ -225,9 +235,7 @@ defineSuite([
});
it('throws with position semantic', function() {
- return Resource.fetchArrayBuffer(batchedModel).then(function(arrayBuffer) {
- var gltf = new Uint8Array(arrayBuffer);
- gltf = parseBinaryGltf(gltf);
+ return loadModel(batchedModel).then(function(gltf) {
gltf.meshes[0].primitives[0].attributes.POSITION = undefined;
expect(function() {
return new ClassificationModel({
@@ -238,9 +246,7 @@ defineSuite([
});
it('throws with batch id semantic', function() {
- return Resource.fetchArrayBuffer(batchedModel).then(function(arrayBuffer) {
- var gltf = new Uint8Array(arrayBuffer);
- gltf = parseBinaryGltf(gltf);
+ return loadModel(batchedModel).then(function(gltf) {
gltf.meshes[0].primitives[0].attributes._BATCHID = undefined;
expect(function() {
return new ClassificationModel({
diff --git a/Specs/Scene/ModelSpec.js b/Specs/Scene/ModelSpec.js
index 253d002cd304..1b44abe81fb0 100644
--- a/Specs/Scene/ModelSpec.js
+++ b/Specs/Scene/ModelSpec.js
@@ -90,6 +90,7 @@ defineSuite([
var texturedBoxKhrBinaryUrl = './Data/Models/Box-Textured-Binary/CesiumTexturedBoxTest.glb';
var boxRtcUrl = './Data/Models/Box-RTC/Box.gltf';
var boxEcefUrl = './Data/Models/Box-ECEF/ecef.gltf';
+ var boxWithUnusedMaterial = './Data/Models/BoxWithUnusedMaterial/Box.gltf';
var cesiumAirUrl = './Data/Models/CesiumAir/Cesium_Air.gltf';
var cesiumAir_0_8Url = './Data/Models/CesiumAir/Cesium_Air_0_8.gltf';
@@ -526,46 +527,21 @@ defineSuite([
// Simulate using procedural glTF as opposed to loading it from a file
return loadModelJson(texturedBoxModel.gltf).then(function(model) {
var rs = {
- frontFace : WebGLConstants.CCW,
cull : {
- enabled : true,
- face : WebGLConstants.BACK
- },
- lineWidth : 1.0,
- polygonOffset : {
- enabled : false,
- factor : 0.0,
- units : 0.0
- },
- depthRange : {
- near : 0.0,
- far : 1.0
+ enabled : true
},
depthTest : {
- enabled : true,
- func : WebGLConstants.LESS
- },
- colorMask : {
- red : true,
- green : true,
- blue : true,
- alpha : true
+ enabled : true
},
depthMask : true,
blending : {
enabled : false,
- color : {
- red : 0.0,
- green : 0.0,
- blue : 0.0,
- alpha : 0.0
- },
equationRgb : WebGLConstants.FUNC_ADD,
equationAlpha : WebGLConstants.FUNC_ADD,
functionSourceRgb : WebGLConstants.ONE,
functionSourceAlpha : WebGLConstants.ONE,
- functionDestinationRgb : WebGLConstants.ZERO,
- functionDestinationAlpha : WebGLConstants.ZERO
+ functionDestinationRgb : WebGLConstants.ONE_MINUS_SRC_ALPHA,
+ functionDestinationAlpha : WebGLConstants.ONE_MINUS_SRC_ALPHA
}
};
@@ -732,13 +708,13 @@ defineSuite([
}).toThrowDeveloperError();
});
- it('ModelMaterial.setValue sets a scalar parameter', function() {
+ it('ModelMaterial.setValue sets a scalar uniform value', function() {
var material = texturedBoxModel.getMaterial('Texture');
material.setValue('shininess', 12.34);
expect(material.getValue('shininess')).toEqual(12.34);
});
- it('ModelMaterial.setValue sets a Cartesian4 parameter', function() {
+ it('ModelMaterial.setValue sets a Cartesian4 uniform value', function() {
var material = texturedBoxModel.getMaterial('Texture');
var specular = new Cartesian4(0.25, 0.5, 0.75, 1.0);
material.setValue('specular', specular);
@@ -752,7 +728,7 @@ defineSuite([
}).toThrowDeveloperError();
});
- it('ModelMaterial.getValue returns undefined when parameter does not exist', function() {
+ it('ModelMaterial.getValue returns undefined when uniform value does not exist', function() {
var material = texturedBoxModel.getMaterial('Texture');
expect(material.getValue('name-of-parameter-that-does-not-exist')).not.toBeDefined();
});
@@ -947,7 +923,7 @@ defineSuite([
// Verify that rotation is converted from
// Axis-Angle (1,0,0,0) to Quaternion (0,0,0,1)
- var rotation = m.gltf.nodes[3].rotation;
+ var rotation = m.gltf.nodes[2].rotation;
expect(rotation).toEqual([0.0, 0.0, 0.0, 1.0]);
verifyRender(m);
@@ -955,6 +931,13 @@ defineSuite([
});
});
+ it('loads a glTF model with unused material', function() {
+ return loadModel(boxWithUnusedMaterial).then(function(m) {
+ verifyRender(m);
+ primitives.remove(m);
+ });
+ });
+
it('loads a glTF model that doesn\'t have a technique', function() {
return loadModel(boxNoTechniqueUrl).then(function(m) {
verifyRender(m);
@@ -1007,7 +990,7 @@ defineSuite([
return new Model({
gltf : arrayBuffer
});
- }).toThrowDeveloperError();
+ }).toThrowRuntimeError();
});
it('Throws because of an invalid Binary glTF header - version', function() {
@@ -1022,7 +1005,7 @@ defineSuite([
return new Model({
gltf : arrayBuffer
});
- }).toThrowDeveloperError();
+ }).toThrowRuntimeError();
});
it('renders a model with the CESIUM_RTC extension', function() {
@@ -2060,7 +2043,7 @@ defineSuite([
expect(scene).toRender([0, 0, 0, 255]);
m.show = true;
m.zoomTo();
- expect(scene).toRender([0, 0, 0, 255]);
+ expect(scene).toRender([51, 51, 51, 255]); // Cesium has minimum lighting
m.show = false;
primitives.remove(m);
From c0db13d593b47498d4d43088f738fb05f14a8296 Mon Sep 17 00:00:00 2001
From: ggetz
Date: Mon, 27 Aug 2018 13:49:38 -0400
Subject: [PATCH 14/52] Fix docs, use gltfPipeline removePipelineExtras
---
Source/Scene/ClassificationModel.js | 4 +-
Source/Scene/Model.js | 10 +++-
Source/Scene/ModelUtility.js | 25 ----------
.../GltfPipeline/removePipelineExtras.js | 46 +++++++++++++++++++
4 files changed, 56 insertions(+), 29 deletions(-)
create mode 100644 Source/ThirdParty/GltfPipeline/removePipelineExtras.js
diff --git a/Source/Scene/ClassificationModel.js b/Source/Scene/ClassificationModel.js
index e901d252799e..81fdfb908de0 100644
--- a/Source/Scene/ClassificationModel.js
+++ b/Source/Scene/ClassificationModel.js
@@ -93,8 +93,8 @@ define([
*
* @private
*
- * @param {Object} [options] Object with the following properties:
- * @param {ArrayBuffer|Uint8Array} [options.gltf] A binary glTF buffer.
+ * @param {Object} options Object with the following properties:
+ * @param {ArrayBuffer|Uint8Array} options.gltf A binary glTF buffer.
* @param {Boolean} [options.show=true] Determines if the model primitive will be shown.
* @param {Matrix4} [options.modelMatrix=Matrix4.IDENTITY] The 4x4 transformation matrix that transforms the model from model to world coordinates.
* @param {Boolean} [options.debugShowBoundingVolume=false] For debugging only. Draws the bounding sphere for each draw command in the model.
diff --git a/Source/Scene/Model.js b/Source/Scene/Model.js
index 40df9e669fee..fd055aea88f0 100644
--- a/Source/Scene/Model.js
+++ b/Source/Scene/Model.js
@@ -48,6 +48,7 @@ define([
'../ThirdParty/GltfPipeline/hasExtension',
'../ThirdParty/GltfPipeline/numberOfComponentsForType',
'../ThirdParty/GltfPipeline/parseGlb',
+ '../ThirdParty/GltfPipeline/removePipelineExtras',
'../ThirdParty/GltfPipeline/updateVersion',
'../ThirdParty/when',
'./Axis',
@@ -120,6 +121,7 @@ define([
hasExtension,
numberOfComponentsForType,
parseGlb,
+ removePipelineExtras,
updateVersion,
when,
Axis,
@@ -225,6 +227,8 @@ define([
* Cesium supports glTF assets with the following extensions:
*
* -
+ * {@link https://github.com/KhronosGroup/glTF/blob/master/extensions/1.0/Khronos/KHR_binary_glTF/README.md|KHR_binary_glTF}
+ *
-
* {@link https://github.com/KhronosGroup/glTF/blob/master/extensions/1.0/Khronos/KHR_materials_common/README.md|KHR_materials_common}
*
-
* {@link https://github.com/KhronosGroup/glTF/blob/master/extensions/1.0/Vendor/WEB3D_quantized_attributes/README.md|WEB3D_quantized_attributes}
@@ -1097,6 +1101,8 @@ define([
* Cesium supports glTF assets with the following extensions:
*
* -
+ * {@link https://github.com/KhronosGroup/glTF/blob/master/extensions/1.0/Khronos/KHR_binary_glTF/README.md|KHR_binary_glTF}
+ *
-
* {@link https://github.com/KhronosGroup/glTF/blob/master/extensions/1.0/Khronos/KHR_materials_common/README.md|KHR_materials_common}
*
-
* {@link https://github.com/KhronosGroup/glTF/blob/master/extensions/1.0/Vendor/WEB3D_quantized_attributes/README.md|WEB3D_quantized_attributes}
@@ -2521,7 +2527,7 @@ define([
}
var enableCulling = !material.doubleSided;
- var blendingEnabled = (material.alphaMode !== 'OPAQUE');
+ var blendingEnabled = (material.alphaMode === 'BLEND');
rendererRenderStates[materialId] = RenderState.fromCache({
cull : {
enabled : enableCulling
@@ -4116,7 +4122,7 @@ define([
}
if (loadResources.finished()) {
- ModelUtility.removePipelineExtras(this.gltf);
+ removePipelineExtras(this.gltf);
this._loadResources = undefined; // Clear CPU memory since WebGL resources were created.
diff --git a/Source/Scene/ModelUtility.js b/Source/Scene/ModelUtility.js
index db5414426975..500bfd02ec71 100644
--- a/Source/Scene/ModelUtility.js
+++ b/Source/Scene/ModelUtility.js
@@ -62,31 +62,6 @@ define([
}
}
- /**
- * Removes empty extra._pipeline object from each object that can have extras in the glTF asset.
- *
- * @param {Object} gltf A javascript object containing a glTF asset.
- * @returns {Object} The glTF asset with the added pipeline extras.
- */
- ModelUtility.removePipelineExtras = function(gltf) {
- ForEach.shader(gltf, function(shader) {
- removeExtrasIfEmpty(shader);
- });
- ForEach.buffer(gltf, function(buffer) {
- removeExtrasIfEmpty(buffer);
- });
- ForEach.image(gltf, function(image) {
- removeExtrasIfEmpty(image);
- ForEach.compressedImage(image, function(compressedImage) {
- removeExtrasIfEmpty(compressedImage);
- });
- });
-
- removeExtrasIfEmpty(gltf);
-
- return gltf;
- };
-
/**
* Updates the model's forward axis if the model is not a 2.0 model.
*
diff --git a/Source/ThirdParty/GltfPipeline/removePipelineExtras.js b/Source/ThirdParty/GltfPipeline/removePipelineExtras.js
new file mode 100644
index 000000000000..8a60ee043672
--- /dev/null
+++ b/Source/ThirdParty/GltfPipeline/removePipelineExtras.js
@@ -0,0 +1,46 @@
+define([
+ './ForEach',
+ '../../Core/defined'
+ ], function(
+ ForEach,
+ defined) {
+ 'use strict';
+
+ /**
+ * Iterate through the objects within the glTF and delete their pipeline extras object.
+ *
+ * @param {Object} gltf A javascript object containing a glTF asset.
+ * @returns {Object} glTF with no pipeline extras.
+ *
+ * @private
+ */
+ function removePipelineExtras(gltf) {
+ ForEach.shader(gltf, function(shader) {
+ removeExtras(shader);
+ });
+ ForEach.buffer(gltf, function(buffer) {
+ removeExtras(buffer);
+ });
+ ForEach.image(gltf, function (image) {
+ removeExtras(image);
+ ForEach.compressedImage(image, function(compressedImage) {
+ removeExtras(compressedImage);
+ });
+ });
+
+ removeExtras(gltf);
+
+ return gltf;
+ }
+
+ function removeExtras(object) {
+ if (defined(object.extras) && defined(object.extras._pipeline)) {
+ delete object.extras._pipeline;
+ }
+ if (Object.keys(object.extras).length === 0) {
+ delete object.extras;
+ }
+ }
+
+ return removePipelineExtras;
+});
From c69505b73ea166affcc723fcc26e17cb59029fb8 Mon Sep 17 00:00:00 2001
From: ggetz
Date: Mon, 27 Aug 2018 13:52:43 -0400
Subject: [PATCH 15/52] Cleanup eslint error
---
Specs/Scene/ClassificationModelSpec.js | 2 --
1 file changed, 2 deletions(-)
diff --git a/Specs/Scene/ClassificationModelSpec.js b/Specs/Scene/ClassificationModelSpec.js
index e763546cff76..f45d4d3fae8e 100644
--- a/Specs/Scene/ClassificationModelSpec.js
+++ b/Specs/Scene/ClassificationModelSpec.js
@@ -75,8 +75,6 @@ defineSuite([
beforeAll(function() {
scene = createScene();
-
-
});
afterAll(function() {
From a7a4cedf2ba2cdda27a8463bfb82316dff565f6d Mon Sep 17 00:00:00 2001
From: ggetz
Date: Mon, 27 Aug 2018 14:21:56 -0400
Subject: [PATCH 16/52] Fix render states
---
Source/Scene/Model.js | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/Source/Scene/Model.js b/Source/Scene/Model.js
index fd055aea88f0..a269818be2e8 100644
--- a/Source/Scene/Model.js
+++ b/Source/Scene/Model.js
@@ -2528,6 +2528,7 @@ define([
var enableCulling = !material.doubleSided;
var blendingEnabled = (material.alphaMode === 'BLEND');
+ var alphaMask = (material.alphaMode === 'MASK');
rendererRenderStates[materialId] = RenderState.fromCache({
cull : {
enabled : enableCulling
@@ -2537,7 +2538,7 @@ define([
},
depthMask : !blendingEnabled,
blending : {
- enabled : blendingEnabled,
+ enabled : blendingEnabled || alphaMask,
equationRgb : blendEquationSeparate[0],
equationAlpha : blendEquationSeparate[1],
functionSourceRgb : blendFuncSeparate[0],
From 514c2b78dd10db4e93a7443458fb369cf07da1e3 Mon Sep 17 00:00:00 2001
From: ggetz
Date: Mon, 27 Aug 2018 14:55:29 -0400
Subject: [PATCH 17/52] Discard instead of blend for alphaMode MASK
---
Source/Scene/Model.js | 3 +--
Source/Scene/processPbrMetallicRoughness.js | 5 ++++-
2 files changed, 5 insertions(+), 3 deletions(-)
diff --git a/Source/Scene/Model.js b/Source/Scene/Model.js
index a269818be2e8..fd055aea88f0 100644
--- a/Source/Scene/Model.js
+++ b/Source/Scene/Model.js
@@ -2528,7 +2528,6 @@ define([
var enableCulling = !material.doubleSided;
var blendingEnabled = (material.alphaMode === 'BLEND');
- var alphaMask = (material.alphaMode === 'MASK');
rendererRenderStates[materialId] = RenderState.fromCache({
cull : {
enabled : enableCulling
@@ -2538,7 +2537,7 @@ define([
},
depthMask : !blendingEnabled,
blending : {
- enabled : blendingEnabled || alphaMask,
+ enabled : blendingEnabled,
equationRgb : blendEquationSeparate[0],
equationAlpha : blendEquationSeparate[1],
functionSourceRgb : blendFuncSeparate[0],
diff --git a/Source/Scene/processPbrMetallicRoughness.js b/Source/Scene/processPbrMetallicRoughness.js
index 782cd24129e2..1d98bd9b35b2 100644
--- a/Source/Scene/processPbrMetallicRoughness.js
+++ b/Source/Scene/processPbrMetallicRoughness.js
@@ -646,7 +646,10 @@ define([
fragmentShader += ' color = LINEARtoSRGB(color);\n';
if (defined(alphaMode)) {
if (alphaMode === 'MASK') {
- fragmentShader += ' gl_FragColor = vec4(color, int(baseColorWithAlpha.a >= u_alphaCutoff));\n';
+ fragmentShader += ' if (baseColorWithAlpha.a < u_alphaCutoff) {\n';
+ fragmentShader += ' discard;\n';
+ fragmentShader += ' }\n';
+ fragmentShader += ' gl_FragColor = vec4(color, 1.0);\n';
} else if (alphaMode === 'BLEND') {
fragmentShader += ' gl_FragColor = vec4(color, baseColorWithAlpha.a);\n';
} else {
From 71ff4c4613b09b97f34319f633ac8391bdc101ae Mon Sep 17 00:00:00 2001
From: ggetz
Date: Mon, 27 Aug 2018 16:50:53 -0400
Subject: [PATCH 18/52] Cleanup eslint error
---
Source/Scene/ModelUtility.js | 15 ---------------
1 file changed, 15 deletions(-)
diff --git a/Source/Scene/ModelUtility.js b/Source/Scene/ModelUtility.js
index 500bfd02ec71..1e61a1a63eb2 100644
--- a/Source/Scene/ModelUtility.js
+++ b/Source/Scene/ModelUtility.js
@@ -47,21 +47,6 @@ define([
*/
var ModelUtility = {};
- function removeExtrasIfEmpty(object) {
- if (!defined(object.extras)) {
- return;
- }
-
- var pipeline = object.extras._pipeline;
- if (!defined(pipeline)) {
- return;
- }
-
- if (Object.keys(pipeline).length === 0) {
- delete object.extras;
- }
- }
-
/**
* Updates the model's forward axis if the model is not a 2.0 model.
*
From ccad16c02266c3a8ce3cf252d80b8972a1b31756 Mon Sep 17 00:00:00 2001
From: Omar Shehata
Date: Thu, 30 Aug 2018 12:22:15 -0400
Subject: [PATCH 19/52] Add KHR_materials_unlit to list of supported extensions
---
Source/Scene/ModelUtility.js | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/Source/Scene/ModelUtility.js b/Source/Scene/ModelUtility.js
index 1e61a1a63eb2..b63a5e02ce0a 100644
--- a/Source/Scene/ModelUtility.js
+++ b/Source/Scene/ModelUtility.js
@@ -473,7 +473,8 @@ define([
'KHR_draco_mesh_compression' : true,
'KHR_materials_common' : true,
'KHR_techniques_webgl' : true,
- 'WEB3D_quantized_attributes' : true
+ 'WEB3D_quantized_attributes' : true,
+ 'KHR_materials_unlit' : true
};
ModelUtility.checkSupportedExtensions = function(extensionsRequired) {
From b1360528be6e6460f6ef5b1e317d4945ffa01a09 Mon Sep 17 00:00:00 2001
From: Omar Shehata
Date: Thu, 30 Aug 2018 13:31:09 -0400
Subject: [PATCH 20/52] Turn off lighting when detects unlit extension
---
Source/Scene/processPbrMetallicRoughness.js | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/Source/Scene/processPbrMetallicRoughness.js b/Source/Scene/processPbrMetallicRoughness.js
index 1d98bd9b35b2..c74470f64d2b 100644
--- a/Source/Scene/processPbrMetallicRoughness.js
+++ b/Source/Scene/processPbrMetallicRoughness.js
@@ -181,6 +181,11 @@ define([
}
};
+ if (defined(material.extensions) && defined(material.extensions.KHR_materials_unlit)) {
+ hasNormals = false;
+ hasTangents = false;
+ }
+
if (hasNormals) {
techniqueUniforms.u_normalMatrix = {
semantic : 'MODELVIEWINVERSETRANSPOSE',
From 7a9faa782bad59f1b7c66367f2fc4ab69c702933 Mon Sep 17 00:00:00 2001
From: Omar Shehata
Date: Thu, 30 Aug 2018 13:50:31 -0400
Subject: [PATCH 21/52] Updated changes.md
---
CHANGES.md | 1 +
1 file changed, 1 insertion(+)
diff --git a/CHANGES.md b/CHANGES.md
index 4fe6de43324d..4fc804e6a82b 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -10,6 +10,7 @@ Change Log
* Improved support for polygon entities using `perPositionHeight`, including supporting vertical polygons. This also improves KML compatibility. [#6791](https://github.com/AnalyticalGraphicsInc/cesium/pull/6791)
* Added `Cartesian3.midpoint` to compute the midpoint between two `Cartesian3` positions [#6836](https://github.com/AnalyticalGraphicsInc/cesium/pull/6836)
* Added `equalsEpsilon` methods to `OrthographicFrustum`, `PerspectiveFrustum`, `OrthographicOffCenterFrustum` and `PerspectiveOffCenterFrustum`.
+* Added support for glTF extension [KHR_materials_unlit](https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_materials_unlit) [#6977](https://github.com/AnalyticalGraphicsInc/cesium/pull/6977).
##### Deprecated :hourglass_flowing_sand:
* Support for 3D Tiles `content.url` is deprecated to reflect updates to the [3D Tiles spec](https://github.com/AnalyticalGraphicsInc/3d-tiles/pull/301). Use `content.uri instead`. Support for `content.url` will remain for backwards compatibility. [#6744](https://github.com/AnalyticalGraphicsInc/cesium/pull/6744)
From c56a33969ec261bcb0614a3ae7a7e8719220693f Mon Sep 17 00:00:00 2001
From: Omar Shehata
Date: Thu, 30 Aug 2018 16:59:06 -0400
Subject: [PATCH 22/52] Ignore unlit and occlusion when unlit
---
Source/Scene/processPbrMetallicRoughness.js | 29 +++++++++++++--------
1 file changed, 18 insertions(+), 11 deletions(-)
diff --git a/Source/Scene/processPbrMetallicRoughness.js b/Source/Scene/processPbrMetallicRoughness.js
index c74470f64d2b..df8f579d7fdb 100644
--- a/Source/Scene/processPbrMetallicRoughness.js
+++ b/Source/Scene/processPbrMetallicRoughness.js
@@ -143,6 +143,7 @@ define([
var hasNormals = false;
var hasTangents = false;
var hasTexCoords = false;
+ var isUnlit = false;
if (defined(primitiveInfo)) {
skinningInfo = primitiveInfo.skinning;
@@ -182,6 +183,7 @@ define([
};
if (defined(material.extensions) && defined(material.extensions.KHR_materials_unlit)) {
+ isUnlit = true;
hasNormals = false;
hasTangents = false;
}
@@ -633,19 +635,22 @@ define([
fragmentShader += ' vec3 color = baseColor;\n';
}
- if (defined(generatedMaterialValues.u_occlusionTexture)) {
- fragmentShader += ' color *= texture2D(u_occlusionTexture, ' + v_texcoord + ').r;\n';
- }
- if (defined(generatedMaterialValues.u_emissiveTexture)) {
- fragmentShader += ' vec3 emissive = SRGBtoLINEAR3(texture2D(u_emissiveTexture, ' + v_texcoord + ').rgb);\n';
- if (defined(generatedMaterialValues.u_emissiveFactor)) {
- fragmentShader += ' emissive *= u_emissiveFactor;\n';
+ // Ignore occlusion and emissive when unlit
+ if (!isUnlit) {
+ if (defined(generatedMaterialValues.u_occlusionTexture)) {
+ fragmentShader += ' color *= texture2D(u_occlusionTexture, ' + v_texcoord + ').r;\n';
}
- fragmentShader += ' color += emissive;\n';
- }
- else if (defined(generatedMaterialValues.u_emissiveFactor)) {
- fragmentShader += ' color += u_emissiveFactor;\n';
+ if (defined(generatedMaterialValues.u_emissiveTexture)) {
+ fragmentShader += ' vec3 emissive = SRGBtoLINEAR3(texture2D(u_emissiveTexture, ' + v_texcoord + ').rgb);\n';
+ if (defined(generatedMaterialValues.u_emissiveFactor)) {
+ fragmentShader += ' emissive *= u_emissiveFactor;\n';
+ }
+ fragmentShader += ' color += emissive;\n';
}
+ else if (defined(generatedMaterialValues.u_emissiveFactor)) {
+ fragmentShader += ' color += u_emissiveFactor;\n';
+ }
+ }
// Final color
fragmentShader += ' color = LINEARtoSRGB(color);\n';
@@ -665,6 +670,8 @@ define([
}
fragmentShader += '}\n';
+ console.log(fragmentShader);
+
// Add shaders
var vertexShaderId = addToArray(shaders, {
type : WebGLConstants.VERTEX_SHADER,
From 21caa93e769eabb086dfc15b96ffbebdaf5af7c9 Mon Sep 17 00:00:00 2001
From: Omar Shehata
Date: Fri, 31 Aug 2018 10:01:48 -0400
Subject: [PATCH 23/52] Remove log and fix formatting
---
Source/Scene/processPbrMetallicRoughness.js | 7 ++-----
1 file changed, 2 insertions(+), 5 deletions(-)
diff --git a/Source/Scene/processPbrMetallicRoughness.js b/Source/Scene/processPbrMetallicRoughness.js
index df8f579d7fdb..745b13f64a16 100644
--- a/Source/Scene/processPbrMetallicRoughness.js
+++ b/Source/Scene/processPbrMetallicRoughness.js
@@ -646,10 +646,9 @@ define([
fragmentShader += ' emissive *= u_emissiveFactor;\n';
}
fragmentShader += ' color += emissive;\n';
+ } else if (defined(generatedMaterialValues.u_emissiveFactor)) {
+ fragmentShader += ' color += u_emissiveFactor;\n';
}
- else if (defined(generatedMaterialValues.u_emissiveFactor)) {
- fragmentShader += ' color += u_emissiveFactor;\n';
- }
}
// Final color
@@ -670,8 +669,6 @@ define([
}
fragmentShader += '}\n';
- console.log(fragmentShader);
-
// Add shaders
var vertexShaderId = addToArray(shaders, {
type : WebGLConstants.VERTEX_SHADER,
From 7c28d2a60958e34ae8b362482091d074046888d1 Mon Sep 17 00:00:00 2001
From: Omar Shehata
Date: Fri, 31 Aug 2018 10:29:39 -0400
Subject: [PATCH 24/52] Added test for unlit
---
Specs/Data/Models/PBR/Box/Box-Unlit.gltf | 151 +++++++++++++++++++++++
Specs/Data/Models/PBR/Box/ReadMe.txt | 1 +
Specs/Scene/ModelSpec.js | 16 +++
3 files changed, 168 insertions(+)
create mode 100644 Specs/Data/Models/PBR/Box/Box-Unlit.gltf
create mode 100644 Specs/Data/Models/PBR/Box/ReadMe.txt
diff --git a/Specs/Data/Models/PBR/Box/Box-Unlit.gltf b/Specs/Data/Models/PBR/Box/Box-Unlit.gltf
new file mode 100644
index 000000000000..f4bda300552c
--- /dev/null
+++ b/Specs/Data/Models/PBR/Box/Box-Unlit.gltf
@@ -0,0 +1,151 @@
+{
+ "asset": {
+ "generator": "COLLADA2GLTF",
+ "version": "2.0"
+ },
+ "extensionsUsed": [
+ "KHR_materials_unlit"
+ ],
+ "extensionsRequired": [
+ "KHR_materials_unlit"
+ ],
+ "scene": 0,
+ "scenes": [
+ {
+ "nodes": [
+ 0
+ ]
+ }
+ ],
+ "nodes": [
+ {
+ "children": [
+ 1
+ ],
+ "matrix": [
+ 1.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ -1.0,
+ 0.0,
+ 0.0,
+ 1.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 1.0
+ ]
+ },
+ {
+ "mesh": 0
+ }
+ ],
+ "meshes": [
+ {
+ "primitives": [
+ {
+ "attributes": {
+ "NORMAL": 1,
+ "POSITION": 2
+ },
+ "indices": 0,
+ "mode": 4,
+ "material": 0
+ }
+ ],
+ "name": "Mesh"
+ }
+ ],
+ "accessors": [
+ {
+ "bufferView": 0,
+ "byteOffset": 0,
+ "componentType": 5123,
+ "count": 36,
+ "max": [
+ 23
+ ],
+ "min": [
+ 0
+ ],
+ "type": "SCALAR"
+ },
+ {
+ "bufferView": 1,
+ "byteOffset": 0,
+ "componentType": 5126,
+ "count": 24,
+ "max": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "min": [
+ -1.0,
+ -1.0,
+ -1.0
+ ],
+ "type": "VEC3"
+ },
+ {
+ "bufferView": 1,
+ "byteOffset": 288,
+ "componentType": 5126,
+ "count": 24,
+ "max": [
+ 0.5,
+ 0.5,
+ 0.5
+ ],
+ "min": [
+ -0.5,
+ -0.5,
+ -0.5
+ ],
+ "type": "VEC3"
+ }
+ ],
+ "materials": [
+ {
+ "pbrMetallicRoughness": {
+ "baseColorFactor": [
+ 0.0,
+ 1.0,
+ 0.0,
+ 1.0
+ ],
+ "metallicFactor": 1.0
+ },
+ "name": "Unlit Green",
+ "extensions": {
+ "KHR_materials_unlit": {}
+ }
+ }
+ ],
+ "bufferViews": [
+ {
+ "buffer": 0,
+ "byteOffset": 576,
+ "byteLength": 72,
+ "target": 34963
+ },
+ {
+ "buffer": 0,
+ "byteOffset": 0,
+ "byteLength": 576,
+ "byteStride": 12,
+ "target": 34962
+ }
+ ],
+ "buffers": [
+ {
+ "byteLength": 648,
+ "uri": "data:application/octet-stream;base64,AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAvwAAAL8AAAA/AAAAPwAAAL8AAAA/AAAAvwAAAD8AAAA/AAAAPwAAAD8AAAA/AAAAPwAAAL8AAAA/AAAAvwAAAL8AAAA/AAAAPwAAAL8AAAC/AAAAvwAAAL8AAAC/AAAAPwAAAD8AAAA/AAAAPwAAAL8AAAA/AAAAPwAAAD8AAAC/AAAAPwAAAL8AAAC/AAAAvwAAAD8AAAA/AAAAPwAAAD8AAAA/AAAAvwAAAD8AAAC/AAAAPwAAAD8AAAC/AAAAvwAAAL8AAAA/AAAAvwAAAD8AAAA/AAAAvwAAAL8AAAC/AAAAvwAAAD8AAAC/AAAAvwAAAL8AAAC/AAAAvwAAAD8AAAC/AAAAPwAAAL8AAAC/AAAAPwAAAD8AAAC/AAABAAIAAwACAAEABAAFAAYABwAGAAUACAAJAAoACwAKAAkADAANAA4ADwAOAA0AEAARABIAEwASABEAFAAVABYAFwAWABUA"
+ }
+ ]
+}
diff --git a/Specs/Data/Models/PBR/Box/ReadMe.txt b/Specs/Data/Models/PBR/Box/ReadMe.txt
new file mode 100644
index 000000000000..75319c641f4c
--- /dev/null
+++ b/Specs/Data/Models/PBR/Box/ReadMe.txt
@@ -0,0 +1 @@
+Box-Unlit.gltf is a modified glTF with the KHR_materials_unlit extension.
\ No newline at end of file
diff --git a/Specs/Scene/ModelSpec.js b/Specs/Scene/ModelSpec.js
index 1b44abe81fb0..d4441dff8b19 100644
--- a/Specs/Scene/ModelSpec.js
+++ b/Specs/Scene/ModelSpec.js
@@ -120,6 +120,7 @@ defineSuite([
var boomBoxUrl = './Data/Models/PBR/BoomBox/BoomBox.gltf';
var boxPbrUrl = './Data/Models/PBR/Box/Box.gltf';
+ var boxPbrUnlitUrl = './Data/Models/PBR/Box/Box-Unlit.gltf';
var boxAnimatedPbrUrl = './Data/Models/PBR/BoxAnimated/BoxAnimated.gltf';
var boxInterleavedPbrUrl = './Data/Models/PBR/BoxInterleaved/BoxInterleaved.gltf';
var riggedSimplePbrUrl = './Data/Models/PBR/RiggedSimple/RiggedSimple.gltf';
@@ -2692,6 +2693,21 @@ defineSuite([
});
});
+ fit('renders with the unlit extension', function() {
+ return loadModel(boxPbrUnlitUrl).then(function(model) {
+ model.show = true;
+ model.zoomTo();
+ // We expect to see the base color when unlit
+ expect(scene).toRenderAndCall(function(rgba) {
+ expect(rgba[0]).toEqual(0);
+ expect(rgba[1]).toEqual(255);
+ expect(rgba[2]).toEqual(0);
+ });
+
+ primitives.remove(model);
+ });
+ });
+
it('silhouetteSupported', function() {
expect(Model.silhouetteSupported(scene)).toBe(true);
scene.context._stencilBits = 0;
From ba4d8404d9e8450851ae3932c12a557cfa94e2ba Mon Sep 17 00:00:00 2001
From: Omar Shehata
Date: Fri, 31 Aug 2018 11:59:55 -0400
Subject: [PATCH 25/52] Moved BoxUnlit to its own folder
---
Specs/Data/Models/PBR/Box/ReadMe.txt | 1 -
.../Models/PBR/{Box/Box-Unlit.gltf => BoxUnlit/BoxUnlit.gltf} | 0
Specs/Scene/ModelSpec.js | 4 ++--
3 files changed, 2 insertions(+), 3 deletions(-)
delete mode 100644 Specs/Data/Models/PBR/Box/ReadMe.txt
rename Specs/Data/Models/PBR/{Box/Box-Unlit.gltf => BoxUnlit/BoxUnlit.gltf} (100%)
diff --git a/Specs/Data/Models/PBR/Box/ReadMe.txt b/Specs/Data/Models/PBR/Box/ReadMe.txt
deleted file mode 100644
index 75319c641f4c..000000000000
--- a/Specs/Data/Models/PBR/Box/ReadMe.txt
+++ /dev/null
@@ -1 +0,0 @@
-Box-Unlit.gltf is a modified glTF with the KHR_materials_unlit extension.
\ No newline at end of file
diff --git a/Specs/Data/Models/PBR/Box/Box-Unlit.gltf b/Specs/Data/Models/PBR/BoxUnlit/BoxUnlit.gltf
similarity index 100%
rename from Specs/Data/Models/PBR/Box/Box-Unlit.gltf
rename to Specs/Data/Models/PBR/BoxUnlit/BoxUnlit.gltf
diff --git a/Specs/Scene/ModelSpec.js b/Specs/Scene/ModelSpec.js
index d4441dff8b19..31417ac46e0e 100644
--- a/Specs/Scene/ModelSpec.js
+++ b/Specs/Scene/ModelSpec.js
@@ -120,7 +120,7 @@ defineSuite([
var boomBoxUrl = './Data/Models/PBR/BoomBox/BoomBox.gltf';
var boxPbrUrl = './Data/Models/PBR/Box/Box.gltf';
- var boxPbrUnlitUrl = './Data/Models/PBR/Box/Box-Unlit.gltf';
+ var boxPbrUnlitUrl = './Data/Models/PBR/BoxUnlit/BoxUnlit.gltf';
var boxAnimatedPbrUrl = './Data/Models/PBR/BoxAnimated/BoxAnimated.gltf';
var boxInterleavedPbrUrl = './Data/Models/PBR/BoxInterleaved/BoxInterleaved.gltf';
var riggedSimplePbrUrl = './Data/Models/PBR/RiggedSimple/RiggedSimple.gltf';
@@ -2693,7 +2693,7 @@ defineSuite([
});
});
- fit('renders with the unlit extension', function() {
+ it('renders with the unlit extension', function() {
return loadModel(boxPbrUnlitUrl).then(function(model) {
model.show = true;
model.zoomTo();
From db96cebf9fb0d100eb112475e0bb87bddd86c09f Mon Sep 17 00:00:00 2001
From: Omar Shehata
Date: Tue, 4 Sep 2018 09:31:35 -0400
Subject: [PATCH 26/52] Added KHR_materials_pbrSpecularGlossiness to supported
extensions
---
Source/Scene/ModelUtility.js | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/Source/Scene/ModelUtility.js b/Source/Scene/ModelUtility.js
index 1e61a1a63eb2..e954154b3e77 100644
--- a/Source/Scene/ModelUtility.js
+++ b/Source/Scene/ModelUtility.js
@@ -473,7 +473,8 @@ define([
'KHR_draco_mesh_compression' : true,
'KHR_materials_common' : true,
'KHR_techniques_webgl' : true,
- 'WEB3D_quantized_attributes' : true
+ 'KHR_materials_pbrSpecularGlossiness' : true,
+ 'WEB3D_quantized_attributes' : true,
};
ModelUtility.checkSupportedExtensions = function(extensionsRequired) {
From ca4dc6c0e5706b64624a167b2e07e9f543857cc8 Mon Sep 17 00:00:00 2001
From: Shehata
Date: Tue, 4 Sep 2018 13:38:03 -0400
Subject: [PATCH 27/52] Add support for spec gloss
---
Source/Scene/processPbrMetallicRoughness.js | 117 ++++++++++++++++----
1 file changed, 96 insertions(+), 21 deletions(-)
diff --git a/Source/Scene/processPbrMetallicRoughness.js b/Source/Scene/processPbrMetallicRoughness.js
index 1d98bd9b35b2..dfaf6f5f9531 100644
--- a/Source/Scene/processPbrMetallicRoughness.js
+++ b/Source/Scene/processPbrMetallicRoughness.js
@@ -99,6 +99,11 @@ define([
defined(material.doubleSided);
}
+ function isSpecularGlossinessMaterial(material) {
+ return defined(material.extensions) &&
+ defined(material.extensions.KHR_materials_pbrSpecularGlossiness);
+ }
+
function generateTechnique(gltf, material, materialIndex, generatedMaterialValues, primitiveByMaterial, options) {
var addBatchIdToGeneratedShaders = defaultValue(options.addBatchIdToGeneratedShaders, false);
@@ -107,9 +112,11 @@ define([
var shaders = techniquesWebgl.shaders;
var programs = techniquesWebgl.programs;
+ var useSpecGloss = isSpecularGlossinessMaterial(material);
+
var uniformName;
var pbrMetallicRoughness = material.pbrMetallicRoughness;
- if (defined(pbrMetallicRoughness)) {
+ if (defined(pbrMetallicRoughness) && !useSpecGloss) {
for (var parameterName in pbrMetallicRoughness) {
if (pbrMetallicRoughness.hasOwnProperty(parameterName)) {
uniformName = 'u_' + parameterName;
@@ -117,6 +124,17 @@ define([
}
}
}
+
+ if (useSpecGloss) {
+ var pbrSpecularGlossiness = material.extensions.KHR_materials_pbrSpecularGlossiness;
+ for (var parameterName in pbrSpecularGlossiness) {
+ if (pbrSpecularGlossiness.hasOwnProperty(parameterName)) {
+ uniformName = 'u_' + parameterName;
+ generatedMaterialValues[uniformName] = pbrSpecularGlossiness[parameterName];
+ }
+ }
+ }
+
for (var additional in material) {
if (material.hasOwnProperty(additional) && ((additional.indexOf('Texture') >= 0) || additional.indexOf('Factor') >= 0)) {
uniformName = 'u_' + additional;
@@ -531,29 +549,67 @@ define([
fragmentShader += ' vec3 baseColor = baseColorWithAlpha.rgb;\n';
if (hasNormals) {
- // Add metallic-roughness to fragment shader
- if (defined(generatedMaterialValues.u_metallicRoughnessTexture)) {
- fragmentShader += ' vec3 metallicRoughness = texture2D(u_metallicRoughnessTexture, ' + v_texcoord + ').rgb;\n';
- fragmentShader += ' float metalness = clamp(metallicRoughness.b, 0.0, 1.0);\n';
- fragmentShader += ' float roughness = clamp(metallicRoughness.g, 0.04, 1.0);\n';
- if (defined(generatedMaterialValues.u_metallicFactor)) {
- fragmentShader += ' metalness *= u_metallicFactor;\n';
- }
- if (defined(generatedMaterialValues.u_roughnessFactor)) {
- fragmentShader += ' roughness *= u_roughnessFactor;\n';
+ if (useSpecGloss) {
+ if (defined(generatedMaterialValues.u_specularGlossinessTexture)) {
+ fragmentShader += ' vec4 specularGlossiness = SRGBtoLINEAR4(texture2D(u_specularGlossinessTexture, ' + v_texcoord + '));\n';
+ fragmentShader += ' vec3 specular = specularGlossiness.rgb;\n';
+ fragmentShader += ' float glossiness = specularGlossiness.a;\n';
+ if (defined(generatedMaterialValues.u_specularFactor)) {
+ fragmentShader += ' specular *= u_specularFactor;\n';
+ }
+ if (defined(generatedMaterialValues.u_glossinessFactor)) {
+ fragmentShader += ' glossiness *= u_glossinessFactor;\n';
+ }
+ } else {
+ if (defined(generatedMaterialValues.u_specularFactor)) {
+ fragmentShader += ' vec3 specular = clamp(u_specularFactor, vec3(0.0), vec3(1.0));\n';
+ } else {
+ fragmentShader += ' vec3 specular = vec3(1.0);\n';
+ }
+ if (defined(generatedMaterialValues.u_glossinessFactor)) {
+ fragmentShader += ' float glossiness *= clamp(u_glossinessFactor, 0.0, 1.0);\n';
+ } else {
+ fragmentShader += ' float glossiness = 1.0;\n';
+ }
}
- } else {
- if (defined(generatedMaterialValues.u_metallicFactor)) {
- fragmentShader += ' float metalness = clamp(u_metallicFactor, 0.0, 1.0);\n';
+ if (defined(generatedMaterialValues.u_diffuseTexture)) {
+ fragmentShader += ' vec4 diffuse = SRGBtoLINEAR4(texture2D(u_diffuseTexture, ' + v_texcoord + '));\n';
+ if (defined(generatedMaterialValues.u_diffuseFactor)) {
+ fragmentShader += ' diffuse *= u_diffuseFactor;\n';
+ }
} else {
- fragmentShader += ' float metalness = 1.0;\n';
+ if (defined(generatedMaterialValues.u_diffuseFactor)) {
+ fragmentShader += ' vec4 diffuse = clamp(u_diffuseFactor, vec4(0.0), vec4(1.0));\n';
+ } else {
+ fragmentShader += ' vec4 diffuse = vec4(1.0);\n';
+ }
}
- if (defined(generatedMaterialValues.u_roughnessFactor)) {
- fragmentShader += ' float roughness = clamp(u_roughnessFactor, 0.04, 1.0);\n';
+ } else {
+ // Add metallic-roughness to fragment shader
+ if (defined(generatedMaterialValues.u_metallicRoughnessTexture)) {
+ fragmentShader += ' vec3 metallicRoughness = texture2D(u_metallicRoughnessTexture, ' + v_texcoord + ').rgb;\n';
+ fragmentShader += ' float metalness = clamp(metallicRoughness.b, 0.0, 1.0);\n';
+ fragmentShader += ' float roughness = clamp(metallicRoughness.g, 0.04, 1.0);\n';
+ if (defined(generatedMaterialValues.u_metallicFactor)) {
+ fragmentShader += ' metalness *= u_metallicFactor;\n';
+ }
+ if (defined(generatedMaterialValues.u_roughnessFactor)) {
+ fragmentShader += ' roughness *= u_roughnessFactor;\n';
+ }
} else {
- fragmentShader += ' float roughness = 1.0;\n';
+ if (defined(generatedMaterialValues.u_metallicFactor)) {
+ fragmentShader += ' float metalness = clamp(u_metallicFactor, 0.0, 1.0);\n';
+ } else {
+ fragmentShader += ' float metalness = 1.0;\n';
+ }
+ if (defined(generatedMaterialValues.u_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
@@ -578,9 +634,17 @@ define([
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) * (1.0 - f0);\n';
- fragmentShader += ' vec3 specularColor = mix(f0, baseColor, metalness);\n';
+ if (useSpecGloss) {
+ fragmentShader += ' float alpha = pow((1.0 - glossiness), 2.0);\n';
+ fragmentShader += ' vec3 diffuseColor = diffuse.rgb * (1.0 - max(max(specular.r, specular.g), specular.b));\n';
+ fragmentShader += ' vec3 specularColor = specular;\n';
+ fragmentShader += ' float roughness = 1.0 - glossiness;\n';
+ } else {
+ fragmentShader += ' float alpha = roughness * roughness;\n';
+ fragmentShader += ' vec3 diffuseColor = baseColor * (1.0 - metalness) * (1.0 - f0);\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';
@@ -716,6 +780,17 @@ define([
return WebGLConstants.SAMPLER_2D;
case 'u_emissiveFactor':
return WebGLConstants.FLOAT_VEC3;
+ // Specular Glossiness Types
+ case 'u_diffuseFactor':
+ return WebGLConstants.FLOAT_VEC4;
+ case 'u_specularFactor':
+ return WebGLConstants.FLOAT_VEC3;
+ case 'u_glossinessFactor':
+ return WebGLConstants.FLOAT;
+ case 'u_diffuseTexture':
+ return WebGLConstants.SAMPLER_2D;
+ case 'u_specularGlossinessTexture':
+ return WebGLConstants.SAMPLER_2D;
}
}
From f3afd0177cb5badd4abcd8f0d72868f2133ee404 Mon Sep 17 00:00:00 2001
From: Shehata
Date: Wed, 5 Sep 2018 09:28:52 -0400
Subject: [PATCH 28/52] Moved changes.md text into October release
---
CHANGES.md | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/CHANGES.md b/CHANGES.md
index 4fc804e6a82b..89a710a88f0e 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -1,6 +1,11 @@
Change Log
==========
+### 1.50 - 2018-10-01
+
+##### Additions :tada:
+* Added support for glTF extension [KHR_materials_unlit](https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_materials_unlit) [#6977](https://github.com/AnalyticalGraphicsInc/cesium/pull/6977).
+
### 1.48 - 2018-08-01
##### Additions :tada:
@@ -10,7 +15,6 @@ Change Log
* Improved support for polygon entities using `perPositionHeight`, including supporting vertical polygons. This also improves KML compatibility. [#6791](https://github.com/AnalyticalGraphicsInc/cesium/pull/6791)
* Added `Cartesian3.midpoint` to compute the midpoint between two `Cartesian3` positions [#6836](https://github.com/AnalyticalGraphicsInc/cesium/pull/6836)
* Added `equalsEpsilon` methods to `OrthographicFrustum`, `PerspectiveFrustum`, `OrthographicOffCenterFrustum` and `PerspectiveOffCenterFrustum`.
-* Added support for glTF extension [KHR_materials_unlit](https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_materials_unlit) [#6977](https://github.com/AnalyticalGraphicsInc/cesium/pull/6977).
##### Deprecated :hourglass_flowing_sand:
* Support for 3D Tiles `content.url` is deprecated to reflect updates to the [3D Tiles spec](https://github.com/AnalyticalGraphicsInc/3d-tiles/pull/301). Use `content.uri instead`. Support for `content.url` will remain for backwards compatibility. [#6744](https://github.com/AnalyticalGraphicsInc/cesium/pull/6744)
From 64014335a7a10e63b917ef87d623a78c6c492a53 Mon Sep 17 00:00:00 2001
From: Shehata
Date: Wed, 5 Sep 2018 10:57:55 -0400
Subject: [PATCH 29/52] Added BoomBox SpecGloss model
---
.../PBR/BoomBoxSpecularGlossiness/BoomBox.bin | Bin 0 -> 207816 bytes
.../BoomBoxSpecularGlossiness/BoomBox.gltf | 233 ++++++++++++++++++
.../BoomBox_baseColor.png | Bin 0 -> 3285844 bytes
.../BoomBox_diffuse.png | Bin 0 -> 3210781 bytes
.../BoomBox_emissive.png | Bin 0 -> 132833 bytes
.../BoomBox_normal.png | Bin 0 -> 2845923 bytes
.../BoomBox_occlusion.png | Bin 0 -> 1855469 bytes
.../BoomBox_roughnessMetallic.png | Bin 0 -> 3131213 bytes
.../BoomBox_specularGlossiness.png | Bin 0 -> 3648876 bytes
9 files changed, 233 insertions(+)
create mode 100644 Specs/Data/Models/PBR/BoomBoxSpecularGlossiness/BoomBox.bin
create mode 100644 Specs/Data/Models/PBR/BoomBoxSpecularGlossiness/BoomBox.gltf
create mode 100644 Specs/Data/Models/PBR/BoomBoxSpecularGlossiness/BoomBox_baseColor.png
create mode 100644 Specs/Data/Models/PBR/BoomBoxSpecularGlossiness/BoomBox_diffuse.png
create mode 100644 Specs/Data/Models/PBR/BoomBoxSpecularGlossiness/BoomBox_emissive.png
create mode 100644 Specs/Data/Models/PBR/BoomBoxSpecularGlossiness/BoomBox_normal.png
create mode 100644 Specs/Data/Models/PBR/BoomBoxSpecularGlossiness/BoomBox_occlusion.png
create mode 100644 Specs/Data/Models/PBR/BoomBoxSpecularGlossiness/BoomBox_roughnessMetallic.png
create mode 100644 Specs/Data/Models/PBR/BoomBoxSpecularGlossiness/BoomBox_specularGlossiness.png
diff --git a/Specs/Data/Models/PBR/BoomBoxSpecularGlossiness/BoomBox.bin b/Specs/Data/Models/PBR/BoomBoxSpecularGlossiness/BoomBox.bin
new file mode 100644
index 0000000000000000000000000000000000000000..6e4c9026b1c50f852c9536015d1c18ffaedeb195
GIT binary patch
literal 207816
zcma%icU;fk7e7L&5Je$MQc2R(@V@7y(%u^H_8yw=_Rc1R>=9Y@J@?*opZC7b)!ej{ncZ-sid)6(*diCIsgGwx)~=M3
zl)~1$;WG)%S22OLO*Cxu$HN%}ero0o~S>QtT%O8oh+;yWa
zlZEX0IAO$s`U_%>{Y}kiU&ZIM6la)MlB6Ddqwnk2{$8;OE&(nn(<06=)kY1nLDN@&R
zrpmR_?1O?6l}f!5&0X(6^_>?)Wa3Em+S^2m#~i6t_PXduqccg)E)?}87Yb_t(aS<7
zGEkZ)l8&(_tF?cosy5qGSazzY<%=y@h15+Q&}~cY>*k6o=3A4M>yN3Xs@9}XwpBFG
z)QVa>Eks2Uq*CQ;q7-$Y`m6Irx#Ji~45~y6H3YlRO;N#J!7ibfL~jMVcx>G&diqt6
z7B@vjBW*~svQl*Snl*XozZAv#Powrb=S6fvu#-rdg*G8cHh&f+Tm*8c8^?wWLaMAB
z!^&G2na7S||Lzu1>4Z0;P2r5%`#%<`jGjv3Ys1-z*_NcDWy1=?MD+TGHRDY!squ0=
zW0fM3kxF5|Gb|~?t(av+GV-oj%JwTxrAlEuLjMI4cUZIS>lwX1A~ZS>>54%tJMoB7
z@s1)E+K9CI_X0NYJdjD?Vs_1Q8nr%N$x4n|k!WZcn_^-`1^%V1OabUd!ggk_%jm+i
zy(}gHNy%>qvzup4H#Ckg!-3Xh`=Np*eYPc$)^TS0&X%IGcCe}_dvaNHgsJ>%Pu`|w
z?B64fbmr4uR+r;Mn(Ip0<15aT@n$=_f6;}SwN|kehK?j(zkyx6WKG_QD_Fgv4F%0#
z$-+O`l6TW079>d3$qQL-wjJ4;l(EDPTe`Ds1*^MhM`ylmV0mNgsj^H;l&F_MotHL?
zrnIKh(cJB#(jBSvdT@Wy)3vFzrtz?7Q*sJ9w2czYHAVfk(PHyFx=?vd)b~LqX*$-5n(n8Q?SuCst
i<^kL&-=2nwVyE+!J
zO3h5_=QNL%Wn__TQ8p7T$R=yONS3diLq8o|*!|!f%5yhmXY_=Aw0DcFA|%vdI*iR0
zrO;tLd6r|9OeSw0iM+R@P^a-5QRCn=vfXo0H1KjNSx)T7N+u;y=k2Q^nSf;Sw%Q}=
zn~*?9x3-D8CGm7yS(|xBCeqvGW0>65nRGbBi3O-6QpX@iR&FzS%aGOcaf%F-q$kSwpu!t;{on)+lGyeyeE6*;jk
zw`BU6=)~HMh4g39Om}WFt(p+eZX_mA-ji9(SSN*CQ|Gf{tz=p-aVb-El+bio&0ZFy
z(6Ps*%(pF-zHHdYhVM!x?&J=pKRcC{4K8P=rl!!vwa1y}fD~H0X8yBt>Du_2EE#gi>0=U8^3J1E7bWaWW1aOPp6bdhON(epr#72fm`@rtnyezBh>RKpKi-;0NBeY(Ui2!Why)ilp&*wc
zqFvb74S5uCWHLKGJ(qqq>$1Bcd9-S~61%k`hjiDfGrLvUbWLpto4+KBy!>UD<(ga?
z`m#4`G0djUWvwEW3)!^n$tgA~KY%8UtzxbF0?715C5zGurbib}F&F<}n$)qA$*c&a
zyLXN;y^&$GKD&(R+z6)^+SROONd$5F$5|BTM_Z0nu$v&JwR#7b#LI_5t2eV%Z+*yJ
zu8cLW7E^lcR(AMO0HwTL$(G3Y)86xIna1k?y8NJ+xvusnWAzd?Z%8059O%rhTo0tW
zuS;3;)*y;3_TAeQCFwm|gkpORpkVvNiicD8Id!E%6DXt=mi4Cy#JiI%^XfsUJ$Q8`iR3w}WV&
z`Bql_Cy4AyikP?{f?}o#>sK63i`wR}t%o8huyhTpIT%5qo*UV`UeQE97O<-=(RAro
z5F3V3^ms@ZYtD)xKGKw}Hj5%RQzKTA9z#Vy4Pzoi?Mrm5XBbyQHdWf
zio5PZetNN@gYrI9pnX@Ad?1K|HdKpR>Vv4{&Rx;+ivgtSeL(bdy-oxLs`d*8FZ$zN!0k#n?&uG
zL<;M@NMBo)T|e$gQ`9V2o_Gdbl9|GesC&|w6Je|?bOtSd5y|>$deZ4_^H@;#47&Vd
z5tBLRN%t48Wt9VcC~{UA+kV1}hBt_q?gbzEdfJj5Tj5RpQv=!Rt3K4`9Ku$w^(GjZ
z%QQWFsa#&dyd{3Le#~69#7#_o8)vfvdOmdh&SJJI#E-rmSjiIOd};Z$B7DY$k<8Kp
z-0T)cbIbDa{?Z8Y{Z@#bdXc0ueHN|}=Brq?5RKml(+%xe*kKw-{Fee8H9L?FW)J|W#cu&aJo{Ji858;v}9ZcE;$xX
z>-MCf$TytkN2Ow)rD0?{PlBbsq0~!Wg5O(%spwA%Qb-Whhe+`9iva4cn~KM``cqy=
z8m94L8d{%@CiY@s-DToYOEFp3Wnr&PLO+J(phdJlbsxyaCH4{2{3H{H-;E&EL0LGb
zcNBfs&%wB`NIEq=7q^-T^L$z!c56gX$qGT=rBUQ@BM%F*A}OmNANQV#rk~om`0P*&
zy*J6ij|R~+d{!3rj*O+oE9tmodNidSOh>2Lu_TE}Me|Ehr29>Rwf$nrWI_ray(iee
zI2ntLVyLSn9Umw~(a>HQ81o{6=1xe%%UKb$??fs-5!Pd3p#ik61kc5!DS3EkM
z3Zc0vi74MUh|ZbBW7WGrs&7lgitYa7bRZr>jQq*#aT3Nx`BBl_1av*`OJAQPqrBh`
zmmEn#562MNR+o&nQw9IFEeZ8i1wRBScp@r*bVeoP(++UAg+kL>ZLu&bHak>W*BiaFR@*N3X-=3v2FFRJhm=GzEgfgk4KVQvO>ZA?dr07UIp~=prYo;&
zz|25r|VK&|>Lvdzy&-`N@Twr@Ua`Dc-e
zV;*i0XV8P^xhQJLq^0vRF{e76@`vW4{)lY4(3p*@zGu^&h%Agt%%Q}l4D6ecLsvu6
z@zS6iy04OkaV(o87O7Y*l||(jC3tRG2KC}4=-W4)a9k=LU7SjrJ5%w3jfA}Q(=j9}
zg{D;q>$N?Z_D;&e_pg)5tuh<++)@bJax_u)BoJODglTqhn8cpmY!D~{fl<_zjZG%R&W
zCTX=a{3-Bn>DpA>_a}jx3R3Xv&?JhvFSOGhPoE7_(d)-d^3lk^ppXPQ^E4fYy3C|y
z!Z>aAOrU$mvT(WiObQm(g-&w@RyZi5%=Q
z&}3yI#rb4m?eQdfkduWi^ApKJ@TV%1lF4jW4n_<}qVG+)C_gcUzFZajs6jGiyvoD2
zOA@O1Hy5o09-S-rTm8B;lIdH3-vvJYQ<9G%g8k~Y72uTAG&=At78mK8(nb3ibUANI
z4Qa7hH_n_M4w;E2yUl3C*f<BsmuEU&YsTd$+A#%~JAnZ#hjQgb@{HWIf6nbAhw2wdSbg~o3R
z$Fq56bgMlATLaB$rfVoJRu+!v4L3cuYEk+D$UJ_=~afJpp&
z3hD0YaBSLTMeinu;i)mx=+}x6JTPt=9q1K|KEk>APgNiqHXx0n0Q|N9XsTTR%KsG6
z^l1S&I$$boJs5y>*DUDl%0L{OVNSmu2jSGkX5_v;8l`$qrD^5S$n|D)>sbu070%m>
z9>ie49ZTBZKN<%sSkO0@82plj6ge^)PjmwL$V6eQ@ZG5cqp|()G>Hnt}lL?%_#VWH|{#d=$}+y
zJonU+9BaLCDQ8JvhWOzGZ*%$)?Sp%tnbD(3VhsFgN=+HQm>p_LbEN!nh(06dT0cA;
zz-V=s82u(qrQS7uIJfUqN}4U`WobbVUBx)I#+(XQ1)!lYU)C@4$8iNy=)?3Nv=5m=
zht3A#O9NBd>o1IBhcQj~A;w9gO({A`jMI~hX-IPbD$g*Y-mSsdY-3EW2ZAwwogo>{
z3&YD(jcMjTVVJPQkp5MO#No}x;B{MVFT#D`$8f*IYF4Z~De!p$9zX0tu|-K3
zqUl1RK8e_J!I2hSjmO0zCn~E-z}uGg#0`$eyaaptQ;~p{n{DZZbUYr-vZVyaL|m?5
zP5TeWqiEYSvY(lRw!-|!%L!<%fwc5tG7eqoOiNcMVPmi(eQQd=`PPSyBLxK~{GD^nAw{|p1KN-D+c|YfEA~w|8
z68A9?e+;vy{k6$B@}UD&%}c_aS;D+Nnv5YottsJ33aYSaboF8~9u)33&*rD%?QvEl
z^+SS(zXE+(DZ%+QjPix{mp=s>SCNEs?HIX_l;A!+5%p6|$69$tq3_c0S=v!(nNcG5_bbc;|@IE_X)6{5~8Tl(?52b`_Y`1ql_L!hcuwsICrT0a`;&j1DOax$!kO}mbue``K=f96ERwptnPRD&ZF7)xTI&?|b?GCwC!#?p%LbY>`(at))2KvOn)k;L(3jNN^Z4>pa|id
z_{0G^>b+^{MGF{I=6Fr(kzqAUb
zbgqH*74BPRol}RypTu