cesium
Version:
CesiumJS is a JavaScript library for creating 3D globes and 2D maps in a web browser without a plugin.
199 lines (169 loc) • 7.6 kB
JavaScript
import BoundingSphere from '../Core/BoundingSphere.js';
import Cartesian3 from '../Core/Cartesian3.js';
import ComponentDatatype from '../Core/ComponentDatatype.js';
import defined from '../Core/defined.js';
import FeatureDetection from '../Core/FeatureDetection.js';
import Geometry from '../Core/Geometry.js';
import GeometryAttribute from '../Core/GeometryAttribute.js';
import PrimitiveType from '../Core/PrimitiveType.js';
import BufferUsage from '../Renderer/BufferUsage.js';
import DrawCommand from '../Renderer/DrawCommand.js';
import Pass from '../Renderer/Pass.js';
import RenderState from '../Renderer/RenderState.js';
import ShaderProgram from '../Renderer/ShaderProgram.js';
import ShaderSource from '../Renderer/ShaderSource.js';
import VertexArray from '../Renderer/VertexArray.js';
import DepthPlaneFS from '../Shaders/DepthPlaneFS.js';
import DepthPlaneVS from '../Shaders/DepthPlaneVS.js';
import SceneMode from './SceneMode.js';
/**
* @private
*/
function DepthPlane() {
this._rs = undefined;
this._sp = undefined;
this._va = undefined;
this._command = undefined;
this._mode = undefined;
this._useLogDepth = false;
}
var depthQuadScratch = FeatureDetection.supportsTypedArrays() ? new Float32Array(12) : [];
var scratchCartesian1 = new Cartesian3();
var scratchCartesian2 = new Cartesian3();
var scratchCartesian3 = new Cartesian3();
var scratchCartesian4 = new Cartesian3();
function computeDepthQuad(ellipsoid, frameState) {
var radii = ellipsoid.radii;
var p = frameState.camera.positionWC;
// Find the corresponding position in the scaled space of the ellipsoid.
var q = Cartesian3.multiplyComponents(ellipsoid.oneOverRadii, p, scratchCartesian1);
var qMagnitude = Cartesian3.magnitude(q);
var qUnit = Cartesian3.normalize(q, scratchCartesian2);
// Determine the east and north directions at q.
var eUnit = Cartesian3.normalize(Cartesian3.cross(Cartesian3.UNIT_Z, q, scratchCartesian3), scratchCartesian3);
var nUnit = Cartesian3.normalize(Cartesian3.cross(qUnit, eUnit, scratchCartesian4), scratchCartesian4);
// Determine the radius of the 'limb' of the ellipsoid.
var wMagnitude = Math.sqrt(Cartesian3.magnitudeSquared(q) - 1.0);
// Compute the center and offsets.
var center = Cartesian3.multiplyByScalar(qUnit, 1.0 / qMagnitude, scratchCartesian1);
var scalar = wMagnitude / qMagnitude;
var eastOffset = Cartesian3.multiplyByScalar(eUnit, scalar, scratchCartesian2);
var northOffset = Cartesian3.multiplyByScalar(nUnit, scalar, scratchCartesian3);
// A conservative measure for the longitudes would be to use the min/max longitudes of the bounding frustum.
var upperLeft = Cartesian3.add(center, northOffset, scratchCartesian4);
Cartesian3.subtract(upperLeft, eastOffset, upperLeft);
Cartesian3.multiplyComponents(radii, upperLeft, upperLeft);
Cartesian3.pack(upperLeft, depthQuadScratch, 0);
var lowerLeft = Cartesian3.subtract(center, northOffset, scratchCartesian4);
Cartesian3.subtract(lowerLeft, eastOffset, lowerLeft);
Cartesian3.multiplyComponents(radii, lowerLeft, lowerLeft);
Cartesian3.pack(lowerLeft, depthQuadScratch, 3);
var upperRight = Cartesian3.add(center, northOffset, scratchCartesian4);
Cartesian3.add(upperRight, eastOffset, upperRight);
Cartesian3.multiplyComponents(radii, upperRight, upperRight);
Cartesian3.pack(upperRight, depthQuadScratch, 6);
var lowerRight = Cartesian3.subtract(center, northOffset, scratchCartesian4);
Cartesian3.add(lowerRight, eastOffset, lowerRight);
Cartesian3.multiplyComponents(radii, lowerRight, lowerRight);
Cartesian3.pack(lowerRight, depthQuadScratch, 9);
return depthQuadScratch;
}
DepthPlane.prototype.update = function(frameState) {
this._mode = frameState.mode;
if (frameState.mode !== SceneMode.SCENE3D) {
return;
}
var context = frameState.context;
var ellipsoid = frameState.mapProjection.ellipsoid;
var useLogDepth = frameState.useLogDepth;
if (!defined(this._command)) {
this._rs = RenderState.fromCache({ // Write depth, not color
cull : {
enabled : true
},
depthTest : {
enabled : true
},
colorMask : {
red : false,
green : false,
blue : false,
alpha : false
}
});
this._command = new DrawCommand({
renderState : this._rs,
boundingVolume : new BoundingSphere(Cartesian3.ZERO, ellipsoid.maximumRadius),
pass : Pass.OPAQUE,
owner : this
});
}
if (!defined(this._sp) || this._useLogDepth !== useLogDepth) {
this._useLogDepth = useLogDepth;
var vs = new ShaderSource({
sources : [DepthPlaneVS]
});
var fs = new ShaderSource({
sources : [DepthPlaneFS]
});
if (useLogDepth) {
var extension =
'#ifdef GL_EXT_frag_depth \n' +
'#extension GL_EXT_frag_depth : enable \n' +
'#endif \n\n';
fs.sources.push(extension);
fs.defines.push('LOG_DEPTH');
vs.defines.push('LOG_DEPTH');
}
this._sp = ShaderProgram.replaceCache({
shaderProgram : this._sp,
context : context,
vertexShaderSource : vs,
fragmentShaderSource : fs,
attributeLocations : {
position : 0
}
});
this._command.shaderProgram = this._sp;
}
// update depth plane
var depthQuad = computeDepthQuad(ellipsoid, frameState);
// depth plane
if (!defined(this._va)) {
var geometry = new Geometry({
attributes : {
position : new GeometryAttribute({
componentDatatype : ComponentDatatype.FLOAT,
componentsPerAttribute : 3,
values : depthQuad
})
},
indices : [0, 1, 2, 2, 1, 3],
primitiveType : PrimitiveType.TRIANGLES
});
this._va = VertexArray.fromGeometry({
context : context,
geometry : geometry,
attributeLocations : {
position : 0
},
bufferUsage : BufferUsage.DYNAMIC_DRAW
});
this._command.vertexArray = this._va;
} else {
this._va.getAttribute(0).vertexBuffer.copyFromArrayView(depthQuad);
}
};
DepthPlane.prototype.execute = function(context, passState) {
if (this._mode === SceneMode.SCENE3D) {
this._command.execute(context, passState);
}
};
DepthPlane.prototype.isDestroyed = function() {
return false;
};
DepthPlane.prototype.destroy = function() {
this._sp = this._sp && this._sp.destroy();
this._va = this._va && this._va.destroy();
};
export default DepthPlane;