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
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"
|
|
);
|