DebugCameraPrimitive.js 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  1. import Cartesian3 from "../Core/Cartesian3.js";
  2. import Color from "../Core/Color.js";
  3. import ColorGeometryInstanceAttribute from "../Core/ColorGeometryInstanceAttribute.js";
  4. import defaultValue from "../Core/defaultValue.js";
  5. import defined from "../Core/defined.js";
  6. import destroyObject from "../Core/destroyObject.js";
  7. import DeveloperError from "../Core/DeveloperError.js";
  8. import FrustumGeometry from "../Core/FrustumGeometry.js";
  9. import FrustumOutlineGeometry from "../Core/FrustumOutlineGeometry.js";
  10. import GeometryInstance from "../Core/GeometryInstance.js";
  11. import Matrix3 from "../Core/Matrix3.js";
  12. import OrthographicFrustum from "../Core/OrthographicFrustum.js";
  13. import OrthographicOffCenterFrustum from "../Core/OrthographicOffCenterFrustum.js";
  14. import PerspectiveFrustum from "../Core/PerspectiveFrustum.js";
  15. import PerspectiveOffCenterFrustum from "../Core/PerspectiveOffCenterFrustum.js";
  16. import Quaternion from "../Core/Quaternion.js";
  17. import PerInstanceColorAppearance from "./PerInstanceColorAppearance.js";
  18. import Primitive from "./Primitive.js";
  19. /**
  20. * Draws the outline of the camera's view frustum.
  21. *
  22. * @alias DebugCameraPrimitive
  23. * @constructor
  24. *
  25. * @param {object} options Object with the following properties:
  26. * @param {Camera} options.camera The camera.
  27. * @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.
  28. * @param {Color} [options.color=Color.CYAN] The color of the debug outline.
  29. * @param {boolean} [options.updateOnChange=true] Whether the primitive updates when the underlying camera changes.
  30. * @param {boolean} [options.show=true] Determines if this primitive will be shown.
  31. * @param {object} [options.id] A user-defined object to return when the instance is picked with {@link Scene#pick}.
  32. *
  33. * @example
  34. * primitives.add(new Cesium.DebugCameraPrimitive({
  35. * camera : camera,
  36. * color : Cesium.Color.YELLOW
  37. * }));
  38. */
  39. function DebugCameraPrimitive(options) {
  40. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  41. //>>includeStart('debug', pragmas.debug);
  42. if (!defined(options.camera)) {
  43. throw new DeveloperError("options.camera is required.");
  44. }
  45. //>>includeEnd('debug');
  46. this._camera = options.camera;
  47. this._frustumSplits = options.frustumSplits;
  48. this._color = defaultValue(options.color, Color.CYAN);
  49. this._updateOnChange = defaultValue(options.updateOnChange, true);
  50. /**
  51. * Determines if this primitive will be shown.
  52. *
  53. * @type {boolean}
  54. * @default true
  55. */
  56. this.show = defaultValue(options.show, true);
  57. /**
  58. * User-defined value returned when the primitive is picked.
  59. *
  60. * @type {*}
  61. * @default undefined
  62. *
  63. * @see Scene#pick
  64. */
  65. this.id = options.id;
  66. this._id = undefined;
  67. this._outlinePrimitives = [];
  68. this._planesPrimitives = [];
  69. }
  70. const scratchRight = new Cartesian3();
  71. const scratchRotation = new Matrix3();
  72. const scratchOrientation = new Quaternion();
  73. const scratchPerspective = new PerspectiveFrustum();
  74. const scratchPerspectiveOffCenter = new PerspectiveOffCenterFrustum();
  75. const scratchOrthographic = new OrthographicFrustum();
  76. const scratchOrthographicOffCenter = new OrthographicOffCenterFrustum();
  77. const scratchColor = new Color();
  78. const scratchSplits = [1.0, 100000.0];
  79. /**
  80. * @private
  81. */
  82. DebugCameraPrimitive.prototype.update = function (frameState) {
  83. if (!this.show) {
  84. return;
  85. }
  86. const planesPrimitives = this._planesPrimitives;
  87. const outlinePrimitives = this._outlinePrimitives;
  88. let i;
  89. let length;
  90. if (this._updateOnChange) {
  91. // Recreate the primitive every frame
  92. length = planesPrimitives.length;
  93. for (i = 0; i < length; ++i) {
  94. outlinePrimitives[i] =
  95. outlinePrimitives[i] && outlinePrimitives[i].destroy();
  96. planesPrimitives[i] =
  97. planesPrimitives[i] && planesPrimitives[i].destroy();
  98. }
  99. planesPrimitives.length = 0;
  100. outlinePrimitives.length = 0;
  101. }
  102. if (planesPrimitives.length === 0) {
  103. const camera = this._camera;
  104. const cameraFrustum = camera.frustum;
  105. let frustum;
  106. if (cameraFrustum instanceof PerspectiveFrustum) {
  107. frustum = scratchPerspective;
  108. } else if (cameraFrustum instanceof PerspectiveOffCenterFrustum) {
  109. frustum = scratchPerspectiveOffCenter;
  110. } else if (cameraFrustum instanceof OrthographicFrustum) {
  111. frustum = scratchOrthographic;
  112. } else {
  113. frustum = scratchOrthographicOffCenter;
  114. }
  115. frustum = cameraFrustum.clone(frustum);
  116. let numFrustums;
  117. let frustumSplits = this._frustumSplits;
  118. if (!defined(frustumSplits) || frustumSplits.length <= 1) {
  119. // Use near and far planes if no splits created
  120. frustumSplits = scratchSplits;
  121. frustumSplits[0] = this._camera.frustum.near;
  122. frustumSplits[1] = this._camera.frustum.far;
  123. numFrustums = 1;
  124. } else {
  125. numFrustums = frustumSplits.length - 1;
  126. }
  127. const position = camera.positionWC;
  128. const direction = camera.directionWC;
  129. const up = camera.upWC;
  130. let right = camera.rightWC;
  131. right = Cartesian3.negate(right, scratchRight);
  132. const rotation = scratchRotation;
  133. Matrix3.setColumn(rotation, 0, right, rotation);
  134. Matrix3.setColumn(rotation, 1, up, rotation);
  135. Matrix3.setColumn(rotation, 2, direction, rotation);
  136. const orientation = Quaternion.fromRotationMatrix(
  137. rotation,
  138. scratchOrientation
  139. );
  140. planesPrimitives.length = outlinePrimitives.length = numFrustums;
  141. for (i = 0; i < numFrustums; ++i) {
  142. frustum.near = frustumSplits[i];
  143. frustum.far = frustumSplits[i + 1];
  144. planesPrimitives[i] = new Primitive({
  145. geometryInstances: new GeometryInstance({
  146. geometry: new FrustumGeometry({
  147. origin: position,
  148. orientation: orientation,
  149. frustum: frustum,
  150. _drawNearPlane: i === 0,
  151. }),
  152. attributes: {
  153. color: ColorGeometryInstanceAttribute.fromColor(
  154. Color.fromAlpha(this._color, 0.1, scratchColor)
  155. ),
  156. },
  157. id: this.id,
  158. pickPrimitive: this,
  159. }),
  160. appearance: new PerInstanceColorAppearance({
  161. translucent: true,
  162. flat: true,
  163. }),
  164. asynchronous: false,
  165. });
  166. outlinePrimitives[i] = new Primitive({
  167. geometryInstances: new GeometryInstance({
  168. geometry: new FrustumOutlineGeometry({
  169. origin: position,
  170. orientation: orientation,
  171. frustum: frustum,
  172. _drawNearPlane: i === 0,
  173. }),
  174. attributes: {
  175. color: ColorGeometryInstanceAttribute.fromColor(this._color),
  176. },
  177. id: this.id,
  178. pickPrimitive: this,
  179. }),
  180. appearance: new PerInstanceColorAppearance({
  181. translucent: false,
  182. flat: true,
  183. }),
  184. asynchronous: false,
  185. });
  186. }
  187. }
  188. length = planesPrimitives.length;
  189. for (i = 0; i < length; ++i) {
  190. outlinePrimitives[i].update(frameState);
  191. planesPrimitives[i].update(frameState);
  192. }
  193. };
  194. /**
  195. * Returns true if this object was destroyed; otherwise, false.
  196. * <p>
  197. * If this object was destroyed, it should not be used; calling any function other than
  198. * <code>isDestroyed</code> will result in a {@link DeveloperError} exception.
  199. * </p>
  200. *
  201. * @returns {boolean} <code>true</code> if this object was destroyed; otherwise, <code>false</code>.
  202. *
  203. * @see DebugCameraPrimitive#destroy
  204. */
  205. DebugCameraPrimitive.prototype.isDestroyed = function () {
  206. return false;
  207. };
  208. /**
  209. * Destroys the WebGL resources held by this object. Destroying an object allows for deterministic
  210. * release of WebGL resources, instead of relying on the garbage collector to destroy this object.
  211. * <p>
  212. * Once an object is destroyed, it should not be used; calling any function other than
  213. * <code>isDestroyed</code> will result in a {@link DeveloperError} exception. Therefore,
  214. * assign the return value (<code>undefined</code>) to the object as done in the example.
  215. * </p>
  216. *
  217. * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
  218. *
  219. * @example
  220. * p = p && p.destroy();
  221. *
  222. * @see DebugCameraPrimitive#isDestroyed
  223. */
  224. DebugCameraPrimitive.prototype.destroy = function () {
  225. const length = this._planesPrimitives.length;
  226. for (let i = 0; i < length; ++i) {
  227. this._outlinePrimitives[i] =
  228. this._outlinePrimitives[i] && this._outlinePrimitives[i].destroy();
  229. this._planesPrimitives[i] =
  230. this._planesPrimitives[i] && this._planesPrimitives[i].destroy();
  231. }
  232. return destroyObject(this);
  233. };
  234. export default DebugCameraPrimitive;