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.

340 lines
10 KiB
JavaScript

import { Cartesian3 } from "../../Source/Cesium.js";
import { Cartographic } from "../../Source/Cesium.js";
import { Color } from "../../Source/Cesium.js";
import { ColorGeometryInstanceAttribute } from "../../Source/Cesium.js";
import { destroyObject } from "../../Source/Cesium.js";
import { Ellipsoid } from "../../Source/Cesium.js";
import { GeometryInstance } from "../../Source/Cesium.js";
import { HeadingPitchRange } from "../../Source/Cesium.js";
import { Math as CesiumMath } from "../../Source/Cesium.js";
import { Matrix4 } from "../../Source/Cesium.js";
import { Rectangle } from "../../Source/Cesium.js";
import { RectangleGeometry } from "../../Source/Cesium.js";
import { Resource } from "../../Source/Cesium.js";
import { Pass } from "../../Source/Cesium.js";
import { RenderState } from "../../Source/Cesium.js";
import { ClassificationModel } from "../../Source/Cesium.js";
import { ClassificationType } from "../../Source/Cesium.js";
import { PerInstanceColorAppearance } from "../../Source/Cesium.js";
import { Primitive } from "../../Source/Cesium.js";
import { StencilConstants } from "../../Source/Cesium.js";
import createScene from "../createScene.js";
import pollToPromise from "../pollToPromise.js";
import { addDefaults } from "../../Source/Cesium.js";
import { parseGlb } from "../../Source/Cesium.js";
import { updateVersion } from "../../Source/Cesium.js";
describe(
"Scene/ClassificationModel",
function () {
var scene;
var modelMatrix;
var centerLongitude = -1.31968;
var centerLatitude = 0.698874;
var batchedModel = "./Data/Models/Classification/batched.glb";
var quantizedModel = "./Data/Models/Classification/batchedQuantization.glb";
var globePrimitive;
var tilesetPrimitive;
var reusableGlobePrimitive;
var reusableTilesetPrimitive;
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));
}
function createPrimitive(rectangle, pass) {
var renderState;
if (pass === Pass.CESIUM_3D_TILE) {
renderState = RenderState.fromCache({
stencilTest: StencilConstants.setCesium3DTileBit(),
stencilMask: StencilConstants.CESIUM_3D_TILE_MASK,
depthTest: {
enabled: true,
},
});
}
var depthColorAttribute = ColorGeometryInstanceAttribute.fromColor(
new Color(0.0, 0.0, 0.0, 1.0)
);
return new Primitive({
geometryInstances: new GeometryInstance({
geometry: new RectangleGeometry({
ellipsoid: Ellipsoid.WGS84,
rectangle: rectangle,
}),
id: "depth rectangle",
attributes: {
color: depthColorAttribute,
},
}),
appearance: new PerInstanceColorAppearance({
translucent: false,
flat: true,
renderState: renderState,
}),
asynchronous: false,
});
}
function MockPrimitive(primitive, pass) {
this._primitive = primitive;
this._pass = pass;
this.show = true;
}
MockPrimitive.prototype.update = function (frameState) {
if (!this.show) {
return;
}
var commandList = frameState.commandList;
var startLength = commandList.length;
this._primitive.update(frameState);
for (var i = startLength; i < commandList.length; ++i) {
var command = commandList[i];
command.pass = this._pass;
}
};
MockPrimitive.prototype.isDestroyed = function () {
return false;
};
MockPrimitive.prototype.destroy = function () {
return destroyObject(this);
};
beforeAll(function () {
scene = createScene();
var translation = Ellipsoid.WGS84.geodeticSurfaceNormalCartographic(
new Cartographic(centerLongitude, centerLatitude)
);
Cartesian3.multiplyByScalar(translation, -5.0, translation);
modelMatrix = Matrix4.fromTranslation(translation);
var offset = CesiumMath.toRadians(0.01);
var rectangle = new Rectangle(
centerLongitude - offset,
centerLatitude - offset,
centerLongitude + offset,
centerLatitude + offset
);
reusableGlobePrimitive = createPrimitive(rectangle, Pass.GLOBE);
reusableTilesetPrimitive = createPrimitive(
rectangle,
Pass.CESIUM_3D_TILE
);
});
afterAll(function () {
reusableGlobePrimitive.destroy();
reusableTilesetPrimitive.destroy();
scene.destroyForSpecs();
});
beforeEach(function () {
setCamera(centerLongitude, centerLatitude);
// wrap rectangle primitive so it gets executed during the globe pass and 3D Tiles pass to lay down depth
globePrimitive = new MockPrimitive(reusableGlobePrimitive, Pass.GLOBE);
tilesetPrimitive = new MockPrimitive(
reusableTilesetPrimitive,
Pass.CESIUM_3D_TILE
);
scene.primitives.add(globePrimitive);
scene.primitives.add(tilesetPrimitive);
});
afterEach(function () {
scene.primitives.removeAll();
globePrimitive =
globePrimitive &&
!globePrimitive.isDestroyed() &&
globePrimitive.destroy();
tilesetPrimitive =
tilesetPrimitive &&
!tilesetPrimitive.isDestroyed() &&
tilesetPrimitive.destroy();
});
function expectRender(scene, model) {
model.show = false;
expect(scene).toRender([0, 0, 0, 255]);
model.show = true;
expect(scene).toRenderAndCall(function (rgba) {
expect(rgba).not.toEqual([0, 0, 0, 255]);
});
}
function expectRenderBlank(scene, model) {
model.show = false;
expect(scene).toRender([0, 0, 0, 255]);
model.show = true;
expect(scene).toRender([0, 0, 0, 255]);
}
function loadGltf(model) {
return Resource.fetchArrayBuffer(model).then(function (arrayBuffer) {
var gltf = new Uint8Array(arrayBuffer);
gltf = parseGlb(gltf);
updateVersion(gltf);
addDefaults(gltf);
return gltf;
});
}
function loadClassificationModel(url, classificationType) {
return Resource.fetchArrayBuffer(url).then(function (arrayBuffer) {
var model = scene.primitives.add(
new ClassificationModel({
gltf: arrayBuffer,
classificationType: classificationType,
modelMatrix: modelMatrix,
})
);
var ready = false;
model.readyPromise.then(function () {
ready = true;
});
return pollToPromise(function () {
scene.renderForSpecs();
return ready;
}).then(function () {
return model;
});
});
}
it("classifies 3D Tiles", function () {
return loadClassificationModel(
batchedModel,
ClassificationType.CESIUM_3D_TILE
).then(function (model) {
globePrimitive.show = false;
tilesetPrimitive.show = true;
expectRender(scene, model);
globePrimitive.show = true;
tilesetPrimitive.show = false;
expectRenderBlank(scene, model);
globePrimitive.show = true;
tilesetPrimitive.show = true;
});
});
it("classifies globe", function () {
return loadClassificationModel(
batchedModel,
ClassificationType.TERRAIN
).then(function (model) {
globePrimitive.show = false;
tilesetPrimitive.show = true;
expectRenderBlank(scene, model);
globePrimitive.show = true;
tilesetPrimitive.show = false;
expectRender(scene, model);
globePrimitive.show = true;
tilesetPrimitive.show = true;
});
});
it("classifies both 3D Tiles and globe", function () {
return loadClassificationModel(
batchedModel,
ClassificationType.BOTH
).then(function (model) {
globePrimitive.show = false;
tilesetPrimitive.show = true;
expectRender(scene, model);
globePrimitive.show = true;
tilesetPrimitive.show = false;
expectRender(scene, model);
globePrimitive.show = true;
tilesetPrimitive.show = true;
});
});
it("renders batched model", function () {
return loadClassificationModel(
batchedModel,
ClassificationType.BOTH
).then(function (model) {
expectRender(scene, model);
});
});
it("renders batched model with quantization", function () {
return loadClassificationModel(
quantizedModel,
ClassificationType.BOTH
).then(function (model) {
expectRender(scene, model);
});
});
it("throws with invalid number of nodes", function () {
return loadGltf(batchedModel).then(function (gltf) {
gltf.nodes.push({});
expect(function () {
return new ClassificationModel({
gltf: gltf,
});
}).toThrowRuntimeError();
});
});
it("throws with invalid number of meshes", function () {
return loadGltf(batchedModel).then(function (gltf) {
gltf.meshes.push({});
expect(function () {
return new ClassificationModel({
gltf: gltf,
});
}).toThrowRuntimeError();
});
});
it("throws with invalid number of primitives", function () {
return loadGltf(batchedModel).then(function (gltf) {
gltf.meshes[0].primitives.push({});
expect(function () {
return new ClassificationModel({
gltf: gltf,
});
}).toThrowRuntimeError();
});
});
it("throws with position semantic", function () {
return loadGltf(batchedModel).then(function (gltf) {
gltf.meshes[0].primitives[0].attributes.POSITION = undefined;
expect(function () {
return new ClassificationModel({
gltf: gltf,
});
}).toThrowRuntimeError();
});
});
it("throws with batch id semantic", function () {
return loadGltf(batchedModel).then(function (gltf) {
gltf.meshes[0].primitives[0].attributes._BATCHID = undefined;
expect(function () {
return new ClassificationModel({
gltf: gltf,
});
}).toThrowRuntimeError();
});
});
},
"WebGL"
);