382 lines
16 KiB
JavaScript
382 lines
16 KiB
JavaScript
|
|
defineSuite([
|
||
|
|
'Scene/Batched3DModel3DTileContent',
|
||
|
|
'Core/Cartesian3',
|
||
|
|
'Core/Color',
|
||
|
|
'Core/HeadingPitchRange',
|
||
|
|
'Core/HeadingPitchRoll',
|
||
|
|
'Core/Matrix4',
|
||
|
|
'Core/Transforms',
|
||
|
|
'Scene/ClippingPlane',
|
||
|
|
'Scene/ClippingPlaneCollection',
|
||
|
|
'Scene/Model',
|
||
|
|
'Specs/Cesium3DTilesTester',
|
||
|
|
'Specs/createScene'
|
||
|
|
], function(
|
||
|
|
Batched3DModel3DTileContent,
|
||
|
|
Cartesian3,
|
||
|
|
Color,
|
||
|
|
HeadingPitchRange,
|
||
|
|
HeadingPitchRoll,
|
||
|
|
Matrix4,
|
||
|
|
Transforms,
|
||
|
|
ClippingPlane,
|
||
|
|
ClippingPlaneCollection,
|
||
|
|
Model,
|
||
|
|
Cesium3DTilesTester,
|
||
|
|
createScene) {
|
||
|
|
'use strict';
|
||
|
|
|
||
|
|
var scene;
|
||
|
|
var centerLongitude = -1.31968;
|
||
|
|
var centerLatitude = 0.698874;
|
||
|
|
|
||
|
|
var withBatchTableUrl = './Data/Cesium3DTiles/Batched/BatchedWithBatchTable/tileset.json';
|
||
|
|
var withBatchTableBinaryUrl = './Data/Cesium3DTiles/Batched/BatchedWithBatchTableBinary/tileset.json';
|
||
|
|
var withoutBatchTableUrl = './Data/Cesium3DTiles/Batched/BatchedWithoutBatchTable/tileset.json';
|
||
|
|
var translucentUrl = './Data/Cesium3DTiles/Batched/BatchedTranslucent/tileset.json';
|
||
|
|
var translucentOpaqueMixUrl = './Data/Cesium3DTiles/Batched/BatchedTranslucentOpaqueMix/tileset.json';
|
||
|
|
var withTransformBoxUrl = './Data/Cesium3DTiles/Batched/BatchedWithTransformBox/tileset.json';
|
||
|
|
var withTransformSphereUrl = './Data/Cesium3DTiles/Batched/BatchedWithTransformSphere/tileset.json';
|
||
|
|
var withTransformRegionUrl = './Data/Cesium3DTiles/Batched/BatchedWithTransformRegion/tileset.json';
|
||
|
|
var texturedUrl = './Data/Cesium3DTiles/Batched/BatchedTextured/tileset.json';
|
||
|
|
var deprecated1Url = './Data/Cesium3DTiles/Batched/BatchedDeprecated1/tileset.json';
|
||
|
|
var deprecated2Url = './Data/Cesium3DTiles/Batched/BatchedDeprecated2/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
|
||
|
|
var center = Cartesian3.fromRadians(longitude, latitude);
|
||
|
|
scene.camera.lookAt(center, new HeadingPitchRange(0.0, -1.57, 15.0));
|
||
|
|
}
|
||
|
|
|
||
|
|
beforeAll(function() {
|
||
|
|
scene = createScene();
|
||
|
|
|
||
|
|
// Keep the error from logging to the console when running tests
|
||
|
|
spyOn(Batched3DModel3DTileContent, '_deprecationWarning');
|
||
|
|
});
|
||
|
|
|
||
|
|
afterAll(function() {
|
||
|
|
scene.destroyForSpecs();
|
||
|
|
});
|
||
|
|
|
||
|
|
beforeEach(function() {
|
||
|
|
setCamera(centerLongitude, centerLatitude);
|
||
|
|
});
|
||
|
|
|
||
|
|
afterEach(function() {
|
||
|
|
scene.primitives.removeAll();
|
||
|
|
});
|
||
|
|
|
||
|
|
it('throws with invalid version', function() {
|
||
|
|
var arrayBuffer = Cesium3DTilesTester.generateBatchedTileBuffer({
|
||
|
|
version : 2
|
||
|
|
});
|
||
|
|
Cesium3DTilesTester.loadTileExpectError(scene, arrayBuffer, 'b3dm');
|
||
|
|
});
|
||
|
|
|
||
|
|
it('recognizes the legacy 20-byte header', function() {
|
||
|
|
return Cesium3DTilesTester.loadTileset(scene, deprecated1Url)
|
||
|
|
.then(function(tileset) {
|
||
|
|
expect(Batched3DModel3DTileContent._deprecationWarning).toHaveBeenCalled();
|
||
|
|
Cesium3DTilesTester.expectRenderTileset(scene, tileset);
|
||
|
|
var batchTable = tileset.root.content.batchTable;
|
||
|
|
expect(batchTable._properties).toBeDefined();
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
it('recognizes the legacy 24-byte header', function() {
|
||
|
|
return Cesium3DTilesTester.loadTileset(scene, deprecated2Url)
|
||
|
|
.then(function(tileset) {
|
||
|
|
expect(Batched3DModel3DTileContent._deprecationWarning).toHaveBeenCalled();
|
||
|
|
Cesium3DTilesTester.expectRenderTileset(scene, tileset);
|
||
|
|
var batchTable = tileset.root.content.batchTable;
|
||
|
|
expect(batchTable._properties).toBeDefined();
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
it('logs deprecation warning for use of BATCHID without prefixed underscore', function() {
|
||
|
|
return Cesium3DTilesTester.loadTileset(scene, deprecated1Url)
|
||
|
|
.then(function(tileset) {
|
||
|
|
expect(Batched3DModel3DTileContent._deprecationWarning).toHaveBeenCalled();
|
||
|
|
Cesium3DTilesTester.expectRenderTileset(scene, tileset);
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
it('throws with empty gltf', function() {
|
||
|
|
// Expect to throw DeveloperError in Model due to invalid gltf magic
|
||
|
|
var arrayBuffer = Cesium3DTilesTester.generateBatchedTileBuffer();
|
||
|
|
Cesium3DTilesTester.loadTileExpectError(scene, arrayBuffer, 'b3dm');
|
||
|
|
});
|
||
|
|
|
||
|
|
it('resolves readyPromise', function() {
|
||
|
|
return Cesium3DTilesTester.resolvesReadyPromise(scene, withoutBatchTableUrl);
|
||
|
|
});
|
||
|
|
|
||
|
|
it('renders with batch table', function() {
|
||
|
|
return Cesium3DTilesTester.loadTileset(scene, withBatchTableUrl).then(function(tileset) {
|
||
|
|
Cesium3DTilesTester.expectRenderTileset(scene, tileset);
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
it('renders with batch table binary', function() {
|
||
|
|
return Cesium3DTilesTester.loadTileset(scene, withBatchTableBinaryUrl).then(function(tileset) {
|
||
|
|
Cesium3DTilesTester.expectRenderTileset(scene, tileset);
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
it('renders without batch table', function() {
|
||
|
|
return Cesium3DTilesTester.loadTileset(scene, withoutBatchTableUrl).then(function(tileset) {
|
||
|
|
Cesium3DTilesTester.expectRenderTileset(scene, tileset);
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
it('renders with all features translucent', function() {
|
||
|
|
return Cesium3DTilesTester.loadTileset(scene, translucentUrl).then(function(tileset) {
|
||
|
|
Cesium3DTilesTester.expectRenderTileset(scene, tileset);
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
it('renders with a mix of opaque and translucent features', function() {
|
||
|
|
return Cesium3DTilesTester.loadTileset(scene, translucentOpaqueMixUrl).then(function(tileset) {
|
||
|
|
Cesium3DTilesTester.expectRenderTileset(scene, tileset);
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
it('renders with textures', function() {
|
||
|
|
return Cesium3DTilesTester.loadTileset(scene, texturedUrl).then(function(tileset) {
|
||
|
|
Cesium3DTilesTester.expectRender(scene, tileset);
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
function expectRenderWithTransform(url) {
|
||
|
|
return Cesium3DTilesTester.loadTileset(scene, url).then(function(tileset) {
|
||
|
|
Cesium3DTilesTester.expectRenderTileset(scene, tileset);
|
||
|
|
|
||
|
|
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);
|
||
|
|
|
||
|
|
// Update tile transform
|
||
|
|
tileset.root.transform = newTransform;
|
||
|
|
scene.renderForSpecs();
|
||
|
|
|
||
|
|
// Move the camera to the new location
|
||
|
|
setCamera(newLongitude, newLatitude);
|
||
|
|
Cesium3DTilesTester.expectRenderTileset(scene, tileset);
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
it('renders with a tile transform and box bounding volume', function() {
|
||
|
|
return expectRenderWithTransform(withTransformBoxUrl);
|
||
|
|
});
|
||
|
|
|
||
|
|
it('renders with a tile transform and sphere bounding volume', function() {
|
||
|
|
return expectRenderWithTransform(withTransformSphereUrl);
|
||
|
|
});
|
||
|
|
|
||
|
|
it('renders with a tile transform and region bounding volume', function() {
|
||
|
|
return expectRenderWithTransform(withTransformRegionUrl);
|
||
|
|
});
|
||
|
|
|
||
|
|
it('picks with batch table', function() {
|
||
|
|
return Cesium3DTilesTester.loadTileset(scene, withBatchTableUrl).then(function(tileset) {
|
||
|
|
var content = tileset.root.content;
|
||
|
|
tileset.show = false;
|
||
|
|
expect(scene).toPickPrimitive(undefined);
|
||
|
|
tileset.show = true;
|
||
|
|
expect(scene).toPickAndCall(function(result) {
|
||
|
|
expect(result).toBeDefined();
|
||
|
|
expect(result.primitive).toBe(tileset);
|
||
|
|
expect(result.content).toBe(content);
|
||
|
|
});
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
it('picks without batch table', function() {
|
||
|
|
return Cesium3DTilesTester.loadTileset(scene, withoutBatchTableUrl).then(function(tileset) {
|
||
|
|
var content = tileset.root.content;
|
||
|
|
tileset.show = false;
|
||
|
|
expect(scene).toPickPrimitive(undefined);
|
||
|
|
tileset.show = true;
|
||
|
|
expect(scene).toPickAndCall(function(result) {
|
||
|
|
expect(result).toBeDefined();
|
||
|
|
expect(result.primitive).toBe(tileset);
|
||
|
|
expect(result.content).toBe(content);
|
||
|
|
});
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
it('can get features and properties', function() {
|
||
|
|
return Cesium3DTilesTester.loadTileset(scene, withBatchTableUrl).then(function(tileset) {
|
||
|
|
var content = tileset.root.content;
|
||
|
|
expect(content.featuresLength).toBe(10);
|
||
|
|
expect(content.innerContents).toBeUndefined();
|
||
|
|
expect(content.hasProperty(0, 'id')).toBe(true);
|
||
|
|
expect(content.getFeature(0)).toBeDefined();
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
it('throws when calling getFeature with invalid index', function() {
|
||
|
|
return Cesium3DTilesTester.loadTileset(scene, withoutBatchTableUrl).then(function(tileset) {
|
||
|
|
var content = tileset.root.content;
|
||
|
|
expect(function(){
|
||
|
|
content.getFeature(-1);
|
||
|
|
}).toThrowDeveloperError();
|
||
|
|
expect(function(){
|
||
|
|
content.getFeature(1000);
|
||
|
|
}).toThrowDeveloperError();
|
||
|
|
expect(function(){
|
||
|
|
content.getFeature();
|
||
|
|
}).toThrowDeveloperError();
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
it('gets memory usage', function() {
|
||
|
|
return Cesium3DTilesTester.loadTileset(scene, texturedUrl).then(function(tileset) {
|
||
|
|
var content = tileset.root.content;
|
||
|
|
|
||
|
|
// 10 buildings, 36 ushort indices and 24 vertices per building, 8 float components (position, normal, uv) and 1 uint component (batchId) per vertex.
|
||
|
|
// 10 * ((24 * (8 * 4 + 1 * 4)) + (36 * 2)) = 9360
|
||
|
|
var geometryByteLength = 9360;
|
||
|
|
|
||
|
|
// Texture is 128x128 RGBA bytes, not mipmapped
|
||
|
|
var texturesByteLength = 65536;
|
||
|
|
|
||
|
|
// One RGBA byte pixel per feature
|
||
|
|
var batchTexturesByteLength = content.featuresLength * 4;
|
||
|
|
var pickTexturesByteLength = content.featuresLength * 4;
|
||
|
|
|
||
|
|
// Features have not been picked or colored yet, so the batch table contribution is 0.
|
||
|
|
expect(content.geometryByteLength).toEqual(geometryByteLength);
|
||
|
|
expect(content.texturesByteLength).toEqual(texturesByteLength);
|
||
|
|
expect(content.batchTableByteLength).toEqual(0);
|
||
|
|
|
||
|
|
// Color a feature and expect the texture memory to increase
|
||
|
|
content.getFeature(0).color = Color.RED;
|
||
|
|
scene.renderForSpecs();
|
||
|
|
expect(content.geometryByteLength).toEqual(geometryByteLength);
|
||
|
|
expect(content.texturesByteLength).toEqual(texturesByteLength);
|
||
|
|
expect(content.batchTableByteLength).toEqual(batchTexturesByteLength);
|
||
|
|
|
||
|
|
// Pick the tile and expect the texture memory to increase
|
||
|
|
scene.pickForSpecs();
|
||
|
|
expect(content.geometryByteLength).toEqual(geometryByteLength);
|
||
|
|
expect(content.texturesByteLength).toEqual(texturesByteLength);
|
||
|
|
expect(content.batchTableByteLength).toEqual(batchTexturesByteLength + pickTexturesByteLength);
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
it('Links model to tileset clipping planes based on bounding volume clipping', function() {
|
||
|
|
return Cesium3DTilesTester.loadTileset(scene, withBatchTableUrl).then(function(tileset) {
|
||
|
|
var tile = tileset.root;
|
||
|
|
var content = tile.content;
|
||
|
|
var model = content._model;
|
||
|
|
|
||
|
|
expect(model.clippingPlanes).toBeUndefined();
|
||
|
|
|
||
|
|
var clippingPlaneCollection = new ClippingPlaneCollection({
|
||
|
|
planes : [
|
||
|
|
new ClippingPlane(Cartesian3.UNIT_X, 0.0)
|
||
|
|
]
|
||
|
|
});
|
||
|
|
tileset.clippingPlanes = clippingPlaneCollection;
|
||
|
|
clippingPlaneCollection.update(scene.frameState);
|
||
|
|
tile.update(tileset, scene.frameState);
|
||
|
|
|
||
|
|
expect(model.clippingPlanes).toBeDefined();
|
||
|
|
expect(model.clippingPlanes).toBe(tileset.clippingPlanes);
|
||
|
|
|
||
|
|
tile._isClipped = false;
|
||
|
|
tile.update(tileset, scene.frameState);
|
||
|
|
|
||
|
|
expect(model.clippingPlanes).toBeUndefined();
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
it('Links model to tileset clipping planes if tileset clipping planes are reassigned', function() {
|
||
|
|
return Cesium3DTilesTester.loadTileset(scene, withBatchTableUrl).then(function(tileset) {
|
||
|
|
var tile = tileset.root;
|
||
|
|
var model = tile.content._model;
|
||
|
|
|
||
|
|
expect(model.clippingPlanes).toBeUndefined();
|
||
|
|
|
||
|
|
var clippingPlaneCollection = new ClippingPlaneCollection({
|
||
|
|
planes : [
|
||
|
|
new ClippingPlane(Cartesian3.UNIT_X, 0.0)
|
||
|
|
]
|
||
|
|
});
|
||
|
|
tileset.clippingPlanes = clippingPlaneCollection;
|
||
|
|
clippingPlaneCollection.update(scene.frameState);
|
||
|
|
tile.update(tileset, scene.frameState);
|
||
|
|
|
||
|
|
expect(model.clippingPlanes).toBeDefined();
|
||
|
|
expect(model.clippingPlanes).toBe(tileset.clippingPlanes);
|
||
|
|
|
||
|
|
var newClippingPlaneCollection = new ClippingPlaneCollection({
|
||
|
|
planes : [
|
||
|
|
new ClippingPlane(Cartesian3.UNIT_X, 0.0)
|
||
|
|
]
|
||
|
|
});
|
||
|
|
tileset.clippingPlanes = newClippingPlaneCollection;
|
||
|
|
newClippingPlaneCollection.update(scene.frameState);
|
||
|
|
expect(model.clippingPlanes).not.toBe(tileset.clippingPlanes);
|
||
|
|
|
||
|
|
tile.update(tileset, scene.frameState);
|
||
|
|
expect(model.clippingPlanes).toBe(tileset.clippingPlanes);
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
it('rebuilds Model shaders when clipping planes change', function() {
|
||
|
|
spyOn(Model, '_getClippingFunction').and.callThrough();
|
||
|
|
|
||
|
|
return Cesium3DTilesTester.loadTileset(scene, withBatchTableUrl).then(function(tileset) {
|
||
|
|
var tile = tileset.root;
|
||
|
|
|
||
|
|
var clippingPlaneCollection = new ClippingPlaneCollection({
|
||
|
|
planes : [
|
||
|
|
new ClippingPlane(Cartesian3.UNIT_X, 0.0)
|
||
|
|
]
|
||
|
|
});
|
||
|
|
tileset.clippingPlanes = clippingPlaneCollection;
|
||
|
|
clippingPlaneCollection.update(scene.frameState);
|
||
|
|
tile.update(tileset, scene.frameState);
|
||
|
|
|
||
|
|
expect(Model._getClippingFunction.calls.count()).toEqual(1);
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
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.camera.lookAt(newCenter, new HeadingPitchRange(0.0, 0.0, 15.0));
|
||
|
|
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);
|
||
|
|
});
|
||
|
|
|
||
|
|
}, 'WebGL');
|