diff --git a/Apps/SampleData/models/DracoCompressed/CesiumMilkTruck.gltf b/Apps/SampleData/models/DracoCompressed/CesiumMilkTruck.gltf index 2132e20303b..f9edc433dec 100644 --- a/Apps/SampleData/models/DracoCompressed/CesiumMilkTruck.gltf +++ b/Apps/SampleData/models/DracoCompressed/CesiumMilkTruck.gltf @@ -17,6 +17,24 @@ "children": [ 3, 1 + ], + "matrix": [ + 0, + 0, + 1, + 0, + 0, + 1, + 0, + 0, + -1, + 0, + 0, + 0, + 0, + 0, + 0, + 1 ] }, { diff --git a/Apps/Sandcastle/gallery/Physically-Based Materials.html b/Apps/Sandcastle/gallery/Physically-Based Materials.html index 960d6d5dc5c..279e730f51c 100644 --- a/Apps/Sandcastle/gallery/Physically-Based Materials.html +++ b/Apps/Sandcastle/gallery/Physically-Based Materials.html @@ -53,7 +53,7 @@ viewer.scene.globe.depthTestAgainstTerrain = true; var position = new Cesium.Cartesian3(-1371108.6511167218, -5508684.080096612, 2901825.449865087); -var heading = Cesium.Math.toRadians(90); +var heading = Cesium.Math.toRadians(180); var pitch = Cesium.Math.toRadians(2); var roll = Cesium.Math.toRadians(-6); var hpr = new Cesium.HeadingPitchRoll(heading, pitch, roll); diff --git a/CHANGES.md b/CHANGES.md index bb1826a35bc..153b0138a7d 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -3,6 +3,9 @@ Change Log ### 1.47 - 2018-07-02 +##### Breaking Changes :mega: +* glTF 2.0 models corrected to face +Z forwards per specification. Internally Cesium uses +X as forward, so a new +Z to +X rotation was added for 2.0 models only. [#6632](https://github.com/AnalyticalGraphicsInc/cesium/pull/6632) + ##### Additions :tada: * `PostProcessStage` has a `selectedFeatures` property which is an array of primitives used for selectively applying a post-process stage. In the fragment shader, use the function `bool czm_selected(vec2 textureCoordinates` to determine whether or not the stage should be applied at that fragment. * The black-and-white and silhouette stages have per-feature support. @@ -27,6 +30,7 @@ Change Log * Removed `Scene.copyGlobeDepth`. Globe depth will now be copied by default when supported. [#6393](https://github.com/AnalyticalGraphicsInc/cesium/pull/6393) * The default `classificationType` for `GroundPrimitive`, `CorridorGraphics`, `EllipseGraphics`, `PolygonGraphics` and `RectangleGraphics` is now `ClassificationType.TERRAIN`. If you wish the geometry to color both terrain and 3D tiles, pass in the option `classificationType: Cesium.ClassificationType.BOTH`. * Removed support for the `options` argument for `Credit` [#6373](https://github.com/AnalyticalGraphicsInc/cesium/issues/6373). Pass in an html string instead. +* glTF 2.0 models corrected to face +Z forwards per specification. Internally Cesium uses +X as forward, so a new +Z to +X rotation was added for 2.0 models only. [#6632](https://github.com/AnalyticalGraphicsInc/cesium/pull/6632) ##### Deprecated :hourglass_flowing_sand: * The `Scene.fxaa` property has been deprecated and will be removed in Cesium 1.47. Use `Scene.postProcessStages.fxaa.enabled`. diff --git a/Source/Scene/Batched3DModel3DTileContent.js b/Source/Scene/Batched3DModel3DTileContent.js index b56ca8dac4f..81709266d6a 100644 --- a/Source/Scene/Batched3DModel3DTileContent.js +++ b/Source/Scene/Batched3DModel3DTileContent.js @@ -12,6 +12,7 @@ define([ '../Core/RequestType', '../Core/RuntimeError', '../Renderer/Pass', + './Axis', './Cesium3DTileBatchTable', './Cesium3DTileFeature', './Cesium3DTileFeatureTable', @@ -32,6 +33,7 @@ define([ RequestType, RuntimeError, Pass, + Axis, Cesium3DTileBatchTable, Cesium3DTileFeature, Cesium3DTileFeatureTable, @@ -356,6 +358,7 @@ define([ requestType : RequestType.TILES3D, modelMatrix : tile.computedTransform, upAxis : tileset._gltfUpAxis, + forwardAxis : Axis.X, shadows: tileset.shadows, debugWireframe: tileset.debugWireframe, incrementallyLoadTextures : false, @@ -376,6 +379,7 @@ define([ requestType : RequestType.TILES3D, modelMatrix : tile.computedTransform, upAxis : tileset._gltfUpAxis, + forwardAxis : Axis.X, debugWireframe : tileset.debugWireframe, vertexShaderLoaded : getVertexShaderCallback(content), classificationShaderLoaded : getClassificationFragmentShaderCallback(content), diff --git a/Source/Scene/Model.js b/Source/Scene/Model.js index 1e28645f54c..6c5d7f88af0 100644 --- a/Source/Scene/Model.js +++ b/Source/Scene/Model.js @@ -577,6 +577,7 @@ define([ this._ignoreCommands = defaultValue(options.ignoreCommands, false); this._requestType = options.requestType; this._upAxis = defaultValue(options.upAxis, Axis.Y); + this._forwardAxis = defaultValue(options.forwardAxis, Axis.Z); /** * @private @@ -970,6 +971,25 @@ define([ } }, + /** + * Gets the model's forward axis. + * By default, glTF 2.0 models are z-forward according to the glTF spec, however older + * glTF (1.0, 0.8) models used x-forward. Note that only Axis.X and Axis.Z are supported. + * + * @memberof Model.prototype + * + * @type {Number} + * @default Axis.Z + * @readonly + * + * @private + */ + forwardAxis : { + get : function() { + return this._forwardAxis; + } + }, + /** * Gets the model's triangle count. * @@ -1367,6 +1387,10 @@ define([ } 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; } @@ -4225,6 +4249,10 @@ define([ }; frameState.brdfLutGenerator.update(frameState); 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; + } ModelUtility.checkSupportedExtensions(this.extensionsRequired); addPipelineExtras(this.gltf); addDefaults(this.gltf); @@ -4358,6 +4386,10 @@ define([ } else if (this._upAxis === Axis.X) { Matrix4.multiplyTransformation(computedModelMatrix, Axis.X_UP_TO_Z_UP, computedModelMatrix); } + if (this._forwardAxis === Axis.Z) { + // glTF 2.0 has a Z-forward convention that must be adapted here to X-forward. + Matrix4.multiplyTransformation(computedModelMatrix, Axis.Z_UP_TO_X_UP, computedModelMatrix); + } } // Update modelMatrix throughout the graph as needed diff --git a/Source/ThirdParty/GltfPipeline/updateVersion.js b/Source/ThirdParty/GltfPipeline/updateVersion.js index 2292007d5fd..637af660308 100644 --- a/Source/ThirdParty/GltfPipeline/updateVersion.js +++ b/Source/ThirdParty/GltfPipeline/updateVersion.js @@ -883,8 +883,12 @@ define([ 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; // 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 diff --git a/Specs/Data/Models/DracoCompression/CesiumMan/CesiumMan.gltf b/Specs/Data/Models/DracoCompression/CesiumMan/CesiumMan.gltf index 440d4adc385..9d07ce45ff7 100644 --- a/Specs/Data/Models/DracoCompression/CesiumMan/CesiumMan.gltf +++ b/Specs/Data/Models/DracoCompression/CesiumMan/CesiumMan.gltf @@ -18,13 +18,13 @@ 1 ], "matrix": [ - 1, 0, 0, + 1, 0, + 1, 0, 0, - -1, 0, 0, 1, diff --git a/Specs/Data/Models/DracoCompression/CesiumMilkTruck/CesiumMilkTruck.gltf b/Specs/Data/Models/DracoCompression/CesiumMilkTruck/CesiumMilkTruck.gltf index 2132e20303b..f9edc433dec 100644 --- a/Specs/Data/Models/DracoCompression/CesiumMilkTruck/CesiumMilkTruck.gltf +++ b/Specs/Data/Models/DracoCompression/CesiumMilkTruck/CesiumMilkTruck.gltf @@ -17,6 +17,24 @@ "children": [ 3, 1 + ], + "matrix": [ + 0, + 0, + 1, + 0, + 0, + 1, + 0, + 0, + -1, + 0, + 0, + 0, + 0, + 0, + 0, + 1 ] }, { diff --git a/Specs/Scene/ModelSpec.js b/Specs/Scene/ModelSpec.js index a9490fe88f1..5919f2619d5 100644 --- a/Specs/Scene/ModelSpec.js +++ b/Specs/Scene/ModelSpec.js @@ -396,7 +396,7 @@ defineSuite([ model.show = false; }); - it('Renders x-up model', function() { + it('renders x-up model', function() { return Resource.fetchJson(boxEcefUrl).then(function(gltf) { // Model data is z-up. Edit the transform to be z-up to x-up. gltf.nodes.node_transform.matrix = Matrix4.pack(Axis.Z_UP_TO_X_UP, new Array(16)); @@ -412,7 +412,7 @@ defineSuite([ }); }); - it('Renders y-up model', function() { + it('renders y-up model', function() { return Resource.fetchJson(boxEcefUrl).then(function(gltf) { // Model data is z-up. Edit the transform to be z-up to y-up. gltf.nodes.node_transform.matrix = Matrix4.pack(Axis.Z_UP_TO_Y_UP, new Array(16)); @@ -428,7 +428,7 @@ defineSuite([ }); }); - it('Renders z-up model', function() { + it('renders z-up model', function() { return Resource.fetchJson(boxEcefUrl).then(function(gltf) { // Model data is z-up. Edit the transform to be the identity. gltf.nodes.node_transform.matrix = Matrix4.pack(Matrix4.IDENTITY, new Array(16)); @@ -444,6 +444,50 @@ defineSuite([ }); }); + it('renders x-forward model', function() { + return Resource.fetchJson(boxEcefUrl).then(function(gltf) { + return loadModelJson(gltf, { + forwardAxis : Axis.X + }).then(function(m) { + verifyRender(m); + expect(m.forwardAxis).toBe(Axis.X); + primitives.remove(m); + }); + }); + }); + + it('renders z-forward model', function() { + return Resource.fetchJson(boxPbrUrl).then(function(gltf) { + return loadModelJson(gltf, { + forwardAxis : Axis.Z + }).then(function(m) { + verifyRender(m); + expect(m.forwardAxis).toBe(Axis.Z); + primitives.remove(m); + }); + }); + }); + + it('detects glTF 1.0 models as x-forward', function() { + return Resource.fetchJson(boxEcefUrl).then(function(gltf) { + return loadModelJson(gltf).then(function(m) { + verifyRender(m); + expect(m.forwardAxis).toBe(Axis.X); + primitives.remove(m); + }); + }); + }); + + it('detects glTF 2.0 models as z-forward', function() { + return Resource.fetchJson(boxPbrUrl).then(function(gltf) { + return loadModelJson(gltf).then(function(m) { + verifyRender(m); + expect(m.forwardAxis).toBe(Axis.Z); + primitives.remove(m); + }); + }); + }); + it('resolves readyPromise', function() { return texturedBoxModel.readyPromise.then(function(model) { verifyRender(model); @@ -2229,6 +2273,7 @@ defineSuite([ function checkVertexColors(model) { model.zoomTo(); + scene.camera.rotateRight(CesiumMath.PI_OVER_TWO); scene.camera.moveUp(0.1); // Red scene.camera.moveLeft(0.5); @@ -2453,7 +2498,8 @@ defineSuite([ it('loads a glTF with KHR_draco_mesh_compression extension with integer attributes', function() { return loadModel(dracoCompressedModelWithAnimationUrl, { - dequantizeInShader : false + dequantizeInShader : false, + forwardAxis : Axis.X }).then(function(m) { verifyRender(m); primitives.remove(m); @@ -2501,7 +2547,8 @@ defineSuite([ it('loads a draco compressed glTF and dequantizes in the shader, skipping generic attributes', function() { return loadModel(dracoCompressedModelWithAnimationUrl, { - dequantizeInShader : true + dequantizeInShader : true, + forwardAxis : Axis.X }).then(function(m) { verifyRender(m);