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.
367 lines
11 KiB
JavaScript
367 lines
11 KiB
JavaScript
import { BoundingSphere } from "../../Source/Cesium.js";
|
|
import { BoxGeometry } from "../../Source/Cesium.js";
|
|
import { Cartesian2 } from "../../Source/Cesium.js";
|
|
import { Cartesian3 } from "../../Source/Cesium.js";
|
|
import { Color } from "../../Source/Cesium.js";
|
|
import { defaultValue } from "../../Source/Cesium.js";
|
|
import { defined } from "../../Source/Cesium.js";
|
|
import { destroyObject } from "../../Source/Cesium.js";
|
|
import { GeometryPipeline } from "../../Source/Cesium.js";
|
|
import { Math as CesiumMath } from "../../Source/Cesium.js";
|
|
import { Matrix4 } from "../../Source/Cesium.js";
|
|
import { Resource } from "../../Source/Cesium.js";
|
|
import { BufferUsage } from "../../Source/Cesium.js";
|
|
import { DrawCommand } from "../../Source/Cesium.js";
|
|
import { Pass } from "../../Source/Cesium.js";
|
|
import { RenderState } from "../../Source/Cesium.js";
|
|
import { Sampler } from "../../Source/Cesium.js";
|
|
import { ShaderProgram } from "../../Source/Cesium.js";
|
|
import { VertexArray } from "../../Source/Cesium.js";
|
|
import { BillboardCollection } from "../../Source/Cesium.js";
|
|
import { BlendingState } from "../../Source/Cesium.js";
|
|
import { TextureAtlas } from "../../Source/Cesium.js";
|
|
import createScene from "../createScene.js";
|
|
import { when } from "../../Source/Cesium.js";
|
|
|
|
describe(
|
|
"Scene/Multifrustum",
|
|
function () {
|
|
var scene;
|
|
var context;
|
|
var primitives;
|
|
var atlas;
|
|
|
|
var greenImage;
|
|
var blueImage;
|
|
var whiteImage;
|
|
|
|
var logDepth;
|
|
|
|
beforeAll(function () {
|
|
scene = createScene();
|
|
logDepth = scene.logarithmicDepthBuffer;
|
|
scene.destroyForSpecs();
|
|
|
|
return when.join(
|
|
Resource.fetchImage("./Data/Images/Green.png").then(function (image) {
|
|
greenImage = image;
|
|
}),
|
|
Resource.fetchImage("./Data/Images/Blue.png").then(function (image) {
|
|
blueImage = image;
|
|
}),
|
|
Resource.fetchImage("./Data/Images/White.png").then(function (image) {
|
|
whiteImage = image;
|
|
})
|
|
);
|
|
});
|
|
|
|
beforeEach(function () {
|
|
scene = createScene();
|
|
context = scene.context;
|
|
primitives = scene.primitives;
|
|
|
|
scene.logarithmicDepthBuffer = false;
|
|
|
|
var camera = scene.camera;
|
|
camera.position = new Cartesian3();
|
|
camera.direction = Cartesian3.negate(Cartesian3.UNIT_Z, new Cartesian3());
|
|
camera.up = Cartesian3.clone(Cartesian3.UNIT_Y);
|
|
camera.right = Cartesian3.clone(Cartesian3.UNIT_X);
|
|
|
|
camera.frustum.near = 1.0;
|
|
camera.frustum.far = 1000000000.0;
|
|
camera.frustum.fov = CesiumMath.toRadians(60.0);
|
|
camera.frustum.aspectRatio = 1.0;
|
|
});
|
|
|
|
afterEach(function () {
|
|
atlas = atlas && atlas.destroy();
|
|
scene.destroyForSpecs();
|
|
});
|
|
|
|
var billboard0;
|
|
var billboard1;
|
|
var billboard2;
|
|
|
|
function createBillboards() {
|
|
atlas = new TextureAtlas({
|
|
context: context,
|
|
borderWidthInPixels: 1,
|
|
initialSize: new Cartesian2(3, 3),
|
|
});
|
|
|
|
// ANGLE Workaround
|
|
atlas.texture.sampler = Sampler.NEAREST;
|
|
|
|
var billboards = new BillboardCollection();
|
|
billboards.textureAtlas = atlas;
|
|
billboards.destroyTextureAtlas = false;
|
|
billboard0 = billboards.add({
|
|
position: new Cartesian3(0.0, 0.0, -50.0),
|
|
image: greenImage,
|
|
});
|
|
primitives.add(billboards);
|
|
|
|
billboards = new BillboardCollection();
|
|
billboards.textureAtlas = atlas;
|
|
billboards.destroyTextureAtlas = false;
|
|
billboard1 = billboards.add({
|
|
position: new Cartesian3(0.0, 0.0, -50000.0),
|
|
image: blueImage,
|
|
});
|
|
primitives.add(billboards);
|
|
|
|
billboards = new BillboardCollection();
|
|
billboards.textureAtlas = atlas;
|
|
billboards.destroyTextureAtlas = false;
|
|
billboard2 = billboards.add({
|
|
position: new Cartesian3(0.0, 0.0, -50000000.0),
|
|
image: whiteImage,
|
|
});
|
|
primitives.add(billboards);
|
|
|
|
return billboards;
|
|
}
|
|
|
|
it("renders primitive in closest frustum", function () {
|
|
createBillboards();
|
|
|
|
expect(scene).toRenderAndCall(function (rgba) {
|
|
expect(rgba[0]).toEqual(0);
|
|
expect(rgba[1]).not.toEqual(0);
|
|
expect(rgba[2]).toEqual(0);
|
|
expect(rgba[3]).toEqual(255);
|
|
});
|
|
|
|
expect(scene).toRenderAndCall(function (rgba) {
|
|
expect(rgba[0]).toEqual(0);
|
|
expect(rgba[1]).not.toEqual(0);
|
|
expect(rgba[2]).toEqual(0);
|
|
expect(rgba[3]).toEqual(255);
|
|
});
|
|
});
|
|
|
|
it("renders primitive in middle frustum", function () {
|
|
createBillboards();
|
|
billboard0.color = new Color(1.0, 1.0, 1.0, 0.0);
|
|
|
|
expect(scene).toRender([0, 0, 255, 255]);
|
|
expect(scene).toRender([0, 0, 255, 255]);
|
|
});
|
|
|
|
it("renders primitive in last frustum", function () {
|
|
createBillboards();
|
|
var color = new Color(1.0, 1.0, 1.0, 0.0);
|
|
billboard0.color = color;
|
|
billboard1.color = color;
|
|
|
|
expect(scene).toRender([255, 255, 255, 255]);
|
|
expect(scene).toRender([255, 255, 255, 255]);
|
|
});
|
|
|
|
it("renders primitive in last frustum with debugShowFrustums", function () {
|
|
createBillboards();
|
|
var color = new Color(1.0, 1.0, 1.0, 1.0);
|
|
billboard0.color = color;
|
|
billboard1.color = color;
|
|
|
|
spyOn(DrawCommand.prototype, "execute");
|
|
|
|
scene.debugShowFrustums = true;
|
|
scene.renderForSpecs();
|
|
|
|
expect(DrawCommand.prototype.execute).toHaveBeenCalled();
|
|
|
|
var calls = DrawCommand.prototype.execute.calls.all();
|
|
var billboardCall;
|
|
var i;
|
|
for (i = 0; i < calls.length; ++i) {
|
|
if (calls[i].object.owner instanceof BillboardCollection) {
|
|
billboardCall = calls[i];
|
|
break;
|
|
}
|
|
}
|
|
|
|
expect(billboardCall).toBeDefined();
|
|
expect(billboardCall.args.length).toEqual(2);
|
|
|
|
var found = false;
|
|
var sources =
|
|
billboardCall.object.shaderProgram.fragmentShaderSource.sources;
|
|
for (var j = 0; j < sources.length; ++j) {
|
|
if (sources[j].indexOf("czm_Debug_main") !== -1) {
|
|
found = true;
|
|
break;
|
|
}
|
|
}
|
|
expect(found).toBe(true);
|
|
});
|
|
|
|
function createPrimitive(bounded, closestFrustum) {
|
|
bounded = defaultValue(bounded, true);
|
|
closestFrustum = defaultValue(closestFrustum, false);
|
|
|
|
function Primitive() {
|
|
this._va = undefined;
|
|
this._sp = undefined;
|
|
this._rs = undefined;
|
|
this._modelMatrix = Matrix4.fromTranslation(
|
|
new Cartesian3(0.0, 0.0, -50000.0),
|
|
new Matrix4()
|
|
);
|
|
|
|
this.color = new Color(1.0, 1.0, 0.0, 1.0);
|
|
|
|
var that = this;
|
|
this._um = {
|
|
u_color: function () {
|
|
return that.color;
|
|
},
|
|
u_model: function () {
|
|
return that._modelMatrix;
|
|
},
|
|
};
|
|
}
|
|
Primitive.prototype.update = function (frameState) {
|
|
if (!defined(this._sp)) {
|
|
var vs = "";
|
|
vs += "attribute vec4 position;";
|
|
vs += "void main()";
|
|
vs += "{";
|
|
vs += " gl_Position = czm_modelViewProjection * position;";
|
|
vs += closestFrustum
|
|
? " gl_Position.z = clamp(gl_Position.z, gl_DepthRange.near, gl_DepthRange.far);"
|
|
: "";
|
|
vs += "}";
|
|
var fs = "";
|
|
fs += "uniform vec4 u_color;";
|
|
fs += "void main()";
|
|
fs += "{";
|
|
fs += " gl_FragColor = u_color;";
|
|
fs += "}";
|
|
|
|
var dimensions = new Cartesian3(500000.0, 500000.0, 500000.0);
|
|
var maximum = Cartesian3.multiplyByScalar(
|
|
dimensions,
|
|
0.5,
|
|
new Cartesian3()
|
|
);
|
|
var minimum = Cartesian3.negate(maximum, new Cartesian3());
|
|
var geometry = BoxGeometry.createGeometry(
|
|
new BoxGeometry({
|
|
minimum: minimum,
|
|
maximum: maximum,
|
|
})
|
|
);
|
|
var attributeLocations = GeometryPipeline.createAttributeLocations(
|
|
geometry
|
|
);
|
|
this._va = VertexArray.fromGeometry({
|
|
context: frameState.context,
|
|
geometry: geometry,
|
|
attributeLocations: attributeLocations,
|
|
bufferUsage: BufferUsage.STATIC_DRAW,
|
|
});
|
|
|
|
this._sp = ShaderProgram.fromCache({
|
|
context: frameState.context,
|
|
vertexShaderSource: vs,
|
|
fragmentShaderSource: fs,
|
|
attributeLocations: attributeLocations,
|
|
});
|
|
|
|
this._rs = RenderState.fromCache({
|
|
blending: BlendingState.ALPHA_BLEND,
|
|
});
|
|
}
|
|
|
|
frameState.commandList.push(
|
|
new DrawCommand({
|
|
renderState: this._rs,
|
|
shaderProgram: this._sp,
|
|
vertexArray: this._va,
|
|
uniformMap: this._um,
|
|
modelMatrix: this._modelMatrix,
|
|
executeInClosestFrustum: closestFrustum,
|
|
boundingVolume: bounded
|
|
? new BoundingSphere(Cartesian3.clone(Cartesian3.ZERO), 500000.0)
|
|
: undefined,
|
|
pass: Pass.OPAQUE,
|
|
})
|
|
);
|
|
};
|
|
|
|
Primitive.prototype.destroy = function () {
|
|
this._va = this._va && this._va.destroy();
|
|
this._sp = this._sp && this._sp.destroy();
|
|
return destroyObject(this);
|
|
};
|
|
|
|
return new Primitive();
|
|
}
|
|
|
|
it("renders primitive with undefined bounding volume", function () {
|
|
var primitive = createPrimitive(false);
|
|
primitives.add(primitive);
|
|
|
|
expect(scene).toRender([255, 255, 0, 255]);
|
|
expect(scene).toRender([255, 255, 0, 255]);
|
|
});
|
|
|
|
it("renders only in the closest frustum", function () {
|
|
createBillboards();
|
|
var color = new Color(1.0, 1.0, 1.0, 0.0);
|
|
billboard0.color = color;
|
|
billboard1.color = color;
|
|
billboard2.color = color;
|
|
|
|
var primitive = createPrimitive(true, true);
|
|
primitive.color = new Color(1.0, 1.0, 0.0, 0.5);
|
|
primitives.add(primitive);
|
|
|
|
expect(scene).toRenderAndCall(function (rgba) {
|
|
expect(rgba[0]).not.toEqual(0);
|
|
expect(rgba[1]).not.toEqual(0);
|
|
expect(rgba[2]).toEqual(0);
|
|
expect(rgba[3]).toEqual(255);
|
|
});
|
|
|
|
expect(scene).toRenderAndCall(function (rgba) {
|
|
expect(rgba[0]).not.toEqual(0);
|
|
expect(rgba[1]).not.toEqual(0);
|
|
expect(rgba[2]).toEqual(0);
|
|
expect(rgba[3]).toEqual(255);
|
|
});
|
|
});
|
|
|
|
it("render without a central body or any primitives", function () {
|
|
scene.renderForSpecs();
|
|
});
|
|
|
|
it("does not crash when near plane is greater than or equal to the far plane", function () {
|
|
var camera = scene.camera;
|
|
camera.frustum.far = 1000.0;
|
|
camera.position = new Cartesian3(0.0, 0.0, 1e12);
|
|
|
|
createBillboards();
|
|
scene.renderForSpecs();
|
|
});
|
|
|
|
it("log depth uses less frustums", function () {
|
|
if (!logDepth) {
|
|
return;
|
|
}
|
|
|
|
createBillboards();
|
|
|
|
scene.render();
|
|
expect(scene.frustumCommandsList.length).toEqual(3);
|
|
|
|
scene.logarithmicDepthBuffer = true;
|
|
scene.render();
|
|
expect(scene.frustumCommandsList.length).toEqual(1);
|
|
});
|
|
},
|
|
"WebGL"
|
|
);
|