diff --git a/CHANGES.md b/CHANGES.md index 546089ba1afc..a700ce5eb83e 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -17,6 +17,7 @@ Change Log * The `PostProcessStageLibrary.createBlackAndWhiteStage` and `PostProcessStageLibrary.createSilhouetteStage` have per-feature support. * Added CZML support for `zIndex` for `corridor`, `ellipse`, `polygon`, `polyline` and `rectangle`. [#6708](https://github.com/AnalyticalGraphicsInc/cesium/pull/6708) * Added CZML `clampToGround` option for `polyline`. [#6706](https://github.com/AnalyticalGraphicsInc/cesium/pull/6706) +* Added support for `RTC_CENTER` property in batched 3D model tilesets to conform to the updated [3D Tiles spec](https://github.com/AnalyticalGraphicsInc/3d-tiles/issues/263). [#6488](https://github.com/AnalyticalGraphicsInc/cesium/issues/6488) * Added `heightReference` and `extrudedHeightReference` properties to `CorridorGraphics`, `EllipseGraphics`, `PolygonGraphics` and `RectangleGraphics`. [#6717](https://github.com/AnalyticalGraphicsInc/cesium/pull/6717) * This can be used in conjunction with the `height` and/or `extrudedHeight` properties to clamp the geometry to terrain or set the height relative to terrain. * Note, this will not make the geometry conform to terrain. Extruded geoemtry that is clamped to the ground will have a flat top will sinks into the terrain at the base. diff --git a/Source/Scene/Batched3DModel3DTileContent.js b/Source/Scene/Batched3DModel3DTileContent.js index 81709266d6a7..b89874f33998 100644 --- a/Source/Scene/Batched3DModel3DTileContent.js +++ b/Source/Scene/Batched3DModel3DTileContent.js @@ -1,5 +1,7 @@ define([ + '../Core/Cartesian3', '../Core/Color', + '../Core/ComponentDatatype', '../Core/defaultValue', '../Core/defined', '../Core/defineProperties', @@ -9,6 +11,7 @@ define([ '../Core/FeatureDetection', '../Core/getBaseUri', '../Core/getStringFromTypedArray', + '../Core/Matrix4', '../Core/RequestType', '../Core/RuntimeError', '../Renderer/Pass', @@ -20,7 +23,9 @@ define([ './Model', './ModelUtility' ], function( + Cartesian3, Color, + ComponentDatatype, defaultValue, defined, defineProperties, @@ -30,6 +35,7 @@ define([ FeatureDetection, getBaseUri, getStringFromTypedArray, + Matrix4, RequestType, RuntimeError, Pass, @@ -73,6 +79,9 @@ define([ this._batchIdAttributeName = undefined; this._diffuseAttributeOrUniformName = {}; + this._rtcCenterTransform = undefined; + this._contentModelMatrix = undefined; + this.featurePropertiesDirty = false; initialize(this, arrayBuffer, byteOffset); @@ -346,6 +355,14 @@ define([ primitive : tileset }; + content._rtcCenterTransform = Matrix4.clone(Matrix4.IDENTITY); + var rtcCenter = featureTable.getGlobalProperty('RTC_CENTER', ComponentDatatype.FLOAT, 3); + if (defined(rtcCenter)) { + content._rtcCenterTransform = Matrix4.fromTranslation(Cartesian3.fromArray(rtcCenter), content._rtcCenterTransform); + } + + content._contentModelMatrix = Matrix4.multiply(tile.computedTransform, content._rtcCenterTransform, new Matrix4()); + if (!defined(tileset.classificationType)) { // PERFORMANCE_IDEA: patch the shader on demand, e.g., the first time show/color changes. // The pick shader still needs to be patched. @@ -356,7 +373,7 @@ define([ opaquePass : Pass.CESIUM_3D_TILE, // Draw opaque portions of the model during the 3D Tiles pass basePath : resource, requestType : RequestType.TILES3D, - modelMatrix : tile.computedTransform, + modelMatrix: content._contentModelMatrix, upAxis : tileset._gltfUpAxis, forwardAxis : Axis.X, shadows: tileset.shadows, @@ -377,7 +394,7 @@ define([ cull : false, // The model is already culled by 3D Tiles basePath : resource, requestType : RequestType.TILES3D, - modelMatrix : tile.computedTransform, + modelMatrix: content._contentModelMatrix, upAxis : tileset._gltfUpAxis, forwardAxis : Axis.X, debugWireframe : tileset.debugWireframe, @@ -438,7 +455,10 @@ define([ // the content's resource loading. In the READY state, it will // actually generate commands. this._batchTable.update(tileset, frameState); - this._model.modelMatrix = this._tile.computedTransform; + + this._contentModelMatrix = Matrix4.multiply(this._tile.computedTransform, this._rtcCenterTransform, this._contentModelMatrix); + this._model.modelMatrix = this._contentModelMatrix; + this._model.shadows = this._tileset.shadows; this._model.debugWireframe = this._tileset.debugWireframe; diff --git a/Specs/Data/Cesium3DTiles/Batched/BatchedWithRtcCenter/batchedWithRtcCenter.b3dm b/Specs/Data/Cesium3DTiles/Batched/BatchedWithRtcCenter/batchedWithRtcCenter.b3dm new file mode 100644 index 000000000000..f9eaa6f7817e Binary files /dev/null and b/Specs/Data/Cesium3DTiles/Batched/BatchedWithRtcCenter/batchedWithRtcCenter.b3dm differ diff --git a/Specs/Data/Cesium3DTiles/Batched/BatchedWithRtcCenter/tileset.json b/Specs/Data/Cesium3DTiles/Batched/BatchedWithRtcCenter/tileset.json new file mode 100644 index 000000000000..fd8a0a97ba2a --- /dev/null +++ b/Specs/Data/Cesium3DTiles/Batched/BatchedWithRtcCenter/tileset.json @@ -0,0 +1,59 @@ +{ + "asset": { + "version": "1.0" + }, + "properties": { + "id": { + "minimum": 0, + "maximum": 9 + }, + "Longitude": { + "minimum": -1.3196972173766555, + "maximum": -1.3196718547473905 + }, + "Latitude": { + "minimum": 0.6988624606923348, + "maximum": 0.6988888301460953 + }, + "Height": { + "minimum": 6.2074098233133554, + "maximum": 12.83180232718587 + } + }, + "geometricError": 70, + "root": { + "transform": [ + 0.9686356343768792, + 0.24848542777253735, + 0, + 0, + -0.15986460744966327, + 0.623177611820219, + 0.765567091384559, + 0, + 0.19023226619126932, + -0.7415555652213445, + 0.6433560667227647, + 0, + 1215011.9317263428, + -4736309.3434217675, + 4081602.0044800863, + 1 + ], + "refine": "ADD", + "boundingVolume": { + "region": [ + -1.3197004795898053, + 0.6988582109, + -1.3196595204101946, + 0.6988897891, + 0, + 20 + ] + }, + "geometricError": 0, + "content": { + "url": "batchedWithRtcCenter.b3dm" + } + } +} diff --git a/Specs/Scene/Batched3DModel3DTileContentSpec.js b/Specs/Scene/Batched3DModel3DTileContentSpec.js index 67503975769e..52a2ef22f301 100644 --- a/Specs/Scene/Batched3DModel3DTileContentSpec.js +++ b/Specs/Scene/Batched3DModel3DTileContentSpec.js @@ -4,6 +4,7 @@ defineSuite([ 'Core/Color', 'Core/HeadingPitchRange', 'Core/HeadingPitchRoll', + 'Core/Matrix4', 'Core/Transforms', 'Scene/ClippingPlane', 'Scene/ClippingPlaneCollection', @@ -16,6 +17,7 @@ defineSuite([ Color, HeadingPitchRange, HeadingPitchRoll, + Matrix4, Transforms, ClippingPlane, ClippingPlaneCollection, @@ -42,6 +44,7 @@ defineSuite([ var deprecated1Url = './Data/Cesium3DTiles/Batched/BatchedDeprecated1/tileset.json'; var deprecated2Url = './Data/Cesium3DTiles/Batched/BatchedDeprecated2/tileset.json'; var gltfZUpUrl = './Data/Cesium3DTiles/Batched/BatchedGltfZUp/tileset.json'; + var withRtcCenterUrl = './Data/Cesium3DTiles/Batched/BatchedWithRtcCenter/tileset.json'; function setCamera(longitude, latitude) { // One feature is located at the center, point the camera there @@ -371,6 +374,31 @@ defineSuite([ }); }); + it('transforms model positions by RTC_CENTER property in the features table', function() { + return Cesium3DTilesTester.loadTileset(scene, withRtcCenterUrl).then(function(tileset) { + Cesium3DTilesTester.expectRenderTileset(scene, tileset); + + var rtcTransform = tileset._root._content._rtcCenterTransform; + expect(rtcTransform).toEqual(Matrix4.fromTranslation(new Cartesian3(0.1, 0.2, 0.3))); + + var expectedModelTransform = Matrix4.multiply(tileset._root.transform, rtcTransform, new Matrix4()); + expect(tileset._root._content._contentModelMatrix).toEqual(expectedModelTransform); + expect(tileset._root._content._model._modelMatrix).toEqual(expectedModelTransform); + + // Update tile transform + var newLongitude = -1.31962; + var newLatitude = 0.698874; + var newCenter = Cartesian3.fromRadians(newLongitude, newLatitude, 0.0); + var newHPR = new HeadingPitchRoll(); + var newTransform = Transforms.headingPitchRollToFixedFrame(newCenter, newHPR); + tileset._root.transform = newTransform; + scene.renderForSpecs(); + + expectedModelTransform = Matrix4.multiply(tileset._root.computedTransform, rtcTransform, expectedModelTransform); + expect(tileset._root._content._model._modelMatrix).toEqual(expectedModelTransform); + }); + }); + it('destroys', function() { return Cesium3DTilesTester.tileDestroys(scene, withoutBatchTableUrl); });