DSDSWeb/static/js/Cesium-1.53/Specs/Scene/PointCloud3DTileContentSpec.js

1035 lines
42 KiB
JavaScript

defineSuite([
'Scene/PointCloud3DTileContent',
'Core/Cartesian3',
'Core/Color',
'Core/ComponentDatatype',
'Core/defined',
'Core/HeadingPitchRange',
'Core/HeadingPitchRoll',
'Core/Math',
'Core/Matrix4',
'Core/PerspectiveFrustum',
'Core/Transforms',
'Renderer/Pass',
'Scene/Cesium3DTileRefine',
'Scene/Cesium3DTileStyle',
'Scene/ClippingPlane',
'Scene/ClippingPlaneCollection',
'Scene/DracoLoader',
'Scene/Expression',
'Specs/Cesium3DTilesTester',
'Specs/createCanvas',
'Specs/createScene',
'Specs/pollToPromise',
'ThirdParty/when'
], function(
PointCloud3DTileContent,
Cartesian3,
Color,
ComponentDatatype,
defined,
HeadingPitchRange,
HeadingPitchRoll,
CesiumMath,
Matrix4,
PerspectiveFrustum,
Transforms,
Pass,
Cesium3DTileRefine,
Cesium3DTileStyle,
ClippingPlane,
ClippingPlaneCollection,
DracoLoader,
Expression,
Cesium3DTilesTester,
createCanvas,
createScene,
pollToPromise,
when) {
'use strict';
var scene;
var centerLongitude = -1.31968;
var centerLatitude = 0.698874;
var pointCloudRGBUrl = './Data/Cesium3DTiles/PointCloud/PointCloudRGB/tileset.json';
var pointCloudRGBAUrl = './Data/Cesium3DTiles/PointCloud/PointCloudRGBA/tileset.json';
var pointCloudRGB565Url = './Data/Cesium3DTiles/PointCloud/PointCloudRGB565/tileset.json';
var pointCloudNoColorUrl = './Data/Cesium3DTiles/PointCloud/PointCloudNoColor/tileset.json';
var pointCloudConstantColorUrl = './Data/Cesium3DTiles/PointCloud/PointCloudConstantColor/tileset.json';
var pointCloudNormalsUrl = './Data/Cesium3DTiles/PointCloud/PointCloudNormals/tileset.json';
var pointCloudNormalsOctEncodedUrl = './Data/Cesium3DTiles/PointCloud/PointCloudNormalsOctEncoded/tileset.json';
var pointCloudQuantizedUrl = './Data/Cesium3DTiles/PointCloud/PointCloudQuantized/tileset.json';
var pointCloudQuantizedOctEncodedUrl = './Data/Cesium3DTiles/PointCloud/PointCloudQuantizedOctEncoded/tileset.json';
var pointCloudDracoUrl = './Data/Cesium3DTiles/PointCloud/PointCloudDraco/tileset.json';
var pointCloudDracoPartialUrl = './Data/Cesium3DTiles/PointCloud/PointCloudDracoPartial/tileset.json';
var pointCloudDracoBatchedUrl = './Data/Cesium3DTiles/PointCloud/PointCloudDracoBatched/tileset.json';
var pointCloudWGS84Url = './Data/Cesium3DTiles/PointCloud/PointCloudWGS84/tileset.json';
var pointCloudBatchedUrl = './Data/Cesium3DTiles/PointCloud/PointCloudBatched/tileset.json';
var pointCloudWithPerPointPropertiesUrl = './Data/Cesium3DTiles/PointCloud/PointCloudWithPerPointProperties/tileset.json';
var pointCloudWithTransformUrl = './Data/Cesium3DTiles/PointCloud/PointCloudWithTransform/tileset.json';
var pointCloudTilesetUrl = './Data/Cesium3DTiles/Tilesets/TilesetPoints/tileset.json';
function setCamera(longitude, latitude) {
// Point the camera to the center of the tile
var center = Cartesian3.fromRadians(longitude, latitude, 5.0);
scene.camera.lookAt(center, new HeadingPitchRange(0.0, -1.57, 5.0));
}
beforeAll(function() {
scene = createScene();
scene.frameState.passes.render = true;
});
afterAll(function() {
scene.destroyForSpecs();
});
beforeEach(function() {
scene.morphTo3D(0.0);
var camera = scene.camera;
camera.frustum = new PerspectiveFrustum();
camera.frustum.aspectRatio = scene.drawingBufferWidth / scene.drawingBufferHeight;
camera.frustum.fov = CesiumMath.toRadians(60.0);
setCamera(centerLongitude, centerLatitude);
});
afterEach(function() {
scene.primitives.removeAll();
});
it('throws with invalid version', function() {
var arrayBuffer = Cesium3DTilesTester.generatePointCloudTileBuffer({
version: 2
});
Cesium3DTilesTester.loadTileExpectError(scene, arrayBuffer, 'pnts');
});
it('throws if featureTableJsonByteLength is 0', function() {
var arrayBuffer = Cesium3DTilesTester.generatePointCloudTileBuffer({
featureTableJsonByteLength : 0
});
Cesium3DTilesTester.loadTileExpectError(scene, arrayBuffer, 'pnts');
});
it('throws if the feature table does not contain POINTS_LENGTH', function() {
var arrayBuffer = Cesium3DTilesTester.generatePointCloudTileBuffer({
featureTableJson : {
POSITION : {
byteOffset : 0
}
}
});
Cesium3DTilesTester.loadTileExpectError(scene, arrayBuffer, 'pnts');
});
it('throws if the feature table does not contain POSITION or POSITION_QUANTIZED', function() {
var arrayBuffer = Cesium3DTilesTester.generatePointCloudTileBuffer({
featureTableJson : {
POINTS_LENGTH : 1
}
});
Cesium3DTilesTester.loadTileExpectError(scene, arrayBuffer, 'pnts');
});
it('throws if the positions are quantized and the feature table does not contain QUANTIZED_VOLUME_SCALE', function() {
var arrayBuffer = Cesium3DTilesTester.generatePointCloudTileBuffer({
featureTableJson : {
POINTS_LENGTH : 1,
POSITION_QUANTIZED : {
byteOffset : 0
},
QUANTIZED_VOLUME_OFFSET : [0.0, 0.0, 0.0]
}
});
Cesium3DTilesTester.loadTileExpectError(scene, arrayBuffer, 'pnts');
});
it('throws if the positions are quantized and the feature table does not contain QUANTIZED_VOLUME_OFFSET', function() {
var arrayBuffer = Cesium3DTilesTester.generatePointCloudTileBuffer({
featureTableJson : {
POINTS_LENGTH : 1,
POSITION_QUANTIZED : {
byteOffset : 0
},
QUANTIZED_VOLUME_SCALE : [1.0, 1.0, 1.0]
}
});
Cesium3DTilesTester.loadTileExpectError(scene, arrayBuffer, 'pnts');
});
it('throws if the BATCH_ID semantic is defined but BATCHES_LENGTH is not', function() {
var arrayBuffer = Cesium3DTilesTester.generatePointCloudTileBuffer({
featureTableJson : {
POINTS_LENGTH : 2,
POSITION : [0.0, 0.0, 0.0, 1.0, 1.0, 1.0],
BATCH_ID : [0, 1]
}
});
Cesium3DTilesTester.loadTileExpectError(scene, arrayBuffer, 'pnts');
});
it('BATCH_ID semantic uses componentType of UNSIGNED_SHORT by default', function() {
var arrayBuffer = Cesium3DTilesTester.generatePointCloudTileBuffer({
featureTableJson : {
POINTS_LENGTH : 2,
POSITION : [0.0, 0.0, 0.0, 1.0, 1.0, 1.0],
BATCH_ID : [0, 1],
BATCH_LENGTH : 2
}
});
var content = Cesium3DTilesTester.loadTile(scene, arrayBuffer, 'pnts');
expect(content._pointCloud._drawCommand._vertexArray._attributes[1].componentDatatype).toEqual(ComponentDatatype.UNSIGNED_SHORT);
});
it('gets tileset properties', function() {
return Cesium3DTilesTester.loadTileset(scene, pointCloudRGBUrl).then(function(tileset) {
var root = tileset.root;
var content = root.content;
expect(content.tileset).toBe(tileset);
expect(content.tile).toBe(root);
expect(content.url.indexOf(root._header.content.uri) > -1).toBe(true);
});
});
it('resolves readyPromise', function() {
return Cesium3DTilesTester.resolvesReadyPromise(scene, pointCloudRGBUrl);
});
it('renders point cloud with rgb colors', function() {
return Cesium3DTilesTester.loadTileset(scene, pointCloudRGBUrl).then(function(tileset) {
Cesium3DTilesTester.expectRender(scene, tileset);
});
});
it('renders point cloud with rgba colors', function() {
return Cesium3DTilesTester.loadTileset(scene, pointCloudRGBAUrl).then(function(tileset) {
Cesium3DTilesTester.expectRender(scene, tileset);
});
});
it('renders point cloud with rgb565 colors', function() {
return Cesium3DTilesTester.loadTileset(scene, pointCloudRGB565Url).then(function(tileset) {
Cesium3DTilesTester.expectRender(scene, tileset);
});
});
it('renders point cloud with no colors', function() {
return Cesium3DTilesTester.loadTileset(scene, pointCloudNoColorUrl).then(function(tileset) {
Cesium3DTilesTester.expectRender(scene, tileset);
});
});
it('renders point cloud with constant colors', function() {
return Cesium3DTilesTester.loadTileset(scene, pointCloudConstantColorUrl).then(function(tileset) {
Cesium3DTilesTester.expectRender(scene, tileset);
});
});
it('renders point cloud with normals', function() {
return Cesium3DTilesTester.loadTileset(scene, pointCloudNormalsUrl).then(function(tileset) {
Cesium3DTilesTester.expectRender(scene, tileset);
});
});
it('renders point cloud with oct encoded normals', function() {
return Cesium3DTilesTester.loadTileset(scene, pointCloudNormalsOctEncodedUrl).then(function(tileset) {
Cesium3DTilesTester.expectRender(scene, tileset);
});
});
it('renders point cloud with quantized positions', function() {
return Cesium3DTilesTester.loadTileset(scene, pointCloudQuantizedUrl).then(function(tileset) {
Cesium3DTilesTester.expectRender(scene, tileset);
});
});
it('renders point cloud with quantized positions and oct-encoded normals', function() {
return Cesium3DTilesTester.loadTileset(scene, pointCloudQuantizedOctEncodedUrl).then(function(tileset) {
Cesium3DTilesTester.expectRender(scene, tileset);
});
});
it('renders point cloud with draco encoded positions, normals, colors, and batch table properties', function() {
return Cesium3DTilesTester.loadTileset(scene, pointCloudDracoUrl).then(function(tileset) {
Cesium3DTilesTester.expectRender(scene, tileset);
// Test that Draco-encoded batch table properties are functioning correctly
tileset.style = new Cesium3DTileStyle({
color : 'vec4(Number(${secondaryColor}[0] < 1.0), 0.0, 0.0, 1.0)'
});
expect(scene).toRenderAndCall(function(rgba) {
// Produces a red color
expect(rgba[0]).toBeGreaterThan(rgba[1]);
expect(rgba[0]).toBeGreaterThan(rgba[2]);
});
});
});
it('renders point cloud with draco encoded positions and uncompressed normals and colors', function() {
return Cesium3DTilesTester.loadTileset(scene, pointCloudDracoPartialUrl).then(function(tileset) {
Cesium3DTilesTester.expectRender(scene, tileset);
});
});
it('renders point cloud with draco encoded positions, colors, and batch ids', function() {
return Cesium3DTilesTester.loadTileset(scene, pointCloudDracoBatchedUrl).then(function(tileset) {
Cesium3DTilesTester.expectRender(scene, tileset);
});
});
it('error decoding a draco point cloud causes loading to fail', function() {
return pollToPromise(function() {
return DracoLoader._taskProcessorReady;
}).then(function() {
var decoder = DracoLoader._getDecoderTaskProcessor();
spyOn(decoder, 'scheduleTask').and.returnValue(when.reject({message : 'my error'}));
return Cesium3DTilesTester.loadTileset(scene, pointCloudDracoUrl).then(function(tileset) {
var root = tileset.root;
return root.contentReadyPromise.then(function() {
fail('should not resolve');
}).otherwise(function(error) {
expect(error.message).toBe('my error');
});
});
});
});
it('renders point cloud that are not defined relative to center', function() {
return Cesium3DTilesTester.loadTileset(scene, pointCloudWGS84Url).then(function(tileset) {
Cesium3DTilesTester.expectRender(scene, tileset);
});
});
it('renders point cloud with batch table', function() {
return Cesium3DTilesTester.loadTileset(scene, pointCloudBatchedUrl).then(function(tileset) {
Cesium3DTilesTester.expectRender(scene, tileset);
});
});
it('renders point cloud with per-point properties', function() {
return Cesium3DTilesTester.loadTileset(scene, pointCloudWithPerPointPropertiesUrl).then(function(tileset) {
Cesium3DTilesTester.expectRender(scene, tileset);
});
});
it('renders point cloud with tile transform', function() {
return Cesium3DTilesTester.loadTileset(scene, pointCloudWithTransformUrl).then(function(tileset) {
Cesium3DTilesTester.expectRender(scene, tileset);
var newLongitude = -1.31962;
var newLatitude = 0.698874;
var newCenter = Cartesian3.fromRadians(newLongitude, newLatitude, 5.0);
var newHPR = new HeadingPitchRoll();
var newTransform = Transforms.headingPitchRollToFixedFrame(newCenter, newHPR);
// Update tile transform
tileset.root.transform = newTransform;
// Move the camera to the new location
setCamera(newLongitude, newLatitude);
Cesium3DTilesTester.expectRender(scene, tileset);
});
});
it('renders with debug color', function() {
CesiumMath.setRandomNumberSeed(0);
return Cesium3DTilesTester.loadTileset(scene, pointCloudRGBUrl).then(function(tileset) {
var color;
expect(scene).toRenderAndCall(function(rgba) {
color = rgba;
});
tileset.debugColorizeTiles = true;
expect(scene).notToRender(color);
tileset.debugColorizeTiles = false;
expect(scene).toRender(color);
});
});
it('renders in CV', function() {
return Cesium3DTilesTester.loadTileset(scene, pointCloudRGBUrl).then(function(tileset) {
scene.morphToColumbusView(0.0);
setCamera(centerLongitude, centerLatitude);
Cesium3DTilesTester.expectRender(scene, tileset);
});
});
it('renders in 2D', function() {
return Cesium3DTilesTester.loadTileset(scene, pointCloudRGBUrl).then(function(tileset) {
scene.morphTo2D(0.0);
setCamera(centerLongitude, centerLatitude);
tileset.maximumScreenSpaceError = 3;
Cesium3DTilesTester.expectRender(scene, tileset);
});
});
it('picks', function() {
return Cesium3DTilesTester.loadTileset(scene, pointCloudRGBUrl).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 based on batchId', function() {
return Cesium3DTilesTester.loadTileset(scene, pointCloudBatchedUrl).then(function(tileset) {
// Get the original color
var color;
expect(scene).toRenderAndCall(function(rgba) {
color = rgba;
});
// Change the color of the picked feature to yellow
expect(scene).toPickAndCall(function(first) {
expect(first).toBeDefined();
first.color = Color.clone(Color.YELLOW, first.color);
// Expect the pixel color to be some shade of yellow
expect(scene).notToRender(color);
// Turn show off. Expect a different feature to get picked.
first.show = false;
expect(scene).toPickAndCall(function(second) {
expect(second).toBeDefined();
expect(second).not.toBe(first);
});
});
});
});
it('point cloud without batch table works', function() {
return Cesium3DTilesTester.loadTileset(scene, pointCloudRGBUrl).then(function(tileset) {
var content = tileset.root.content;
expect(content.featuresLength).toBe(0);
expect(content.innerContents).toBeUndefined();
expect(content.hasProperty(0, 'name')).toBe(false);
expect(content.getFeature(0)).toBeUndefined();
});
});
it('batched point cloud works', function() {
return Cesium3DTilesTester.loadTileset(scene, pointCloudBatchedUrl).then(function(tileset) {
var content = tileset.root.content;
expect(content.featuresLength).toBe(8);
expect(content.innerContents).toBeUndefined();
expect(content.hasProperty(0, 'name')).toBe(true);
expect(content.getFeature(0)).toBeDefined();
});
});
it('point cloud with per-point properties work', function() {
// When the batch table contains per-point properties, aka no batching, then a Cesium3DTileBatchTable is not
// created. There is no per-point show/color/pickId because the overhead is too high. Instead points are styled
// based on their properties, and these are not accessible from the API.
return Cesium3DTilesTester.loadTileset(scene, pointCloudWithPerPointPropertiesUrl).then(function(tileset) {
var content = tileset.root.content;
expect(content.featuresLength).toBe(0);
expect(content.innerContents).toBeUndefined();
expect(content.hasProperty(0, 'name')).toBe(false);
expect(content.getFeature(0)).toBeUndefined();
});
});
it('throws when calling getFeature with invalid index', function() {
return Cesium3DTilesTester.loadTileset(scene, pointCloudBatchedUrl).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('Supports back face culling when there are per-point normals', function() {
return Cesium3DTilesTester.loadTileset(scene, pointCloudBatchedUrl).then(function(tileset) {
var content = tileset.root.content;
// Get the number of picked sections with back face culling on
var pickedCountCulling = 0;
var pickedCount = 0;
var picked;
expect(scene).toPickAndCall(function(result) {
// Set culling to true
content._pointCloud.backFaceCulling = true;
expect(scene).toPickAndCall(function(result) {
picked = result;
});
/* jshint loopfunc: true */
while (defined(picked)) {
picked.show = false;
expect(scene).toPickAndCall(function(result) { //eslint-disable-line no-loop-func
picked = result;
});
++pickedCountCulling;
}
// Set the shows back to true
var length = content.featuresLength;
for (var i = 0; i < length; ++i) {
var feature = content.getFeature(i);
feature.show = true;
}
// Set culling to false
content._pointCloud.backFaceCulling = false;
expect(scene).toPickAndCall(function(result) {
picked = result;
});
/* jshint loopfunc: true */
while (defined(picked)) {
picked.show = false;
expect(scene).toPickAndCall(function(result) { //eslint-disable-line no-loop-func
picked = result;
});
++pickedCount;
}
expect(pickedCount).toBeGreaterThan(pickedCountCulling);
});
});
});
var noAttenuationPixelCount;
function attenuationTest(postLoadCallback) {
var scene = createScene({
canvas : createCanvas(10, 10)
});
noAttenuationPixelCount = scene.logarithmicDepthBuffer ? 20 : 16;
var center = new Cartesian3.fromRadians(centerLongitude, centerLatitude, 5.0);
scene.camera.lookAt(center, new HeadingPitchRange(0.0, -1.57, 5.0));
scene.postProcessStages.fxaa.enabled = false;
scene.camera.zoomIn(6);
return Cesium3DTilesTester.loadTileset(scene, pointCloudNoColorUrl).then(function(tileset) {
tileset.pointCloudShading.eyeDomeLighting = false;
tileset.root.refine = Cesium3DTileRefine.REPLACE;
postLoadCallback(scene, tileset);
scene.destroyForSpecs();
});
}
it('attenuates points based on geometric error', function() {
return attenuationTest(function(scene, tileset) {
tileset.pointCloudShading.attenuation = true;
tileset.pointCloudShading.geometricErrorScale = 1.0;
tileset.pointCloudShading.maximumAttenuation = undefined;
tileset.pointCloudShading.baseResolution = undefined;
tileset.maximumScreenSpaceError = 16;
expect(scene).toRenderPixelCountAndCall(function(pixelCount) {
expect(pixelCount).toBeGreaterThan(noAttenuationPixelCount);
});
});
});
it('modulates attenuation using the tileset screen space error', function() {
return attenuationTest(function(scene, tileset) {
tileset.pointCloudShading.attenuation = true;
tileset.pointCloudShading.geometricErrorScale = 1.0;
tileset.pointCloudShading.maximumAttenuation = undefined;
tileset.pointCloudShading.baseResolution = undefined;
tileset.maximumScreenSpaceError = 1;
expect(scene).toRenderPixelCountAndCall(function(pixelCount) {
expect(pixelCount).toEqual(noAttenuationPixelCount);
});
});
});
it('modulates attenuation using the maximumAttenuation parameter', function() {
return attenuationTest(function(scene, tileset) {
tileset.pointCloudShading.attenuation = true;
tileset.pointCloudShading.geometricErrorScale = 1.0;
tileset.pointCloudShading.maximumAttenuation = 1;
tileset.pointCloudShading.baseResolution = undefined;
tileset.maximumScreenSpaceError = 16;
expect(scene).toRenderPixelCountAndCall(function(pixelCount) {
expect(pixelCount).toEqual(noAttenuationPixelCount);
});
});
});
it('modulates attenuation using the baseResolution parameter', function() {
return attenuationTest(function(scene, tileset) {
// pointCloudNoColorUrl is a single tile with GeometricError = 0,
// which results in default baseResolution being computed
tileset.pointCloudShading.attenuation = true;
tileset.pointCloudShading.geometricErrorScale = 1.0;
tileset.pointCloudShading.maximumAttenuation = undefined;
tileset.pointCloudShading.baseResolution = 0.20;
tileset.maximumScreenSpaceError = 16;
expect(scene).toRenderPixelCountAndCall(function(pixelCount) {
expect(pixelCount).toEqual(noAttenuationPixelCount);
});
});
});
it('modulates attenuation using the geometricErrorScale parameter', function() {
return attenuationTest(function(scene, tileset) {
tileset.pointCloudShading.attenuation = true;
tileset.pointCloudShading.geometricErrorScale = 0.2;
tileset.pointCloudShading.maximumAttenuation = undefined;
tileset.pointCloudShading.baseResolution = 1.0;
tileset.maximumScreenSpaceError = 1;
expect(scene).toRenderPixelCountAndCall(function(pixelCount) {
expect(pixelCount).toEqual(noAttenuationPixelCount);
});
});
});
it('attenuates points based on geometric error in 2D', function() {
return attenuationTest(function(scene, tileset) {
scene.morphTo2D(0);
tileset.pointCloudShading.attenuation = true;
tileset.pointCloudShading.geometricErrorScale = 1.0;
tileset.pointCloudShading.maximumAttenuation = undefined;
tileset.pointCloudShading.baseResolution = undefined;
tileset.maximumScreenSpaceError = 16;
expect(scene).toRenderPixelCountAndCall(function(pixelCount) {
expect(pixelCount).toBeGreaterThan(noAttenuationPixelCount);
});
});
});
it('applies shader style', function() {
return Cesium3DTilesTester.loadTileset(scene, pointCloudWithPerPointPropertiesUrl).then(function(tileset) {
var content = tileset.root.content;
// Solid red color
tileset.style = new Cesium3DTileStyle({
color : 'color("red")'
});
expect(scene).toRender([255, 0, 0, 255]);
expect(content._pointCloud._styleTranslucent).toBe(false);
// Applies translucency
tileset.style = new Cesium3DTileStyle({
color : 'rgba(255, 0, 0, 0.005)'
});
expect(scene).toRenderAndCall(function(rgba) {
// Pixel is a darker red
expect(rgba[0]).toBeLessThan(255);
expect(rgba[1]).toBe(0);
expect(rgba[2]).toBe(0);
expect(rgba[3]).toBe(255);
expect(content._pointCloud._styleTranslucent).toBe(true);
});
// Style with property
tileset.style = new Cesium3DTileStyle({
color : 'color() * ${temperature}'
});
expect(scene).toRenderAndCall(function(rgba) {
// Pixel color is some shade of gray
expect(rgba[0]).toBe(rgba[1]);
expect(rgba[0]).toBe(rgba[2]);
expect(rgba[0]).toBeGreaterThan(0);
expect(rgba[0]).toBeLessThan(255);
});
// When no conditions are met the default color is white
tileset.style = new Cesium3DTileStyle({
color : {
conditions : [
['${secondaryColor}[0] > 1.0', 'color("red")'] // This condition will not be met
]
}
});
expect(scene).toRender([255, 255, 255, 255]);
// Apply style with conditions
tileset.style = new Cesium3DTileStyle({
color : {
conditions : [
['${temperature} < 0.1', 'color("#000099")'],
['${temperature} < 0.2', 'color("#00cc99", 1.0)'],
['${temperature} < 0.3', 'color("#66ff33", 0.5)'],
['${temperature} < 0.4', 'rgba(255, 255, 0, 0.1)'],
['${temperature} < 0.5', 'rgb(255, 128, 0)'],
['${temperature} < 0.6', 'color("red")'],
['${temperature} < 0.7', 'color("rgb(255, 102, 102)")'],
['${temperature} < 0.8', 'hsl(0.875, 1.0, 0.6)'],
['${temperature} < 0.9', 'hsla(0.83, 1.0, 0.5, 0.1)'],
['true', 'color("#FFFFFF", 1.0)']
]
}
});
expect(scene).notToRender([0, 0, 0, 255]);
// Apply show style
tileset.style = new Cesium3DTileStyle({
show : true
});
expect(scene).notToRender([0, 0, 0, 255]);
// Apply show style that hides all points
tileset.style = new Cesium3DTileStyle({
show : false
});
expect(scene).toRender([0, 0, 0, 255]);
// Apply show style with property
tileset.style = new Cesium3DTileStyle({
show : '${temperature} > 0.1'
});
expect(scene).notToRender([0, 0, 0, 255]);
tileset.style = new Cesium3DTileStyle({
show : '${temperature} > 1.0'
});
expect(scene).toRender([0, 0, 0, 255]);
// Apply style with point cloud semantics
tileset.style = new Cesium3DTileStyle({
color : '${COLOR} / 2.0',
show : '${POSITION}[0] > 0.5'
});
expect(scene).notToRender([0, 0, 0, 255]);
// Apply pointSize style
tileset.style = new Cesium3DTileStyle({
pointSize : 5.0
});
expect(scene).notToRender([0, 0, 0, 255]);
});
});
it('rebuilds shader style when expression changes', function() {
return Cesium3DTilesTester.loadTileset(scene, pointCloudTilesetUrl).then(function(tileset) {
// Solid red color
tileset.style = new Cesium3DTileStyle({
color : 'color("red")'
});
expect(scene).toRender([255, 0, 0, 255]);
tileset.style.color = new Expression('color("lime")');
tileset.makeStyleDirty();
expect(scene).toRender([0, 255, 0, 255]);
tileset.style.color = new Expression('color("blue", 0.5)');
tileset.makeStyleDirty();
expect(scene).toRenderAndCall(function(rgba) {
expect(rgba).toEqualEpsilon([0, 0, 255, 255], 5);
});
var i;
var commands = scene.frameState.commandList;
var commandsLength = commands.length;
expect(commandsLength).toBeGreaterThan(1); // Just check that at least some children are rendered
for (i = 0; i < commandsLength; ++i) {
expect(commands[i].pass).toBe(Pass.TRANSLUCENT);
}
tileset.style.color = new Expression('color("yellow")');
tileset.makeStyleDirty();
expect(scene).toRender([255, 255, 0, 255]);
commands = scene.frameState.commandList;
commandsLength = commands.length;
for (i = 0; i < commandsLength; ++i) {
expect(commands[i].pass).not.toBe(Pass.TRANSLUCENT);
}
});
});
it('applies shader style to point cloud with normals', function() {
return Cesium3DTilesTester.loadTileset(scene, pointCloudQuantizedOctEncodedUrl).then(function(tileset) {
tileset.style = new Cesium3DTileStyle({
color : 'color("red")'
});
expect(scene).toRenderAndCall(function(rgba) {
expect(rgba[0]).toBeGreaterThan(0);
expect(rgba[0]).toBeLessThan(255);
});
});
});
it('applies shader style to point cloud with normals', function() {
return Cesium3DTilesTester.loadTileset(scene, pointCloudQuantizedOctEncodedUrl).then(function(tileset) {
tileset.style = new Cesium3DTileStyle({
color : 'color("red")'
});
expect(scene).toRenderAndCall(function(rgba) {
expect(rgba[0]).toBeGreaterThan(0);
});
});
});
it('applies shader style to point cloud without colors', function() {
return Cesium3DTilesTester.loadTileset(scene, pointCloudNoColorUrl).then(function(tileset) {
tileset.style = new Cesium3DTileStyle({
color : 'color("red")'
});
expect(scene).toRender([255, 0, 0, 255]);
});
});
it('throws if style references the NORMAL semantic but the point cloud does not have per-point normals', function() {
return Cesium3DTilesTester.loadTileset(scene, pointCloudRGBUrl).then(function(tileset) {
tileset.style = new Cesium3DTileStyle({
color : '${NORMAL}[0] > 0.5'
});
expect(function() {
scene.renderForSpecs();
}).toThrowRuntimeError();
});
});
it('throws when shader style reference a non-existent property', function() {
return Cesium3DTilesTester.loadTileset(scene, pointCloudWithPerPointPropertiesUrl).then(function(tileset) {
tileset.style = new Cesium3DTileStyle({
color : 'color() * ${non_existent_property}'
});
expect(function() {
scene.renderForSpecs();
}).toThrowRuntimeError();
});
});
it('does not apply shader style if the point cloud has a batch table', function() {
return Cesium3DTilesTester.loadTileset(scene, pointCloudBatchedUrl).then(function(tileset) {
var content = tileset.root.content;
var shaderProgram = content._pointCloud._drawCommand.shaderProgram;
tileset.style = new Cesium3DTileStyle({
color:'color("red")'
});
scene.renderForSpecs();
expect(content._pointCloud._drawCommand.shaderProgram).toBe(shaderProgram);
// Point cloud is styled through the batch table
expect(scene).notToRender([0, 0, 0, 255]);
});
});
it('throws when shader style is invalid', function() {
return Cesium3DTilesTester.loadTileset(scene, pointCloudRGBUrl).then(function(tileset) {
tileset.style = new Cesium3DTileStyle({
show : '1 < "2"'
});
expect(function() {
scene.renderForSpecs();
}).toThrowRuntimeError();
});
});
it('gets memory usage', function() {
var promises = [
Cesium3DTilesTester.loadTileset(scene, pointCloudNoColorUrl),
Cesium3DTilesTester.loadTileset(scene, pointCloudRGBUrl),
Cesium3DTilesTester.loadTileset(scene, pointCloudNormalsUrl),
Cesium3DTilesTester.loadTileset(scene, pointCloudQuantizedOctEncodedUrl)
];
// 1000 points
var expectedGeometryMemory = [
1000 * 12, // 3 floats (xyz)
1000 * 15, // 3 floats (xyz), 3 bytes (rgb)
1000 * 27, // 3 floats (xyz), 3 bytes (rgb), 3 floats (normal)
1000 * 11 // 3 shorts (quantized xyz), 3 bytes (rgb), 2 bytes (oct-encoded normal)
];
return when.all(promises).then(function(tilesets) {
var length = tilesets.length;
for (var i = 0; i < length; ++i) {
var content = tilesets[i].root.content;
expect(content.geometryByteLength).toEqual(expectedGeometryMemory[i]);
expect(content.texturesByteLength).toEqual(0);
}
});
});
it('gets memory usage for batch point cloud', function() {
return Cesium3DTilesTester.loadTileset(scene, pointCloudBatchedUrl).then(function(tileset) {
var content = tileset.root.content;
// Point cloud consists of positions, colors, normals, and batchIds
// 3 floats (xyz), 3 floats (normal), 1 byte (batchId)
var pointCloudGeometryMemory = 1000 * 25;
// 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(pointCloudGeometryMemory);
expect(content.texturesByteLength).toEqual(0);
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(pointCloudGeometryMemory);
expect(content.texturesByteLength).toEqual(0);
expect(content.batchTableByteLength).toEqual(batchTexturesByteLength);
// Pick the tile and expect the texture memory to increase
scene.pickForSpecs();
expect(content.geometryByteLength).toEqual(pointCloudGeometryMemory);
expect(content.texturesByteLength).toEqual(0);
expect(content.batchTableByteLength).toEqual(batchTexturesByteLength + pickTexturesByteLength);
});
});
it('rebuilds shaders when clipping planes are enabled, change between union and intersection, or change count', function () {
return Cesium3DTilesTester.loadTileset(scene, pointCloudRGBUrl).then(function(tileset) {
var tile = tileset.root;
tile._isClipped = true;
var content = tile.content;
var noClipFS = content._pointCloud._drawCommand.shaderProgram._fragmentShaderText;
expect(noClipFS.indexOf('clip') !== -1).toBe(false);
var clippingPlanes = new ClippingPlaneCollection({
planes : [
new ClippingPlane(Cartesian3.UNIT_X, 0.0)
],
unionClippingRegions : false
});
tileset.clippingPlanes = clippingPlanes;
clippingPlanes.update(scene.frameState);
tile.update(tileset, scene.frameState);
var clipOneIntersectFS = content._pointCloud._drawCommand.shaderProgram._fragmentShaderText;
expect(clipOneIntersectFS.indexOf('= clip(') !== -1).toBe(true);
expect(clipOneIntersectFS.indexOf('float clip') !== -1).toBe(true);
clippingPlanes.unionClippingRegions = true;
clippingPlanes.update(scene.frameState);
tile.update(tileset, scene.frameState);
var clipOneUnionFS = content._pointCloud._drawCommand.shaderProgram._fragmentShaderText;
expect(clipOneUnionFS.indexOf('= clip(') !== -1).toBe(true);
expect(clipOneUnionFS.indexOf('float clip') !== -1).toBe(true);
expect(clipOneUnionFS).not.toEqual(clipOneIntersectFS);
clippingPlanes.add(new ClippingPlane(Cartesian3.UNIT_Y, 1.0));
clippingPlanes.update(scene.frameState);
tile.update(tileset, scene.frameState);
var clipTwoUnionFS = content._pointCloud._drawCommand.shaderProgram._fragmentShaderText;
expect(clipTwoUnionFS.indexOf('= clip(') !== -1).toBe(true);
expect(clipTwoUnionFS.indexOf('float clip') !== -1).toBe(true);
expect(clipTwoUnionFS).not.toEqual(clipOneIntersectFS);
expect(clipTwoUnionFS).not.toEqual(clipOneUnionFS);
});
});
it('clipping planes selectively disable rendering', function () {
return Cesium3DTilesTester.loadTileset(scene, pointCloudRGBUrl).then(function(tileset) {
var color;
expect(scene).toRenderAndCall(function(rgba) {
color = rgba;
});
var clipPlane = new ClippingPlane(Cartesian3.UNIT_Z, -10.0);
tileset.clippingPlanes = new ClippingPlaneCollection({
planes : [
clipPlane
]
});
expect(scene).notToRender(color);
clipPlane.distance = 0.0;
expect(scene).toRender(color);
});
});
it('clipping planes apply edge styling', function() {
return Cesium3DTilesTester.loadTileset(scene, pointCloudRGBUrl).then(function(tileset) {
var color;
expect(scene).toRenderAndCall(function(rgba) {
color = rgba;
});
var clipPlane = new ClippingPlane(Cartesian3.UNIT_Z, -10.0);
tileset.clippingPlanes = new ClippingPlaneCollection ({
planes : [
clipPlane
],
modelMatrix : Transforms.eastNorthUpToFixedFrame(tileset.boundingSphere.center),
edgeWidth : 20.0,
edgeColor : Color.RED
});
expect(scene).notToRender(color);
});
});
it('clipping planes union regions (Uint8)', function() {
// Force uint8 mode - there's a slight rendering difference between
// float and packed uint8 clipping planes for this test due to the small context
spyOn(ClippingPlaneCollection, 'useFloatTexture').and.returnValue(false);
return Cesium3DTilesTester.loadTileset(scene, pointCloudRGBUrl).then(function(tileset) {
var color;
expect(scene).toRenderAndCall(function(rgba) {
color = rgba;
});
tileset.clippingPlanes = new ClippingPlaneCollection ({
planes : [
new ClippingPlane(Cartesian3.UNIT_Z, 0.0),
new ClippingPlane(Cartesian3.UNIT_X, 0.0)
],
modelMatrix : Transforms.eastNorthUpToFixedFrame(tileset.boundingSphere.center),
unionClippingRegions: true
});
expect(scene).notToRender(color);
tileset.clippingPlanes.unionClippingRegions = false;
expect(scene).toRender(color);
});
});
it('clipping planes union regions (Float)', function() {
if (!ClippingPlaneCollection.useFloatTexture(scene.context)) {
// This configuration for the test fails in uint8 mode due to the small context
return;
}
return Cesium3DTilesTester.loadTileset(scene, pointCloudRGBUrl).then(function(tileset) {
var color;
expect(scene).toRenderAndCall(function(rgba) {
color = rgba;
});
tileset.clippingPlanes = new ClippingPlaneCollection ({
planes : [
new ClippingPlane(Cartesian3.UNIT_Z, -10.0),
new ClippingPlane(Cartesian3.UNIT_X, 0.0)
],
modelMatrix : Transforms.eastNorthUpToFixedFrame(tileset.boundingSphere.center),
unionClippingRegions: true
});
expect(scene).notToRender(color);
tileset.clippingPlanes.unionClippingRegions = false;
expect(scene).toRender(color);
});
});
it('destroys', function() {
return Cesium3DTilesTester.tileDestroys(scene, pointCloudRGBUrl);
});
}, 'WebGL');