377 lines
12 KiB
JavaScript
377 lines
12 KiB
JavaScript
defineSuite([
|
|
'Core/BoundingSphere',
|
|
'Core/BoxGeometry',
|
|
'Core/Cartesian2',
|
|
'Core/Cartesian3',
|
|
'Core/Color',
|
|
'Core/defaultValue',
|
|
'Core/defined',
|
|
'Core/destroyObject',
|
|
'Core/GeometryPipeline',
|
|
'Core/Math',
|
|
'Core/Matrix4',
|
|
'Core/Resource',
|
|
'Renderer/BufferUsage',
|
|
'Renderer/DrawCommand',
|
|
'Renderer/Pass',
|
|
'Renderer/RenderState',
|
|
'Renderer/Sampler',
|
|
'Renderer/ShaderProgram',
|
|
'Renderer/TextureMagnificationFilter',
|
|
'Renderer/TextureMinificationFilter',
|
|
'Renderer/VertexArray',
|
|
'Scene/BillboardCollection',
|
|
'Scene/BlendingState',
|
|
'Scene/TextureAtlas',
|
|
'Specs/createScene',
|
|
'ThirdParty/when'
|
|
], 'Scene/Multifrustum', function(
|
|
BoundingSphere,
|
|
BoxGeometry,
|
|
Cartesian2,
|
|
Cartesian3,
|
|
Color,
|
|
defaultValue,
|
|
defined,
|
|
destroyObject,
|
|
GeometryPipeline,
|
|
CesiumMath,
|
|
Matrix4,
|
|
Resource,
|
|
BufferUsage,
|
|
DrawCommand,
|
|
Pass,
|
|
RenderState,
|
|
Sampler,
|
|
ShaderProgram,
|
|
TextureMagnificationFilter,
|
|
TextureMinificationFilter,
|
|
VertexArray,
|
|
BillboardCollection,
|
|
BlendingState,
|
|
TextureAtlas,
|
|
createScene,
|
|
when) {
|
|
'use strict';
|
|
|
|
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 = new Sampler({
|
|
minificationFilter : TextureMinificationFilter.NEAREST,
|
|
magnificationFilter : TextureMagnificationFilter.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[i].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');
|