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.

258 lines
8.4 KiB
JavaScript

import Cartesian3 from "../Core/Cartesian3.js";
import Color from "../Core/Color.js";
import ColorGeometryInstanceAttribute from "../Core/ColorGeometryInstanceAttribute.js";
import defaultValue from "../Core/defaultValue.js";
import defined from "../Core/defined.js";
import destroyObject from "../Core/destroyObject.js";
import DeveloperError from "../Core/DeveloperError.js";
import FrustumGeometry from "../Core/FrustumGeometry.js";
import FrustumOutlineGeometry from "../Core/FrustumOutlineGeometry.js";
import GeometryInstance from "../Core/GeometryInstance.js";
import Matrix3 from "../Core/Matrix3.js";
import OrthographicFrustum from "../Core/OrthographicFrustum.js";
import OrthographicOffCenterFrustum from "../Core/OrthographicOffCenterFrustum.js";
import PerspectiveFrustum from "../Core/PerspectiveFrustum.js";
import PerspectiveOffCenterFrustum from "../Core/PerspectiveOffCenterFrustum.js";
import Quaternion from "../Core/Quaternion.js";
import PerInstanceColorAppearance from "./PerInstanceColorAppearance.js";
import Primitive from "./Primitive.js";
/**
* Draws the outline of the camera's view frustum.
*
* @alias DebugCameraPrimitive
* @constructor
*
* @param {Object} options Object with the following properties:
* @param {Camera} options.camera The camera.
* @param {Number[]} [options.frustumSplits] Distances to the near and far planes of the camera frustums. This overrides the camera's frustum near and far values.
* @param {Color} [options.color=Color.CYAN] The color of the debug outline.
* @param {Boolean} [options.updateOnChange=true] Whether the primitive updates when the underlying camera changes.
* @param {Boolean} [options.show=true] Determines if this primitive will be shown.
* @param {Object} [options.id] A user-defined object to return when the instance is picked with {@link Scene#pick}.
*
* @example
* primitives.add(new Cesium.DebugCameraPrimitive({
* camera : camera,
* color : Cesium.Color.YELLOW
* }));
*/
function DebugCameraPrimitive(options) {
options = defaultValue(options, defaultValue.EMPTY_OBJECT);
//>>includeStart('debug', pragmas.debug);
if (!defined(options.camera)) {
throw new DeveloperError("options.camera is required.");
}
//>>includeEnd('debug');
this._camera = options.camera;
this._frustumSplits = options.frustumSplits;
this._color = defaultValue(options.color, Color.CYAN);
this._updateOnChange = defaultValue(options.updateOnChange, true);
/**
* Determines if this primitive will be shown.
*
* @type Boolean
* @default true
*/
this.show = defaultValue(options.show, true);
/**
* User-defined value returned when the primitive is picked.
*
* @type {*}
* @default undefined
*
* @see Scene#pick
*/
this.id = options.id;
this._id = undefined;
this._outlinePrimitives = [];
this._planesPrimitives = [];
}
var scratchRight = new Cartesian3();
var scratchRotation = new Matrix3();
var scratchOrientation = new Quaternion();
var scratchPerspective = new PerspectiveFrustum();
var scratchPerspectiveOffCenter = new PerspectiveOffCenterFrustum();
var scratchOrthographic = new OrthographicFrustum();
var scratchOrthographicOffCenter = new OrthographicOffCenterFrustum();
var scratchColor = new Color();
var scratchSplits = [1.0, 100000.0];
/**
* @private
*/
DebugCameraPrimitive.prototype.update = function (frameState) {
if (!this.show) {
return;
}
var planesPrimitives = this._planesPrimitives;
var outlinePrimitives = this._outlinePrimitives;
var i;
var length;
if (this._updateOnChange) {
// Recreate the primitive every frame
length = planesPrimitives.length;
for (i = 0; i < length; ++i) {
outlinePrimitives[i] =
outlinePrimitives[i] && outlinePrimitives[i].destroy();
planesPrimitives[i] =
planesPrimitives[i] && planesPrimitives[i].destroy();
}
planesPrimitives.length = 0;
outlinePrimitives.length = 0;
}
if (planesPrimitives.length === 0) {
var camera = this._camera;
var cameraFrustum = camera.frustum;
var frustum;
if (cameraFrustum instanceof PerspectiveFrustum) {
frustum = scratchPerspective;
} else if (cameraFrustum instanceof PerspectiveOffCenterFrustum) {
frustum = scratchPerspectiveOffCenter;
} else if (cameraFrustum instanceof OrthographicFrustum) {
frustum = scratchOrthographic;
} else {
frustum = scratchOrthographicOffCenter;
}
frustum = cameraFrustum.clone(frustum);
var numFrustums;
var frustumSplits = this._frustumSplits;
if (!defined(frustumSplits) || frustumSplits.length <= 1) {
// Use near and far planes if no splits created
frustumSplits = scratchSplits;
frustumSplits[0] = this._camera.frustum.near;
frustumSplits[1] = this._camera.frustum.far;
numFrustums = 1;
} else {
numFrustums = frustumSplits.length - 1;
}
var position = camera.positionWC;
var direction = camera.directionWC;
var up = camera.upWC;
var right = camera.rightWC;
right = Cartesian3.negate(right, scratchRight);
var rotation = scratchRotation;
Matrix3.setColumn(rotation, 0, right, rotation);
Matrix3.setColumn(rotation, 1, up, rotation);
Matrix3.setColumn(rotation, 2, direction, rotation);
var orientation = Quaternion.fromRotationMatrix(
rotation,
scratchOrientation
);
planesPrimitives.length = outlinePrimitives.length = numFrustums;
for (i = 0; i < numFrustums; ++i) {
frustum.near = frustumSplits[i];
frustum.far = frustumSplits[i + 1];
planesPrimitives[i] = new Primitive({
geometryInstances: new GeometryInstance({
geometry: new FrustumGeometry({
origin: position,
orientation: orientation,
frustum: frustum,
_drawNearPlane: i === 0,
}),
attributes: {
color: ColorGeometryInstanceAttribute.fromColor(
Color.fromAlpha(this._color, 0.1, scratchColor)
),
},
id: this.id,
pickPrimitive: this,
}),
appearance: new PerInstanceColorAppearance({
translucent: true,
flat: true,
}),
asynchronous: false,
});
outlinePrimitives[i] = new Primitive({
geometryInstances: new GeometryInstance({
geometry: new FrustumOutlineGeometry({
origin: position,
orientation: orientation,
frustum: frustum,
_drawNearPlane: i === 0,
}),
attributes: {
color: ColorGeometryInstanceAttribute.fromColor(this._color),
},
id: this.id,
pickPrimitive: this,
}),
appearance: new PerInstanceColorAppearance({
translucent: false,
flat: true,
}),
asynchronous: false,
});
}
}
length = planesPrimitives.length;
for (i = 0; i < length; ++i) {
outlinePrimitives[i].update(frameState);
planesPrimitives[i].update(frameState);
}
};
/**
* Returns true if this object was destroyed; otherwise, false.
* <p>
* If this object was destroyed, it should not be used; calling any function other than
* <code>isDestroyed</code> will result in a {@link DeveloperError} exception.
* </p>
*
* @returns {Boolean} <code>true</code> if this object was destroyed; otherwise, <code>false</code>.
*
* @see DebugCameraPrimitive#destroy
*/
DebugCameraPrimitive.prototype.isDestroyed = function () {
return false;
};
/**
* Destroys the WebGL resources held by this object. Destroying an object allows for deterministic
* release of WebGL resources, instead of relying on the garbage collector to destroy this object.
* <p>
* Once an object is destroyed, it should not be used; calling any function other than
* <code>isDestroyed</code> will result in a {@link DeveloperError} exception. Therefore,
* assign the return value (<code>undefined</code>) to the object as done in the example.
* </p>
*
* @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
*
* @example
* p = p && p.destroy();
*
* @see DebugCameraPrimitive#isDestroyed
*/
DebugCameraPrimitive.prototype.destroy = function () {
var length = this._planesPrimitives.length;
for (var i = 0; i < length; ++i) {
this._outlinePrimitives[i] =
this._outlinePrimitives[i] && this._outlinePrimitives[i].destroy();
this._planesPrimitives[i] =
this._planesPrimitives[i] && this._planesPrimitives[i].destroy();
}
return destroyObject(this);
};
export default DebugCameraPrimitive;