PerspectiveFrustum.js 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  1. /*global define*/
  2. define([
  3. '../Core/defined',
  4. '../Core/defineProperties',
  5. '../Core/DeveloperError',
  6. './PerspectiveOffCenterFrustum'
  7. ], function(
  8. defined,
  9. defineProperties,
  10. DeveloperError,
  11. PerspectiveOffCenterFrustum) {
  12. "use strict";
  13. /**
  14. * The viewing frustum is defined by 6 planes.
  15. * Each plane is represented by a {@link Cartesian4} object, where the x, y, and z components
  16. * define the unit vector normal to the plane, and the w component is the distance of the
  17. * plane from the origin/camera position.
  18. *
  19. * @alias PerspectiveFrustum
  20. * @constructor
  21. *
  22. * @see PerspectiveOffCenterFrustum
  23. *
  24. * @example
  25. * var frustum = new Cesium.PerspectiveFrustum();
  26. * frustum.aspectRatio = canvas.clientWidth / canvas.clientHeight;
  27. * frustum.fov = Cesium.Math.PI_OVER_THREE;
  28. * frustum.near = 1.0;
  29. * frustum.far = 2.0;
  30. */
  31. var PerspectiveFrustum = function() {
  32. this._offCenterFrustum = new PerspectiveOffCenterFrustum();
  33. /**
  34. * The angle of the field of view (FOV), in radians. This angle will be used
  35. * as the horizontal FOV if the width is greater than the height, otherwise
  36. * it will be the vertical FOV.
  37. * @type {Number}
  38. * @default undefined
  39. */
  40. this.fov = undefined;
  41. this._fov = undefined;
  42. this._fovy = undefined;
  43. /**
  44. * The aspect ratio of the frustum's width to it's height.
  45. * @type {Number}
  46. * @default undefined
  47. */
  48. this.aspectRatio = undefined;
  49. this._aspectRatio = undefined;
  50. /**
  51. * The distance of the near plane.
  52. * @type {Number}
  53. * @default 1.0
  54. */
  55. this.near = 1.0;
  56. this._near = this.near;
  57. /**
  58. * The distance of the far plane.
  59. * @type {Number}
  60. * @default 500000000.0
  61. */
  62. this.far = 500000000.0;
  63. this._far = this.far;
  64. };
  65. function update(frustum) {
  66. //>>includeStart('debug', pragmas.debug);
  67. if (!defined(frustum.fov) || !defined(frustum.aspectRatio) || !defined(frustum.near) || !defined(frustum.far)) {
  68. throw new DeveloperError('fov, aspectRatio, near, or far parameters are not set.');
  69. }
  70. //>>includeEnd('debug');
  71. var f = frustum._offCenterFrustum;
  72. if (frustum.fov !== frustum._fov || frustum.aspectRatio !== frustum._aspectRatio ||
  73. frustum.near !== frustum._near || frustum.far !== frustum._far) {
  74. //>>includeStart('debug', pragmas.debug);
  75. if (frustum.fov < 0 || frustum.fov >= Math.PI) {
  76. throw new DeveloperError('fov must be in the range [0, PI).');
  77. }
  78. if (frustum.aspectRatio < 0) {
  79. throw new DeveloperError('aspectRatio must be positive.');
  80. }
  81. if (frustum.near < 0 || frustum.near > frustum.far) {
  82. throw new DeveloperError('near must be greater than zero and less than far.');
  83. }
  84. //>>includeEnd('debug');
  85. frustum._aspectRatio = frustum.aspectRatio;
  86. frustum._fov = frustum.fov;
  87. frustum._fovy = (frustum.aspectRatio <= 1) ? frustum.fov : Math.atan(Math.tan(frustum.fov * 0.5) / frustum.aspectRatio) * 2.0;
  88. frustum._near = frustum.near;
  89. frustum._far = frustum.far;
  90. f.top = frustum.near * Math.tan(0.5 * frustum._fovy);
  91. f.bottom = -f.top;
  92. f.right = frustum.aspectRatio * f.top;
  93. f.left = -f.right;
  94. f.near = frustum.near;
  95. f.far = frustum.far;
  96. }
  97. }
  98. defineProperties(PerspectiveFrustum.prototype, {
  99. /**
  100. * Gets the perspective projection matrix computed from the view frustum.
  101. * @memberof PerspectiveFrustum.prototype
  102. * @type {Matrix4}
  103. *
  104. * @see PerspectiveFrustum#infiniteProjectionMatrix
  105. */
  106. projectionMatrix : {
  107. get : function() {
  108. update(this);
  109. return this._offCenterFrustum.projectionMatrix;
  110. }
  111. },
  112. /**
  113. * The perspective projection matrix computed from the view frustum with an infinite far plane.
  114. * @memberof PerspectiveFrustum.prototype
  115. * @type {Matrix4}
  116. *
  117. * @see PerspectiveFrustum#projectionMatrix
  118. */
  119. infiniteProjectionMatrix : {
  120. get : function() {
  121. update(this);
  122. return this._offCenterFrustum.infiniteProjectionMatrix;
  123. }
  124. },
  125. /**
  126. * Gets the angle of the vertical field of view, in radians.
  127. * @memberof PerspectiveFrustum.prototype
  128. * @type {Number}
  129. * @default undefined
  130. */
  131. fovy : {
  132. get : function() {
  133. update(this);
  134. return this._fovy;
  135. }
  136. }
  137. });
  138. /**
  139. * Creates a culling volume for this frustum.
  140. *
  141. * @param {Cartesian3} position The eye position.
  142. * @param {Cartesian3} direction The view direction.
  143. * @param {Cartesian3} up The up direction.
  144. * @returns {CullingVolume} A culling volume at the given position and orientation.
  145. *
  146. * @example
  147. * // Check if a bounding volume intersects the frustum.
  148. * var cullingVolume = frustum.computeCullingVolume(cameraPosition, cameraDirection, cameraUp);
  149. * var intersect = cullingVolume.computeVisibility(boundingVolume);
  150. */
  151. PerspectiveFrustum.prototype.computeCullingVolume = function(position, direction, up) {
  152. update(this);
  153. return this._offCenterFrustum.computeCullingVolume(position, direction, up);
  154. };
  155. /**
  156. * Returns the pixel's width and height in meters.
  157. *
  158. * @param {Cartesian2} drawingBufferDimensions A {@link Cartesian2} with width and height in the x and y properties, respectively.
  159. * @param {Number} [distance=near plane distance] The distance to the near plane in meters.
  160. * @param {Cartesian2} [result] The object onto which to store the result.
  161. * @returns {Cartesian2} The modified result parameter or a new instance of {@link Cartesian2} with the pixel's width and height in the x and y properties, respectively.
  162. *
  163. * @exception {DeveloperError} drawingBufferDimensions.x must be greater than zero.
  164. * @exception {DeveloperError} drawingBufferDimensions.y must be greater than zero.
  165. *
  166. * @example
  167. * // Example 1
  168. * // Get the width and height of a pixel.
  169. * var pixelSize = camera.frustum.getPixelSize({
  170. * width : canvas.clientWidth,
  171. * height : canvas.clientHeight
  172. * });
  173. *
  174. * @example
  175. * // Example 2
  176. * // Get the width and height of a pixel if the near plane was set to 'distance'.
  177. * // For example, get the size of a pixel of an image on a billboard.
  178. * var position = camera.position;
  179. * var direction = camera.direction;
  180. * var toCenter = Cesium.Cartesian3.subtract(primitive.boundingVolume.center, position, new Cesium.Cartesian3()); // vector from camera to a primitive
  181. * var toCenterProj = Cesium.Cartesian3.multiplyByScalar(direction, Cesium.Cartesian3.dot(direction, toCenter)); // project vector onto camera direction vector
  182. * var distance = Cesium.Cartesian3.magnitude(toCenterProj);
  183. * var pixelSize = camera.frustum.getPixelSize({
  184. * width : canvas.clientWidth,
  185. * height : canvas.clientHeight
  186. * }, distance);
  187. */
  188. PerspectiveFrustum.prototype.getPixelSize = function(drawingBufferDimensions, distance, result) {
  189. update(this);
  190. return this._offCenterFrustum.getPixelSize(drawingBufferDimensions, distance, result);
  191. };
  192. /**
  193. * Returns a duplicate of a PerspectiveFrustum instance.
  194. *
  195. * @param {PerspectiveFrustum} [result] The object onto which to store the result.
  196. * @returns {PerspectiveFrustum} The modified result parameter or a new PerspectiveFrustum instance if one was not provided.
  197. */
  198. PerspectiveFrustum.prototype.clone = function(result) {
  199. if (!defined(result)) {
  200. result = new PerspectiveFrustum();
  201. }
  202. result.aspectRatio = this.aspectRatio;
  203. result.fov = this.fov;
  204. result.near = this.near;
  205. result.far = this.far;
  206. // force update of clone to compute matrices
  207. result._aspectRatio = undefined;
  208. result._fov = undefined;
  209. result._near = undefined;
  210. result._far = undefined;
  211. this._offCenterFrustum.clone(result._offCenterFrustum);
  212. return result;
  213. };
  214. /**
  215. * Compares the provided PerspectiveFrustum componentwise and returns
  216. * <code>true</code> if they are equal, <code>false</code> otherwise.
  217. *
  218. * @param {PerspectiveFrustum} [other] The right hand side PerspectiveFrustum.
  219. * @returns {Boolean} <code>true</code> if they are equal, <code>false</code> otherwise.
  220. */
  221. PerspectiveFrustum.prototype.equals = function(other) {
  222. if (!defined(other)) {
  223. return false;
  224. }
  225. update(this);
  226. update(other);
  227. return (this.fov === other.fov &&
  228. this.aspectRatio === other.aspectRatio &&
  229. this.near === other.near &&
  230. this.far === other.far &&
  231. this._offCenterFrustum.equals(other._offCenterFrustum));
  232. };
  233. return PerspectiveFrustum;
  234. });