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

1331 lines
47 KiB
JavaScript
Raw Normal View History

2024-07-11 18:02:47 +08:00
defineSuite([
'Scene/Primitive',
'Core/BoundingSphere',
'Core/BoxGeometry',
'Core/Cartesian3',
'Core/ColorGeometryInstanceAttribute',
'Core/ComponentDatatype',
'Core/CylinderGeometry',
'Core/defined',
'Core/DistanceDisplayConditionGeometryInstanceAttribute',
'Core/Ellipsoid',
'Core/Geometry',
'Core/GeometryAttribute',
'Core/GeometryInstance',
'Core/GeometryInstanceAttribute',
'Core/HeadingPitchRange',
'Core/Math',
'Core/Matrix4',
'Core/PerspectiveFrustum',
'Core/PolygonGeometry',
'Core/PrimitiveType',
'Core/Rectangle',
'Core/RectangleGeometry',
'Core/ShowGeometryInstanceAttribute',
'Core/Transforms',
'Scene/Camera',
'Scene/MaterialAppearance',
'Scene/PerInstanceColorAppearance',
'Scene/SceneMode',
'Specs/BadGeometry',
'Specs/createContext',
'Specs/createFrameState',
'Specs/createScene',
'Specs/pollToPromise'
], function(
Primitive,
BoundingSphere,
BoxGeometry,
Cartesian3,
ColorGeometryInstanceAttribute,
ComponentDatatype,
CylinderGeometry,
defined,
DistanceDisplayConditionGeometryInstanceAttribute,
Ellipsoid,
Geometry,
GeometryAttribute,
GeometryInstance,
GeometryInstanceAttribute,
HeadingPitchRange,
CesiumMath,
Matrix4,
PerspectiveFrustum,
PolygonGeometry,
PrimitiveType,
Rectangle,
RectangleGeometry,
ShowGeometryInstanceAttribute,
Transforms,
Camera,
MaterialAppearance,
PerInstanceColorAppearance,
SceneMode,
BadGeometry,
createContext,
createFrameState,
createScene,
pollToPromise) {
'use strict';
var scene;
var context;
var frameStateContext;
var frameState;
var ellipsoid;
var rectangle1;
var rectangle2;
var rectangleInstance1;
var rectangleInstance2;
var primitive;
beforeAll(function() {
scene = createScene();
scene.primitives.destroyPrimitives = false;
context = scene.context;
ellipsoid = Ellipsoid.WGS84;
frameStateContext = createContext();
});
afterAll(function() {
scene.destroyForSpecs();
frameStateContext.destroyForSpecs();
});
beforeEach(function() {
scene.morphTo3D(0);
var camera = scene.camera;
camera.frustum = new PerspectiveFrustum();
camera.frustum.aspectRatio = scene.drawingBufferWidth / scene.drawingBufferHeight;
camera.frustum.fov = CesiumMath.toRadians(60.0);
scene.frameState.passes.render = true;
scene.frameState.passes.pick = false;
// Mock frameState, separate from scene.frameState, used for test that call primitive.update directly
frameState = createFrameState(frameStateContext);
rectangle1 = Rectangle.fromDegrees(-80.0, 20.0, -70.0, 30.0);
rectangle2 = Rectangle.fromDegrees(70.0, 20.0, 80.0, 30.0);
var translation = Cartesian3.multiplyByScalar(Cartesian3.normalize(ellipsoid.cartographicToCartesian(Rectangle.center(rectangle1)), new Cartesian3()), 2.0, new Cartesian3());
rectangleInstance1 = new GeometryInstance({
geometry : new RectangleGeometry({
vertexFormat : PerInstanceColorAppearance.VERTEX_FORMAT,
ellipsoid : ellipsoid,
rectangle : rectangle1
}),
modelMatrix : Matrix4.fromTranslation(translation, new Matrix4()),
id : 'rectangle1',
attributes : {
color : new ColorGeometryInstanceAttribute(1.0, 1.0, 0.0, 1.0),
show : new ShowGeometryInstanceAttribute(true)
}
});
translation = Cartesian3.multiplyByScalar(Cartesian3.normalize(ellipsoid.cartographicToCartesian(Rectangle.center(rectangle2)), new Cartesian3()), 3.0, new Cartesian3());
rectangleInstance2 = new GeometryInstance({
geometry : new RectangleGeometry({
vertexFormat : PerInstanceColorAppearance.VERTEX_FORMAT,
ellipsoid : ellipsoid,
rectangle : rectangle2
}),
modelMatrix : Matrix4.fromTranslation(translation, new Matrix4()),
id : 'rectangle2',
attributes : {
color : new ColorGeometryInstanceAttribute(0.0, 1.0, 1.0, 1.0),
show : new ShowGeometryInstanceAttribute(true)
}
});
});
afterEach(function() {
scene.primitives.removeAll();
primitive = primitive && !primitive.isDestroyed() && primitive.destroy();
});
it('default constructs', function() {
primitive = new Primitive();
expect(primitive.geometryInstances).not.toBeDefined();
expect(primitive.appearance).not.toBeDefined();
expect(primitive.depthFailAppearance).not.toBeDefined();
expect(primitive.modelMatrix).toEqual(Matrix4.IDENTITY);
expect(primitive.show).toEqual(true);
expect(primitive.vertexCacheOptimize).toEqual(false);
expect(primitive.interleave).toEqual(false);
expect(primitive.compressVertices).toEqual(true);
expect(primitive.releaseGeometryInstances).toEqual(true);
expect(primitive.allowPicking).toEqual(true);
expect(primitive.cull).toEqual(true);
expect(primitive.asynchronous).toEqual(true);
expect(primitive.debugShowBoundingVolume).toEqual(false);
});
it('Constructs with options', function() {
var geometryInstances = {};
var appearance = {};
var depthFailAppearance = {};
var modelMatrix = Matrix4.fromUniformScale(5.0);
primitive = new Primitive({
geometryInstances : geometryInstances,
appearance : appearance,
depthFailAppearance : depthFailAppearance,
modelMatrix : modelMatrix,
show : false,
vertexCacheOptimize : true,
interleave : true,
compressVertices : false,
releaseGeometryInstances : false,
allowPicking : false,
cull : false,
asynchronous : false,
debugShowBoundingVolume : true
});
expect(primitive.geometryInstances).toEqual(geometryInstances);
expect(primitive.appearance).toEqual(appearance);
expect(primitive.depthFailAppearance).toEqual(depthFailAppearance);
expect(primitive.modelMatrix).toEqual(modelMatrix);
expect(primitive.show).toEqual(false);
expect(primitive.vertexCacheOptimize).toEqual(true);
expect(primitive.interleave).toEqual(true);
expect(primitive.compressVertices).toEqual(false);
expect(primitive.releaseGeometryInstances).toEqual(false);
expect(primitive.allowPicking).toEqual(false);
expect(primitive.cull).toEqual(false);
expect(primitive.asynchronous).toEqual(false);
expect(primitive.debugShowBoundingVolume).toEqual(true);
});
it('releases geometry instances when releaseGeometryInstances is true', function() {
primitive = new Primitive({
geometryInstances : [rectangleInstance1, rectangleInstance2],
appearance : new PerInstanceColorAppearance(),
releaseGeometryInstances : true,
asynchronous : false
});
expect(primitive.geometryInstances).toBeDefined();
scene.primitives.add(primitive);
scene.renderForSpecs();
expect(primitive.geometryInstances).not.toBeDefined();
});
it('does not release geometry instances when releaseGeometryInstances is false', function() {
primitive = new Primitive({
geometryInstances : [rectangleInstance1, rectangleInstance2],
appearance : new PerInstanceColorAppearance(),
releaseGeometryInstances : false,
asynchronous : false
});
expect(primitive.geometryInstances).toBeDefined();
scene.primitives.add(primitive);
scene.renderForSpecs();
expect(primitive.geometryInstances).toBeDefined();
});
it('adds afterRender promise to frame state', function() {
primitive = new Primitive({
geometryInstances : [rectangleInstance1, rectangleInstance2],
appearance : new PerInstanceColorAppearance(),
releaseGeometryInstances : false,
asynchronous : false
});
scene.primitives.add(primitive);
scene.renderForSpecs();
return primitive.readyPromise.then(function(param) {
expect(param.ready).toBe(true);
});
});
it('does not render when geometryInstances is an empty array', function() {
primitive = new Primitive({
geometryInstances : [],
appearance : new PerInstanceColorAppearance(),
asynchronous : false
});
frameState.commandList.length = 0;
primitive.update(frameState);
expect(frameState.commandList.length).toEqual(0);
});
it('does not render when show is false', function() {
primitive = new Primitive({
geometryInstances : [rectangleInstance1, rectangleInstance2],
appearance : new PerInstanceColorAppearance(),
asynchronous : false
});
primitive.update(frameState);
expect(frameState.commandList.length).toBeGreaterThan(0);
frameState.commandList.length = 0;
primitive.show = false;
primitive.update(frameState);
expect(frameState.commandList.length).toEqual(0);
});
it('does not render other than for the color or pick pass', function() {
primitive = new Primitive({
geometryInstances : [rectangleInstance1, rectangleInstance2],
appearance : new PerInstanceColorAppearance(),
asynchronous : false
});
frameState.passes.render = false;
frameState.passes.pick = false;
primitive.update(frameState);
expect(frameState.commandList.length).toEqual(0);
});
it('does not render when scene3DOnly is true and the scene mode is SCENE2D', function() {
primitive = new Primitive({
geometryInstances : [rectangleInstance1, rectangleInstance2],
appearance : new PerInstanceColorAppearance(),
asynchronous : false
});
frameState.mode = SceneMode.SCENE2D;
frameState.scene3DOnly = true;
primitive.update(frameState);
expect(frameState.commandList.length).toEqual(0);
});
it('does not render when scene3DOnly is true and the scene mode is COLUMBUS_VIEW', function() {
primitive = new Primitive({
geometryInstances : [rectangleInstance1, rectangleInstance2],
appearance : new PerInstanceColorAppearance(),
asynchronous : false
});
frameState.mode = SceneMode.COLUMBUS_VIEW;
frameState.scene3DOnly = true;
primitive.update(frameState);
expect(frameState.commandList.length).toEqual(0);
});
it('renders in two passes for closed, translucent geometry', function() {
primitive = new Primitive({
geometryInstances : new GeometryInstance({
geometry : BoxGeometry.fromDimensions({
vertexFormat : PerInstanceColorAppearance.VERTEX_FORMAT,
dimensions : new Cartesian3(500000.0, 500000.0, 500000.0)
}),
id : 'box',
attributes : {
color : new ColorGeometryInstanceAttribute(1.0, 1.0, 0.0, 0.5)
}
}),
appearance : new PerInstanceColorAppearance({
closed : true,
translucent : true
}),
asynchronous : false
});
var frameState = scene.frameState;
frameState.commandList.length = 0;
// set scene3DOnly to true so that the geometry is not split due to the IDL
frameState.scene3DOnly = true;
scene.primitives.add(primitive);
scene.render();
expect(frameState.commandList.length).toEqual(2);
});
function verifyPrimitiveRender(primitive, rectangle) {
scene.primitives.removeAll();
if (defined(rectangle)){
scene.camera.setView({ destination : rectangle });
}
expect(scene).toRender([0, 0, 0, 255]);
scene.primitives.add(primitive);
expect(scene).notToRender([0, 0, 0, 255]);
}
it('renders in Columbus view when scene3DOnly is false', function() {
scene.frameState.scene3DOnly = false;
primitive = new Primitive({
geometryInstances : [rectangleInstance1, rectangleInstance2],
appearance : new PerInstanceColorAppearance(),
asynchronous : false
});
scene.morphToColumbusView(0);
verifyPrimitiveRender(primitive, rectangle1);
verifyPrimitiveRender(primitive, rectangle2);
});
it('renders in 2D when scene3DOnly is false', function() {
scene.frameState.scene3DOnly = false;
primitive = new Primitive({
geometryInstances : [rectangleInstance1, rectangleInstance2],
appearance : new PerInstanceColorAppearance(),
asynchronous : false
});
scene.morphTo2D(0);
verifyPrimitiveRender(primitive, rectangle1);
verifyPrimitiveRender(primitive, rectangle2);
});
it('renders RTC', function() {
var dimensions = new Cartesian3(400.0, 300.0, 500.0);
var positionOnEllipsoid = Cartesian3.fromDegrees(-105.0, 45.0);
var boxModelMatrix = Matrix4.multiplyByTranslation(
Transforms.eastNorthUpToFixedFrame(positionOnEllipsoid),
new Cartesian3(0.0, 0.0, dimensions.z * 0.5), new Matrix4());
var boxGeometry = BoxGeometry.createGeometry(BoxGeometry.fromDimensions({
vertexFormat : PerInstanceColorAppearance.VERTEX_FORMAT,
dimensions : dimensions
}));
var positions = boxGeometry.attributes.position.values;
var newPositions = new Float32Array(positions.length);
for (var i = 0; i < positions.length; ++i) {
newPositions[i] = positions[i];
}
boxGeometry.attributes.position.values = newPositions;
boxGeometry.attributes.position.componentDatatype = ComponentDatatype.FLOAT;
BoundingSphere.transform(boxGeometry.boundingSphere, boxModelMatrix, boxGeometry.boundingSphere);
var boxGeometryInstance = new GeometryInstance({
geometry : boxGeometry,
attributes : {
color : new ColorGeometryInstanceAttribute(1.0, 0.0, 0.0, 0.5)
}
});
var primitive = new Primitive({
geometryInstances : boxGeometryInstance,
appearance : new PerInstanceColorAppearance({
closed: true
}),
asynchronous : false,
allowPicking : false,
rtcCenter : boxGeometry.boundingSphere.center
});
// create test camera
var camera = scene.camera;
var testCamera = new Camera(scene);
testCamera.viewBoundingSphere(boxGeometry.boundingSphere);
scene.camera = testCamera;
scene.frameState.scene3DOnly = true;
verifyPrimitiveRender(primitive);
scene.camera = camera;
});
it('renders with depth fail appearance', function() {
var rect = Rectangle.fromDegrees(-1.0, -1.0, 1.0, 1.0);
var translation = Cartesian3.multiplyByScalar(Cartesian3.normalize(ellipsoid.cartographicToCartesian(Rectangle.center(rect)), new Cartesian3()), 100.0, new Cartesian3());
var rectInstance = new GeometryInstance({
geometry : new RectangleGeometry({
vertexFormat : PerInstanceColorAppearance.VERTEX_FORMAT,
ellipsoid : ellipsoid,
rectangle : rect
}),
modelMatrix : Matrix4.fromTranslation(translation, new Matrix4()),
id : 'rect',
attributes : {
color : new ColorGeometryInstanceAttribute(1.0, 1.0, 0.0, 1.0)
}
});
var p0 = new Primitive({
geometryInstances : rectInstance,
appearance : new PerInstanceColorAppearance({
translucent : false
}),
asynchronous : false
});
var rectInstance2 = new GeometryInstance({
geometry : new RectangleGeometry({
vertexFormat : PerInstanceColorAppearance.VERTEX_FORMAT,
ellipsoid : ellipsoid,
rectangle : rect
}),
id : 'rect2',
attributes : {
color : new ColorGeometryInstanceAttribute(1.0, 0.0, 0.0, 1.0),
depthFailColor : new ColorGeometryInstanceAttribute(1.0, 0.0, 1.0, 1.0)
}
});
var p1 = new Primitive({
geometryInstances : rectInstance2,
appearance : new PerInstanceColorAppearance({
translucent : false
}),
depthFailAppearance : new PerInstanceColorAppearance({
translucent : false
}),
asynchronous : false
});
scene.primitives.add(p0);
scene.primitives.add(p1);
scene.camera.setView({ destination : rect });
scene.renderForSpecs();
expect(scene).toRender([255, 0, 255, 255]);
});
it('pick with depth fail appearance', function() {
var rect = Rectangle.fromDegrees(-1.0, -1.0, 1.0, 1.0);
var translation = Cartesian3.multiplyByScalar(Cartesian3.normalize(ellipsoid.cartographicToCartesian(Rectangle.center(rect)), new Cartesian3()), 100.0, new Cartesian3());
var rectInstance = new GeometryInstance({
geometry : new RectangleGeometry({
vertexFormat : PerInstanceColorAppearance.VERTEX_FORMAT,
ellipsoid : ellipsoid,
rectangle : rect
}),
modelMatrix : Matrix4.fromTranslation(translation, new Matrix4()),
id : 'rect',
attributes : {
color : new ColorGeometryInstanceAttribute(1.0, 1.0, 0.0, 1.0)
}
});
var p0 = new Primitive({
geometryInstances : rectInstance,
appearance : new PerInstanceColorAppearance({
translucent : false
}),
asynchronous : false
});
var rectInstance2 = new GeometryInstance({
geometry : new RectangleGeometry({
vertexFormat : PerInstanceColorAppearance.VERTEX_FORMAT,
ellipsoid : ellipsoid,
rectangle : rect
}),
id : 'rect2',
attributes : {
color : new ColorGeometryInstanceAttribute(1.0, 0.0, 0.0, 1.0),
depthFailColor : new ColorGeometryInstanceAttribute(1.0, 0.0, 1.0, 1.0)
}
});
var p1 = new Primitive({
geometryInstances : rectInstance2,
appearance : new PerInstanceColorAppearance({
translucent : false
}),
depthFailAppearance : new PerInstanceColorAppearance({
translucent : false
}),
asynchronous : false
});
scene.primitives.add(p0);
scene.primitives.add(p1);
scene.camera.setView({ destination : rect });
scene.renderForSpecs();
expect(scene).toPickAndCall(function(result) {
expect(result.primitive).toEqual(p1);
expect(result.id).toEqual('rect2');
});
});
it('RTC throws with more than one instance', function() {
expect(function() {
return new Primitive({
geometryInstances : [rectangleInstance1, rectangleInstance2],
appearance : new PerInstanceColorAppearance({
closed: true
}),
asynchronous : false,
allowPicking : false,
rtcCenter : Cartesian3.ZERO
});
}).toThrowDeveloperError();
});
it('RTC throws if the scene is not 3D only', function() {
scene.frameState.scene3DOnly = false;
var primitive = new Primitive({
geometryInstances : rectangleInstance1,
appearance : new PerInstanceColorAppearance({
closed: true
}),
asynchronous : false,
allowPicking : false,
rtcCenter : Cartesian3.ZERO
});
expect(function() {
verifyPrimitiveRender(primitive);
}).toThrowDeveloperError();
});
it('updates model matrix for one instance in 3D', function() {
primitive = new Primitive({
geometryInstances : rectangleInstance1,
appearance : new PerInstanceColorAppearance(),
asynchronous : false
});
primitive.update(frameState);
var commands = frameState.commandList;
expect(commands.length).toEqual(1);
expect(commands[0].modelMatrix).toEqual(primitive.modelMatrix);
var modelMatrix = Matrix4.fromUniformScale(10.0);
primitive.modelMatrix = modelMatrix;
commands.length = 0;
primitive.update(frameState);
expect(commands.length).toEqual(1);
expect(commands[0].modelMatrix).toEqual(modelMatrix);
});
it('updates model matrix for more than one instance in 3D with equal model matrices in 3D only scene', function() {
var modelMatrix = Matrix4.fromUniformScale(2.0);
rectangleInstance1.modelMatrix = modelMatrix;
rectangleInstance2.modelMatrix = modelMatrix;
primitive = new Primitive({
geometryInstances : [rectangleInstance1, rectangleInstance2],
appearance : new PerInstanceColorAppearance(),
asynchronous : false
});
frameState.scene3DOnly = true;
var commands = frameState.commandList;
commands.length = 0;
primitive.update(frameState);
expect(commands.length).toEqual(1);
expect(commands[0].modelMatrix).toEqual(modelMatrix);
modelMatrix = Matrix4.fromUniformScale(10.0);
primitive.modelMatrix = modelMatrix;
commands.length = 0;
primitive.update(frameState);
expect(commands.length).toEqual(1);
expect(commands[0].modelMatrix).toEqual(modelMatrix);
});
it('computes model matrix when given one for a single instance and for the primitive in 3D only', function() {
var instanceModelMatrix = Matrix4.fromUniformScale(2.0);
var dimensions = new Cartesian3(400000.0, 300000.0, 500000.0);
var positionOnEllipsoid = Cartesian3.fromDegrees(-105.0, 45.0);
var primitiveModelMatrix = Matrix4.multiplyByTranslation(
Transforms.eastNorthUpToFixedFrame(positionOnEllipsoid),
new Cartesian3(0.0, 0.0, dimensions.z * 0.5), new Matrix4());
var boxGeometry = BoxGeometry.fromDimensions({
vertexFormat : PerInstanceColorAppearance.VERTEX_FORMAT,
dimensions : dimensions
});
var boxGeometryInstance = new GeometryInstance({
geometry : boxGeometry,
modelMatrix : instanceModelMatrix,
attributes : {
color : new ColorGeometryInstanceAttribute(1.0, 0.0, 0.0, 1.0)
}
});
primitive = new Primitive({
geometryInstances : boxGeometryInstance,
modelMatrix : primitiveModelMatrix,
appearance : new PerInstanceColorAppearance({
translucent : false,
closed: true
}),
asynchronous : false
});
var expectedModelMatrix = Matrix4.multiplyTransformation(primitiveModelMatrix, instanceModelMatrix, new Matrix4());
frameState.scene3DOnly = true;
var commands = frameState.commandList;
commands.length = 0;
primitive.update(frameState);
expect(commands.length).toEqual(1);
expect(commands[0].modelMatrix).toEqual(expectedModelMatrix);
});
it('update model matrix throws in Columbus view', function() {
primitive = new Primitive({
geometryInstances : [rectangleInstance1, rectangleInstance2],
appearance : new PerInstanceColorAppearance(),
asynchronous : false
});
frameState.mode = SceneMode.COLUMBUS_VIEW;
frameState.scene3DOnly = false;
var commands = frameState.commandList;
commands.length = 0;
primitive.update(frameState);
expect(commands.length).toEqual(1);
expect(commands[0].modelMatrix).toEqual(Matrix4.IDENTITY);
var modelMatrix = Matrix4.fromUniformScale(10.0);
primitive.modelMatrix = modelMatrix;
commands.length = 0;
expect(function() {
primitive.update(frameState);
}).toThrowDeveloperError();
});
it('update model matrix throws in 2D', function() {
primitive = new Primitive({
geometryInstances : [rectangleInstance1, rectangleInstance2],
appearance : new PerInstanceColorAppearance(),
asynchronous : false
});
frameState.mode = SceneMode.SCENE2D;
frameState.scene3DOnly = false;
var commands = frameState.commandList;
primitive.update(frameState);
expect(commands.length).toEqual(1);
expect(commands[0].modelMatrix).toEqual(Matrix4.IDENTITY);
var modelMatrix = Matrix4.fromUniformScale(10.0);
primitive.modelMatrix = modelMatrix;
commands.length = 0;
expect(function() {
primitive.update(frameState);
}).toThrowDeveloperError();
});
it('renders bounding volume with debugShowBoundingVolume', function() {
primitive = new Primitive({
geometryInstances : rectangleInstance1,
appearance : new PerInstanceColorAppearance(),
asynchronous : false,
debugShowBoundingVolume : true
});
scene.primitives.add(primitive);
scene.camera.setView({ destination : rectangle1 });
expect(scene).toRenderAndCall(function(rgba) {
expect(rgba[0]).not.toEqual(0);
expect(rgba[1]).toBeGreaterThanOrEqualTo(0);
expect(rgba[2]).toBeGreaterThanOrEqualTo(0);
expect(rgba[3]).toEqual(255);
});
});
it('transforms to world coordinates', function() {
primitive = new Primitive({
geometryInstances : [rectangleInstance1, rectangleInstance2],
appearance : new PerInstanceColorAppearance(),
asynchronous : false
});
verifyPrimitiveRender(primitive, rectangle1);
verifyPrimitiveRender(primitive, rectangle2);
expect(primitive.modelMatrix).toEqual(Matrix4.IDENTITY);
});
it('does not transform to world coordinates', function() {
rectangleInstance2.modelMatrix = Matrix4.clone(rectangleInstance1.modelMatrix);
primitive = new Primitive({
geometryInstances : [rectangleInstance1, rectangleInstance2],
appearance : new PerInstanceColorAppearance(),
asynchronous : false
});
scene.frameState.scene3DOnly = true;
verifyPrimitiveRender(primitive, rectangle1);
verifyPrimitiveRender(primitive, rectangle2);
expect(primitive.modelMatrix).not.toEqual(Matrix4.IDENTITY);
scene.frameState.scene3DOnly = true;
});
it('get common per instance attributes', function() {
rectangleInstance2.attributes.not_used = new GeometryInstanceAttribute({
componentDatatype : ComponentDatatype.FLOAT,
componentsPerAttribute : 1,
value : [0.5]
});
primitive = new Primitive({
geometryInstances : [rectangleInstance1, rectangleInstance2],
appearance : new PerInstanceColorAppearance(),
asynchronous : false
});
scene.primitives.add(primitive);
scene.renderForSpecs();
var attributes = primitive.getGeometryInstanceAttributes('rectangle1');
expect(attributes.color).toBeDefined();
expect(attributes.show).toBeDefined();
attributes = primitive.getGeometryInstanceAttributes('rectangle2');
expect(attributes.color).toBeDefined();
expect(attributes.show).toBeDefined();
expect(attributes.not_used).not.toBeDefined();
});
it('modify color instance attribute', function() {
primitive = new Primitive({
geometryInstances : rectangleInstance1,
appearance : new PerInstanceColorAppearance(),
asynchronous : false
});
scene.camera.setView({ destination : rectangle1 });
scene.primitives.add(primitive);
var pixels;
expect(scene).toRenderAndCall(function(rgba) {
pixels = rgba;
expect(rgba).not.toEqual([0, 0, 0, 255]);
});
var attributes = primitive.getGeometryInstanceAttributes('rectangle1');
expect(attributes.color).toBeDefined();
attributes.color = [255, 255, 255, 255];
expect(scene).toRenderAndCall(function(rgba) {
expect(rgba).not.toEqual([0, 0, 0, 255]);
expect(rgba).not.toEqual(pixels);
});
});
it('modify show instance attribute', function() {
primitive = new Primitive({
geometryInstances : rectangleInstance1,
appearance : new PerInstanceColorAppearance(),
asynchronous : false
});
scene.primitives.add(primitive);
scene.camera.setView({ destination : rectangle1 });
expect(scene).notToRender([0, 0, 0, 255]);
var attributes = primitive.getGeometryInstanceAttributes('rectangle1');
expect(attributes.show).toBeDefined();
attributes.show = [0];
expect(scene).toRender([0, 0, 0, 255]);
});
it('get bounding sphere from per instance attribute', function() {
primitive = new Primitive({
geometryInstances : rectangleInstance1,
appearance : new PerInstanceColorAppearance(),
asynchronous : false
});
verifyPrimitiveRender(primitive, rectangle1);
var attributes = primitive.getGeometryInstanceAttributes('rectangle1');
expect(attributes.boundingSphere).toBeDefined();
});
it('renders with distance display condition per instance attribute', function() {
if (!context.floatingPointTexture) {
return;
}
var near = 10000.0;
var far = 1000000.0;
var rect = Rectangle.fromDegrees(-1.0, -1.0, 1.0, 1.0);
var translation = Cartesian3.multiplyByScalar(Cartesian3.normalize(ellipsoid.cartographicToCartesian(Rectangle.center(rect)), new Cartesian3()), 2.0, new Cartesian3());
var rectInstance = new GeometryInstance({
geometry : new RectangleGeometry({
vertexFormat : PerInstanceColorAppearance.VERTEX_FORMAT,
ellipsoid : ellipsoid,
rectangle : rect
}),
modelMatrix : Matrix4.fromTranslation(translation, new Matrix4()),
id : 'rect',
attributes : {
color : new ColorGeometryInstanceAttribute(1.0, 1.0, 0.0, 1.0),
distanceDisplayCondition : new DistanceDisplayConditionGeometryInstanceAttribute(near, far)
}
});
primitive = new Primitive({
geometryInstances : rectInstance,
appearance : new PerInstanceColorAppearance(),
asynchronous : false
});
scene.primitives.add(primitive);
scene.camera.setView({ destination : rect });
scene.renderForSpecs();
var boundingSphere = primitive.getGeometryInstanceAttributes('rect').boundingSphere;
var center = boundingSphere.center;
var radius = boundingSphere.radius;
scene.camera.lookAt(center, new HeadingPitchRange(0.0, -CesiumMath.PI_OVER_TWO, radius));
expect(scene).toRender([0, 0, 0, 255]);
scene.camera.lookAt(center, new HeadingPitchRange(0.0, -CesiumMath.PI_OVER_TWO, radius + near + 1.0));
expect(scene).notToRender([0, 0, 0, 255]);
scene.camera.lookAt(center, new HeadingPitchRange(0.0, -CesiumMath.PI_OVER_TWO, radius + far + 1.0));
expect(scene).toRender([0, 0, 0, 255]);
});
it('primitive with display condition properly transforms boundingSphere', function() {
var near = 10000.0;
var far = 1000000.0;
var translation = new Cartesian3(10, 20, 30);
var cylinder = new GeometryInstance({
id : 'cylinder',
vertexFormat : PerInstanceColorAppearance.VERTEX_FORMAT,
geometry : new CylinderGeometry({
length : 10,
topRadius : 10,
bottomRadius : 10
}),
attributes : {
color : new ColorGeometryInstanceAttribute(1.0, 1.0, 0.0, 1.0),
show : new ShowGeometryInstanceAttribute(true),
distanceDisplayCondition : new DistanceDisplayConditionGeometryInstanceAttribute(near, far)
}
});
primitive = new Primitive({
geometryInstances : cylinder,
appearance : new PerInstanceColorAppearance(),
modelMatrix : Matrix4.fromTranslation(translation, new Matrix4()),
asynchronous : false
});
scene.primitives.add(primitive);
scene.frameState.scene3DOnly = true;
scene.renderForSpecs();
var boundingSphere = primitive.getGeometryInstanceAttributes('cylinder').boundingSphere;
var center = boundingSphere.center;
expect(center).toEqual(translation);
});
it('primitive without display condition properly transforms boundingSphere', function() {
var translation = new Cartesian3(10, 20, 30);
var cylinder = new GeometryInstance({
id : 'cylinder',
vertexFormat : PerInstanceColorAppearance.VERTEX_FORMAT,
geometry : new CylinderGeometry({
length : 10,
topRadius : 10,
bottomRadius : 10
}),
attributes : {
color : new ColorGeometryInstanceAttribute(1.0, 1.0, 0.0, 1.0),
show : new ShowGeometryInstanceAttribute(true)
}
});
primitive = new Primitive({
geometryInstances : cylinder,
appearance : new PerInstanceColorAppearance(),
modelMatrix : Matrix4.fromTranslation(translation, new Matrix4()),
asynchronous : false
});
scene.primitives.add(primitive);
scene.frameState.scene3DOnly = true;
scene.renderForSpecs();
var boundingSphere = primitive.getGeometryInstanceAttributes('cylinder').boundingSphere;
var center = boundingSphere.center;
expect(center).toEqual(translation);
});
it('getGeometryInstanceAttributes returns same object each time', function() {
primitive = new Primitive({
geometryInstances : rectangleInstance1,
appearance : new PerInstanceColorAppearance(),
asynchronous : false
});
verifyPrimitiveRender(primitive, rectangle1);
var attributes = primitive.getGeometryInstanceAttributes('rectangle1');
var attributes2 = primitive.getGeometryInstanceAttributes('rectangle1');
expect(attributes).toBe(attributes2);
});
it('picking', function() {
primitive = new Primitive({
geometryInstances : [rectangleInstance1, rectangleInstance2],
appearance : new PerInstanceColorAppearance(),
asynchronous : false
});
verifyPrimitiveRender(primitive, rectangle1);
expect(scene).toPickAndCall(function(result) {
expect(result.primitive).toEqual(primitive);
expect(result.id).toEqual('rectangle1');
});
verifyPrimitiveRender(primitive, rectangle2);
expect(scene).toPickAndCall(function(result) {
expect(result.primitive).toEqual(primitive);
expect(result.id).toEqual('rectangle2');
});
});
it('does not pick when allowPicking is false', function() {
primitive = new Primitive({
geometryInstances : [rectangleInstance1],
appearance : new PerInstanceColorAppearance(),
allowPicking : false,
asynchronous : false
});
verifyPrimitiveRender(primitive, rectangle1);
expect(scene).notToPick();
});
it('does not cull when cull is false', function() {
primitive = new Primitive({
geometryInstances : rectangleInstance1,
appearance : new PerInstanceColorAppearance(),
asynchronous : false,
cull : false
});
frameState.commandList.length = 0;
primitive.update(frameState);
expect(frameState.commandList[0].cull).toEqual(false);
});
it('update throws when geometry primitive types are different', function() {
primitive = new Primitive({
geometryInstances : [
new GeometryInstance({
geometry : new Geometry({
attributes : {
position : new GeometryAttribute({
componentDatatype : ComponentDatatype.FLOAT,
componentsPerAttribute : 3,
values : new Float32Array([1.0, 2.0, 3.0, 4.0])
})
},
primitiveType : PrimitiveType.LINES
})
}),
new GeometryInstance({
geometry : new Geometry({
attributes : {
position : new GeometryAttribute({
componentDatatype : ComponentDatatype.FLOAT,
componentsPerAttribute : 3,
values : new Float32Array([1.0, 2.0, 3.0, 4.0, 5.0, 6.0])
})
},
primitiveType : PrimitiveType.TRIANGLES
})
})
],
appearance : new PerInstanceColorAppearance(),
asynchronous : false
});
expect(function() {
primitive.update(frameState);
}).toThrowDeveloperError();
});
it('failed geometry rejects promise and throws on next update', function() {
primitive = new Primitive({
geometryInstances : [new GeometryInstance({
geometry : new BadGeometry()
})],
appearance : new MaterialAppearance({
materialSupport : MaterialAppearance.MaterialSupport.ALL
}),
compressVertices : false
});
scene.frameState.afterRender.length = 0;
scene.primitives.add(primitive);
return pollToPromise(function() {
for (var i = 0; i < frameState.afterRender.length; ++i) {
frameState.afterRender[i]();
return true;
}
primitive.update(frameState);
return false;
}).then(function() {
return primitive.readyPromise.then(function() {
fail('should not be called');
}).otherwise(function(e) {
expect(e).toBe(primitive._error);
// Use toThrow since the error is thrown by RequireJS for the web worker import script
expect(function() {
scene.render();
}).toThrow();
});
});
});
it('internally invalid asynchronous geometry resolves promise and sets ready', function() {
primitive = new Primitive({
geometryInstances : [new GeometryInstance({
geometry : PolygonGeometry.fromPositions({
positions : []
})
})],
appearance : new MaterialAppearance({
materialSupport : MaterialAppearance.MaterialSupport.ALL
}),
compressVertices : false
});
scene.frameState.afterRender.length = 0;
return pollToPromise(function() {
for (var i = 0; i < frameState.afterRender.length; ++i) {
frameState.afterRender[i]();
return true;
}
primitive.update(frameState);
return false;
}).then(function() {
return primitive.readyPromise.then(function(arg) {
expect(arg).toBe(primitive);
expect(primitive.ready).toBe(true);
});
});
});
it('internally invalid synchronous geometry resolves promise and sets ready', function() {
primitive = new Primitive({
geometryInstances : [new GeometryInstance({
geometry : PolygonGeometry.fromPositions({
positions : []
})
})],
appearance : new MaterialAppearance({
materialSupport : MaterialAppearance.MaterialSupport.ALL
}),
asynchronous : false,
compressVertices : false
});
scene.frameState.afterRender.length = 0;
return pollToPromise(function() {
if (scene.frameState.afterRender.length > 0) {
scene.frameState.afterRender[0]();
return true;
}
primitive.update(scene.frameState);
return false;
}).then(function() {
return primitive.readyPromise.then(function(arg) {
expect(arg).toBe(primitive);
expect(primitive.ready).toBe(true);
});
});
});
it('can mix valid and invalid geometry', function() {
var instances = [];
instances.push(rectangleInstance1);
instances.push(new GeometryInstance({
geometry : PolygonGeometry.fromPositions({
positions : []
}),
attributes : {
color : new ColorGeometryInstanceAttribute(1.0, 0.0, 1.0, 1.0)
},
id : 'invalid'
}));
instances.push(rectangleInstance2);
primitive = new Primitive({
geometryInstances : instances,
appearance : new PerInstanceColorAppearance({
flat : true
})
});
return pollToPromise(function() {
primitive.update(frameState);
if (frameState.afterRender.length > 0) {
frameState.afterRender[0]();
}
return primitive.ready;
}).then(function() {
expect(primitive.getGeometryInstanceAttributes('rectangle1').boundingSphere).toBeDefined();
expect(primitive.getGeometryInstanceAttributes('rectangle2').boundingSphere).toBeDefined();
expect(primitive.getGeometryInstanceAttributes('invalid').boundingSphere).not.toBeDefined();
});
});
it('shader validation', function() {
if (!!window.webglStub) {
return;
}
primitive = new Primitive({
geometryInstances : [rectangleInstance1, rectangleInstance2],
appearance : new MaterialAppearance({
materialSupport : MaterialAppearance.MaterialSupport.ALL
}),
asynchronous : false,
compressVertices : false
});
expect(function() {
primitive.update(frameState);
}).toThrowDeveloperError();
});
it('setting per instance attribute throws when value is undefined', function() {
primitive = new Primitive({
geometryInstances : rectangleInstance1,
appearance : new PerInstanceColorAppearance(),
asynchronous : false
});
primitive.update(frameState);
var attributes = primitive.getGeometryInstanceAttributes('rectangle1');
expect(function() {
attributes.color = undefined;
}).toThrowDeveloperError();
});
it('can disable picking when asynchronous', function() {
primitive = new Primitive({
geometryInstances : rectangleInstance1,
appearance : new PerInstanceColorAppearance(),
asynchronous : true,
allowPicking : false
});
frameState.afterRender.length = 0;
scene.primitives.add(primitive);
return pollToPromise(function() {
if (frameState.afterRender.length > 0) {
frameState.afterRender[0]();
}
scene.render();
return primitive.ready;
}).then(function() {
var attributes = primitive.getGeometryInstanceAttributes('rectangle1');
expect(function() {
attributes.color = undefined;
}).toThrowDeveloperError();
});
});
it('getGeometryInstanceAttributes throws without id', function() {
primitive = new Primitive({
geometryInstances : rectangleInstance1,
appearance : new PerInstanceColorAppearance(),
asynchronous : false
});
scene.primitives.add(primitive);
scene.renderForSpecs();
expect(function() {
primitive.getGeometryInstanceAttributes();
}).toThrowDeveloperError();
});
it('getGeometryInstanceAttributes throws if update was not called', function() {
primitive = new Primitive({
geometryInstances : rectangleInstance1,
appearance : new PerInstanceColorAppearance(),
asynchronous : false
});
expect(function() {
primitive.getGeometryInstanceAttributes('rectangle1');
}).toThrowDeveloperError();
});
it('getGeometryInstanceAttributes returns undefined if id does not exist', function() {
primitive = new Primitive({
geometryInstances : rectangleInstance1,
appearance : new PerInstanceColorAppearance(),
asynchronous : false
});
scene.primitives.add(primitive);
scene.renderForSpecs();
expect(primitive.getGeometryInstanceAttributes('unknown')).not.toBeDefined();
});
it('isDestroyed', function() {
primitive = new Primitive();
expect(primitive.isDestroyed()).toEqual(false);
primitive.destroy();
expect(primitive.isDestroyed()).toEqual(true);
});
it('renders when using asynchronous pipeline', function() {
primitive = new Primitive({
geometryInstances : rectangleInstance1,
appearance : new PerInstanceColorAppearance({
flat : true
})
});
var frameState = scene.frameState;
return pollToPromise(function() {
primitive.update(frameState);
for (var i = 0; i < frameState.afterRender.length; ++i) {
frameState.afterRender[i]();
}
return primitive.ready;
}).then(function() {
verifyPrimitiveRender(primitive, rectangle1);
});
});
it('destroy before asynchonous pipeline is complete', function() {
primitive = new Primitive({
geometryInstances : rectangleInstance1,
appearance : new PerInstanceColorAppearance()
});
primitive.update(frameState);
primitive.destroy();
expect(primitive.isDestroyed()).toEqual(true);
});
}, 'WebGL');