You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Cesium-Prequel/Specs/Scene/GlobeSurfaceTileProviderSpe...

1312 lines
42 KiB
JavaScript

import { Cartesian3 } from "../../Source/Cesium.js";
import { Cartesian4 } from "../../Source/Cesium.js";
import { CesiumTerrainProvider } from "../../Source/Cesium.js";
import { Color } from "../../Source/Cesium.js";
import { Credit } from "../../Source/Cesium.js";
import { defined } from "../../Source/Cesium.js";
import { Ellipsoid } from "../../Source/Cesium.js";
import { EllipsoidTerrainProvider } from "../../Source/Cesium.js";
import { GeographicProjection } from "../../Source/Cesium.js";
import { HeadingPitchRoll } from "../../Source/Cesium.js";
import { Rectangle } from "../../Source/Cesium.js";
import { WebMercatorProjection } from "../../Source/Cesium.js";
import { ContextLimits } from "../../Source/Cesium.js";
import { RenderState } from "../../Source/Cesium.js";
import { BlendingState } from "../../Source/Cesium.js";
import { ClippingPlane } from "../../Source/Cesium.js";
import { ClippingPlaneCollection } from "../../Source/Cesium.js";
import { Fog } from "../../Source/Cesium.js";
import { Globe } from "../../Source/Cesium.js";
import { GlobeSurfaceShaderSet } from "../../Source/Cesium.js";
import { GlobeSurfaceTileProvider } from "../../Source/Cesium.js";
import { ImageryLayerCollection } from "../../Source/Cesium.js";
import { ImagerySplitDirection } from "../../Source/Cesium.js";
import { Model } from "../../Source/Cesium.js";
import { QuadtreeTile } from "../../Source/Cesium.js";
import { QuadtreeTileProvider } from "../../Source/Cesium.js";
import { SceneMode } from "../../Source/Cesium.js";
import { SingleTileImageryProvider } from "../../Source/Cesium.js";
import { WebMapServiceImageryProvider } from "../../Source/Cesium.js";
import createScene from "../createScene.js";
import pollToPromise from "../pollToPromise.js";
describe(
"Scene/GlobeSurfaceTileProvider",
function () {
var scene;
function forEachRenderedTile(
quadtreePrimitive,
minimumTiles,
maximumTiles,
callback
) {
var tileCount = 0;
quadtreePrimitive.forEachRenderedTile(function (tile) {
++tileCount;
callback(tile);
});
if (defined(minimumTiles)) {
expect(tileCount).not.toBeLessThan(minimumTiles);
}
if (defined(maximumTiles)) {
expect(tileCount).not.toBeGreaterThan(maximumTiles);
}
}
/**
* Repeatedly calls update until the load queue is empty. You must wrap any code to follow
* this in a "runs" function.
*/
function updateUntilDone(globe) {
// update until the load queue is empty.
return pollToPromise(function () {
scene.renderForSpecs();
return (
globe._surface.tileProvider.ready &&
globe._surface._tileLoadQueueHigh.length === 0 &&
globe._surface._tileLoadQueueMedium.length === 0 &&
globe._surface._tileLoadQueueLow.length === 0 &&
globe._surface._debug.tilesWaitingForChildren === 0
);
});
}
var cameraDestination = new Rectangle(0.0001, 0.0001, 0.003, 0.003);
function switchViewMode(mode, projection) {
scene.mode = mode;
scene.frameState.mapProjection = projection;
scene.camera.update(scene.mode);
scene.camera.setView({
destination: cameraDestination,
});
}
beforeAll(function () {
scene = createScene();
scene.frameState.scene3DOnly = false;
});
afterAll(function () {
scene.destroyForSpecs();
});
beforeEach(function () {
scene.globe = new Globe();
});
afterEach(function () {
scene.imageryLayers.removeAll();
scene.primitives.removeAll();
});
it("conforms to QuadtreeTileProvider interface", function () {
expect(GlobeSurfaceTileProvider).toConformToInterface(
QuadtreeTileProvider
);
});
describe(
"construction",
function () {
it("throws if a terrainProvider is not provided", function () {
function constructWithoutTerrainProvider() {
return new GlobeSurfaceTileProvider({
imageryLayers: new ImageryLayerCollection(),
surfaceShaderSet: new GlobeSurfaceShaderSet(),
});
}
expect(constructWithoutTerrainProvider).toThrowDeveloperError();
});
it("throws if a imageryLayers is not provided", function () {
function constructWithoutImageryLayerCollection() {
return new GlobeSurfaceTileProvider({
terrainProvider: new EllipsoidTerrainProvider(),
surfaceShaderSet: new GlobeSurfaceShaderSet(),
});
}
expect(
constructWithoutImageryLayerCollection
).toThrowDeveloperError();
});
it("throws if a surfaceShaderSet is not provided", function () {
function constructWithoutImageryLayerCollection() {
return new GlobeSurfaceTileProvider({
terrainProvider: new EllipsoidTerrainProvider(),
imageryLayers: new ImageryLayerCollection(),
});
}
expect(
constructWithoutImageryLayerCollection
).toThrowDeveloperError();
});
},
"WebGL"
);
describe(
"layer updating",
function () {
it("removing a layer removes it from all tiles", function () {
var layer = scene.imageryLayers.addImageryProvider(
new SingleTileImageryProvider({
url: "Data/Images/Red16x16.png",
})
);
return updateUntilDone(scene.globe).then(function () {
// All tiles should have one or more associated images.
forEachRenderedTile(scene.globe._surface, 1, undefined, function (
tile
) {
expect(tile.data.imagery.length).toBeGreaterThan(0);
for (var i = 0; i < tile.data.imagery.length; ++i) {
expect(tile.data.imagery[i].readyImagery.imageryLayer).toEqual(
layer
);
}
});
scene.imageryLayers.remove(layer);
// All associated images should be gone.
forEachRenderedTile(scene.globe._surface, 1, undefined, function (
tile
) {
expect(tile.data.imagery.length).toEqual(0);
});
});
});
it("adding a layer adds it to all tiles after update", function () {
scene.imageryLayers.addImageryProvider(
new SingleTileImageryProvider({
url: "Data/Images/Red16x16.png",
})
);
return updateUntilDone(scene.globe).then(function () {
// Add another layer
var layer2 = scene.imageryLayers.addImageryProvider(
new SingleTileImageryProvider({
url: "Data/Images/Green4x4.png",
})
);
return updateUntilDone(scene.globe).then(function () {
// All tiles should have one or more associated images.
forEachRenderedTile(scene.globe._surface, 1, undefined, function (
tile
) {
expect(tile.data.imagery.length).toBeGreaterThan(0);
var hasImageFromLayer2 = false;
for (var i = 0; i < tile.data.imagery.length; ++i) {
var imageryTile = tile.data.imagery[i].readyImagery;
if (!defined(imageryTile)) {
imageryTile = tile.data.imagery[i].loadingImagery;
}
if (imageryTile.imageryLayer === layer2) {
hasImageFromLayer2 = true;
}
}
expect(hasImageFromLayer2).toEqual(true);
});
});
});
});
it("moving a layer moves the corresponding TileImagery instances on every tile", function () {
var layer1 = scene.imageryLayers.addImageryProvider(
new SingleTileImageryProvider({
url: "Data/Images/Red16x16.png",
})
);
var layer2 = scene.imageryLayers.addImageryProvider(
new SingleTileImageryProvider({
url: "Data/Images/Green4x4.png",
})
);
return updateUntilDone(scene.globe).then(function () {
forEachRenderedTile(scene.globe._surface, 1, undefined, function (
tile
) {
expect(tile.data.imagery.length).toBeGreaterThan(0);
var indexOfFirstLayer1 = tile.data.imagery.length;
var indexOfLastLayer1 = -1;
var indexOfFirstLayer2 = tile.data.imagery.length;
for (var i = 0; i < tile.data.imagery.length; ++i) {
if (tile.data.imagery[i].readyImagery.imageryLayer === layer1) {
indexOfFirstLayer1 = Math.min(indexOfFirstLayer1, i);
indexOfLastLayer1 = i;
} else {
expect(
tile.data.imagery[i].readyImagery.imageryLayer
).toEqual(layer2);
indexOfFirstLayer2 = Math.min(indexOfFirstLayer2, i);
}
}
expect(indexOfFirstLayer1).toBeLessThan(indexOfFirstLayer2);
expect(indexOfLastLayer1).toBeLessThan(indexOfFirstLayer2);
});
scene.imageryLayers.raiseToTop(layer1);
return updateUntilDone(scene.globe).then(function () {
forEachRenderedTile(scene.globe._surface, 1, undefined, function (
tile
) {
expect(tile.data.imagery.length).toBeGreaterThan(0);
var indexOfFirstLayer2 = tile.data.imagery.length;
var indexOfLastLayer2 = -1;
var indexOfFirstLayer1 = tile.data.imagery.length;
for (var i = 0; i < tile.data.imagery.length; ++i) {
if (
tile.data.imagery[i].readyImagery.imageryLayer === layer2
) {
indexOfFirstLayer2 = Math.min(indexOfFirstLayer2, i);
indexOfLastLayer2 = i;
} else {
expect(
tile.data.imagery[i].readyImagery.imageryLayer
).toEqual(layer1);
indexOfFirstLayer1 = Math.min(indexOfFirstLayer1, i);
}
}
expect(indexOfFirstLayer2).toBeLessThan(indexOfFirstLayer1);
expect(indexOfLastLayer2).toBeLessThan(indexOfFirstLayer1);
});
});
});
});
it("adding a layer creates its skeletons only once", function () {
scene.imageryLayers.addImageryProvider(
new SingleTileImageryProvider({
url: "Data/Images/Red16x16.png",
})
);
return updateUntilDone(scene.globe).then(function () {
// Add another layer
var layer2 = scene.imageryLayers.addImageryProvider(
new SingleTileImageryProvider({
url: "Data/Images/Green4x4.png",
})
);
return updateUntilDone(scene.globe).then(function () {
// All tiles should have one or more associated images.
forEachRenderedTile(scene.globe._surface, 1, undefined, function (
tile
) {
expect(tile.data.imagery.length).toBeGreaterThan(0);
var tilesFromLayer2 = 0;
for (var i = 0; i < tile.data.imagery.length; ++i) {
var imageryTile = tile.data.imagery[i].readyImagery;
if (!defined(imageryTile)) {
imageryTile = tile.data.imagery[i].loadingImagery;
}
if (imageryTile.imageryLayer === layer2) {
++tilesFromLayer2;
}
}
expect(tilesFromLayer2).toBe(1);
});
});
});
});
it("calling _reload adds a callback per layer per tile", function () {
var layer1 = scene.imageryLayers.addImageryProvider(
new SingleTileImageryProvider({
url: "Data/Images/Red16x16.png",
})
);
var layer2 = scene.imageryLayers.addImageryProvider(
new SingleTileImageryProvider({
url: "Data/Images/Green4x4.png",
})
);
return updateUntilDone(scene.globe).then(function () {
// Verify that each tile has 2 imagery objects and no loaded callbacks
forEachRenderedTile(scene.globe._surface, 1, undefined, function (
tile
) {
expect(tile.data.imagery.length).toBe(2);
expect(Object.keys(tile._loadedCallbacks).length).toBe(0);
});
// Reload each layer
layer1._imageryProvider._reload();
layer2._imageryProvider._reload();
// These should be ignored
layer1._imageryProvider._reload();
layer2._imageryProvider._reload();
// Verify that each tile has 4 imagery objects (the old imagery and the reloaded imagery for each layer)
// and also has 2 callbacks so the old imagery will be removed once loaded.
forEachRenderedTile(scene.globe._surface, 1, undefined, function (
tile
) {
expect(tile.data.imagery.length).toBe(4);
expect(Object.keys(tile._loadedCallbacks).length).toBe(2);
});
return updateUntilDone(scene.globe).then(function () {
// Verify the old imagery was removed and the callbacks are no longer there
forEachRenderedTile(scene.globe._surface, 1, undefined, function (
tile
) {
expect(tile.data.imagery.length).toBe(2);
expect(Object.keys(tile._loadedCallbacks).length).toBe(0);
});
});
});
});
},
"WebGL"
);
it("renders in 2D geographic", function () {
expect(scene).toRender([0, 0, 0, 255]);
scene.imageryLayers.addImageryProvider(
new SingleTileImageryProvider({
url: "Data/Images/Red16x16.png",
})
);
switchViewMode(
SceneMode.SCENE2D,
new GeographicProjection(Ellipsoid.WGS84)
);
return updateUntilDone(scene.globe).then(function () {
expect(scene).notToRender([0, 0, 0, 255]);
});
});
it("renders in 2D web mercator", function () {
expect(scene).toRender([0, 0, 0, 255]);
scene.imageryLayers.addImageryProvider(
new SingleTileImageryProvider({
url: "Data/Images/Red16x16.png",
})
);
switchViewMode(
SceneMode.SCENE2D,
new WebMercatorProjection(Ellipsoid.WGS84)
);
return updateUntilDone(scene.globe).then(function () {
expect(scene).notToRender([0, 0, 0, 255]);
});
});
it("renders in Columbus View geographic", function () {
expect(scene).toRender([0, 0, 0, 255]);
scene.imageryLayers.addImageryProvider(
new SingleTileImageryProvider({
url: "Data/Images/Red16x16.png",
})
);
switchViewMode(
SceneMode.COLUMBUS_VIEW,
new GeographicProjection(Ellipsoid.WGS84)
);
return updateUntilDone(scene.globe).then(function () {
expect(scene).notToRender([0, 0, 0, 255]);
});
});
it("renders in Columbus View web mercator", function () {
expect(scene).toRender([0, 0, 0, 255]);
scene.imageryLayers.addImageryProvider(
new SingleTileImageryProvider({
url: "Data/Images/Red16x16.png",
})
);
switchViewMode(
SceneMode.COLUMBUS_VIEW,
new WebMercatorProjection(Ellipsoid.WGS84)
);
return updateUntilDone(scene.globe).then(function () {
expect(scene).notToRender([0, 0, 128, 255]);
});
});
it("renders in 3D", function () {
expect(scene).toRender([0, 0, 0, 255]);
scene.imageryLayers.addImageryProvider(
new SingleTileImageryProvider({
url: "Data/Images/Red16x16.png",
})
);
switchViewMode(
SceneMode.SCENE3D,
new GeographicProjection(Ellipsoid.WGS84)
);
return updateUntilDone(scene.globe).then(function () {
expect(scene).notToRender([0, 0, 0, 255]);
});
});
it("renders in 3D (2)", function () {
expect(scene).toRender([0, 0, 0, 255]);
scene.imageryLayers.addImageryProvider(
new SingleTileImageryProvider({
url: "Data/Images/Red16x16.png",
})
);
switchViewMode(
SceneMode.SCENE3D,
new GeographicProjection(Ellipsoid.WGS84)
);
return updateUntilDone(scene.globe).then(function () {
expect(scene).notToRender([0, 0, 0, 255]);
});
});
describe("fog", function () {
it("culls tiles in full fog", function () {
expect(scene).toRender([0, 0, 0, 255]);
scene.imageryLayers.addImageryProvider(
new SingleTileImageryProvider({
url: "Data/Images/Red16x16.png",
})
);
var oldFog = scene.fog;
scene.fog = new Fog();
switchViewMode(
SceneMode.SCENE3D,
new GeographicProjection(Ellipsoid.WGS84)
);
scene.camera.lookUp(1.2); // Horizon-view
return updateUntilDone(scene.globe).then(function () {
expect(scene).notToRender([0, 0, 0, 255]);
scene.fog.enabled = true;
scene.fog.density = 1.0;
scene.fog.screenSpaceErrorFactor = 0.0;
expect(scene).toRender([0, 0, 0, 255]);
scene.fog = oldFog;
});
});
it("culls tiles because of increased SSE", function () {
expect(scene).toRender([0, 0, 0, 255]);
scene.imageryLayers.addImageryProvider(
new SingleTileImageryProvider({
url: "Data/Images/Red16x16.png",
})
);
var oldFog = scene.fog;
scene.fog = new Fog();
switchViewMode(
SceneMode.SCENE3D,
new GeographicProjection(Ellipsoid.WGS84)
);
scene.camera.lookUp(1.2); // Horizon-view
return updateUntilDone(scene.globe).then(function () {
expect(scene).notToRender([0, 0, 0, 255]);
scene.fog.enabled = true;
scene.fog.density = 0.001;
scene.fog.screenSpaceErrorFactor = 0.0;
var result;
expect(scene).toRenderAndCall(function (rgba) {
result = rgba;
expect(rgba).not.toEqual([0, 0, 0, 255]);
});
scene.fog.screenSpaceErrorFactor = 10000.0;
expect(scene).notToRender(result);
scene.fog = oldFog;
});
});
});
it("can change baseColor", function () {
expect(scene).toRender([0, 0, 0, 255]);
scene.globe.baseColor = Color.RED;
scene.fog.enabled = false;
switchViewMode(
SceneMode.SCENE3D,
new GeographicProjection(Ellipsoid.WGS84)
);
return updateUntilDone(scene.globe).then(function () {
expect(scene).toRender([255, 0, 0, 255]);
});
});
it("renders in 3D and then Columbus View", function () {
scene.imageryLayers.addImageryProvider(
new SingleTileImageryProvider({
url: "Data/Images/Red16x16.png",
})
);
switchViewMode(
SceneMode.SCENE3D,
new GeographicProjection(Ellipsoid.WGS84)
);
return updateUntilDone(scene.globe).then(function () {
expect(scene).notToRender([0, 0, 0, 255]);
switchViewMode(
SceneMode.COLUMBUS_VIEW,
new GeographicProjection(Ellipsoid.WGS84)
);
return updateUntilDone(scene.globe).then(function () {
expect(scene).notToRender([0, 0, 0, 255]);
});
});
});
it("renders even if imagery root tiles fail to load", function () {
expect(scene).toRender([0, 0, 0, 255]);
var providerWithInvalidRootTiles = new WebMapServiceImageryProvider({
url: "/invalid",
layers: "invalid",
});
scene.imageryLayers.addImageryProvider(providerWithInvalidRootTiles);
switchViewMode(
SceneMode.SCENE3D,
new GeographicProjection(Ellipsoid.WGS84)
);
return updateUntilDone(scene.globe).then(function () {
expect(scene).notToRender([0, 0, 0, 255]);
});
});
it("passes layer adjustment values as uniforms", function () {
expect(scene).toRender([0, 0, 0, 255]);
var layer = scene.imageryLayers.addImageryProvider(
new SingleTileImageryProvider({
url: "Data/Images/Red16x16.png",
})
);
layer.alpha = 0.123;
layer.nightAlpha = 0.658;
layer.dayAlpha = 0.356;
layer.brightness = 0.456;
layer.contrast = 0.654;
layer.gamma = 0.321;
layer.saturation = 0.123;
layer.hue = 0.456;
layer.splitDirection = ImagerySplitDirection.LEFT;
switchViewMode(
SceneMode.SCENE3D,
new GeographicProjection(Ellipsoid.WGS84)
);
return updateUntilDone(scene.globe).then(function () {
expect(scene).notToRender([0, 0, 0, 255]);
var tileCommandCount = 0;
var commandList = scene.frameState.commandList;
for (var i = 0; i < commandList.length; ++i) {
var command = commandList[i];
var uniforms = command.uniformMap;
if (!defined(uniforms) || !defined(uniforms.u_dayTextureAlpha)) {
continue;
}
++tileCommandCount;
expect(uniforms.u_dayTextureAlpha()).toEqual([0.123]);
expect(uniforms.u_dayTextureNightAlpha()).toEqual([0.658]);
expect(uniforms.u_dayTextureDayAlpha()).toEqual([0.356]);
expect(uniforms.u_dayTextureBrightness()).toEqual([0.456]);
expect(uniforms.u_dayTextureContrast()).toEqual([0.654]);
expect(uniforms.u_dayTextureOneOverGamma()).toEqual([1.0 / 0.321]);
expect(uniforms.u_dayTextureSaturation()).toEqual([0.123]);
expect(uniforms.u_dayTextureHue()).toEqual([0.456]);
expect(uniforms.u_dayTextureSplit()).toEqual([
ImagerySplitDirection.LEFT,
]);
}
expect(tileCommandCount).toBeGreaterThan(0);
});
});
it("renders imagery cutout", function () {
expect(scene).toRender([0, 0, 0, 255]);
var layer = scene.imageryLayers.addImageryProvider(
new SingleTileImageryProvider({
url: "Data/Images/Red16x16.png",
})
);
layer.cutoutRectangle = cameraDestination;
switchViewMode(
SceneMode.SCENE3D,
new GeographicProjection(Ellipsoid.WGS84)
);
var baseColor;
return updateUntilDone(scene.globe)
.then(function () {
expect(scene).toRenderAndCall(function (rgba) {
baseColor = rgba;
expect(rgba).not.toEqual([0, 0, 0, 255]);
});
layer.cutoutRectangle = undefined;
return updateUntilDone(scene.globe);
})
.then(function () {
expect(scene).toRenderAndCall(function (rgba) {
expect(rgba).not.toEqual(baseColor);
expect(rgba).not.toEqual([0, 0, 0, 255]);
});
});
});
it("renders imagery with color-to-alpha", function () {
expect(scene).toRender([0, 0, 0, 255]);
var layer = scene.imageryLayers.addImageryProvider(
new SingleTileImageryProvider({
url: "Data/Images/Red16x16.png",
})
);
switchViewMode(
SceneMode.SCENE3D,
new GeographicProjection(Ellipsoid.WGS84)
);
var layerColor;
return updateUntilDone(scene.globe)
.then(function () {
expect(scene).toRenderAndCall(function (rgba) {
layerColor = rgba;
// Expect the layer color to be mostly red
expect(layerColor[0]).toBeGreaterThan(layerColor[1]);
expect(layerColor[0]).toBeGreaterThan(layerColor[2]);
});
layer.colorToAlpha = new Color(1.0, 0.0, 0.0);
layer.colorToAlphaThreshold = 0.1;
return updateUntilDone(scene.globe);
})
.then(function () {
var commandList = scene.frameState.commandList;
for (var i = 0; i < commandList.length; ++i) {
var command = commandList[i];
var uniforms = command.uniformMap;
if (!defined(uniforms) || !defined(uniforms.u_dayTextureAlpha)) {
continue;
}
expect(uniforms.u_colorsToAlpha()).toEqual([
new Cartesian4(1.0, 0.0, 0.0, 0.1),
]);
}
expect(scene).toRenderAndCall(function (rgba) {
expect(rgba).not.toEqual(layerColor);
});
});
});
it("skips layer with uniform alpha value of zero", function () {
var layer = scene.imageryLayers.addImageryProvider(
new SingleTileImageryProvider({
url: "Data/Images/Red16x16.png",
})
);
layer.alpha = 0.0;
switchViewMode(
SceneMode.SCENE3D,
new GeographicProjection(Ellipsoid.WGS84)
);
return updateUntilDone(scene.globe).then(function () {
expect(scene).notToRender([0, 0, 0, 255]);
var tileCommandCount = 0;
var commandList = scene.frameState.commandList;
for (var i = 0; i < commandList.length; ++i) {
var command = commandList[i];
var uniforms = command.uniformMap;
if (!defined(uniforms) || !defined(uniforms.u_dayTextureAlpha)) {
continue;
}
++tileCommandCount;
expect(uniforms.u_dayTextureAlpha()).toEqual([]);
}
expect(tileCommandCount).toBeGreaterThan(0);
});
});
it("can render more imagery layers than the available texture units", function () {
for (var i = 0; i < ContextLimits.maximumTextureImageUnits + 1; ++i) {
scene.imageryLayers.addImageryProvider(
new SingleTileImageryProvider({
url: "Data/Images/Red16x16.png",
})
);
}
switchViewMode(
SceneMode.SCENE3D,
new GeographicProjection(Ellipsoid.WGS84)
);
return updateUntilDone(scene.globe).then(function () {
expect(scene).notToRender([0, 0, 0, 255]);
var renderStateWithAlphaBlending = RenderState.fromCache({
blending: BlendingState.ALPHA_BLEND,
});
var drawCommandsPerTile = {};
var commandList = scene.frameState.commandList;
for (var i = 0; i < commandList.length; ++i) {
var command = commandList[i];
if (command.owner instanceof QuadtreeTile) {
var tile = command.owner;
var key = "L" + tile.level + "X" + tile.x + "Y" + tile.y;
if (!defined(drawCommandsPerTile[key])) {
drawCommandsPerTile[key] = 0;
// The first draw command for each tile should use a non-alpha-blending render state.
expect(command.renderState.blending).not.toEqual(
renderStateWithAlphaBlending.blending
);
} else {
// Successive draw commands per tile should alpha blend.
expect(command.renderState.blending).toEqual(
renderStateWithAlphaBlending.blending
);
expect(command.uniformMap.u_initialColor().w).toEqual(0.0);
}
++drawCommandsPerTile[key];
}
}
var tileCount = 0;
for (var tileID in drawCommandsPerTile) {
if (drawCommandsPerTile.hasOwnProperty(tileID)) {
++tileCount;
expect(drawCommandsPerTile[tileID]).toBeGreaterThanOrEqualTo(2);
}
}
expect(tileCount).toBeGreaterThanOrEqualTo(1);
});
});
it("adds terrain and imagery credits to the CreditDisplay", function () {
var imageryCredit = new Credit("imagery credit");
scene.imageryLayers.addImageryProvider(
new SingleTileImageryProvider({
url: "Data/Images/Red16x16.png",
credit: imageryCredit,
})
);
var terrainCredit = new Credit("terrain credit");
scene.terrainProvider = new CesiumTerrainProvider({
url: "https://s3.amazonaws.com/cesiumjs/smallTerrain",
credit: terrainCredit,
});
return updateUntilDone(scene.globe).then(function () {
var creditDisplay = scene.frameState.creditDisplay;
creditDisplay.showLightbox();
expect(
creditDisplay._currentFrameCredits.lightboxCredits.values
).toContain(imageryCredit);
expect(
creditDisplay._currentFrameCredits.lightboxCredits.values
).toContain(terrainCredit);
creditDisplay.hideLightbox();
});
});
describe(
"switching terrain providers",
function () {
it("clears the replacement queue", function () {
return updateUntilDone(scene.globe).then(function () {
var surface = scene.globe._surface;
var replacementQueue = surface._tileReplacementQueue;
expect(replacementQueue.count).toBeGreaterThan(0);
var oldTile = replacementQueue.head;
surface.tileProvider.terrainProvider = new EllipsoidTerrainProvider();
scene.renderForSpecs();
expect(replacementQueue.count).toBeGreaterThan(0);
expect(replacementQueue.head).not.toBe(oldTile);
});
});
it("recreates the level zero tiles", function () {
var surface = scene.globe._surface;
scene.renderForSpecs();
var levelZeroTiles = surface._levelZeroTiles;
expect(levelZeroTiles.length).toBe(2);
var levelZero0 = levelZeroTiles[0];
var levelZero1 = levelZeroTiles[1];
surface.tileProvider.terrainProvider = new EllipsoidTerrainProvider();
scene.renderForSpecs();
scene.renderForSpecs();
levelZeroTiles = surface._levelZeroTiles;
expect(levelZeroTiles[0]).not.toBe(levelZero0);
expect(levelZeroTiles[1]).not.toBe(levelZero1);
});
it("does nothing if the new provider is the same as the old", function () {
var surface = scene.globe._surface;
var provider = surface.tileProvider.terrainProvider;
scene.renderForSpecs();
var levelZeroTiles = surface._levelZeroTiles;
expect(levelZeroTiles.length).toBe(2);
var levelZero0 = levelZeroTiles[0];
var levelZero1 = levelZeroTiles[1];
surface.tileProvider.terrainProvider = provider;
scene.renderForSpecs();
levelZeroTiles = surface._levelZeroTiles;
expect(levelZeroTiles[0]).toBe(levelZero0);
expect(levelZeroTiles[1]).toBe(levelZero1);
});
},
"WebGL"
);
it("renders back side of globe when camera is near the poles", function () {
var camera = scene.camera;
camera.position = new Cartesian3(
2909078.1077849553,
-38935053.40234136,
-63252400.94628872
);
camera.direction = new Cartesian3(
-0.03928753135806185,
0.44884096070717633,
0.8927476025569903
);
camera.up = new Cartesian3(
0.00002847975895320034,
-0.8934368803055558,
0.4491887577613425
);
camera.right = new Cartesian3(
0.99922794650124,
0.017672942642764363,
0.03508814656908402
);
scene.cullingVolume = camera.frustum.computeCullingVolume(
camera.position,
camera.direction,
camera.up
);
return updateUntilDone(scene.globe).then(function () {
// Both level zero tiles should be rendered.
forEachRenderedTile(scene.globe._surface, 2, 2, function (tile) {});
});
});
it("throws if baseColor is assigned undefined", function () {
expect(function () {
scene.globe._surface.tileProvider.baseColor = undefined;
}).toThrowDeveloperError();
});
it("clipping planes selectively disable rendering globe surface", function () {
expect(scene).toRender([0, 0, 0, 255]);
switchViewMode(
SceneMode.SCENE3D,
new GeographicProjection(Ellipsoid.WGS84)
);
return updateUntilDone(scene.globe).then(function () {
expect(scene).notToRender([0, 0, 0, 255]);
var result;
expect(scene).toRenderAndCall(function (rgba) {
result = rgba;
expect(rgba).not.toEqual([0, 0, 0, 255]);
});
var clipPlane = new ClippingPlane(Cartesian3.UNIT_Z, -10000.0);
scene.globe.clippingPlanes = new ClippingPlaneCollection({
planes: [clipPlane],
});
expect(scene).notToRender(result);
clipPlane.distance = 0.0;
expect(scene).toRender(result);
scene.globe.clippingPlanes = undefined;
});
});
it("renders with clipping planes edge styling on globe surface", function () {
expect(scene).toRender([0, 0, 0, 255]);
switchViewMode(
SceneMode.SCENE3D,
new GeographicProjection(Ellipsoid.WGS84)
);
return updateUntilDone(scene.globe).then(function () {
expect(scene).notToRender([0, 0, 0, 255]);
var result;
expect(scene).toRenderAndCall(function (rgba) {
result = rgba;
expect(rgba).not.toEqual([0, 0, 0, 255]);
});
var clipPlane = new ClippingPlane(Cartesian3.UNIT_Z, -1000.0);
scene.globe.clippingPlanes = new ClippingPlaneCollection({
planes: [clipPlane],
edgeWidth: 20.0,
edgeColor: Color.RED,
});
expect(scene).notToRender(result);
clipPlane.distance = 0.0;
expect(scene).toRender([255, 0, 0, 255]);
scene.globe.clippingPlanes = undefined;
});
});
it("renders with multiple clipping planes clipping regions according to the value of unionClippingPlane", function () {
expect(scene).toRender([0, 0, 0, 255]);
switchViewMode(
SceneMode.SCENE3D,
new GeographicProjection(Ellipsoid.WGS84)
);
return updateUntilDone(scene.globe).then(function () {
expect(scene).notToRender([0, 0, 0, 255]);
var result;
expect(scene).toRenderAndCall(function (rgba) {
result = rgba;
expect(rgba).not.toEqual([0, 0, 0, 255]);
});
scene.globe.clippingPlanes = new ClippingPlaneCollection({
planes: [
new ClippingPlane(Cartesian3.UNIT_Z, -10000.0),
new ClippingPlane(Cartesian3.UNIT_X, -1000.0),
],
unionClippingRegions: true,
});
expect(scene).notToRender(result);
scene.globe.clippingPlanes.unionClippingRegions = false;
expect(scene).toRender(result);
scene.globe.clippingPlanes = undefined;
});
});
it("No extra tiles culled with no clipping planes", function () {
var globe = scene.globe;
switchViewMode(
SceneMode.SCENE3D,
new GeographicProjection(Ellipsoid.WGS84)
);
return updateUntilDone(globe).then(function () {
expect(scene.frameState.commandList.length).toBe(4);
});
});
it("Culls tiles when completely inside clipping region", function () {
var globe = scene.globe;
globe.clippingPlanes = new ClippingPlaneCollection({
planes: [new ClippingPlane(Cartesian3.UNIT_Z, -1000000.0)],
});
switchViewMode(
SceneMode.SCENE3D,
new GeographicProjection(Ellipsoid.WGS84)
);
return updateUntilDone(globe).then(function () {
var surface = globe._surface;
var tile = surface._levelZeroTiles[0];
expect(tile.isClipped).toBe(true);
expect(scene.frameState.commandList.length).toBe(2);
});
});
it("Doesn't cull, but clips tiles when intersecting clipping plane", function () {
var globe = scene.globe;
globe.clippingPlanes = new ClippingPlaneCollection({
planes: [new ClippingPlane(Cartesian3.UNIT_Z, 0.0)],
});
switchViewMode(
SceneMode.SCENE3D,
new GeographicProjection(Ellipsoid.WGS84)
);
return updateUntilDone(globe).then(function () {
var surface = globe._surface;
var tile = surface._levelZeroTiles[0];
expect(tile.isClipped).toBe(true);
expect(scene.frameState.commandList.length).toBe(4);
});
});
it("Doesn't cull or clip tiles when completely outside clipping region", function () {
var globe = scene.globe;
globe.clippingPlanes = new ClippingPlaneCollection({
planes: [new ClippingPlane(Cartesian3.UNIT_Z, 10000000.0)],
});
switchViewMode(
SceneMode.SCENE3D,
new GeographicProjection(Ellipsoid.WGS84)
);
return updateUntilDone(globe).then(function () {
var surface = globe._surface;
var tile = surface._levelZeroTiles[0];
expect(tile.isClipped).toBe(false);
expect(scene.frameState.commandList.length).toBe(4);
});
});
it("destroys attached ClippingPlaneCollections that have been detached", function () {
var clippingPlanes = new ClippingPlaneCollection({
planes: [new ClippingPlane(Cartesian3.UNIT_Z, 10000000.0)],
});
var globe = scene.globe;
globe.clippingPlanes = clippingPlanes;
expect(clippingPlanes.isDestroyed()).toBe(false);
globe.clippingPlanes = undefined;
expect(clippingPlanes.isDestroyed()).toBe(true);
});
it("throws a DeveloperError when given a ClippingPlaneCollection attached to a Model", function () {
var clippingPlanes = new ClippingPlaneCollection({
planes: [new ClippingPlane(Cartesian3.UNIT_Z, 10000000.0)],
});
var model = scene.primitives.add(
Model.fromGltf({
url: "./Data/Models/Box/CesiumBoxTest.gltf",
})
);
model.clippingPlanes = clippingPlanes;
var globe = scene.globe;
expect(function () {
globe.clippingPlanes = clippingPlanes;
}).toThrowDeveloperError();
});
it("cartographicLimitRectangle selectively enables rendering globe surface", function () {
expect(scene).toRender([0, 0, 0, 255]);
switchViewMode(
SceneMode.COLUMBUS_VIEW,
new GeographicProjection(Ellipsoid.WGS84)
);
var result;
return updateUntilDone(scene.globe)
.then(function () {
expect(scene).notToRender([0, 0, 0, 255]);
expect(scene).toRenderAndCall(function (rgba) {
result = rgba;
expect(rgba).not.toEqual([0, 0, 0, 255]);
});
scene.globe.cartographicLimitRectangle = Rectangle.fromDegrees(
-2,
-2,
-1,
-1
);
expect(scene).notToRender(result);
scene.camera.setView({
destination: scene.globe.cartographicLimitRectangle,
});
return updateUntilDone(scene.globe);
})
.then(function () {
expect(scene).toRender(result);
});
});
it("cartographicLimitRectangle defaults to Rectangle.MAX_VALUE", function () {
scene.globe.cartographicLimitRectangle = undefined;
expect(
scene.globe.cartographicLimitRectangle.equals(Rectangle.MAX_VALUE)
).toBe(true);
});
it("cartographicLimitRectangle culls tiles outside the region", function () {
switchViewMode(
SceneMode.COLUMBUS_VIEW,
new GeographicProjection(Ellipsoid.WGS84)
);
var unculledCommandCount;
return updateUntilDone(scene.globe)
.then(function () {
unculledCommandCount = scene.frameState.commandList.length;
scene.globe.cartographicLimitRectangle = Rectangle.fromDegrees(
-2,
-2,
-1,
-1
);
return updateUntilDone(scene.globe);
})
.then(function () {
expect(unculledCommandCount).toBeGreaterThan(
scene.frameState.commandList.length
);
});
});
it("cartographicLimitRectangle may cross the antimeridian", function () {
switchViewMode(
SceneMode.SCENE2D,
new GeographicProjection(Ellipsoid.WGS84)
);
var unculledCommandCount;
return updateUntilDone(scene.globe)
.then(function () {
unculledCommandCount = scene.frameState.commandList.length;
scene.globe.cartographicLimitRectangle = Rectangle.fromDegrees(
179,
-2,
-179,
-1
);
return updateUntilDone(scene.globe);
})
.then(function () {
expect(unculledCommandCount).toBeGreaterThan(
scene.frameState.commandList.length
);
});
});
it("disables skirts and enables back face culling when camera is underground", function () {
switchViewMode(
SceneMode.SCENE3D,
new GeographicProjection(Ellipsoid.WGS84)
);
return updateUntilDone(scene.globe)
.then(function () {
var command = scene.frameState.commandList[0];
expect(command.count).toBe(
command.owner.data.renderedMesh.indices.length
); // Has skirts
expect(command.renderState.cull.enabled).toBe(true); // Has back face culling
// Look underground
scene.camera.setView({
destination: new Cartesian3(
-746658.0557573901,
-5644191.0002196245,
2863585.099969967
),
orientation: new HeadingPitchRoll(
0.3019699121236403,
0.07316306869231592,
0.0007089903642230055
),
});
return updateUntilDone(scene.globe);
})
.then(function () {
var command = scene.frameState.commandList[0];
expect(command.count).toBe(
command.owner.data.renderedMesh.indexCountWithoutSkirts
); // No skirts
expect(command.renderState.cull.enabled).toBe(false); // No back face culling
});
});
},
"WebGL"
);