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.

2406 lines
71 KiB
JavaScript

import { BoundingSphere } from "../../Source/Cesium.js";
import { Cartesian2 } from "../../Source/Cesium.js";
import { Cartesian3 } from "../../Source/Cesium.js";
import { CesiumTerrainProvider } from "../../Source/Cesium.js";
import { Color } from "../../Source/Cesium.js";
import { defined } from "../../Source/Cesium.js";
import { Ellipsoid } from "../../Source/Cesium.js";
import { GeographicProjection } from "../../Source/Cesium.js";
import { GeometryInstance } from "../../Source/Cesium.js";
import { HeadingPitchRoll } from "../../Source/Cesium.js";
import { JulianDate } from "../../Source/Cesium.js";
import { Math as CesiumMath } from "../../Source/Cesium.js";
import { PerspectiveFrustum } from "../../Source/Cesium.js";
import { PixelFormat } from "../../Source/Cesium.js";
import { Rectangle } from "../../Source/Cesium.js";
import { RectangleGeometry } from "../../Source/Cesium.js";
import { RequestScheduler } from "../../Source/Cesium.js";
import { RuntimeError } from "../../Source/Cesium.js";
import { TaskProcessor } from "../../Source/Cesium.js";
import { WebGLConstants } from "../../Source/Cesium.js";
import { WebMercatorProjection } from "../../Source/Cesium.js";
import { DrawCommand } from "../../Source/Cesium.js";
import { Framebuffer } from "../../Source/Cesium.js";
import { Pass } from "../../Source/Cesium.js";
import { PixelDatatype } from "../../Source/Cesium.js";
import { RenderState } from "../../Source/Cesium.js";
import { ShaderProgram } from "../../Source/Cesium.js";
import { ShaderSource } from "../../Source/Cesium.js";
import { Texture } from "../../Source/Cesium.js";
import { Camera } from "../../Source/Cesium.js";
import { DirectionalLight } from "../../Source/Cesium.js";
import { EllipsoidSurfaceAppearance } from "../../Source/Cesium.js";
import { FrameState } from "../../Source/Cesium.js";
import { Globe } from "../../Source/Cesium.js";
import { Material } from "../../Source/Cesium.js";
import { Primitive } from "../../Source/Cesium.js";
import { PrimitiveCollection } from "../../Source/Cesium.js";
import { Scene } from "../../Source/Cesium.js";
import { SceneTransforms } from "../../Source/Cesium.js";
import { ScreenSpaceCameraController } from "../../Source/Cesium.js";
import { SunLight } from "../../Source/Cesium.js";
import { TweenCollection } from "../../Source/Cesium.js";
import { Sun } from "../../Source/Cesium.js";
import { GroundPrimitive } from "../../Source/Cesium.js";
import { PerInstanceColorAppearance } from "../../Source/Cesium.js";
import { ColorGeometryInstanceAttribute } from "../../Source/Cesium.js";
import createCanvas from "../createCanvas.js";
import createScene from "../createScene.js";
import pollToPromise from "../pollToPromise.js";
import render from "../render.js";
describe(
"Scene/Scene",
function () {
var scene;
var simpleShaderProgram;
var simpleRenderState;
beforeAll(function () {
scene = createScene();
simpleShaderProgram = ShaderProgram.fromCache({
context: scene.context,
vertexShaderSource: new ShaderSource({
sources: ["void main() { gl_Position = vec4(1.0); }"],
}),
fragmentShaderSource: new ShaderSource({
sources: ["void main() { gl_FragColor = vec4(1.0); }"],
}),
});
simpleRenderState = new RenderState();
return GroundPrimitive.initializeTerrainHeights();
});
afterEach(function () {
scene.backgroundColor = new Color(0.0, 0.0, 0.0, 0.0);
scene.debugCommandFilter = undefined;
scene.postProcessStages.fxaa.enabled = false;
scene.primitives.removeAll();
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);
});
afterAll(function () {
scene.destroyForSpecs();
});
function createRectangle(rectangle, height) {
return new Primitive({
geometryInstances: new GeometryInstance({
geometry: new RectangleGeometry({
rectangle: rectangle,
vertexFormat: EllipsoidSurfaceAppearance.VERTEX_FORMAT,
height: height,
}),
}),
appearance: new EllipsoidSurfaceAppearance({
aboveGround: false,
}),
asynchronous: false,
});
}
it("constructor has expected defaults", function () {
expect(scene.canvas).toBeInstanceOf(HTMLCanvasElement);
expect(scene.primitives).toBeInstanceOf(PrimitiveCollection);
expect(scene.camera).toBeInstanceOf(Camera);
expect(scene.screenSpaceCameraController).toBeInstanceOf(
ScreenSpaceCameraController
);
expect(scene.mapProjection).toBeInstanceOf(GeographicProjection);
expect(scene.frameState).toBeInstanceOf(FrameState);
expect(scene.tweens).toBeInstanceOf(TweenCollection);
var contextAttributes = scene.context._gl.getContextAttributes();
// Do not check depth and antialias since they are requests not requirements
expect(contextAttributes.alpha).toEqual(false);
expect(contextAttributes.stencil).toEqual(true);
expect(contextAttributes.premultipliedAlpha).toEqual(true);
expect(contextAttributes.preserveDrawingBuffer).toEqual(false);
});
it("constructor sets options", function () {
var webglOptions = {
alpha: true,
depth: true, //TODO Change to false when https://bugzilla.mozilla.org/show_bug.cgi?id=745912 is fixed.
stencil: true,
antialias: false,
premultipliedAlpha: true, // Workaround IE 11.0.8, which does not honor false.
preserveDrawingBuffer: true,
};
var mapProjection = new WebMercatorProjection();
var s = createScene({
contextOptions: {
webgl: webglOptions,
},
mapProjection: mapProjection,
});
var contextAttributes = s.context._gl.getContextAttributes();
expect(contextAttributes.alpha).toEqual(webglOptions.alpha);
expect(contextAttributes.depth).toEqual(webglOptions.depth);
expect(contextAttributes.stencil).toEqual(webglOptions.stencil);
expect(contextAttributes.antialias).toEqual(webglOptions.antialias);
expect(contextAttributes.premultipliedAlpha).toEqual(
webglOptions.premultipliedAlpha
);
expect(contextAttributes.preserveDrawingBuffer).toEqual(
webglOptions.preserveDrawingBuffer
);
expect(s.mapProjection).toEqual(mapProjection);
s.destroyForSpecs();
});
it("constructor throws without options", function () {
expect(function () {
return new Scene();
}).toThrowDeveloperError();
});
it("constructor throws without options.canvas", function () {
expect(function () {
return new Scene({});
}).toThrowDeveloperError();
});
it("draws background color", function () {
expect(scene).toRender([0, 0, 0, 255]);
scene.backgroundColor = Color.BLUE;
expect(scene).toRender([0, 0, 255, 255]);
});
it("calls afterRender functions", function () {
var spyListener = jasmine.createSpy("listener");
var primitive = {
update: function (frameState) {
frameState.afterRender.push(spyListener);
},
destroy: function () {},
};
scene.primitives.add(primitive);
scene.renderForSpecs();
expect(spyListener).toHaveBeenCalled();
});
function CommandMockPrimitive(command) {
this.update = function (frameState) {
frameState.commandList.push(command);
};
this.destroy = function () {};
}
it("debugCommandFilter filters commands", function () {
var c = new DrawCommand({
shaderProgram: simpleShaderProgram,
renderState: simpleRenderState,
pass: Pass.OPAQUE,
});
c.execute = function () {};
spyOn(c, "execute");
scene.primitives.add(new CommandMockPrimitive(c));
scene.debugCommandFilter = function (command) {
return command !== c; // Do not execute command
};
scene.renderForSpecs();
expect(c.execute).not.toHaveBeenCalled();
});
it("debugCommandFilter does not filter commands", function () {
var originalLogDepth = scene.logarithmicDepthBuffer;
scene.logarithmicDepthBuffer = false;
var c = new DrawCommand({
shaderProgram: simpleShaderProgram,
renderState: simpleRenderState,
pass: Pass.OPAQUE,
});
c.execute = function () {};
spyOn(c, "execute");
scene.primitives.add(new CommandMockPrimitive(c));
expect(scene.debugCommandFilter).toBeUndefined();
scene.renderForSpecs();
expect(c.execute).toHaveBeenCalled();
scene.logarithmicDepthBuffer = originalLogDepth;
});
it("debugShowBoundingVolume draws a bounding sphere", function () {
var originalLogDepth = scene.logarithmicDepthBuffer;
scene.logarithmicDepthBuffer = false;
var radius = 10.0;
var center = Cartesian3.add(
scene.camera.position,
scene.camera.direction,
new Cartesian3()
);
var c = new DrawCommand({
shaderProgram: simpleShaderProgram,
renderState: simpleRenderState,
pass: Pass.OPAQUE,
debugShowBoundingVolume: true,
boundingVolume: new BoundingSphere(center, radius),
});
c.execute = function () {};
scene.primitives.add(new CommandMockPrimitive(c));
scene.depthTestAgainstTerrain = true;
expect(scene).toRenderAndCall(function (rgba) {
expect(rgba[0]).not.toEqual(0); // Red bounding sphere
});
scene.logarithmicDepthBuffer = originalLogDepth;
});
it("debugShowCommands tints commands", function () {
var originalLogDepth = scene.logarithmicDepthBuffer;
scene.logarithmicDepthBuffer = false;
var c = new DrawCommand({
shaderProgram: simpleShaderProgram,
renderState: simpleRenderState,
pass: Pass.OPAQUE,
});
c.execute = function () {};
var originalShallowClone = DrawCommand.shallowClone;
spyOn(DrawCommand, "shallowClone").and.callFake(function (
command,
result
) {
result = originalShallowClone(command, result);
result.execute = function () {
result.uniformMap.debugShowCommandsColor();
};
return result;
});
scene.primitives.add(new CommandMockPrimitive(c));
scene.debugShowCommands = true;
scene.renderForSpecs();
expect(c._debugColor).toBeDefined();
scene.debugShowCommands = false;
scene.logarithmicDepthBuffer = originalLogDepth;
});
it("debugShowFramesPerSecond", function () {
scene.debugShowFramesPerSecond = true;
scene.renderForSpecs();
expect(scene._performanceDisplay).toBeDefined();
scene.debugShowFramesPerSecond = false;
});
it("debugShowGlobeDepth", function () {
if (!scene.context.depthTexture) {
return;
}
var rectangle = Rectangle.fromDegrees(-100.0, 30.0, -90.0, 40.0);
scene.camera.setView({ destination: rectangle });
var rectanglePrimitive = createRectangle(rectangle);
rectanglePrimitive.appearance.material.uniforms.color = new Color(
1.0,
0.0,
0.0,
1.0
);
scene.primitives.add(rectanglePrimitive);
expect(scene).toRender([255, 0, 0, 255]);
scene.debugShowGlobeDepth = true;
expect(scene).notToRender([255, 0, 0, 255]);
scene.debugShowGlobeDepth = false;
});
it("opaque/translucent render order (1)", function () {
var rectangle = Rectangle.fromDegrees(-100.0, 30.0, -90.0, 40.0);
var rectanglePrimitive1 = createRectangle(rectangle);
rectanglePrimitive1.appearance.material.uniforms.color = new Color(
1.0,
0.0,
0.0,
1.0
);
var rectanglePrimitive2 = createRectangle(rectangle, 1000.0);
rectanglePrimitive2.appearance.material.uniforms.color = new Color(
0.0,
1.0,
0.0,
0.5
);
var primitives = scene.primitives;
primitives.add(rectanglePrimitive1);
primitives.add(rectanglePrimitive2);
scene.camera.setView({ destination: rectangle });
expect(scene).toRenderAndCall(function (rgba) {
expect(rgba[0]).not.toEqual(0);
expect(rgba[1]).not.toEqual(0);
expect(rgba[2]).toEqual(0);
});
primitives.raiseToTop(rectanglePrimitive1);
expect(scene).toRenderAndCall(function (rgba) {
expect(rgba[0]).not.toEqual(0);
expect(rgba[1]).not.toEqual(0);
expect(rgba[2]).toEqual(0);
});
});
it("opaque/translucent render order (2)", function () {
var rectangle = Rectangle.fromDegrees(-100.0, 30.0, -90.0, 40.0);
var rectanglePrimitive1 = createRectangle(rectangle, 1000.0);
rectanglePrimitive1.appearance.material.uniforms.color = new Color(
1.0,
0.0,
0.0,
1.0
);
var rectanglePrimitive2 = createRectangle(rectangle);
rectanglePrimitive2.appearance.material.uniforms.color = new Color(
0.0,
1.0,
0.0,
0.5
);
var primitives = scene.primitives;
primitives.add(rectanglePrimitive1);
primitives.add(rectanglePrimitive2);
scene.camera.setView({ destination: rectangle });
expect(scene).toRenderAndCall(function (rgba) {
expect(rgba[0]).not.toEqual(0);
expect(rgba[1]).toEqual(0);
expect(rgba[2]).toEqual(0);
});
primitives.raiseToTop(rectanglePrimitive1);
expect(scene).toRenderAndCall(function (rgba) {
expect(rgba[0]).not.toEqual(0);
expect(rgba[1]).toEqual(0);
expect(rgba[2]).toEqual(0);
});
});
it("renders with OIT and without FXAA", function () {
var rectangle = Rectangle.fromDegrees(-100.0, 30.0, -90.0, 40.0);
var rectanglePrimitive = createRectangle(rectangle, 1000.0);
rectanglePrimitive.appearance.material.uniforms.color = new Color(
1.0,
0.0,
0.0,
0.5
);
var primitives = scene.primitives;
primitives.add(rectanglePrimitive);
scene.camera.setView({ destination: rectangle });
scene.postProcessStages.fxaa.enabled = false;
expect(scene).toRenderAndCall(function (rgba) {
expect(rgba[0]).not.toEqual(0);
expect(rgba[1]).toEqual(0);
expect(rgba[2]).toEqual(0);
});
});
it("renders with forced FXAA", function () {
var context = scene.context;
// Workaround for Firefox on Mac, which does not support RGBA + depth texture
// attachments, which is allowed by the spec.
if (context.depthTexture) {
var framebuffer = new Framebuffer({
context: context,
colorTextures: [
new Texture({
context: context,
width: 1,
height: 1,
pixelFormat: PixelFormat.RGBA,
pixelDatatype: PixelDatatype.UNSIGNED_BYTE,
}),
],
depthTexture: new Texture({
context: context,
width: 1,
height: 1,
pixelFormat: PixelFormat.DEPTH_COMPONENT,
pixelDatatype: PixelDatatype.UNSIGNED_SHORT,
}),
});
var status = framebuffer.status;
framebuffer.destroy();
if (status !== WebGLConstants.FRAMEBUFFER_COMPLETE) {
return;
}
}
var s = createScene();
if (defined(s._oit)) {
s._oit._translucentMRTSupport = false;
s._oit._translucentMultipassSupport = false;
}
s.postProcessStages.fxaa.enabled = false;
var rectangle = Rectangle.fromDegrees(-100.0, 30.0, -90.0, 40.0);
var rectanglePrimitive = createRectangle(rectangle, 1000.0);
rectanglePrimitive.appearance.material.uniforms.color = new Color(
1.0,
0.0,
0.0,
1.0
);
var primitives = s.primitives;
primitives.add(rectanglePrimitive);
s.camera.setView({ destination: rectangle });
expect(s).toRenderAndCall(function (rgba) {
expect(rgba[0]).not.toEqual(0);
expect(rgba[1]).toEqual(0);
expect(rgba[2]).toEqual(0);
});
s.destroyForSpecs();
});
it("setting a globe", function () {
var scene = createScene();
var ellipsoid = Ellipsoid.UNIT_SPHERE;
var globe = new Globe(ellipsoid);
scene.globe = globe;
expect(scene.globe).toBe(globe);
scene.destroyForSpecs();
});
it("destroys primitive on set globe", function () {
var scene = createScene();
var globe = new Globe(Ellipsoid.UNIT_SPHERE);
scene.globe = globe;
expect(globe.isDestroyed()).toEqual(false);
scene.globe = undefined;
expect(globe.isDestroyed()).toEqual(true);
scene.destroyForSpecs();
});
describe("render tests", function () {
var s;
beforeEach(function () {
s = createScene();
});
afterEach(function () {
s.destroyForSpecs();
});
it("renders a globe", function () {
s.globe = new Globe(Ellipsoid.UNIT_SPHERE);
s.camera.position = new Cartesian3(1.02, 0.0, 0.0);
s.camera.up = Cartesian3.clone(Cartesian3.UNIT_Z);
s.camera.direction = Cartesian3.negate(
Cartesian3.normalize(s.camera.position, new Cartesian3()),
new Cartesian3()
);
// To avoid Jasmine's spec has no expectations error
expect(true).toEqual(true);
return expect(s).toRenderAndCall(function () {
return pollToPromise(function () {
render(s.frameState, s.globe);
return !jasmine.matchersUtil.equals(s._context.readPixels(), [
0,
0,
0,
0,
]);
});
});
});
it("renders a globe with an ElevationContour", function () {
s.globe = new Globe(Ellipsoid.UNIT_SPHERE);
s.globe.material = Material.fromType("ElevationContour");
s.camera.position = new Cartesian3(1.02, 0.0, 0.0);
s.camera.up = Cartesian3.clone(Cartesian3.UNIT_Z);
s.camera.direction = Cartesian3.negate(
Cartesian3.normalize(s.camera.position, new Cartesian3()),
new Cartesian3()
);
// To avoid Jasmine's spec has no expectations error
expect(true).toEqual(true);
return expect(s).toRenderAndCall(function () {
return pollToPromise(function () {
render(s.frameState, s.globe);
return !jasmine.matchersUtil.equals(s._context.readPixels(), [
0,
0,
0,
0,
]);
});
});
});
it("renders a globe with a SlopeRamp", function () {
s.globe = new Globe(Ellipsoid.UNIT_SPHERE);
s.globe.material = Material.fromType("SlopeRamp");
s.camera.position = new Cartesian3(1.02, 0.0, 0.0);
s.camera.up = Cartesian3.clone(Cartesian3.UNIT_Z);
s.camera.direction = Cartesian3.negate(
Cartesian3.normalize(s.camera.position, new Cartesian3()),
new Cartesian3()
);
// To avoid Jasmine's spec has no expectations error
expect(true).toEqual(true);
return expect(s).toRenderAndCall(function () {
return pollToPromise(function () {
render(s.frameState, s.globe);
return !jasmine.matchersUtil.equals(s._context.readPixels(), [
0,
0,
0,
0,
]);
});
});
});
it("renders a globe with AspectRamp", function () {
s.globe = new Globe(Ellipsoid.UNIT_SPHERE);
s.globe.material = Material.fromType("AspectRamp");
s.camera.position = new Cartesian3(1.02, 0.0, 0.0);
s.camera.up = Cartesian3.clone(Cartesian3.UNIT_Z);
s.camera.direction = Cartesian3.negate(
Cartesian3.normalize(s.camera.position, new Cartesian3()),
new Cartesian3()
);
// To avoid Jasmine's spec has no expectations error
expect(true).toEqual(true);
return expect(s).toRenderAndCall(function () {
return pollToPromise(function () {
render(s.frameState, s.globe);
return !jasmine.matchersUtil.equals(s._context.readPixels(), [
0,
0,
0,
0,
]);
});
});
});
it("renders a globe with a ElevationRamp", function () {
s.globe = new Globe(Ellipsoid.UNIT_SPHERE);
s.globe.material = Material.fromType("ElevationRamp");
s.camera.position = new Cartesian3(1.02, 0.0, 0.0);
s.camera.up = Cartesian3.clone(Cartesian3.UNIT_Z);
s.camera.direction = Cartesian3.negate(
Cartesian3.normalize(s.camera.position, new Cartesian3()),
new Cartesian3()
);
// To avoid Jasmine's spec has no expectations error
expect(true).toEqual(true);
return expect(s).toRenderAndCall(function () {
return pollToPromise(function () {
render(s.frameState, s.globe);
return !jasmine.matchersUtil.equals(s._context.readPixels(), [
0,
0,
0,
0,
]);
});
});
});
it("renders a globe with an ElevationBand", function () {
s.globe = new Globe(Ellipsoid.UNIT_SPHERE);
s.globe.material = Material.fromType("ElevationBand");
s.camera.position = new Cartesian3(1.02, 0.0, 0.0);
s.camera.up = Cartesian3.clone(Cartesian3.UNIT_Z);
s.camera.direction = Cartesian3.negate(
Cartesian3.normalize(s.camera.position, new Cartesian3()),
new Cartesian3()
);
// To avoid Jasmine's spec has no expectations error
expect(true).toEqual(true);
return expect(s).toRenderAndCall(function () {
return pollToPromise(function () {
render(s.frameState, s.globe);
return !jasmine.matchersUtil.equals(s._context.readPixels(), [
0,
0,
0,
0,
]);
});
});
});
});
it("renders with multipass OIT if MRT is available", function () {
if (scene.context.drawBuffers) {
var s = createScene();
if (defined(s._oit)) {
s._oit._translucentMRTSupport = false;
s._oit._translucentMultipassSupport = true;
var rectangle = Rectangle.fromDegrees(-100.0, 30.0, -90.0, 40.0);
var rectanglePrimitive = createRectangle(rectangle, 1000.0);
rectanglePrimitive.appearance.material.uniforms.color = new Color(
1.0,
0.0,
0.0,
0.5
);
var primitives = s.primitives;
primitives.add(rectanglePrimitive);
s.camera.setView({ destination: rectangle });
expect(s).toRenderAndCall(function (rgba) {
expect(rgba[0]).not.toEqual(0);
expect(rgba[1]).toEqual(0);
expect(rgba[2]).toEqual(0);
});
}
s.destroyForSpecs();
}
});
it("renders with alpha blending if floating point textures are available", function () {
if (!scene.context.floatingPointTexture) {
return;
}
var s = createScene();
if (defined(s._oit)) {
s._oit._translucentMRTSupport = false;
s._oit._translucentMultipassSupport = false;
var rectangle = Rectangle.fromDegrees(-100.0, 30.0, -90.0, 40.0);
var rectanglePrimitive = createRectangle(rectangle, 1000.0);
rectanglePrimitive.appearance.material.uniforms.color = new Color(
1.0,
0.0,
0.0,
0.5
);
var primitives = s.primitives;
primitives.add(rectanglePrimitive);
s.camera.setView({ destination: rectangle });
expect(s).toRenderAndCall(function (rgba) {
expect(rgba[0]).not.toEqual(0);
expect(rgba[1]).toEqual(0);
expect(rgba[2]).toEqual(0);
});
}
s.destroyForSpecs();
});
it("renders map twice when in 2D", function () {
scene.morphTo2D(0.0);
var rectangle = Rectangle.fromDegrees(-180.0, -90.0, 180.0, 90.0);
var rectanglePrimitive1 = createRectangle(rectangle, 0.0);
rectanglePrimitive1.appearance.material.uniforms.color = new Color(
1.0,
0.0,
0.0,
1.0
);
var primitives = scene.primitives;
primitives.add(rectanglePrimitive1);
scene.camera.setView({
destination: new Cartesian3(
Ellipsoid.WGS84.maximumRadius * Math.PI + 10000.0,
0.0,
10.0
),
convert: false,
});
expect(scene).toRenderAndCall(function (rgba) {
expect(rgba[0]).not.toEqual(0);
expect(rgba[1]).toEqual(0);
expect(rgba[2]).toEqual(0);
});
});
it("renders map when the camera is on the IDL in 2D", function () {
var s = createScene({
canvas: createCanvas(5, 5),
});
s.morphTo2D(0.0);
var rectangle = Rectangle.fromDegrees(-180.0, -90.0, 180.0, 90.0);
var rectanglePrimitive1 = createRectangle(rectangle, 0.0);
rectanglePrimitive1.appearance.material.uniforms.color = new Color(
1.0,
0.0,
0.0,
1.0
);
var primitives = s.primitives;
primitives.add(rectanglePrimitive1);
s.camera.setView({
destination: new Cartesian3(
Ellipsoid.WGS84.maximumRadius * Math.PI,
0.0,
10.0
),
convert: false,
});
expect(s).toRenderAndCall(function (rgba) {
expect(rgba[0]).not.toEqual(0);
expect(rgba[1]).toEqual(0);
expect(rgba[2]).toEqual(0);
});
s.destroyForSpecs();
});
it("renders with HDR when available", function () {
if (!scene.highDynamicRangeSupported) {
return;
}
var s = createScene();
s.highDynamicRange = true;
var rectangle = Rectangle.fromDegrees(-100.0, 30.0, -90.0, 40.0);
var rectanglePrimitive = createRectangle(rectangle, 1000.0);
rectanglePrimitive.appearance.material.uniforms.color = new Color(
10.0,
0.0,
0.0,
1.0
);
var primitives = s.primitives;
primitives.add(rectanglePrimitive);
s.camera.setView({ destination: rectangle });
expect(s).toRenderAndCall(function (rgba) {
expect(rgba[0]).toBeGreaterThan(0);
expect(rgba[0]).toBeLessThanOrEqualTo(255);
expect(rgba[1]).toEqual(0);
expect(rgba[2]).toEqual(0);
});
s.destroyForSpecs();
});
it("copies the globe depth", function () {
var scene = createScene();
if (scene.context.depthTexture) {
var rectangle = Rectangle.fromDegrees(-100.0, 30.0, -90.0, 40.0);
var rectanglePrimitive = createRectangle(rectangle, 1000.0);
rectanglePrimitive.appearance.material.uniforms.color = new Color(
1.0,
0.0,
0.0,
0.5
);
var primitives = scene.primitives;
primitives.add(rectanglePrimitive);
scene.camera.setView({ destination: rectangle });
var uniformState = scene.context.uniformState;
expect(scene).toRenderAndCall(function (rgba) {
expect(uniformState.globeDepthTexture).toBeDefined();
});
}
scene.destroyForSpecs();
});
it("pickPosition", function () {
if (!scene.pickPositionSupported) {
return;
}
var rectangle = Rectangle.fromDegrees(-0.0001, -0.0001, 0.0001, 0.0001);
scene.camera.setView({ destination: rectangle });
var canvas = scene.canvas;
var windowPosition = new Cartesian2(
canvas.clientWidth / 2,
canvas.clientHeight / 2
);
expect(scene).toRenderAndCall(function () {
var position = scene.pickPosition(windowPosition);
expect(position).not.toBeDefined();
var rectanglePrimitive = createRectangle(rectangle);
rectanglePrimitive.appearance.material.uniforms.color = new Color(
1.0,
0.0,
0.0,
1.0
);
var primitives = scene.primitives;
primitives.add(rectanglePrimitive);
});
expect(scene).toRenderAndCall(function () {
var position = scene.pickPosition(windowPosition);
expect(position.x).toBeGreaterThan(Ellipsoid.WGS84.minimumRadius);
expect(position.y).toEqualEpsilon(0.0, CesiumMath.EPSILON5);
expect(position.z).toEqualEpsilon(0.0, CesiumMath.EPSILON5);
});
});
it("pickPosition in CV", function () {
if (!scene.pickPositionSupported) {
return;
}
scene.morphToColumbusView(0.0);
var rectangle = Rectangle.fromDegrees(-0.0001, -0.0001, 0.0001, 0.0001);
scene.camera.setView({ destination: rectangle });
var canvas = scene.canvas;
var windowPosition = new Cartesian2(
canvas.clientWidth / 2,
canvas.clientHeight / 2
);
expect(scene).toRenderAndCall(function () {
var position = scene.pickPosition(windowPosition);
expect(position).not.toBeDefined();
var rectanglePrimitive = createRectangle(rectangle);
rectanglePrimitive.appearance.material.uniforms.color = new Color(
1.0,
0.0,
0.0,
1.0
);
var primitives = scene.primitives;
primitives.add(rectanglePrimitive);
});
expect(scene).toRenderAndCall(function () {
var position = scene.pickPosition(windowPosition);
expect(position.x).toBeGreaterThan(Ellipsoid.WGS84.minimumRadius);
expect(position.y).toEqualEpsilon(0.0, CesiumMath.EPSILON5);
expect(position.z).toEqualEpsilon(0.0, CesiumMath.EPSILON5);
});
});
it("pickPosition in 2D", function () {
if (!scene.pickPositionSupported) {
return;
}
scene.morphTo2D(0.0);
var rectangle = Rectangle.fromDegrees(-0.0001, -0.0001, 0.0001, 0.0001);
scene.camera.setView({ destination: rectangle });
var canvas = scene.canvas;
var windowPosition = new Cartesian2(
canvas.clientWidth / 2,
canvas.clientHeight / 2
);
expect(scene).toRenderAndCall(function () {
var position = scene.pickPosition(windowPosition);
expect(position).not.toBeDefined();
var rectanglePrimitive = createRectangle(rectangle);
rectanglePrimitive.appearance.material.uniforms.color = new Color(
1.0,
0.0,
0.0,
1.0
);
var primitives = scene.primitives;
primitives.add(rectanglePrimitive);
});
expect(scene).toRenderAndCall(function () {
var position = scene.pickPosition(windowPosition);
expect(position.x).toBeGreaterThan(Ellipsoid.WGS84.minimumRadius);
expect(position.y).toEqualEpsilon(0.0, CesiumMath.EPSILON5);
expect(position.z).toEqualEpsilon(0.0, CesiumMath.EPSILON5);
});
});
it("pickPosition returns undefined when useDepthPicking is false", function () {
if (!scene.pickPositionSupported) {
return;
}
var rectangle = Rectangle.fromDegrees(-100.0, 30.0, -90.0, 40.0);
scene.camera.setView({
destination: rectangle,
});
var canvas = scene.canvas;
var windowPosition = new Cartesian2(
canvas.clientWidth / 2,
canvas.clientHeight / 2
);
var rectanglePrimitive = createRectangle(rectangle);
rectanglePrimitive.appearance.material.uniforms.color = new Color(
1.0,
0.0,
0.0,
1.0
);
var primitives = scene.primitives;
primitives.add(rectanglePrimitive);
scene.useDepthPicking = false;
expect(scene).toRenderAndCall(function () {
var position = scene.pickPosition(windowPosition);
expect(position).not.toBeDefined();
});
scene.useDepthPicking = true;
expect(scene).toRenderAndCall(function () {
var position = scene.pickPosition(windowPosition);
expect(position).toBeDefined();
});
});
it("pickPosition picks translucent geometry when pickTranslucentDepth is true", function () {
if (!scene.pickPositionSupported) {
return;
}
var rectangle = Rectangle.fromDegrees(-100.0, 30.0, -90.0, 40.0);
scene.camera.setView({
destination: rectangle,
});
var canvas = scene.canvas;
var windowPosition = new Cartesian2(
canvas.clientWidth / 2,
canvas.clientHeight / 2
);
var rectanglePrimitive = scene.primitives.add(createRectangle(rectangle));
rectanglePrimitive.appearance.material.uniforms.color = new Color(
1.0,
0.0,
0.0,
0.5
);
scene.useDepthPicking = true;
scene.pickTranslucentDepth = false;
expect(scene).toRenderAndCall(function () {
var position = scene.pickPosition(windowPosition);
expect(position).not.toBeDefined();
});
scene.pickTranslucentDepth = true;
expect(scene).toRenderAndCall(function () {
var position = scene.pickPosition(windowPosition);
expect(position).toBeDefined();
});
});
it("pickPosition caches results per frame", function () {
if (!scene.pickPositionSupported) {
return;
}
var rectangle = Rectangle.fromDegrees(-100.0, 30.0, -90.0, 40.0);
scene.camera.setView({ destination: rectangle });
var canvas = scene.canvas;
var windowPosition = new Cartesian2(
canvas.clientWidth / 2,
canvas.clientHeight / 2
);
spyOn(
SceneTransforms,
"transformWindowToDrawingBuffer"
).and.callThrough();
expect(scene).toRenderAndCall(function () {
scene.pickPosition(windowPosition);
expect(
SceneTransforms.transformWindowToDrawingBuffer
).toHaveBeenCalled();
scene.pickPosition(windowPosition);
expect(
SceneTransforms.transformWindowToDrawingBuffer.calls.count()
).toEqual(1);
var rectanglePrimitive = createRectangle(rectangle);
rectanglePrimitive.appearance.material.uniforms.color = new Color(
1.0,
0.0,
0.0,
1.0
);
var primitives = scene.primitives;
primitives.add(rectanglePrimitive);
});
expect(scene).toRenderAndCall(function () {
scene.pickPosition(windowPosition);
expect(
SceneTransforms.transformWindowToDrawingBuffer.calls.count()
).toEqual(2);
scene.pickPosition(windowPosition);
expect(
SceneTransforms.transformWindowToDrawingBuffer.calls.count()
).toEqual(2);
});
});
it("pickPosition throws without windowPosition", function () {
expect(function () {
scene.pickPosition();
}).toThrowDeveloperError();
});
it("isDestroyed", function () {
var s = createScene();
expect(s.isDestroyed()).toEqual(false);
s.destroyForSpecs();
expect(s.isDestroyed()).toEqual(true);
});
it("raises renderError when render throws", function () {
var s = createScene({
rethrowRenderErrors: false,
});
var spyListener = jasmine.createSpy("listener");
s.renderError.addEventListener(spyListener);
var error = "foo";
s.primitives.update = function () {
throw error;
};
s.render();
expect(spyListener).toHaveBeenCalledWith(s, error);
s.destroyForSpecs();
});
it("a render error is rethrown if rethrowRenderErrors is true", function () {
var s = createScene();
s.rethrowRenderErrors = true;
var spyListener = jasmine.createSpy("listener");
s.renderError.addEventListener(spyListener);
var error = new RuntimeError("error");
s.primitives.update = function () {
throw error;
};
expect(function () {
s.render();
}).toThrowRuntimeError();
expect(spyListener).toHaveBeenCalledWith(s, error);
s.destroyForSpecs();
});
it("alwayas raises preUpdate event prior to updating", function () {
var s = createScene();
var spyListener = jasmine.createSpy("listener");
s.preUpdate.addEventListener(spyListener);
s.render();
expect(spyListener.calls.count()).toBe(1);
s.requestRenderMode = true;
s.maximumRenderTimeChange = undefined;
s.render();
expect(spyListener.calls.count()).toBe(2);
s.destroyForSpecs();
});
it("always raises preUpdate event after updating", function () {
var s = createScene();
var spyListener = jasmine.createSpy("listener");
s.preUpdate.addEventListener(spyListener);
s.render();
expect(spyListener.calls.count()).toBe(1);
s.requestRenderMode = true;
s.maximumRenderTimeChange = undefined;
s.render();
expect(spyListener.calls.count()).toBe(2);
s.destroyForSpecs();
});
it("raises the preRender event prior to rendering only if the scene renders", function () {
var s = createScene();
var spyListener = jasmine.createSpy("listener");
s.preRender.addEventListener(spyListener);
s.render();
expect(spyListener.calls.count()).toBe(1);
s.requestRenderMode = true;
s.maximumRenderTimeChange = undefined;
s.render();
expect(spyListener.calls.count()).toBe(1);
s.destroyForSpecs();
});
it("raises the postRender event after rendering if the scene rendered", function () {
var s = createScene();
var spyListener = jasmine.createSpy("listener");
s.postRender.addEventListener(spyListener);
s.render();
expect(spyListener.calls.count()).toBe(1);
s.requestRenderMode = true;
s.maximumRenderTimeChange = undefined;
s.render();
expect(spyListener.calls.count()).toBe(1);
s.destroyForSpecs();
});
it("raises the cameraMoveStart event after moving the camera", function () {
var s = createScene();
s.render();
var spyListener = jasmine.createSpy("listener");
s.camera.moveStart.addEventListener(spyListener);
s._cameraStartFired = false; // reset this value after camera changes for initial render trigger the event
s.camera.moveLeft();
s.render();
expect(spyListener.calls.count()).toBe(1);
s.destroyForSpecs();
});
it("raises the cameraMoveEvent event when the camera stops moving", function () {
var s = createScene();
s.render();
var spyListener = jasmine.createSpy("listener");
s.camera.moveEnd.addEventListener(spyListener);
// We use negative time here to ensure the event runs on the next frame.
s.cameraEventWaitTime = -1.0;
s.camera.moveLeft();
// The first render will trigger the moveStart event.
s.render();
// The second will trigger the moveEnd.
s.render();
expect(spyListener.calls.count()).toBe(1);
s.destroyForSpecs();
});
it("raises the camera changed event on direction changed", function () {
var s = createScene();
var spyListener = jasmine.createSpy("listener");
s.camera.changed.addEventListener(spyListener);
s.initializeFrame();
s.render();
s.camera.lookLeft(
s.camera.frustum.fov * (s.camera.percentageChanged + 0.1)
);
s.initializeFrame();
s.render();
expect(spyListener.calls.count()).toBe(1);
var args = spyListener.calls.allArgs();
expect(args.length).toEqual(1);
expect(args[0].length).toEqual(1);
expect(args[0][0]).toBeGreaterThan(s.camera.percentageChanged);
s.destroyForSpecs();
});
it("raises the camera changed event on position changed", function () {
var s = createScene();
var spyListener = jasmine.createSpy("listener");
s.camera.changed.addEventListener(spyListener);
s.initializeFrame();
s.render();
s.camera.moveLeft(
s.camera.positionCartographic.height *
(s.camera.percentageChanged + 0.1)
);
s.initializeFrame();
s.render();
expect(spyListener.calls.count()).toBe(1);
var args = spyListener.calls.allArgs();
expect(args.length).toEqual(1);
expect(args[0].length).toEqual(1);
expect(args[0][0]).toBeGreaterThan(s.camera.percentageChanged);
s.destroyForSpecs();
});
it("raises the camera changed event in 2D", function () {
var s = createScene();
s.morphTo2D(0);
var spyListener = jasmine.createSpy("listener");
s.camera.changed.addEventListener(spyListener);
s.initializeFrame();
s.render();
s.camera.moveLeft(
s.camera.positionCartographic.height *
(s.camera.percentageChanged + 0.1)
);
s.initializeFrame();
s.render();
expect(spyListener.calls.count()).toBe(1);
var args = spyListener.calls.allArgs();
expect(args.length).toEqual(1);
expect(args[0].length).toEqual(1);
expect(args[0][0]).toBeGreaterThan(s.camera.percentageChanged);
s.destroyForSpecs();
});
it("get maximumAliasedLineWidth", function () {
var s = createScene();
expect(s.maximumAliasedLineWidth).toBeGreaterThanOrEqualTo(1);
s.destroyForSpecs();
});
it("get maximumCubeMapSize", function () {
var s = createScene();
expect(s.maximumCubeMapSize).toBeGreaterThanOrEqualTo(16);
s.destroyForSpecs();
});
it("does not throw with debugShowCommands", function () {
var s = createScene();
if (s.context.drawBuffers) {
s.debugShowCommands = true;
var rectangle = Rectangle.fromDegrees(-100.0, 30.0, -90.0, 40.0);
var rectanglePrimitive = createRectangle(rectangle, 1000.0);
rectanglePrimitive.appearance.material.uniforms.color = new Color(
1.0,
0.0,
0.0,
0.5
);
var primitives = s.primitives;
primitives.add(rectanglePrimitive);
s.camera.setView({ destination: rectangle });
expect(function () {
s.renderForSpecs();
}).not.toThrowRuntimeError();
}
s.destroyForSpecs();
});
it("does not throw with debugShowFrustums", function () {
var s = createScene();
if (s.context.drawBuffers) {
s.debugShowFrustums = true;
var rectangle = Rectangle.fromDegrees(-100.0, 30.0, -90.0, 40.0);
var rectanglePrimitive = createRectangle(rectangle, 1000.0);
rectanglePrimitive.appearance.material.uniforms.color = new Color(
1.0,
0.0,
0.0,
0.5
);
var primitives = s.primitives;
primitives.add(rectanglePrimitive);
s.camera.setView({ destination: rectangle });
expect(function () {
s.renderForSpecs();
}).not.toThrowRuntimeError();
}
s.destroyForSpecs();
});
it("throws when minimumDisableDepthTestDistance is set less than 0.0", function () {
expect(function () {
scene.minimumDisableDepthTestDistance = -1.0;
}).toThrowDeveloperError();
});
it("converts to canvas coordinates", function () {
var mockPosition = new Cartesian3();
spyOn(SceneTransforms, "wgs84ToWindowCoordinates");
scene.cartesianToCanvasCoordinates(mockPosition);
expect(SceneTransforms.wgs84ToWindowCoordinates).toHaveBeenCalledWith(
scene,
mockPosition,
undefined
);
});
it("converts to canvas coordinates and return it in a variable", function () {
var result = new Cartesian2();
var mockPosition = new Cartesian3();
spyOn(SceneTransforms, "wgs84ToWindowCoordinates");
scene.cartesianToCanvasCoordinates(mockPosition, result);
expect(SceneTransforms.wgs84ToWindowCoordinates).toHaveBeenCalledWith(
scene,
mockPosition,
result
);
});
it("Gets imageryLayers", function () {
var scene = createScene();
var globe = (scene.globe = new Globe(Ellipsoid.UNIT_SPHERE));
expect(scene.imageryLayers).toBe(globe.imageryLayers);
scene.globe = undefined;
expect(scene.imageryLayers).toBeUndefined();
scene.destroyForSpecs();
});
it("Gets terrainProvider", function () {
var scene = createScene();
var globe = (scene.globe = new Globe(Ellipsoid.UNIT_SPHERE));
expect(scene.terrainProvider).toBe(globe.terrainProvider);
scene.globe = undefined;
expect(scene.terrainProvider).toBeUndefined();
scene.destroyForSpecs();
});
it("Sets terrainProvider", function () {
var scene = createScene();
var globe = (scene.globe = new Globe(Ellipsoid.UNIT_SPHERE));
scene.terrainProvider = new CesiumTerrainProvider({
url: "//terrain/tiles",
});
expect(scene.terrainProvider).toBe(globe.terrainProvider);
scene.globe = undefined;
expect(function () {
scene.terrainProvider = new CesiumTerrainProvider({
url: "//newTerrain/tiles",
});
}).not.toThrow();
scene.destroyForSpecs();
});
it("Gets terrainProviderChanged", function () {
var scene = createScene();
var globe = (scene.globe = new Globe(Ellipsoid.UNIT_SPHERE));
expect(scene.terrainProviderChanged).toBe(globe.terrainProviderChanged);
scene.globe = undefined;
expect(scene.terrainProviderChanged).toBeUndefined();
scene.destroyForSpecs();
});
it("Sets material", function () {
var scene = createScene();
var globe = (scene.globe = new Globe(Ellipsoid.UNIT_SPHERE));
var material = Material.fromType("ElevationContour");
globe.material = material;
expect(globe.material).toBe(material);
globe.material = undefined;
expect(globe.material).toBeUndefined();
scene.destroyForSpecs();
});
var scratchTime = new JulianDate();
it("doesn't render scene if requestRenderMode is enabled", function () {
var scene = createScene();
scene.renderForSpecs();
var lastFrameNumber = scene.frameState.frameNumber;
scene.requestRenderMode = true;
scene.maximumRenderTimeChange = undefined;
scene.renderForSpecs();
expect(scene.frameState.frameNumber).toEqual(lastFrameNumber);
scene.destroyForSpecs();
});
it("requestRender causes a new frame to be rendered in requestRenderMode", function () {
var scene = createScene();
scene.renderForSpecs();
var lastFrameNumber = scene.frameState.frameNumber;
expect(scene._renderRequested).toBe(false);
scene.requestRenderMode = true;
scene.maximumRenderTimeChange = undefined;
scene.requestRender();
expect(scene._renderRequested).toBe(true);
scene.renderForSpecs();
expect(scene.frameState.frameNumber).not.toEqual(lastFrameNumber);
scene.destroyForSpecs();
});
it("moving the camera causes a new frame to be rendered in requestRenderMode", function () {
var scene = createScene();
scene.renderForSpecs();
var lastFrameNumber = scene.frameState.frameNumber;
expect(scene._renderRequested).toBe(false);
scene.requestRenderMode = true;
scene.maximumRenderTimeChange = undefined;
scene.camera.moveLeft();
scene.renderForSpecs();
expect(scene.frameState.frameNumber).not.toEqual(lastFrameNumber);
scene.destroyForSpecs();
});
it("changing the camera frustum does not cause continuous rendering in requestRenderMode", function () {
var scene = createScene();
scene.renderForSpecs();
var lastFrameNumber = scene.frameState.frameNumber;
expect(scene._renderRequested).toBe(false);
scene.requestRenderMode = true;
scene.maximumRenderTimeChange = undefined;
scene.camera.frustum.near *= 1.1;
// Render once properly
scene.renderForSpecs();
expect(scene.frameState.frameNumber).not.toEqual(lastFrameNumber);
// Render again - but this time nothing should happen.
lastFrameNumber = scene.frameState.frameNumber;
scene.renderForSpecs();
expect(scene.frameState.frameNumber).toEqual(lastFrameNumber);
scene.destroyForSpecs();
});
it("successful completed requests causes a new frame to be rendered in requestRenderMode", function () {
var scene = createScene();
scene.renderForSpecs();
var lastFrameNumber = scene.frameState.frameNumber;
expect(scene._renderRequested).toBe(false);
scene.requestRenderMode = true;
scene.maximumRenderTimeChange = undefined;
RequestScheduler.requestCompletedEvent.raiseEvent();
scene.renderForSpecs();
expect(scene._renderRequested).toBe(true);
scene.renderForSpecs();
expect(scene.frameState.frameNumber).not.toEqual(lastFrameNumber);
scene.destroyForSpecs();
});
it("data returning from a web worker causes a new frame to be rendered in requestRenderMode", function () {
var scene = createScene();
scene.renderForSpecs();
var lastFrameNumber = scene.frameState.frameNumber;
expect(scene._renderRequested).toBe(false);
scene.requestRenderMode = true;
scene.maximumRenderTimeChange = undefined;
TaskProcessor.taskCompletedEvent.raiseEvent();
scene.renderForSpecs();
expect(scene._renderRequested).toBe(true);
scene.renderForSpecs();
expect(scene.frameState.frameNumber).not.toEqual(lastFrameNumber);
scene.destroyForSpecs();
});
it("Executing an after render function causes a new frame to be rendered in requestRenderMode", function () {
var scene = createScene();
scene.renderForSpecs();
var lastFrameNumber = scene.frameState.frameNumber;
expect(scene._renderRequested).toBe(false);
scene.requestRenderMode = true;
scene.maximumRenderTimeChange = undefined;
var functionCalled = false;
scene._frameState.afterRender.push(function () {
functionCalled = true;
});
scene.renderForSpecs();
expect(functionCalled).toBe(true);
expect(scene._renderRequested).toBe(true);
scene.renderForSpecs();
expect(scene.frameState.frameNumber).not.toEqual(lastFrameNumber);
scene.destroyForSpecs();
});
it("Globe tile loading triggers a new frame to be rendered in requestRenderMode", function () {
var scene = createScene();
scene.renderForSpecs();
var lastFrameNumber = scene.frameState.frameNumber;
expect(scene._renderRequested).toBe(false);
scene.requestRenderMode = true;
scene.maximumRenderTimeChange = undefined;
var ellipsoid = Ellipsoid.UNIT_SPHERE;
var globe = new Globe(ellipsoid);
scene.globe = globe;
scene.requestRender();
Object.defineProperty(globe, "tilesLoaded", { value: false });
scene.renderForSpecs();
lastFrameNumber = scene.frameState.frameNumber;
expect(scene._renderRequested).toBe(true);
scene.renderForSpecs();
expect(scene.frameState.frameNumber).not.toEqual(lastFrameNumber);
scene.destroyForSpecs();
});
it("Globe imagery updates triggers a new frame to be rendered in requestRenderMode", function () {
var scene = createScene();
scene.renderForSpecs();
var lastFrameNumber = scene.frameState.frameNumber;
expect(scene._renderRequested).toBe(false);
scene.requestRenderMode = true;
scene.maximumRenderTimeChange = undefined;
var ellipsoid = Ellipsoid.UNIT_SPHERE;
var globe = new Globe(ellipsoid);
scene.globe = globe;
globe.imageryLayersUpdatedEvent.raiseEvent();
scene.renderForSpecs();
expect(scene._renderRequested).toBe(true);
scene.renderForSpecs();
expect(scene.frameState.frameNumber).not.toEqual(lastFrameNumber);
scene.destroyForSpecs();
});
it("Globe changing terrain providers triggers a new frame to be rendered in requestRenderMode", function () {
var scene = createScene();
scene.renderForSpecs();
var lastFrameNumber = scene.frameState.frameNumber;
expect(scene._renderRequested).toBe(false);
scene.requestRenderMode = true;
scene.maximumRenderTimeChange = undefined;
var ellipsoid = Ellipsoid.UNIT_SPHERE;
var globe = new Globe(ellipsoid);
scene.globe = globe;
globe.terrainProviderChanged.raiseEvent();
scene.renderForSpecs();
expect(scene._renderRequested).toBe(true);
scene.renderForSpecs();
expect(scene.frameState.frameNumber).not.toEqual(lastFrameNumber);
scene.destroyForSpecs();
});
it("scene morphing causes a new frame to be rendered in requestRenderMode", function () {
var scene = createScene();
scene.renderForSpecs();
var lastFrameNumber = scene.frameState.frameNumber;
var lastRenderTime = JulianDate.clone(scene.lastRenderTime, scratchTime);
expect(lastRenderTime).toBeDefined();
expect(scene._renderRequested).toBe(false);
scene.requestRenderMode = true;
scene.maximumRenderTimeChange = undefined;
scene.morphTo2D(1.0);
scene.renderForSpecs(
JulianDate.addSeconds(lastRenderTime, 0.5, new JulianDate())
);
expect(scene.frameState.frameNumber).not.toEqual(lastFrameNumber);
scene.completeMorph();
scene.renderForSpecs();
lastFrameNumber = scene.frameState.frameNumber;
scene.renderForSpecs();
expect(scene.frameState.frameNumber).toEqual(lastFrameNumber);
lastFrameNumber = scene.frameState.frameNumber;
lastRenderTime = JulianDate.clone(scene.lastRenderTime, scratchTime);
scene.morphToColumbusView(1.0);
scene.renderForSpecs(
JulianDate.addSeconds(lastRenderTime, 0.5, new JulianDate())
);
expect(scene.frameState.frameNumber).not.toEqual(lastFrameNumber);
scene.completeMorph();
scene.renderForSpecs();
lastFrameNumber = scene.frameState.frameNumber;
scene.renderForSpecs();
expect(scene.frameState.frameNumber).toEqual(lastFrameNumber);
lastFrameNumber = scene.frameState.frameNumber;
lastRenderTime = JulianDate.clone(scene.lastRenderTime, scratchTime);
scene.morphTo3D(1.0);
scene.renderForSpecs(
JulianDate.addSeconds(lastRenderTime, 0.5, new JulianDate())
);
expect(scene.frameState.frameNumber).not.toEqual(lastFrameNumber);
scene.completeMorph();
scene.renderForSpecs();
lastFrameNumber = scene.frameState.frameNumber;
scene.renderForSpecs();
expect(scene.frameState.frameNumber).toEqual(lastFrameNumber);
scene.destroyForSpecs();
});
it("time change exceeding maximumRenderTimeChange causes a new frame to be rendered in requestRenderMode", function () {
var scene = createScene();
scene.renderForSpecs();
var lastFrameNumber = scene.frameState.frameNumber;
var lastRenderTime = JulianDate.clone(scene.lastRenderTime, scratchTime);
expect(lastRenderTime).toBeDefined();
expect(scene._renderRequested).toBe(false);
scene.requestRenderMode = true;
scene.renderForSpecs(lastRenderTime);
expect(scene.frameState.frameNumber).toEqual(lastFrameNumber);
scene.maximumRenderTimeChange = 100.0;
scene.renderForSpecs(
JulianDate.addSeconds(lastRenderTime, 50.0, new JulianDate())
);
expect(scene.frameState.frameNumber).toEqual(lastFrameNumber);
scene.renderForSpecs(
JulianDate.addSeconds(lastRenderTime, 150.0, new JulianDate())
);
expect(scene.frameState.frameNumber).not.toEqual(lastFrameNumber);
scene.destroyForSpecs();
});
it("undefined maximumRenderTimeChange will not cause a new frame to be rendered in requestRenderMode", function () {
var scene = createScene();
scene.renderForSpecs();
var lastFrameNumber = scene.frameState.frameNumber;
var lastRenderTime = JulianDate.clone(scene.lastRenderTime, scratchTime);
expect(lastRenderTime).toBeDefined();
expect(scene._renderRequested).toBe(false);
scene.requestRenderMode = true;
scene.maximumRenderTimeChange = undefined;
var farFuture = JulianDate.addDays(
lastRenderTime,
10000,
new JulianDate()
);
scene.renderForSpecs();
scene.renderForSpecs(farFuture);
expect(scene.frameState.frameNumber).toEqual(lastFrameNumber);
scene.destroyForSpecs();
});
it("forceRender renders a scene regardless of whether a render was requested", function () {
var scene = createScene();
scene.renderForSpecs();
var lastFrameNumber = scene.frameState.frameNumber;
expect(scene._renderRequested).toBe(false);
scene.requestRenderMode = true;
scene.maximumRenderTimeChange = undefined;
scene.forceRender();
expect(scene.frameState.frameNumber).not.toEqual(lastFrameNumber);
scene.destroyForSpecs();
});
function getFrustumCommandsLength(scene, pass) {
var commandsLength = 0;
var frustumCommandsList = scene.frustumCommandsList;
var frustumsLength = frustumCommandsList.length;
for (var i = 0; i < frustumsLength; ++i) {
var frustumCommands = frustumCommandsList[i];
for (var j = 0; j < Pass.NUMBER_OF_PASSES; ++j) {
if (!defined(pass) || j === pass) {
commandsLength += frustumCommands.indices[j];
}
}
}
return commandsLength;
}
it("occludes primitive", function () {
var scene = createScene();
scene.globe = new Globe(Ellipsoid.WGS84);
var rectangle = Rectangle.fromDegrees(-100.0, 30.0, -90.0, 40.0);
var rectanglePrimitive = createRectangle(rectangle, 10);
scene.primitives.add(rectanglePrimitive);
scene.camera.setView({
destination: new Cartesian3(
-588536.1057451078,
-10512475.371849751,
6737159.100747835
),
orientation: new HeadingPitchRoll(
6.283185307179586,
-1.5688261558859757,
0.0
),
});
scene.renderForSpecs();
expect(getFrustumCommandsLength(scene)).toBe(1);
scene.camera.setView({
destination: new Cartesian3(
-5754647.167415793,
14907694.100240812,
-483807.2406259497
),
orientation: new HeadingPitchRoll(
6.283185307179586,
-1.5698869547885104,
0.0
),
});
scene.renderForSpecs();
expect(getFrustumCommandsLength(scene)).toBe(0);
// Still on opposite side of globe but now show is false, the command should not be occluded anymore
scene.globe.show = false;
scene.renderForSpecs();
expect(getFrustumCommandsLength(scene)).toBe(1);
scene.destroyForSpecs();
});
it("does not occlude if DrawCommand.occlude is false", function () {
var scene = createScene();
scene.globe = new Globe(Ellipsoid.WGS84);
var rectangle = Rectangle.fromDegrees(-100.0, 30.0, -90.0, 40.0);
var rectanglePrimitive = createRectangle(rectangle, 10);
scene.primitives.add(rectanglePrimitive);
scene.renderForSpecs();
rectanglePrimitive._colorCommands[0].occlude = false;
scene.camera.setView({
destination: new Cartesian3(
-5754647.167415793,
14907694.100240812,
-483807.2406259497
),
orientation: new HeadingPitchRoll(
6.283185307179586,
-1.5698869547885104,
0.0
),
});
scene.renderForSpecs();
expect(getFrustumCommandsLength(scene)).toBe(1);
scene.destroyForSpecs();
});
it("sets light", function () {
var scene = createScene();
var uniformState = scene.context.uniformState;
var lightDirectionWC = uniformState._lightDirectionWC;
var sunDirectionWC = uniformState._sunDirectionWC;
var lightColor = uniformState._lightColor;
var lightColorHdr = uniformState._lightColorHdr;
// Default light is a sun light
scene.renderForSpecs();
expect(lightDirectionWC).toEqual(sunDirectionWC);
expect(lightColor).toEqual(new Cartesian3(1.0, 1.0, 1.0));
expect(lightColorHdr).toEqual(new Cartesian3(2.0, 2.0, 2.0));
// Test directional light
scene.light = new DirectionalLight({
direction: new Cartesian3(1.0, 0.0, 0.0),
color: Color.RED,
intensity: 2.0,
});
scene.renderForSpecs();
expect(lightDirectionWC).toEqual(new Cartesian3(-1.0, 0.0, 0.0)); // Negated because the uniform is the direction to the light, not from the light
expect(lightColor).toEqual(new Cartesian3(1.0, 0.0, 0.0));
expect(lightColorHdr).toEqual(new Cartesian3(2.0, 0.0, 0.0));
// Test sun light
scene.light = new SunLight({
color: Color.BLUE,
intensity: 0.5,
});
scene.renderForSpecs();
expect(lightDirectionWC).toEqual(sunDirectionWC);
expect(lightColor).toEqual(new Cartesian3(0.0, 0.0, 0.5));
expect(lightColorHdr).toEqual(new Cartesian3(0.0, 0.0, 0.5));
// Test light set to undefined
scene.light = undefined;
scene.renderForSpecs();
expect(lightDirectionWC).toEqual(sunDirectionWC);
expect(lightColor).toEqual(new Cartesian3(1.0, 1.0, 1.0));
expect(lightColorHdr).toEqual(new Cartesian3(2.0, 2.0, 2.0));
scene.destroyForSpecs();
});
function updateGlobeUntilDone(scene) {
return pollToPromise(function () {
scene.renderForSpecs();
return scene.globe.tilesLoaded;
});
}
it("detects when camera is underground", function () {
var scene = createScene();
var globe = new Globe();
scene.globe = globe;
scene.camera.setView({
destination: new Rectangle(0.0001, 0.0001, 0.003, 0.003),
});
return updateGlobeUntilDone(scene)
.then(function () {
expect(scene.cameraUnderground).toBe(false);
// Look underground
scene.camera.setView({
destination: new Cartesian3(
-746658.0557573901,
-5644191.0002196245,
2863585.099969967
),
orientation: new HeadingPitchRoll(
0.3019699121236403,
0.07316306869231592,
0.0007089903642230055
),
});
return updateGlobeUntilDone(scene);
})
.then(function () {
expect(scene.cameraUnderground).toBe(true);
scene.destroyForSpecs();
});
});
it("detects that camera is above ground if globe is undefined", function () {
var scene = createScene();
scene.renderForSpecs();
expect(scene.cameraUnderground).toBe(false);
scene.destroyForSpecs();
});
it("detects that camera is above ground if scene mode is 2D", function () {
var scene = createScene();
var globe = new Globe();
scene.globe = globe;
scene.morphTo2D(0.0);
expect(scene.cameraUnderground).toBe(false);
scene.destroyForSpecs();
});
it("detects that camera is above ground if scene mode is morphing", function () {
var scene = createScene();
var globe = new Globe();
scene.globe = globe;
scene.morphTo2D(1.0);
expect(scene.cameraUnderground).toBe(false);
scene.destroyForSpecs();
});
it("detects that camera is underground in Columbus View", function () {
var scene = createScene();
var globe = new Globe();
scene.globe = globe;
// Look underground
scene.camera.setView({
destination: new Cartesian3(
-4643042.379120885,
4314056.579506199,
-451828.8968118975
),
orientation: new HeadingPitchRoll(
6.283185307179586,
-0.7855491933100796,
6.283185307179586
),
});
scene.morphToColumbusView(0.0);
return updateGlobeUntilDone(scene).then(function () {
expect(scene.cameraUnderground).toBe(true);
scene.destroyForSpecs();
});
});
it("does not occlude primitives when camera is underground", function () {
var scene = createScene();
var globe = new Globe();
scene.globe = globe;
// A primitive at height -25000.0 is less than the minor axis for WGS84 and will get culled unless the camera is underground
var center = Cartesian3.fromRadians(
2.3929070618374535,
-0.07149851443375346,
-25000.0,
globe.ellipsoid
);
var radius = 10.0;
var command = new DrawCommand({
shaderProgram: simpleShaderProgram,
renderState: simpleRenderState,
pass: Pass.OPAQUE,
boundingVolume: new BoundingSphere(center, radius),
});
scene.primitives.add(new CommandMockPrimitive(command));
spyOn(DrawCommand.prototype, "execute"); // Don't execute any commands, just watch what gets added to the frustum commands list
return updateGlobeUntilDone(scene)
.then(function () {
expect(getFrustumCommandsLength(scene, Pass.OPAQUE)).toBe(0);
// Look underground at the primitive
scene.camera.setView({
destination: new Cartesian3(
-4643042.379120885,
4314056.579506199,
-451828.8968118975
),
orientation: new HeadingPitchRoll(
6.283185307179586,
-0.7855491933100796,
6.283185307179586
),
});
return updateGlobeUntilDone(scene);
})
.then(function () {
expect(getFrustumCommandsLength(scene, Pass.OPAQUE)).toBe(1);
scene.destroyForSpecs();
});
});
it("does not occlude primitives when the globe is translucent", function () {
var scene = createScene();
var globe = new Globe();
scene.globe = globe;
// A primitive at height -25000.0 is less than the minor axis for WGS84 and will get culled unless the globe is translucent
var center = Cartesian3.fromRadians(
2.3929070618374535,
-0.07149851443375346,
-25000.0,
globe.ellipsoid
);
var radius = 10.0;
var command = new DrawCommand({
shaderProgram: simpleShaderProgram,
renderState: simpleRenderState,
pass: Pass.OPAQUE,
boundingVolume: new BoundingSphere(center, radius),
});
scene.primitives.add(new CommandMockPrimitive(command));
spyOn(DrawCommand.prototype, "execute"); // Don't execute any commands, just watch what gets added to the frustum commands list
scene.renderForSpecs();
expect(getFrustumCommandsLength(scene, Pass.OPAQUE)).toBe(0);
scene.globe.translucency.enabled = true;
scene.globe.translucency.frontFaceAlpha = 0.5;
scene.renderForSpecs();
expect(getFrustumCommandsLength(scene, Pass.OPAQUE)).toBe(1);
scene.destroyForSpecs();
});
it("does not render environment when camera is underground and translucency is disabled", function () {
var scene = createScene();
var globe = new Globe();
scene.globe = globe;
scene.sun = new Sun();
// Look underground at the sun
scene.camera.setView({
destination: new Cartesian3(
2838477.9315700866,
-4939120.816857662,
1978094.4576285738
),
orientation: new HeadingPitchRoll(
5.955798516387474,
-1.0556025616093283,
0.39098563693868016
),
});
return updateGlobeUntilDone(scene).then(function () {
var time = JulianDate.fromIso8601(
"2020-04-25T03:07:26.04924034334544558Z"
);
globe.translucency.enabled = true;
globe.translucency.frontFaceAlpha = 0.5;
scene.renderForSpecs(time);
expect(scene.environmentState.isSunVisible).toBe(true);
globe.translucency.enabled = false;
scene.renderForSpecs(time);
expect(scene.environmentState.isSunVisible).toBe(false);
scene.destroyForSpecs(time);
});
});
it("renders globe with translucency", function () {
var scene = createScene();
var globe = new Globe();
scene.globe = globe;
scene.camera.setView({
destination: new Cartesian3(
2764681.3022502237,
-20999839.371941473,
14894754.464869803
),
orientation: new HeadingPitchRoll(
6.283185307179586,
-1.5687983447998315,
0
),
});
return updateGlobeUntilDone(scene).then(function () {
var opaqueColor;
expect(scene).toRenderAndCall(function (rgba) {
opaqueColor = rgba;
});
globe.translucency.enabled = true;
globe.translucency.frontFaceAlpha = 0.5;
expect(scene).toRenderAndCall(function (rgba) {
expect(rgba).not.toEqual(opaqueColor);
scene.destroyForSpecs();
});
});
});
it("renders ground primitive on translucent globe", function () {
var scene = createScene();
var globe = new Globe();
scene.globe = globe;
globe.baseColor = Color.BLACK;
globe.translucency.enabled = true;
globe.translucency.frontFaceAlpha = 0.5;
scene.camera.setView({
destination: new Cartesian3(
-557278.4840232887,
-6744284.200717078,
2794079.461722868
),
orientation: new HeadingPitchRoll(
6.283185307179586,
-1.5687983448015541,
0
),
});
var redRectangleInstance = new GeometryInstance({
geometry: new RectangleGeometry({
rectangle: Rectangle.fromDegrees(-110.0, 20.0, -80.0, 25.0),
vertexFormat: PerInstanceColorAppearance.VERTEX_FORMAT,
}),
attributes: {
color: ColorGeometryInstanceAttribute.fromColor(
new Color(1.0, 0.0, 0.0, 0.5)
),
},
});
scene.primitives.add(
new GroundPrimitive({
geometryInstances: [redRectangleInstance],
appearance: new PerInstanceColorAppearance({
closed: true,
}),
asynchronous: false,
})
);
return updateGlobeUntilDone(scene).then(function () {
expect(scene).toRenderAndCall(function (rgba) {
expect(rgba[0]).toBeGreaterThan(0);
scene.destroyForSpecs();
});
});
});
it("picks ground primitive on translucent globe", function () {
var scene = createScene();
var globe = new Globe();
scene.globe = globe;
globe.baseColor = Color.BLACK;
globe.translucency.enabled = true;
globe.translucency.frontFaceAlpha = 0.5;
scene.camera.setView({
destination: new Cartesian3(
-557278.4840232887,
-6744284.200717078,
2794079.461722868
),
orientation: new HeadingPitchRoll(
6.283185307179586,
-1.5687983448015541,
0
),
});
var redRectangleInstance = new GeometryInstance({
geometry: new RectangleGeometry({
rectangle: Rectangle.fromDegrees(-110.0, 20.0, -80.0, 25.0),
vertexFormat: PerInstanceColorAppearance.VERTEX_FORMAT,
}),
attributes: {
color: ColorGeometryInstanceAttribute.fromColor(
new Color(1.0, 0.0, 0.0, 0.5)
),
},
});
var primitive = scene.primitives.add(
new GroundPrimitive({
geometryInstances: [redRectangleInstance],
appearance: new PerInstanceColorAppearance({
closed: true,
}),
asynchronous: false,
})
);
return updateGlobeUntilDone(scene).then(function () {
expect(scene).toPickPrimitive(primitive);
scene.destroyForSpecs();
});
});
},
"WebGL"
);