Permalink
Browse files

Merge pull request #510 from AnalyticalGraphicsInc/terrain

Terrain
  • Loading branch information...
2 parents 1238aab + ddbaee3 commit 1c45e056d5391365f8590790afc9fe6d68940907 @pjcozzi pjcozzi committed Feb 15, 2013
Showing with 6,043 additions and 838 deletions.
  1. +165 −0 Apps/Sandcastle/gallery/Terrain.html
  2. BIN Apps/Sandcastle/gallery/Terrain.jpg
  3. +4 −0 CHANGES.md
  4. BIN Source/Assets/Textures/waterNormals.jpg
  5. BIN Source/Assets/Textures/waterNormalsSmall.jpg
  6. +4 −4 Source/Core/BoundingSphere.js
  7. +29 −0 Source/Core/Ellipsoid.js
  8. +3 −3 Source/Core/EllipsoidalOccluder.js
  9. +24 −9 Source/Core/Extent.js
  10. +1 −0 Source/Core/ExtentTessellator.js
  11. +330 −0 Source/Core/HeightmapTessellator.js
  12. +20 −20 Source/Core/Matrix4.js
  13. +14 −14 Source/Core/Occluder.js
  14. +1 −1 Source/Core/Quaternion.js
  15. +4 −4 Source/Core/ScreenSpaceEventHandler.js
  16. +1 −1 Source/Core/TimeIntervalCollection.js
  17. +30 −23 Source/Core/loadArrayBuffer.js
  18. +318 −1 Source/Renderer/ShaderProgram.js
  19. +4 −4 Source/Renderer/TextureAtlas.js
  20. +343 −48 Source/Renderer/UniformState.js
  21. +237 −0 Source/Scene/ArcGisImageServerTerrainProvider.js
  22. +6 −6 Source/Scene/ArcGisMapServerImageryProvider.js
  23. +5 −5 Source/Scene/BingMapsImageryProvider.js
  24. +2 −2 Source/Scene/CameraEventAggregator.js
  25. +127 −27 Source/Scene/CentralBody.js
  26. +109 −160 Source/Scene/CentralBodySurface.js
  27. +2 −5 Source/Scene/CentralBodySurfaceShaderSet.js
  28. +197 −0 Source/Scene/CesiumTerrainProvider.js
  29. +101 −126 Source/Scene/EllipsoidTerrainProvider.js
  30. +562 −0 Source/Scene/HeightmapTerrainData.js
  31. +5 −5 Source/Scene/ImageryLayer.js
  32. +1 −1 Source/Scene/ImageryProvider.js
  33. +1 −1 Source/Scene/OpenStreetMapImageryProvider.js
  34. +1 −1 Source/Scene/ScreenSpaceCameraController.js
  35. +5 −5 Source/Scene/SingleTileImageryProvider.js
  36. +103 −0 Source/Scene/TerrainData.js
  37. +75 −0 Source/Scene/TerrainMesh.js
  38. +88 −46 Source/Scene/TerrainProvider.js
  39. +19 −0 Source/Scene/TerrainState.js
  40. +508 −73 Source/Scene/Tile.js
  41. +1 −1 Source/Scene/TileMapServiceImageryProvider.js
  42. +23 −22 Source/Scene/{ImageryProviderError.js → TileProviderError.js}
  43. +12 −3 Source/Scene/TileReplacementQueue.js
  44. +3 −7 Source/Scene/TileState.js
  45. +204 −0 Source/Scene/TileTerrain.js
  46. +1 −1 Source/Scene/WebMapServiceImageryProvider.js
  47. +56 −9 Source/Shaders/BuiltinFunctions.glsl
  48. +109 −6 Source/Shaders/CentralBodyFS.glsl
  49. +12 −7 Source/Shaders/CentralBodyVS.glsl
  50. +1 −36 Source/Shaders/Materials/Water.glsl
  51. +1 −1 Source/Shaders/PolygonFS.glsl
  52. +0 −24 Source/Workers/createVerticesFromExtent.js
  53. +68 −0 Source/Workers/createVerticesFromHeightmap.js
  54. +35 −0 Specs/Core/EllipsoidSpec.js
  55. +160 −3 Specs/Renderer/AutomaticUniformSpec.js
  56. +262 −0 Specs/Scene/ArcGisImageServerTerrainProviderSpec.js
  57. +46 −0 Specs/Scene/CentralBodySurfaceSpec.js
  58. +186 −0 Specs/Scene/CesiumTerrainProviderSpec.js
  59. +9 −35 Specs/Scene/EllipsoidTerrainProviderSpec.js
  60. +373 −0 Specs/Scene/HeightmapTerrainDataSpec.js
  61. +419 −0 Specs/Scene/HeightmapTessellatorSpec.js
  62. +73 −59 Specs/Scene/TileReplacementQueueSpec.js
  63. +451 −28 Specs/Scene/TileSpec.js
  64. +88 −0 Specs/Scene/TilingSchemeSpec.js
  65. +1 −1 build.xml
View
165 Apps/Sandcastle/gallery/Terrain.html
@@ -0,0 +1,165 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="utf-8">
+ <meta http-equiv="X-UA-Compatible" content="IE=Edge,chrome=1"> <!-- Use Chrome Frame in IE -->
+ <meta name="viewport" content="width=device-width, height=device-height, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no">
+ <meta name="description" content="Visualize worldwide, high-resolution terrain.">
+ <title>Cesium Demo</title>
+ <script type="text/javascript" src="../Sandcastle-header.js"></script>
+ <script type="text/javascript">
+ var dojoConfig = {
+ baseUrl : '../../../Source',
+ packages: [
+ { name: 'dojo', location: '../ThirdParty/dojo-release-1.8.3-src/dojo' },
+ { name: 'dijit', location: '../ThirdParty/dojo-release-1.8.3-src/dijit' },
+ { name: 'dojox', location: '../ThirdParty/dojo-release-1.8.3-src/dojox' }
+ ]
+ };
+ </script>
+ <script data-dojo-config="async: 1, tlmSiblingOfDojo: 0" src="../../../ThirdParty/dojo-release-1.8.3-src/dojo/dojo.js"></script>
+ <link rel="stylesheet" href="../../../ThirdParty/dojo-release-1.8.3-src/dijit/themes/claro/claro.css" type="text/css">
+ <link rel="stylesheet" href="../../../Source/Widgets/Dojo/CesiumViewerWidget.css" type="text/css">
+</head>
+<body class="claro sandcastle-loading" data-sandcastle-bucket="bucket-dojo.html" data-sandcastle-title="Cesium + Dojo">
+<style>
+ @import url(../templates/bucket.css);
+</style>
+<div id="cesiumContainer" class="fullSize"></div>
+<div id="loadingOverlay"><h1>Loading...</h1></div>
+<div id="toolbar">
+<div id="terrainMenu"></div>
+<div id="zoomButtons"></div>
+</div>
+<script id="cesium_sandcastle_script">
+require([
+ 'Cesium',
+ 'Widgets/Dojo/CesiumViewerWidget',
+ 'dijit/DropDownMenu',
+ 'dijit/MenuItem',
+ 'dijit/form/Button',
+ 'dijit/form/DropDownButton'
+], function(
+ Cesium,
+ CesiumViewerWidget,
+ DropDownMenu,
+ MenuItem,
+ Button,
+ DropDownButton) {
+ "use strict";
+
+ function createTerrainMenu(terrainProviders) {
+ var menu = new DropDownMenu();
+ var button = new DropDownButton({
+ label : terrainProviders[0].name,
+ dropDown : menu
+ });
+
+ function createTerrainMenuItem(button, providerInfo) {
+ return new MenuItem({
+ label : providerInfo.name,
+ onClick : function() {
+ centralBody.terrainProvider = providerInfo.provider;
+ button.set('label', providerInfo.name);
+ }
+ });
+ }
+
+ for (var i = 0, len = terrainProviders.length; i < len; ++i) {
+ menu.addChild(createTerrainMenuItem(button, terrainProviders[i]));
+ }
+
+ button.placeAt('terrainMenu');
+
+ new Button({
+ label: 'Mount Everest',
+ onClick: function() {
+ var eye, target, up;
+
+ if (scene.mode === Cesium.SceneMode.SCENE3D) {
+ eye = new Cesium.Cartesian3(294572.0645397696, 5637826.573008351, 2978624.6868285);
+ target = eye.add(new Cesium.Cartesian3(0.9028130862217908, -0.42449297750082904, -0.06880583840911567));
+ up = new Cesium.Cartesian3(0.40668971896562117, 0.790807045510862, 0.45741413322152297);
+ scene.getCamera().controller.lookAt(eye, target, up);
+ } else if (scene.mode === Cesium.SceneMode.COLUMBUS_VIEW) {
+ eye = new Cesium.Cartesian3(9684590.891310014, 3114799.076252769, 9849.375792522824);
+ target = eye.add(new Cesium.Cartesian3(-0.8929328433855669, -0.00005779973945286486, -0.45018988645076763));
+ up = new Cesium.Cartesian3(-0.4501898855076042, -0.0000291369789812141, 0.8929328452557279);
+ scene.getCamera().controller.lookAt(eye, target, up);
+ } else {
+ scene.getCamera().controller.viewExtent(new Cesium.Extent(1.516102969, 0.48744464, 1.518102969, 0.48944464));
+ }
+ }
+ }).placeAt('zoomButtons');
+
+ new Button({
+ label: 'Half Dome',
+ onClick: function() {
+ var eye, target, up;
+
+ if (scene.mode === Cesium.SceneMode.SCENE3D) {
+ eye = new Cesium.Cartesian3(-2496304.1498512086, -4391818.97382059, 3884176.4503971986);
+ target = eye.add(new Cesium.Cartesian3(0.9279518715011381, -0.29488412129953234, -0.22792252890604328));
+ up = new Cesium.Cartesian3(-0.11836693744723503, -0.8130611584421428, 0.5700182635106171);
+ scene.getCamera().controller.lookAt(eye, target, up);
+ } else if (scene.mode === Cesium.SceneMode.COLUMBUS_VIEW) {
+ eye = new Cesium.Cartesian3(-13314946.646404704, 4200941.442507448, 2468.225945515426);
+ target = eye.add(new Cesium.Cartesian3(0.9624895834866811, 0.04124314776883213, -0.26816562874787864));
+ up = new Cesium.Cartesian3(0.2679197697914868, 0.011480478929947842, 0.9633728227203466);
+ scene.getCamera().controller.lookAt(eye, target, up);
+ } else {
+ scene.getCamera().controller.viewExtent(new Cesium.Extent(-2.08724538, 0.6577939, -2.08524538, 0.6597939));
+ }
+ }
+ }).placeAt('zoomButtons');
+
+ new Button({
+ label: 'San Francisco Bay',
+ onClick: function() {
+ var eye, target, up;
+
+ if (scene.mode === Cesium.SceneMode.SCENE3D) {
+ eye = new Cesium.Cartesian3(-2674718.9291375633, -4332137.224608461, 3888180.6614196445);
+ target = eye.add(new Cesium.Cartesian3(-0.40034097132786534, 0.9155843741828319, 0.03784653786617176));
+ up = new Cesium.Cartesian3(-0.6502679490649945, -0.3129458646313862, 0.6922546353438556);
+ scene.getCamera().controller.lookAt(eye, target, up);
+ } else if (scene.mode === Cesium.SceneMode.COLUMBUS_VIEW) {
+ eye = new Cesium.Cartesian3(-13562569.113918452, 4176598.9965795614, 37656.37201701476);
+ target = eye.add(new Cesium.Cartesian3(-0.8108519561707095, 0.4023795334200999, -0.42498213639958615));
+ up = new Cesium.Cartesian3(-0.3806859699462094, 0.18891270085627615, 0.905201736488051);
+ scene.getCamera().controller.lookAt(eye, target, up);
+ } else {
+ scene.getCamera().controller.viewExtent(new Cesium.Extent(-2.147621889, 0.64829691, -2.125621889, 0.67029691));
+ }
+ }
+ }).placeAt('zoomButtons');
+ }
+
+ var widget = new CesiumViewerWidget();
+ widget.placeAt('cesiumContainer');
+ widget.fullscreenElement = document.body;
+ widget.startup();
+
+ var scene = widget.scene;
+ var centralBody = scene.getPrimitives().getCentralBody();
+
+ var terrainProvider = new Cesium.CesiumTerrainProvider({
+ url : 'http://cesium.agi.com/smallterrain'
+ });
+
+ centralBody.terrainProvider = terrainProvider;
+
+ var ellipsoidProvider = new Cesium.EllipsoidTerrainProvider();
+
+ var terrainProviders = [
+ { name : 'CesiumTerrainProvider', provider : terrainProvider },
+ { name : 'EllipsoidTerrainProvider', provider : ellipsoidProvider }
+ ];
+
+ createTerrainMenu(terrainProviders);
+
+ Sandcastle.finishedLoading();
+});
+</script>
+</body>
+</html>
View
BIN Apps/Sandcastle/gallery/Terrain.jpg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
4 CHANGES.md
@@ -8,11 +8,15 @@ Beta Releases
* Breaking changes:
* `IntersectionTests.rayPlane` now takes the new `Plane` type instead of separate `planeNormal` and `planeD` arguments.
+ * Renamed `ImageryProviderError` to `TileProviderError`.
+* Added support for global terrain visualization via `CesiumTerrainProvider` and `ArcGisImageServerTerrainProvider`. See the [Terrain Tutorial](http://cesium.agi.com/2013/02/15/Cesium-Terrain-Tutorial/) for more information.
* Added `Plane` for representing the equation of a plane.
* Added a line segment-plane intersection test to `IntersectionTests`.
* Fixed an issue where a `PolylineCollection` with a model matrix other than the identity would be incorrectly rendered in 2D and Columbus view.
* Fixed an issue in the `ScreenSpaceCameraController` where disabled mouse events can cause the camera to be moved after being re-enabled.
* Added interactive extent drawing to the `Picking` Sandcastle example.
+* Added `HeightmapTessellator` to create a mesh from a heightmap.
+* Improved the lighting used in 2D and Columbus View modes. In general, the surface lighting in these modes should look just like it does in 3D.
### b13 - 2013-02-01
View
BIN Source/Assets/Textures/waterNormals.jpg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN Source/Assets/Textures/waterNormalsSmall.jpg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
8 Source/Core/BoundingSphere.js
@@ -211,10 +211,10 @@ define([
};
var defaultProjection = new GeographicProjection();
- var fromExtent2DLowerLeft = new Cartesian3(0.0, 0.0, 0.0);
- var fromExtent2DUpperRight = new Cartesian3(0.0, 0.0, 0.0);
- var fromExtent2DSouthwest = new Cartographic(0.0, 0.0, 0.0);
- var fromExtent2DNortheast = new Cartographic(0.0, 0.0, 0.0);
+ var fromExtent2DLowerLeft = new Cartesian3();
+ var fromExtent2DUpperRight = new Cartesian3();
+ var fromExtent2DSouthwest = new Cartographic();
+ var fromExtent2DNortheast = new Cartographic();
/**
* Computes a bounding sphere from an extent projected in 2D.
View
29 Source/Core/Ellipsoid.js
@@ -71,6 +71,35 @@ define([
};
/**
+ * Duplicates an Ellipsoid instance.
+ *
+ * @memberof Ellipsoid
+ *
+ * @param {Ellipsoid} ellipsoid The ellipsoid to duplicate.
+ * @param {Ellipsoid} [result] The object onto which to store the result, or undefined if a new
+ * instance should be created.
+ * @returns {Ellipsoid} The cloned Ellipsoid.
+ */
+ Ellipsoid.clone = function(ellipsoid, result) {
+ var radii = ellipsoid._radii;
+
+ if (typeof result === 'undefined') {
+ return new Ellipsoid(radii.x, radii.y, radii.z);
+ }
+
+ Cartesian3.clone(radii, result._radii);
+ Cartesian3.clone(ellipsoid._radiiSquared, result._radiiSquared);
+ Cartesian3.clone(ellipsoid._radiiToTheFourth, result._radiiToTheFourth);
+ Cartesian3.clone(ellipsoid._oneOverRadii, result._oneOverRadii);
+ Cartesian3.clone(ellipsoid._oneOverRadiiSquared, result._oneOverRadiiSquared);
+ result._minimumRadius = ellipsoid._minimumRadius;
+ result._maximumRadius = ellipsoid._maximumRadius;
+ result._centerToleranceSquared = ellipsoid._centerToleranceSquared;
+
+ return result;
+ };
+
+ /**
* Computes an Ellipsoid from a Cartesian specifying the radii in x, y, and z directions.
*
* @param {Cartesian3} [radii=Cartesian3.ZERO] The ellipsoid's radius in the x, y, and z directions.
View
6 Source/Core/EllipsoidalOccluder.js
@@ -45,8 +45,8 @@ define([
}
this._ellipsoid = ellipsoid;
- this._cameraPosition = new Cartesian3(0.0, 0.0, 0.0);
- this._cameraPositionInScaledSpace = new Cartesian3(0.0, 0.0, 0.0);
+ this._cameraPosition = new Cartesian3();
+ this._cameraPositionInScaledSpace = new Cartesian3();
this._distanceToLimbInScaledSpaceSquared = 0.0;
// setCameraPosition fills in the above values
@@ -95,7 +95,7 @@ define([
return this._cameraPosition;
};
- var scratchCartesian = new Cartesian3(0.0, 0.0, 0.0);
+ var scratchCartesian = new Cartesian3();
/**
* Determines whether or not a point, the <code>occludee</code>, is hidden from view by the occluder.
View
33 Source/Core/Extent.js
@@ -52,26 +52,41 @@ define([
};
/**
- * Duplicates this Extent.
+ * Duplicates an Extent.
*
- * @param {Extent} [result] The object onto which to store the result.
+ * @memberof Extent
+ *
+ * @param {Extent} extent The extent to clone.
+ * @param {Extent} [result] The object onto which to store the result, or undefined if a new instance should be created.
* @return {Extent} The modified result parameter or a new Extent instance if none was provided.
*/
- Extent.prototype.clone = function(result) {
+ Extent.clone = function(extent, result) {
if (typeof result === 'undefined') {
- return new Extent(this.west, this.south, this.east, this.north);
+ return new Extent(extent.west, extent.south, extent.east, extent.north);
}
- result.west = this.west;
- result.south = this.south;
- result.east = this.east;
- result.north = this.north;
+ result.west = extent.west;
+ result.south = extent.south;
+ result.east = extent.east;
+ result.north = extent.north;
return result;
};
/**
+ * Duplicates this Extent.
+ *
+ * @memberof Extent
+ *
+ * @param {Extent} [result] The object onto which to store the result.
+ * @return {Extent} The modified result parameter or a new Extent instance if none was provided.
+ */
+ Extent.prototype.clone = function(result) {
+ return Extent.clone(this, result);
+ };
+
+ /**
* Compares the provided Extent with this Extent componentwise and returns
* <code>true</code> if they are equal, <code>false</code> otherwise.
- * @memberof Cartesian3
+ * @memberof Extent
*
* @param {Extent} [other] The Extent to compare.
* @return {Boolean} <code>true</code> if the Extents are equal, <code>false</code> otherwise.
View
1 Source/Core/ExtentTessellator.js
@@ -24,6 +24,7 @@ define([
*
* @exports ExtentTessellator
*
+ * @see HeightmapTessellator
* @see CubeMapEllipsoidTessellator
* @see BoxTessellator
* @see PlaneTessellator
View
330 Source/Core/HeightmapTessellator.js
@@ -0,0 +1,330 @@
+/*global define*/
+define([
+ './defaultValue',
+ './freezeObject',
+ './getImagePixels',
+ './DeveloperError',
+ './Cartesian3',
+ './ComponentDatatype',
+ './Ellipsoid',
+ './Extent',
+ './Math',
+ './PrimitiveType'
+ ], function(
+ defaultValue,
+ freezeObject,
+ getImagePixels,
+ DeveloperError,
+ Cartesian3,
+ ComponentDatatype,
+ Ellipsoid,
+ Extent,
+ CesiumMath,
+ PrimitiveType) {
+ "use strict";
+
+ /**
+ * Contains functions to create a mesh from a heightmap image.
+ *
+ * @exports HeightmapTessellator
+ *
+ * @see ExtentTessellator
+ * @see CubeMapEllipsoidTessellator
+ * @see BoxTessellator
+ * @see PlaneTessellator
+ */
+ var HeightmapTessellator = {};
+
+ /**
+ * The default structure of a heightmap, as given to {@link HeightmapTessellator.computeVertices}.
+ *
+ * @memberof HeightmapTessellator
+ */
+ HeightmapTessellator.DEFAULT_STRUCTURE = freezeObject({
+ heightScale : 1.0,
+ heightOffset : 0.0,
+ elementsPerHeight : 1,
+ stride : 1,
+ elementMultiplier : 256.0,
+ isBigEndian : false
+ });
+
+ /**
+ * Fills an array of vertices from a heightmap image. On return, the vertex data is in the order
+ * [X, Y, Z, H, U, V], where X, Y, and Z represent the Cartesian position of the vertex, H is the
+ * height above the ellipsoid, and U and V are the texture coordinates.
+ *
+ * @memberof HeightmapTessellator
+ *
+ * @param {Array|Float32Array} description.vertices The array to use to store computed vertices.
+ * If description.skirtHeight is 0.0, the array should have
+ * description.width * description.height * 6 elements. If
+ * description.skirtHeight is greater than 0.0, the array should
+ * have (description.width + 2) * (description.height * 2) * 6
+ * elements.
+ * @param {TypedArray} description.heightmap The heightmap to tessellate.
+ * @param {Number} description.width The width of the heightmap, in height samples.
+ * @param {Number} description.height The height of the heightmap, in height samples.
+ * @param {Number} description.skirtHeight The height of skirts to drape at the edges of the heightmap.
+ * @param {Extent} description.nativeExtent An extent in the native coordinates of the heightmap's projection. For
+ * a heightmap with a geographic projection, this is degrees. For the web mercator
+ * projection, this is meters.
+ * @param {Extent} [description.extent] The extent covered by the heightmap, in geodetic coordinates with north, south, east and
+ * west properties in radians. Either extent or nativeExtent must be provided. If both
+ * are provided, they're assumed to be consistent.
+ * @param {Boolean} [description.isGeographic=true] True if the heightmap uses a {@link GeographicProjection}, or false if it uses
+ * a {@link WebMercatorProjection}.
+ * @param {Cartesian3} [description.relativetoCenter=Cartesian3.ZERO] The positions will be computed as <code>worldPosition.subtract(relativeToCenter)</code>.
+ * @param {Ellipsoid} [description.ellipsoid=Ellipsoid.WGS84] The ellipsoid to which the heightmap applies.
+ * @param {Object} [description.structure] An object describing the structure of the height data.
+ * @param {Number} [description.structure.heightScale=1.0] The factor by which to multiply height samples in order to obtain
+ * the height above the heightOffset, in meters. The heightOffset is added to the resulting
+ * height after multiplying by the scale.
+ * @param {Number} [description.structure.heightOffset=0.0] The offset to add to the scaled height to obtain the final
+ * height in meters. The offset is added after the height sample is multiplied by the
+ * heightScale.
+ * @param {Number} [description.structure.elementsPerHeight=1] The number of elements in the buffer that make up a single height
+ * sample. This is usually 1, indicating that each element is a separate height sample. If
+ * it is greater than 1, that number of elements together form the height sample, which is
+ * computed according to the structure.elementMultiplier and structure.isBigEndian properties.
+ * @param {Number} [description.structure.stride=1] The number of elements to skip to get from the first element of
+ * one height to the first element of the next height.
+ * @param {Number} [description.structure.elementMultiplier=256.0] The multiplier used to compute the height value when the
+ * stride property is greater than 1. For example, if the stride is 4 and the strideMultiplier
+ * is 256, the height is computed as follows:
+ * `height = buffer[index] + buffer[index + 1] * 256 + buffer[index + 2] * 256 * 256 + buffer[index + 3] * 256 * 256 * 256`
+ * This is assuming that the isBigEndian property is false. If it is true, the order of the
+ * elements is reversed.
+ * @param {Boolean} [description.structure.isBigEndian=false] Indicates endianness of the elements in the buffer when the
+ * stride property is greater than 1. If this property is false, the first element is the
+ * low-order element. If it is true, the first element is the high-order element.
+ *
+ * @example
+ * var width = 5;
+ * var height = 5;
+ * var vertices = new Float32Array(width * height * 6);
+ * var description = ;
+ * HeightmapTessellator.computeVertices({
+ * vertices : vertices,
+ * heightmap : [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0],
+ * width : width,
+ * height : height,
+ * skirtHeight : 0.0,
+ * nativeExtent : {
+ * west : 10.0,
+ * east : 20.0,
+ * south : 30.0,
+ * north : 40.0
+ * }
+ * });
+ */
+ HeightmapTessellator.computeVertices = function(description) {
+ if (typeof description === 'undefined' || typeof description.heightmap === 'undefined') {
+ throw new DeveloperError('description.heightmap is required.');
+ }
+
+ if (typeof description.width === 'undefined' || typeof description.height === 'undefined') {
+ throw new DeveloperError('description.width and description.height are required.');
+ }
+
+ if (typeof description.vertices === 'undefined') {
+ throw new DeveloperError('description.vertices is required.');
+ }
+
+ if (typeof description.nativeExtent === 'undefined') {
+ throw new DeveloperError('description.nativeExtent is required.');
+ }
+
+ if (typeof description.skirtHeight === 'undefined') {
+ throw new DeveloperError('description.skirtHeight is required.');
+ }
+
+ // This function tends to be a performance hotspot for terrain rendering,
+ // so it employs a lot of inlining and unrolling as an optimization.
+ // In particular, the functionality of Ellipsoid.cartographicToCartesian
+ // is inlined.
+
+ var cos = Math.cos;
+ var sin = Math.sin;
+ var sqrt = Math.sqrt;
+ var atan = Math.atan;
+ var exp = Math.exp;
+ var piOverTwo = CesiumMath.PI_OVER_TWO;
+ var toRadians = CesiumMath.toRadians;
+
+ var vertices = description.vertices;
+ var heightmap = description.heightmap;
+ var width = description.width;
+ var height = description.height;
+ var skirtHeight = description.skirtHeight;
+
+ var isGeographic = defaultValue(description.isGeographic, true);
+ var ellipsoid = defaultValue(description.ellipsoid, Ellipsoid.WGS84);
+
+ var oneOverCentralBodySemimajorAxis = 1.0 / ellipsoid.getMaximumRadius();
+
+ var nativeExtent = description.nativeExtent;
+
+ var geographicWest;
+ var geographicSouth;
+ var geographicEast;
+ var geographicNorth;
+
+ var extent = description.extent;
+ if (typeof extent === 'undefined') {
+ if (isGeographic) {
+ geographicWest = toRadians(nativeExtent.west);
+ geographicSouth = toRadians(nativeExtent.south);
+ geographicEast = toRadians(nativeExtent.east);
+ geographicNorth = toRadians(nativeExtent.north);
+ } else {
+ geographicWest = nativeExtent.west * oneOverCentralBodySemimajorAxis;
+ geographicSouth = piOverTwo - (2.0 * atan(exp(-nativeExtent.south * oneOverCentralBodySemimajorAxis)));
+ geographicEast = nativeExtent.east * oneOverCentralBodySemimajorAxis;
+ geographicNorth = piOverTwo - (2.0 * atan(exp(-nativeExtent.north * oneOverCentralBodySemimajorAxis)));
+ }
+ } else {
+ geographicWest = extent.west;
+ geographicSouth = extent.south;
+ geographicEast = extent.east;
+ geographicNorth = extent.north;
+ }
+
+ var relativeToCenter = defaultValue(description.relativeToCenter, Cartesian3.ZERO);
+
+ var structure = defaultValue(description.structure, HeightmapTessellator.DEFAULT_STRUCTURE);
+ var heightScale = defaultValue(structure.heightScale, HeightmapTessellator.DEFAULT_STRUCTURE.heightScale);
+ var heightOffset = defaultValue(structure.heightOffset, HeightmapTessellator.DEFAULT_STRUCTURE.heightOffset);
+ var elementsPerHeight = defaultValue(structure.elementsPerHeight, HeightmapTessellator.DEFAULT_STRUCTURE.elementsPerHeight);
+ var stride = defaultValue(structure.stride, HeightmapTessellator.DEFAULT_STRUCTURE.stride);
+ var elementMultiplier = defaultValue(structure.elementMultiplier, HeightmapTessellator.DEFAULT_STRUCTURE.elementMultiplier);
+ var isBigEndian = defaultValue(structure.isBigEndian, HeightmapTessellator.DEFAULT_STRUCTURE.isBigEndian);
+
+ var granularityX = (nativeExtent.east - nativeExtent.west) / (width - 1);
+ var granularityY = (nativeExtent.north - nativeExtent.south) / (height - 1);
+
+ var radiiSquared = ellipsoid.getRadiiSquared();
+ var radiiSquaredX = radiiSquared.x;
+ var radiiSquaredY = radiiSquared.y;
+ var radiiSquaredZ = radiiSquared.z;
+
+ var vertexArrayIndex = 0;
+
+ var minimumHeight = 65536.0;
+ var maximumHeight = -65536.0;
+
+ var startRow = 0;
+ var endRow = height;
+ var startCol = 0;
+ var endCol = width;
+
+ if (skirtHeight > 0) {
+ --startRow;
+ ++endRow;
+ --startCol;
+ ++endCol;
+ }
+
+ for ( var rowIndex = startRow; rowIndex < endRow; ++rowIndex) {
+ var row = rowIndex;
+ if (row < 0) {
+ row = 0;
+ }
+ if (row >= height) {
+ row = height - 1;
+ }
+
+ var latitude = nativeExtent.north - granularityY * row;
+
+ if (!isGeographic) {
+ latitude = piOverTwo - (2.0 * atan(exp(-latitude * oneOverCentralBodySemimajorAxis)));
+ } else {
+ latitude = toRadians(latitude);
+ }
+
+ var cosLatitude = cos(latitude);
+ var nZ = sin(latitude);
+ var kZ = radiiSquaredZ * nZ;
+
+ var v = (latitude - geographicSouth) / (geographicNorth - geographicSouth);
+
+ for ( var colIndex = startCol; colIndex < endCol; ++colIndex) {
+ var col = colIndex;
+ if (col < 0) {
+ col = 0;
+ }
+ if (col >= width) {
+ col = width - 1;
+ }
+
+ var longitude = nativeExtent.west + granularityX * col;
+
+ if (!isGeographic) {
+ longitude = longitude * oneOverCentralBodySemimajorAxis;
+ } else {
+ longitude = toRadians(longitude);
+ }
+
+ var terrainOffset = row * (width * stride) + col * stride;
+
+ var heightSample;
+ if (elementsPerHeight === 1) {
+ heightSample = heightmap[terrainOffset];
+ } else {
+ heightSample = 0;
+
+ var elementOffset;
+ if (isBigEndian) {
+ for (elementOffset = 0; elementOffset < elementsPerHeight; ++elementOffset) {
+ heightSample = (heightSample * elementMultiplier) + heightmap[terrainOffset + elementOffset];
+ }
+ } else {
+ for (elementOffset = elementsPerHeight - 1; elementOffset >= 0; --elementOffset) {
+ heightSample = (heightSample * elementMultiplier) + heightmap[terrainOffset + elementOffset];
+ }
+ }
+ }
+
+ heightSample = heightSample * heightScale + heightOffset;
+
+ maximumHeight = Math.max(maximumHeight, heightSample);
+ minimumHeight = Math.min(minimumHeight, heightSample);
+
+ if (colIndex !== col || rowIndex !== row) {
+ heightSample -= skirtHeight;
+ }
+
+ var nX = cosLatitude * cos(longitude);
+ var nY = cosLatitude * sin(longitude);
+
+ var kX = radiiSquaredX * nX;
+ var kY = radiiSquaredY * nY;
+
+ var gamma = sqrt((kX * nX) + (kY * nY) + (kZ * nZ));
+ var oneOverGamma = 1.0 / gamma;
+
+ var rSurfaceX = kX * oneOverGamma;
+ var rSurfaceY = kY * oneOverGamma;
+ var rSurfaceZ = kZ * oneOverGamma;
+
+ vertices[vertexArrayIndex++] = rSurfaceX + nX * heightSample - relativeToCenter.x;
+ vertices[vertexArrayIndex++] = rSurfaceY + nY * heightSample - relativeToCenter.y;
+ vertices[vertexArrayIndex++] = rSurfaceZ + nZ * heightSample - relativeToCenter.z;
+
+ vertices[vertexArrayIndex++] = heightSample;
+
+ var u = (longitude - geographicWest) / (geographicEast - geographicWest);
+
+ vertices[vertexArrayIndex++] = u;
+ vertices[vertexArrayIndex++] = v;
+ }
+ }
+
+ return {
+ maximumHeight : maximumHeight,
+ minimumHeight : minimumHeight
+ };
+ };
+
+ return HeightmapTessellator;
+});
View
40 Source/Core/Matrix4.js
@@ -1539,26 +1539,26 @@ define([
*
* @see Matrix3
*/
- Matrix4.getRotation = function(matrix, result) {
- if (typeof matrix === 'undefined') {
- throw new DeveloperError('matrix is required');
- }
- if (typeof result === 'undefined') {
- return new Matrix3(matrix[0], matrix[4], matrix[8],
- matrix[1], matrix[5], matrix[9],
- matrix[2], matrix[6], matrix[10]);
- }
- result[0] = matrix[0];
- result[1] = matrix[1];
- result[2] = matrix[2];
- result[3] = matrix[4];
- result[4] = matrix[5];
- result[5] = matrix[6];
- result[6] = matrix[8];
- result[7] = matrix[9];
- result[8] = matrix[10];
- return result;
- };
+ Matrix4.getRotation = function(matrix, result) {
+ if (typeof matrix === 'undefined') {
+ throw new DeveloperError('matrix is required');
+ }
+ if (typeof result === 'undefined') {
+ return new Matrix3(matrix[0], matrix[4], matrix[8],
+ matrix[1], matrix[5], matrix[9],
+ matrix[2], matrix[6], matrix[10]);
+ }
+ result[0] = matrix[0];
+ result[1] = matrix[1];
+ result[2] = matrix[2];
+ result[3] = matrix[4];
+ result[4] = matrix[5];
+ result[5] = matrix[6];
+ result[6] = matrix[8];
+ result[7] = matrix[9];
+ result[8] = matrix[10];
+ return result;
+ };
/**
* Computes the inverse of the provided matrix using Cramers Rule.
View
28 Source/Core/Occluder.js
@@ -110,7 +110,7 @@ define([
this._cameraPosition = cameraPosition;
};
- var tempVecScratch = new Cartesian3(0.0, 0.0, 0.0);
+ var tempVecScratch = new Cartesian3();
/**
* Determines whether or not a point, the <code>occludee</code>, is hidden from view by the occluder.
@@ -130,19 +130,19 @@ define([
*
* @see Occluder#getVisibility
*/
- Occluder.prototype.isPointVisible = function(occludee) {
- if (this._horizonDistance !== Number.MAX_VALUE) {
- var tempVec = Cartesian3.subtract(occludee, this._occluderPosition, tempVecScratch);
- var temp = this._occluderRadius;
- temp = tempVec.magnitudeSquared() - (temp * temp);
- if (temp > 0.0) {
- temp = Math.sqrt(temp) + this._horizonDistance;
- tempVec = Cartesian3.subtract(occludee, this._cameraPosition, tempVec);
- return temp * temp > tempVec.magnitudeSquared();
- }
- }
- return false;
- };
+ Occluder.prototype.isPointVisible = function(occludee) {
+ if (this._horizonDistance !== Number.MAX_VALUE) {
+ var tempVec = Cartesian3.subtract(occludee, this._occluderPosition, tempVecScratch);
+ var temp = this._occluderRadius;
+ temp = tempVec.magnitudeSquared() - (temp * temp);
+ if (temp > 0.0) {
+ temp = Math.sqrt(temp) + this._horizonDistance;
+ tempVec = Cartesian3.subtract(occludee, this._cameraPosition, tempVec);
+ return temp * temp > tempVec.magnitudeSquared();
+ }
+ }
+ return false;
+ };
/**
* Determines whether or not a sphere, the <code>occludee</code>, is hidden from view by the occluder.
View
2 Source/Core/Quaternion.js
@@ -517,7 +517,7 @@ define([
var w = quaternion.w;
if (Math.abs(w - 1.0) < CesiumMath.EPSILON6) {
if (typeof result === 'undefined') {
- return new Cartesian3(0.0, 0.0, 0.0);
+ return new Cartesian3();
}
result.x = result.y = result.z = 0;
return result;
View
8 Source/Core/ScreenSpaceEventHandler.js
@@ -286,7 +286,7 @@ define([
var movement = {
startPosition : new Cartesian2(this._lastMouseX, this._lastMouseY),
endPosition : new Cartesian2(pos.x, pos.y),
- motion : new Cartesian2(0.0, 0.0)
+ motion : new Cartesian2()
};
var modifier = this._getModifier(event);
@@ -420,7 +420,7 @@ define([
movement = {
startPosition : new Cartesian2(this._lastMouseX, this._lastMouseY),
endPosition : new Cartesian2(pos.x, pos.y),
- motion : new Cartesian2(0.0, 0.0)
+ motion : new Cartesian2()
};
action = this.getInputAction(ScreenSpaceEventType.MOUSE_MOVE, modifier);
@@ -462,12 +462,12 @@ define([
'distance' : {
startPosition : new Cartesian2(0, prevDist),
endPosition : new Cartesian2(0, dist),
- motion : new Cartesian2(0.0, 0.0)
+ motion : new Cartesian2()
},
'angleAndHeight' : {
startPosition : new Cartesian2(prevAngle, prevCY),
endPosition : new Cartesian2(angle, cY),
- motion : new Cartesian2(0.0, 0.0)
+ motion : new Cartesian2()
}
};
action(movement);
View
2 Source/Core/TimeIntervalCollection.js
@@ -25,7 +25,7 @@ define([
* @see JulianDate
*
*/
- var TimeIntervalCollection = function() {
+ var TimeIntervalCollection = function() {
this._intervals = [];
};
View
53 Source/Core/loadArrayBuffer.js
@@ -39,38 +39,45 @@ define([
}
return when(url, function(url) {
- var xhr = new XMLHttpRequest();
- xhr.open('GET', url, true);
+ var deferred = when.defer();
- if (typeof headers !== 'undefined') {
- for ( var key in headers) {
- if (headers.hasOwnProperty(key)) {
- xhr.setRequestHeader(key, headers[key]);
- }
- }
- }
+ loadArrayBuffer.load(url, headers, deferred);
- xhr.responseType = 'arraybuffer';
+ return deferred.promise;
+ });
+ };
- var deferred = when.defer();
+ // This is broken out into a separate function so that it can be mocked for testing purposes.
+ loadArrayBuffer.load = function(url, headers, deferred) {
+ var xhr = new XMLHttpRequest();
+ xhr.open('GET', url, true);
- xhr.onload = function(e) {
- if (xhr.status === 200) {
- deferred.resolve(xhr.response);
- } else {
- deferred.reject(new RequestErrorEvent(xhr.status, xhr.response));
+ if (typeof headers !== 'undefined') {
+ for ( var key in headers) {
+ if (headers.hasOwnProperty(key)) {
+ xhr.setRequestHeader(key, headers[key]);
}
- };
+ }
+ }
- xhr.onerror = function(e) {
- deferred.reject(new RequestErrorEvent());
- };
+ xhr.responseType = 'arraybuffer';
- xhr.send();
+ xhr.onload = function(e) {
+ if (xhr.status === 200) {
+ deferred.resolve(xhr.response);
+ } else {
+ deferred.reject(new RequestErrorEvent(xhr.status, xhr.response));
+ }
+ };
- return deferred.promise;
- });
+ xhr.onerror = function(e) {
+ deferred.reject(new RequestErrorEvent());
+ };
+
+ xhr.send();
};
+ loadArrayBuffer.defaultLoad = loadArrayBuffer.load;
+
return loadArrayBuffer;
});
View
319 Source/Renderer/ShaderProgram.js
@@ -275,6 +275,44 @@ define([
},
/**
+ * An automatic GLSL uniform representing a 4x4 view transformation matrix that
+ * transforms 3D world coordinates to eye coordinates. In 3D mode, this is identical to
+ * {@link czm_view}, but in 2D and Columbus View it represents the view matrix
+ * as if the camera were at an equivalent location in 3D mode. This is useful for lighting
+ * 2D and Columbus View in the same way that 3D is lit.
+ * <br /><br />
+ * Like all automatic uniforms, <code>czm_view3D</code> does not need to be explicitly declared.
+ * However, it can be explicitly declared when a shader is also used by other applications such
+ * as a third-party authoring tool.
+ *
+ * @alias czm_view3D
+ * @glslUniform
+ *
+ * @see UniformState#getView3D
+ * @see czm_view
+ *
+ * @example
+ * // GLSL declaration
+ * uniform mat4 czm_view3D;
+ *
+ * // Example
+ * vec4 eyePosition3D = czm_view3D * worldPosition3D;
+ */
+ czm_view3D : {
+ getSize : function() {
+ return 1;
+ },
+
+ getDatatype : function() {
+ return UniformDatatype.FLOAT_MATRIX4;
+ },
+
+ getValue : function(uniformState) {
+ return uniformState.getView3D();
+ }
+ },
+
+ /**
* An automatic GLSL uniform representing a 3x3 view rotation matrix that
* transforms vectors in world coordinates to eye coordinates.
* <br /><br />
@@ -312,6 +350,44 @@ define([
},
/**
+ * An automatic GLSL uniform representing a 3x3 view rotation matrix that
+ * transforms vectors in 3D world coordinates to eye coordinates. In 3D mode, this is identical to
+ * {@link czm_viewRotation}, but in 2D and Columbus View it represents the view matrix
+ * as if the camera were at an equivalent location in 3D mode. This is useful for lighting
+ * 2D and Columbus View in the same way that 3D is lit.
+ * <br /><br />
+ * Like all automatic uniforms, <code>czm_viewRotation3D</code> does not need to be explicitly declared.
+ * However, it can be explicitly declared when a shader is also used by other applications such
+ * as a third-party authoring tool.
+ *
+ * @alias czm_viewRotation3D
+ * @glslUniform
+ *
+ * @see UniformState#getViewRotation3D
+ * @see czm_viewRotation
+ *
+ * @example
+ * // GLSL declaration
+ * uniform mat3 czm_viewRotation3D;
+ *
+ * // Example
+ * vec3 eyeVector = czm_viewRotation3D * worldVector;
+ */
+ czm_viewRotation3D : {
+ getSize : function() {
+ return 1;
+ },
+
+ getDatatype : function() {
+ return UniformDatatype.FLOAT_MATRIX3;
+ },
+
+ getValue : function(uniformState) {
+ return uniformState.getViewRotation3D();
+ }
+ },
+
+ /**
* An automatic GLSL uniform representing a 4x4 transformation matrix that
* transforms from eye coordinates to world coordinates.
* <br /><br />
@@ -348,6 +424,44 @@ define([
},
/**
+ * An automatic GLSL uniform representing a 4x4 transformation matrix that
+ * transforms from 3D eye coordinates to world coordinates. In 3D mode, this is identical to
+ * {@link czm_inverseView}, but in 2D and Columbus View it represents the inverse view matrix
+ * as if the camera were at an equivalent location in 3D mode. This is useful for lighting
+ * 2D and Columbus View in the same way that 3D is lit.
+ * <br /><br />
+ * Like all automatic uniforms, <code>czm_inverseView3D</code> does not need to be explicitly declared.
+ * However, it can be explicitly declared when a shader is also used by other applications such
+ * as a third-party authoring tool.
+ *
+ * @alias czm_inverseView3D
+ * @glslUniform
+ *
+ * @see UniformState#getInverseView3D
+ * @see czm_inverseView
+ *
+ * @example
+ * // GLSL declaration
+ * uniform mat4 czm_inverseView3D;
+ *
+ * // Example
+ * vec4 worldPosition = czm_inverseView3D * eyePosition;
+ */
+ czm_inverseView3D : {
+ getSize : function() {
+ return 1;
+ },
+
+ getDatatype : function() {
+ return UniformDatatype.FLOAT_MATRIX4;
+ },
+
+ getValue : function(uniformState) {
+ return uniformState.getInverseView3D();
+ }
+ },
+
+ /**
* An automatic GLSL uniform representing a 3x3 rotation matrix that
* transforms vectors from eye coordinates to world coordinates.
* <br /><br />
@@ -385,6 +499,44 @@ define([
},
/**
+ * An automatic GLSL uniform representing a 3x3 rotation matrix that
+ * transforms vectors from 3D eye coordinates to world coordinates. In 3D mode, this is identical to
+ * {@link czm_inverseViewRotation}, but in 2D and Columbus View it represents the inverse view matrix
+ * as if the camera were at an equivalent location in 3D mode. This is useful for lighting
+ * 2D and Columbus View in the same way that 3D is lit.
+ * <br /><br />
+ * Like all automatic uniforms, <code>czm_inverseViewRotation3D</code> does not need to be explicitly declared.
+ * However, it can be explicitly declared when a shader is also used by other applications such
+ * as a third-party authoring tool.
+ *
+ * @alias czm_inverseViewRotation3D
+ * @glslUniform
+ *
+ * @see UniformState#getInverseView3D
+ * @see czm_inverseViewRotation
+ *
+ * @example
+ * // GLSL declaration
+ * uniform mat3 czm_inverseViewRotation3D;
+ *
+ * // Example
+ * vec4 worldVector = czm_inverseViewRotation3D * eyeVector;
+ */
+ czm_inverseViewRotation3D : {
+ getSize : function() {
+ return 1;
+ },
+
+ getDatatype : function() {
+ return UniformDatatype.FLOAT_MATRIX3;
+ },
+
+ getValue : function(uniformState) {
+ return uniformState.getInverseViewRotation3D();
+ }
+ },
+
+ /**
* An automatic GLSL uniform representing a 4x4 projection transformation matrix that
* transforms eye coordinates to clip coordinates. Clip coordinates is the
* coordinate system for a vertex shader's <code>gl_Position</code> output.
@@ -543,6 +695,50 @@ define([
/**
* An automatic GLSL uniform representing a 4x4 model-view transformation matrix that
+ * transforms 3D model coordinates to eye coordinates. In 3D mode, this is identical to
+ * {@link czm_modelView}, but in 2D and Columbus View it represents the model-view matrix
+ * as if the camera were at an equivalent location in 3D mode. This is useful for lighting
+ * 2D and Columbus View in the same way that 3D is lit.
+ * <br /><br />
+ * Positions should be transformed to eye coordinates using <code>czm_modelView3D</code> and
+ * normals should be transformed using {@link czm_normal3D}.
+ * <br /><br />
+ * Like all automatic uniforms, <code>czm_modelView3D</code> does not need to be explicitly declared.
+ * However, it can be explicitly declared when a shader is also used by other applications such
+ * as a third-party authoring tool.
+ *
+ * @alias czm_modelView3D
+ * @glslUniform
+ *
+ * @see UniformState#getModelView3D
+ * @see czm_modelView
+ *
+ * @example
+ * // GLSL declaration
+ * uniform mat4 czm_modelView3D;
+ *
+ * // Example
+ * vec4 eyePosition = czm_modelView3D * modelPosition;
+ *
+ * // The above is equivalent to, but more efficient than:
+ * vec4 eyePosition = czm_view3D * czm_model * modelPosition;
+ */
+ czm_modelView3D : {
+ getSize : function() {
+ return 1;
+ },
+
+ getDatatype : function() {
+ return UniformDatatype.FLOAT_MATRIX4;
+ },
+
+ getValue : function(uniformState) {
+ return uniformState.getModelView3D();
+ }
+ },
+
+ /**
+ * An automatic GLSL uniform representing a 4x4 model-view transformation matrix that
* transforms model coordinates, relative to the eye, to eye coordinates. This is used
* in conjunction with {@link czm_translateRelativeToEye}.
* <br /><br />
@@ -621,6 +817,45 @@ define([
},
/**
+ * An automatic GLSL uniform representing a 4x4 transformation matrix that
+ * transforms from eye coordinates to 3D model coordinates. In 3D mode, this is identical to
+ * {@link czm_inverseModelView}, but in 2D and Columbus View it represents the inverse model-view matrix
+ * as if the camera were at an equivalent location in 3D mode. This is useful for lighting
+ * 2D and Columbus View in the same way that 3D is lit.
+ * <br /><br />
+ * Like all automatic uniforms, <code>czm_inverseModelView3D</code> does not need to be explicitly declared.
+ * However, it can be explicitly declared when a shader is also used by other applications such
+ * as a third-party authoring tool.
+ *
+ * @alias czm_inverseModelView3D
+ * @glslUniform
+ *
+ * @see UniformState#getInverseModelView
+ * @see czm_inverseModelView
+ * @see czm_modelView3D
+ *
+ * @example
+ * // GLSL declaration
+ * uniform mat4 czm_inverseModelView3D;
+ *
+ * // Example
+ * vec4 modelPosition = czm_inverseModelView3D * eyePosition;
+ */
+ czm_inverseModelView3D : {
+ getSize : function() {
+ return 1;
+ },
+
+ getDatatype : function() {
+ return UniformDatatype.FLOAT_MATRIX4;
+ },
+
+ getValue : function(uniformState) {
+ return uniformState.getInverseModelView3D();
+ }
+ },
+
+ /**
* An automatic GLSL uniform representing a 4x4 view-projection transformation matrix that
* transforms world coordinates to clip coordinates. Clip coordinates is the
* coordinate system for a vertex shader's <code>gl_Position</code> output.
@@ -835,8 +1070,50 @@ define([
/**
* An automatic GLSL uniform representing a 3x3 normal transformation matrix that
+ * transforms normal vectors in 3D model coordinates to eye coordinates.
+ * In 3D mode, this is identical to
+ * {@link czm_normal}, but in 2D and Columbus View it represents the normal transformation
+ * matrix as if the camera were at an equivalent location in 3D mode. This is useful for lighting
+ * 2D and Columbus View in the same way that 3D is lit.
+ * <br /><br />
+ * Positions should be transformed to eye coordinates using {@link czm_modelView3D} and
+ * normals should be transformed using <code>czm_normal3D</code>.
+ * <br /><br />
+ * Like all automatic uniforms, <code>czm_normal3D</code> does not need to be explicitly declared.
+ * However, it can be explicitly declared when a shader is also used by other applications such
+ * as a third-party authoring tool.
+ *
+ * @alias czm_normal3D
+ * @glslUniform
+ *
+ * @see UniformState#getNormal3D
+ * @see czm_normal
+ *
+ * @example
+ * // GLSL declaration
+ * uniform mat3 czm_normal3D;
+ *
+ * // Example
+ * vec3 eyeNormal = czm_normal3D * normal;
+ */
+ czm_normal3D : {
+ getSize : function() {
+ return 1;
+ },
+
+ getDatatype : function() {
+ return UniformDatatype.FLOAT_MATRIX3;
+ },
+
+ getValue : function(uniformState) {
+ return uniformState.getNormal3D();
+ }
+ },
+
+ /**
+ * An automatic GLSL uniform representing a 3x3 normal transformation matrix that
* transforms normal vectors in eye coordinates to model coordinates. This is
- * in the opposite transform provided by {@link czm_normal}.
+ * the opposite of the transform provided by {@link czm_normal}.
* <br /><br />
* Like all automatic uniforms, <code>czm_inverseNormal</code> does not need to be explicitly declared.
* However, it can be explicitly declared when a shader is also used by other applications such
@@ -872,6 +1149,46 @@ define([
},
/**
+ * An automatic GLSL uniform representing a 3x3 normal transformation matrix that
+ * transforms normal vectors in eye coordinates to 3D model coordinates. This is
+ * the opposite of the transform provided by {@link czm_normal}.
+ * In 3D mode, this is identical to
+ * {@link czm_inverseNormal}, but in 2D and Columbus View it represents the inverse normal transformation
+ * matrix as if the camera were at an equivalent location in 3D mode. This is useful for lighting
+ * 2D and Columbus View in the same way that 3D is lit.
+ * <br /><br />
+ * Like all automatic uniforms, <code>czm_inverseNormal3D</code> does not need to be explicitly declared.
+ * However, it can be explicitly declared when a shader is also used by other applications such
+ * as a third-party authoring tool.
+ *
+ * @alias czm_inverseNormal3D
+ * @glslUniform
+ *
+ * @see UniformState#getInverseNormal3D
+ * @see czm_inverseNormal
+ *
+ * @example
+ * // GLSL declaration
+ * uniform mat3 czm_inverseNormal3D;
+ *
+ * // Example
+ * vec3 normalMC = czm_inverseNormal3D * normalEC;
+ */
+ czm_inverseNormal3D : {
+ getSize : function() {
+ return 1;
+ },
+
+ getDatatype : function() {
+ return UniformDatatype.FLOAT_MATRIX3;
+ },
+
+ getValue : function(uniformState) {
+ return uniformState.getInverseNormal3D();
+ }
+ },
+
+ /**
* An automatic GLSL uniform containing the near distance (<code>x</code>) and the far distance (<code>y</code>)
* of the frustum defined by the camera. This is the largest possible frustum, not an individual
* frustum used for mult-frustum rendering.
View
8 Source/Renderer/TextureAtlas.js
@@ -88,7 +88,7 @@ define([
height : initialSize.y,
pixelFormat : this._pixelFormat
});
- this._root = new TextureAtlasNode(new Cartesian2(0.0, 0.0), new Cartesian2(initialSize.x, initialSize.y));
+ this._root = new TextureAtlasNode(new Cartesian2(), new Cartesian2(initialSize.x, initialSize.y));
// Add initial images if there are any.
if (typeof images !== 'undefined' && (images.length > 0)) {
@@ -113,9 +113,9 @@ define([
// Create new node structure, putting the old root node in the bottom left.
var nodeBottomRight = new TextureAtlasNode(new Cartesian2(oldAtlasWidth + this._borderWidthInPixels, 0.0), new Cartesian2(atlasWidth, oldAtlasHeight));
- var nodeBottomHalf = new TextureAtlasNode(new Cartesian2(0.0, 0.0), new Cartesian2(atlasWidth, oldAtlasHeight), this._root, nodeBottomRight);
+ var nodeBottomHalf = new TextureAtlasNode(new Cartesian2(), new Cartesian2(atlasWidth, oldAtlasHeight), this._root, nodeBottomRight);
var nodeTopHalf = new TextureAtlasNode(new Cartesian2(0.0, oldAtlasHeight + this._borderWidthInPixels), new Cartesian2(atlasWidth, atlasHeight));
- var nodeMain = new TextureAtlasNode(new Cartesian2(0.0, 0.0), new Cartesian2(atlasWidth, atlasHeight), nodeBottomHalf, nodeTopHalf);
+ var nodeMain = new TextureAtlasNode(new Cartesian2(), new Cartesian2(atlasWidth, atlasHeight), nodeBottomHalf, nodeTopHalf);
this._root = nodeMain;
// Resize texture coordinates.
@@ -156,7 +156,7 @@ define([
height : initialHeight,
pixelFormat : this._pixelFormat
});
- this._root = new TextureAtlasNode(new Cartesian2(0.0, 0.0), new Cartesian2(initialWidth, initialHeight));
+ this._root = new TextureAtlasNode(new Cartesian2(), new Cartesian2(initialWidth, initialHeight));
}
};
View
391 Source/Renderer/UniformState.js
@@ -8,6 +8,8 @@ define([
'../Core/Cartesian2',
'../Core/Cartesian3',
'../Core/Cartesian4',
+ '../Core/Cartographic',
+ '../Core/Math',
'../Core/EncodedCartesian3',
'../Core/BoundingRectangle',
'../Core/Transforms',
@@ -22,6 +24,8 @@ define([
Cartesian2,
Cartesian3,
Cartesian4,
+ Cartographic,
+ CesiumMath,
EncodedCartesian3,
BoundingRectangle,
Transforms,
@@ -54,24 +58,39 @@ define([
this._temeToPseudoFixed = Matrix3.IDENTITY.clone();
// Derived members
+ this._view3DDirty = true;
+ this._view3D = new Matrix4();
+
+ this._inverseView3DDirty = true;
+ this._inverseView3D = new Matrix4();
+
this._inverseModelDirty = true;
this._inverseModel = new Matrix4();
this._viewRotation = new Matrix3();
this._inverseViewRotation = new Matrix3();
+ this._viewRotation3D = new Matrix3();
+ this._inverseViewRotation3D = new Matrix3();
+
this._inverseProjectionDirty = true;
this._inverseProjection = new Matrix4();
this._modelViewDirty = true;
this._modelView = new Matrix4();
+ this._modelView3DDirty = true;
+ this._modelView3D = new Matrix4();
+
this._modelViewRelativeToEyeDirty = true;
this._modelViewRelativeToEye = new Matrix4();
this._inverseModelViewDirty = true;
this._inverseModelView = new Matrix4();
+ this._inverseModelView3DDirty = true;
+ this._inverseModelView3D = new Matrix4();
+
this._viewProjectionDirty = true;
this._viewProjection = new Matrix4();
@@ -87,31 +106,50 @@ define([
this._normalDirty = true;
this._normal = new Matrix3();
+ this._normal3DDirty = true;
+ this._normal3D = new Matrix3();
+
this._inverseNormalDirty = true;
this._inverseNormal = new Matrix3();
+ this._inverseNormal3DDirty = true;
+ this._inverseNormal3D = new Matrix3();
+
this._encodedCameraPositionMCDirty = true;
this._encodedCameraPositionMC = new EncodedCartesian3();
this._cameraPosition = new Cartesian3();
this._sunDirectionWC = new Cartesian3();
this._sunDirectionEC = new Cartesian3();
this._moonDirectionEC = new Cartesian3();
+
+ this._mode = undefined;
+ this._mapProjection = undefined;
+ this._cameraDirection = new Cartesian3();
+ this._cameraRight = new Cartesian3();
+ this._cameraUp = new Cartesian3();
+ this._frustum2DWidth = 0.0;
};
function setView(uniformState, matrix) {
Matrix4.clone(matrix, uniformState._view);
Matrix4.getRotation(matrix, uniformState._viewRotation);
+ uniformState._view3DDirty = true;
+ uniformState._inverseView3DDirty = true;
uniformState._modelViewDirty = true;
+ uniformState._modelView3DDirty = true;
uniformState._modelViewRelativeToEyeDirty = true;
uniformState._inverseModelViewDirty = true;
+ uniformState._inverseModelView3DDirty = true;
uniformState._viewProjectionDirty = true;
uniformState._modelViewProjectionDirty = true;
uniformState._modelViewProjectionRelativeToEyeDirty = true;
uniformState._modelViewInfiniteProjectionDirty = true;
uniformState._normalDirty = true;
uniformState._inverseNormalDirty = true;
+ uniformState._normal3DDirty = true;
+ uniformState._inverseNormal3DDirty = true;
}
function setInverseView(uniformState, matrix) {
@@ -134,43 +172,26 @@ define([
uniformState._modelViewInfiniteProjectionDirty = true;
}
- function setCameraPosition(uniformState, position) {
- Cartesian3.clone(position, uniformState._cameraPosition);
+ function setCamera(uniformState, camera) {
+ Cartesian3.clone(camera.getPositionWC(), uniformState._cameraPosition);
+ Cartesian3.clone(camera.getDirectionWC(), uniformState._cameraDirection);
+ Cartesian3.clone(camera.getRightWC(), uniformState._cameraRight);
+ Cartesian3.clone(camera.getUpWC(), uniformState._cameraUp);
uniformState._encodedCameraPositionMCDirty = true;
}
var sunPositionWC = new Cartesian3();
var sunPositionScratch = new Cartesian3();
function setSunAndMoonDirections(uniformState, frameState) {
- if (frameState.mode === SceneMode.SCENE3D) {
- computeSunPosition(frameState.time, sunPositionWC);
+ computeSunPosition(frameState.time, sunPositionWC);
- Cartesian3.normalize(sunPositionWC, uniformState._sunDirectionWC);
- Matrix3.multiplyByVector(uniformState._viewRotation, sunPositionWC, sunPositionScratch);
- Cartesian3.normalize(sunPositionScratch, uniformState._sunDirectionEC);
+ Cartesian3.normalize(sunPositionWC, uniformState._sunDirectionWC);
+ Matrix3.multiplyByVector(uniformState.getViewRotation3D(), sunPositionWC, sunPositionScratch);
+ Cartesian3.normalize(sunPositionScratch, uniformState._sunDirectionEC);
- // Pseudo direction for now just for lighting
- Cartesian3.negate(uniformState._sunDirectionEC, uniformState._moonDirectionEC);
- } else {
- // Made up direction for now just for lighting
-
- sunPositionWC.x = 1000000.0; // height
- sunPositionWC.y = -10000000.0; // x
- sunPositionWC.z = 0.0; // y
-
- Cartesian3.normalize(sunPositionWC, uniformState._sunDirectionWC);
- Matrix3.multiplyByVector(uniformState._viewRotation, sunPositionWC, sunPositionScratch);
- Cartesian3.normalize(sunPositionScratch, uniformState._sunDirectionEC);
-
- sunPositionWC.x = 1000000.0; // height
- sunPositionWC.y = 10000000.0; // x
- sunPositionWC.z = 0.0; // y
-
- Cartesian3.normalize(sunPositionWC, sunPositionScratch);
- Matrix3.multiplyByVector(uniformState._viewRotation, sunPositionScratch, sunPositionScratch);
- Cartesian3.normalize(sunPositionScratch, uniformState._moonDirectionEC);
- }
+ // Pseudo direction for now just for lighting
+ Cartesian3.negate(uniformState._sunDirectionEC, uniformState._moonDirectionEC);
}
/**
@@ -199,11 +220,21 @@ define([
* @param {FrameState} frameState The frameState to synchronize with.
*/
UniformState.prototype.update = function(frameState) {
+ this._mode = frameState.mode;
+ this._mapProjection = frameState.scene2D.projection;
+
var camera = frameState.camera;
setView(this, camera.getViewMatrix());
setInverseView(this, camera.getInverseViewMatrix());
- setCameraPosition(this, camera.getPositionWC());
+ setCamera(this, camera);
+
+ if (frameState.mode === SceneMode.SCENE2D) {
+ this._frustum2DWidth = camera.frustum.right - camera.frustum.left;
+ } else {
+ this._frustum2DWidth = 0.0;
+ }
+
setSunAndMoonDirections(this, frameState);
this._entireFrustum.x = camera.frustum.near;
@@ -292,6 +323,8 @@ define([
UniformState.prototype.setModel = function(matrix) {
Matrix4.clone(matrix, this._model);
+ this._modelView3DDirty = true;
+ this._inverseModelView3DDirty = true;
this._inverseModelDirty = true;
this._modelViewDirty = true;
this._modelViewRelativeToEyeDirty = true;
@@ -301,6 +334,8 @@ define([
this._modelViewInfiniteProjectionDirty = true;
this._normalDirty = true;
this._inverseNormalDirty = true;
+ this._normal3DDirty = true;
+ this._inverseNormal3DDirty = true;
this._encodedCameraPositionMCDirty = true;
};
@@ -329,15 +364,15 @@ define([
* @see UniformState#getModel
* @see czm_inverseModel
*/
- UniformState.prototype.getInverseModel = function() {
- if (this._inverseModelDirty) {
- this._inverseModelDirty = false;
+ UniformState.prototype.getInverseModel = function() {
+ if (this._inverseModelDirty) {
+ this._inverseModelDirty = false;
- this._model.inverse(this._inverseModel);
- }
+ this._model.inverse(this._inverseModel);
+ }
- return this._inverseModel;
- };
+ return this._inverseModel;
+ };
/**
* DOC_TBA
@@ -353,6 +388,30 @@ define([
};
/**
+ * Gets the 3D view matrix. In 3D mode, this is identical to {@link UniformState#getView},
+ * but in 2D and Columbus View it is a synthetic matrix based on the equivalent position
+ * of the camera in the 3D world.
+ *
+ * @memberof UniformState
+ *
+ * @return {Matrix4} The 3D view matrix.
+ *
+ * @see czm_view3D
+ */
+ UniformState.prototype.getView3D = function() {
+ if (this._view3DDirty) {
+ if (this._mode === SceneMode.SCENE3D) {
+ Matrix4.clone(this._view, this._view3D);
+ } else {
+ view2Dto3D(this._cameraPosition, this._cameraDirection, this._cameraRight, this._cameraUp, this._frustum2DWidth, this._mode, this._mapProjection, this._view3D);
+ }
+ Matrix4.getRotation(this._view3D, this._viewRotation3D);
+ this._view3DDirty = false;
+ }
+ return this._view3D;
+ };
+
+ /**
* Returns the 3x3 rotation matrix of the current view matrix ({@link UniformState#getView}).
*
* @memberof UniformState
@@ -367,6 +426,22 @@ define([
};
/**
+ * Returns the 3x3 rotation matrix of the current 3D view matrix ({@link UniformState#getView3D}).
+ *
+ * @memberof UniformState
+ *
+ * @return {Matrix3} The 3x3 rotation matrix of the current 3D view matrix.
+ *
+ * @see UniformState#getView3D
+ * @see czm_viewRotation3D
+ */
+ UniformState.prototype.getViewRotation3D = function() {
+ this.getView3D();
+ return this._viewRotation3D;
+ };
+
+
+ /**
* Returns the 4x4 inverse-view matrix that transforms from eye to world coordinates.
*
* @memberof UniformState
@@ -380,6 +455,26 @@ define([
};
/**
+ * Returns the 4x4 inverse-view matrix that transforms from eye to 3D world coordinates. In 3D mode, this is
+ * identical to {@link UniformState#getInverseView}, but in 2D and Columbus View it is a synthetic matrix
+ * based on the equivalent position of the camera in the 3D world.
+ *
+ * @memberof UniformState
+ *
+ * @return {Matrix4} The 4x4 inverse-view matrix that transforms from eye to 3D world coordinates.
+ *
+ * @see czm_inverseView3D
+ */
+ UniformState.prototype.getInverseView3D = function() {
+ if (this._inverseView3DDirty) {
+ Matrix4.inverseTransformation(this.getView3D(), this._inverseView3D);
+ Matrix4.getRotation(this._inverseView3D, this._inverseViewRotation3D);
+ this._inverseView3DDirty = false;
+ }
+ return this._inverseView3D;
+ };
+
+ /**
* Returns the 3x3 rotation matrix of the current inverse-view matrix ({@link UniformState#getInverseView}).
*
* @memberof UniformState
@@ -394,6 +489,21 @@ define([
};
/**
+ * Returns the 3x3 rotation matrix of the current 3D inverse-view matrix ({@link UniformState#getInverseView3D}).
+ *
+ * @memberof UniformState
+ *
+ * @return {Matrix3} The 3x3 rotation matrix of the current 3D inverse-view matrix.
+ *
+ * @see UniformState#getInverseView3D
+ * @see czm_inverseViewRotation3D
+ */
+ UniformState.prototype.getInverseViewRotation3D = function() {
+ this.getInverseView3D();
+ return this._inverseViewRotation3D;
+ };
+
+ /**
* DOC_TBA
*
* @memberof UniformState
@@ -453,11 +563,11 @@ define([
}
/**
- * DOC_TBA
+ * Gets the model-view matrix.
*
* @memberof UniformState
*
- * @return {Matrix4} DOC_TBA.
+ * @return {Matrix4} The model-view matrix.
*
* @see czm_modelView
*/
@@ -466,6 +576,29 @@ define([
return this._modelView;
};
+ function cleanModelView3D(uniformState) {
+ if (uniformState._modelView3DDirty) {
+ uniformState._modelView3DDirty = false;
+
+ Matrix4.multiply(uniformState.getView3D(), uniformState._model, uniformState._modelView3D);
+ }
+ }
+
+ /**
+ * Gets the 3D model-view matrix. In 3D mode, this is equivalent to {@link UniformState#getModelView}. In 2D and
+ * Columbus View, however, it is a synthetic matrix based on the equivalent position of the camera in the 3D world.
+ *
+ * @memberof UniformState
+ *
+ * @return {Matrix4} The 3D model-view matrix.
+ *
+ * @see czm_modelView3D
+ */
+ UniformState.prototype.getModelView3D = function() {
+ cleanModelView3D(this);
+ return this._modelView3D;
+ };
+
function cleanModelViewRelativeToEye(uniformState) {
if (uniformState._modelViewRelativeToEyeDirty) {
uniformState._modelViewRelativeToEyeDirty = false;
@@ -514,11 +647,11 @@ define([
}
/**
- * DOC_TBA
+ * Gets the inverse of the model-view matrix.
*
* @memberof UniformState
*
- * @return {Matrix4} DOC_TBA.
+ * @return {Matrix4} The inverse of the model-view matrix.
*
* @see czm_inverseModelView
*/
@@ -527,6 +660,29 @@ define([
return this._inverseModelView;
};
+ function cleanInverseModelView3D(uniformState) {
+ if (uniformState._inverseModelView3DDirty) {
+ uniformState._inverseModelView3DDirty = false;
+
+ Matrix4.inverse(uniformState.getModelView3D(), uniformState._inverseModelView3D);
+ }
+ }
+
+ /**
+ * Gets the inverse of the 3D model-view matrix. In 3D mode, this is equivalent to {@link UniformState#getInverseModelView}.
+ * In 2D and Columbus View, however, it is a synthetic matrix based on the equivalent position of the camera in the 3D world.
+ *
+ * @memberof UniformState
+ *
+ * @return {Matrix4} The inverse of the 3D model-view matrix.
+ *
+ * @see czm_inverseModelView3D
+ */
+ UniformState.prototype.getInverseModelView3D = function() {
+ cleanInverseModelView3D(this);
+ return this._inverseModelView3D;
+ };
+
function cleanViewProjection(uniformState) {
if (uniformState._viewProjectionDirty) {
uniformState._viewProjectionDirty = false;
@@ -627,11 +783,12 @@ define([
}
/**
- * DOC_TBA
+ * Gets a 3x3 normal transformation matrix that transforms normal vectors in model coordinates to
+ * eye coordinates.
*
* @memberof UniformState
*
- * @return {Matrix3} DOC_TBA.
+ * @return {Matrix3} The normal transformation matrix.
*
* @see czm_normal
*/
@@ -640,6 +797,32 @@ define([
return this._normal;
};
+ function cleanNormal3D(uniformState) {
+ if (uniformState._normal3DDirty) {
+ uniformState._normal3DDirty = false;
+
+ Matrix4.transpose(uniformState.getInverseModelView3D(), normalScratch);
+ Matrix4.getRotation(normalScratch, uniformState._normal3D);
+ }
+ }
+
+ /**
+ * Gets a 3x3 normal transformation matrix that transforms normal vectors in 3D model
+ * coordinates to eye coordinates. In 3D mode, this is identical to
+ * {@link UniformState#getNormal}, but in 2D and Columbus View it represents the normal transformation
+ * matrix as if the camera were at an equivalent location in 3D mode.
+ *
+ * @memberof UniformState
+ *
+ * @return {Matrix3} The normal transformation matrix.
+ *
+ * @see czm_normal3D
+ */
+ UniformState.prototype.getNormal3D = function() {
+ cleanNormal3D(this);
+ return this._normal3D;
+ };
+
function cleanInverseNormal(uniformState) {
if (uniformState._inverseNormalDirty) {
uniformState._inverseNormalDirty = false;
@@ -649,11 +832,12 @@ define([
}
/**
- * DOC_TBA
+ * Gets an inverse 3x3 normal transformation matrix that transforms normal vectors in model coordinates
+ * to eye coordinates.
*
* @memberof UniformState
*
- * @return {Matrix3} DOC_TBA.
+ * @return {Matrix3} The inverse normal transformation matrix.
*
* @see czm_inverseNormal
*/
@@ -662,6 +846,31 @@ define([
return this._inverseNormal;
};
+ function cleanInverseNormal3D(uniformState) {
+ if (uniformState._inverseNormal3DDirty) {
+ uniformState._inverseNormal3DDirty = false;
+
+ Matrix4.getRotation(uniformState.getInverseModelView3D(), uniformState._inverseNormal3D);
+ }
+ }
+
+ /**
+ * Gets an inverse 3x3 normal transformation matrix that transforms normal vectors in eye coordinates
+ * to 3D model coordinates. In 3D mode, this is identical to
+ * {@link UniformState#getInverseNormal}, but in 2D and Columbus View it represents the normal transformation
+ * matrix as if the camera were at an equivalent location in 3D mode.
+ *
+ * @memberof UniformState
+ *
+ * @return {Matrix3} The inverse normal transformation matrix.
+ *
+ * @see czm_inverseNormal3D
+ */
+ UniformState.prototype.getInverseNormal3D = function() {
+ cleanInverseNormal3D(this);
+ return this._inverseNormal3D;
+ };
+
/**
* Returns the near distance (<code>x</code>) and the far distance (<code>y</code>) of the frustum defined by the camera.
*
@@ -676,11 +885,12 @@ define([
};
/**
- * Returns a normalized vector to the sun in world coordinates at the current scene time.
+ * Returns a normalized vector to the sun in 3D world coordinates at the current scene time. Even in 2D or
+ * Columbus View mode, this returns the position of the sun in the 3D scene.
*
* @memberof UniformState
*
- * @return {Cartesian3} A normalized vector to the sun in world coordinates at the current scene time.
+ * @return {Cartesian3} A normalized vector to the sun in 3D world coordinates at the current scene time.
*
* @see czm_sunDirectionWC
*/
@@ -689,7 +899,9 @@ define([
};
/**
- * Returns a normalized vector to the sun in eye coordinates at the current scene time.
+ * Returns a normalized vector to the sun in eye coordinates at the current scene time. In 3D mode, this
+ * returns the actual vector from the camera position to the sun position. In 2D and Columbus View, it returns
+ * the vector from the equivalent 3D camera position to the position of the sun in the 3D scene.
*
* @memberof UniformState
*
@@ -702,7 +914,9 @@ define([
};
/**
- * Returns a normalized vector to the moon in eye coordinates at the current scene time.
+ * Returns a normalized vector to the moon in eye coordinates at the current scene time. In 3D mode, this
+ * returns the actual vector from the camera position to the moon position. In 2D and Columbus View, it returns
+ * the vector from the equivalent 3D camera position to the position of the moon in the 3D scene.
*
* @memberof UniformState
*
@@ -795,5 +1009,86 @@ define([
return 1.0;
};
+ var view2Dto3DPScratch = new Cartesian3();
+ var view2Dto3DRScratch = new Cartesian4();
+ var view2Dto3DUScratch = new Cartesian4();
+ var view2Dto3DDScratch = new Cartesian4();
+ var view2Dto3DCartographicScratch = new Cartographic();
+ var view2Dto3DCartesian3Scratch = new Cartesian3();
+ var view2Dto3DMatrix4Scratch = new Matrix4();
+
+ function view2Dto3D(position2D, direction2D, right2D, up2D, frustum2DWidth, mode, projection, result) {
+ // The camera position and directions are expressed in the 2D coordinate system where the Y axis is to the East,
+ // the Z axis is to the North, and the X axis is out of the map. Express them instead in the ENU axes where
+ // X is to the East, Y is to the North, and Z is out of the local horizontal plane.
+ var p = view2Dto3DPScratch;
+ p.x = position2D.y;
+ p.y = position2D.z;
+ p.z = position2D.x;
+
+ var r = view2Dto3DRScratch;
+ r.x = right2D.y;
+ r.y = right2D.z;
+ r.z = right2D.x;
+
+ var u = view2Dto3DUScratch;
+ u.x = up2D.y;
+ u.y = up2D.z;
+ u.z = up2D.x;
+
+ var d = view2Dto3DDScratch;
+ d.x = direction2D.y;
+ d.y = direction2D.z;
+ d.z = direction2D.x;
+
+ // In 2D, the camera height is always 12.7 million meters.
+ // The apparent height is equal to half the frustum width.
+ if (mode === SceneMode.SCENE2D) {
+ p.z = frustum2DWidth * 0.5;
+ }
+
+ // Compute the equivalent camera position in the real (3D) world.
+ // In 2D and Columbus View, the camera can travel outside the projection, and when it does so
+ // there's not really any corresponding location in the real world. So clamp the unprojected
+ // longitude and latitude to their valid ranges.
+ var cartographic = projection.unproject(p, view2Dto3DCartographicScratch);
+ cartographic.longitude = CesiumMath.clamp(cartographic.longitude, -Math.PI, Math.PI);
+ cartographic.latitude = CesiumMath.clamp(cartographic.latitude, -CesiumMath.PI_OVER_TWO, CesiumMath.PI_OVER_TWO);
+ var ellipsoid = projection.getEllipsoid();
+ var position3D = ellipsoid.cartographicToCartesian(cartographic, view2Dto3DCartesian3Scratch);
+
+ // Compute the rotation from the local ENU at the real world camera position to the fixed axes.
+ var enuToFixed = Transforms.eastNorthUpToFixedFrame(position3D, ellipsoid, view2Dto3DMatrix4Scratch);
+
+ // Transform each camera direction to the fixed axes.
+ enuToFixed.multiplyByVector(r, r);
+ enuToFixed.multiplyByVector(u, u);
+ enuToFixed.multiplyByVector(d, d);
+
+ // Compute the view matrix based on the new fixed-frame camera position and directions.
+ if (typeof result === 'undefined') {
+ result = new Matrix4();
+ }
+
+ result[0] = r.x;
+ result[1] = u.x;
+ result[2] = -d.x;
+ result[3] = 0.0;
+ result[4] = r.y;
+ result[5] = u.y;
+ result[6] = -d.y;
+ result[7] = 0.0;
+ result[8] = r.z;
+ result[9] = u.z;
+ result[10] = -d.z;
+ result[11] = 0.0;
+ result[12] = -Cartesian3.dot(r, position3D);
+ result[13] = -Cartesian3.dot(u, position3D);
+ result[14] = Cartesian3.dot(d, position3D);
+ result[15] = 1.0;
+
+ return result;
+ }
+
return UniformState;
});
View
237 Source/Scene/ArcGisImageServerTerrainProvider.js
@@ -0,0 +1,237 @@
+/*global define*/
+define([
+ '../Core/defaultValue',
+ '../Core/loadImage',
+ '../Core/getImagePixels',
+ '../Core/throttleRequestByServer',
+ '../Core/writeTextToCanvas',
+ '../Core/DeveloperError',
+ '../Core/Math',
+ '../Core/Ellipsoid',
+ '../Core/Event',
+ './TerrainProvider',
+ './GeographicTilingScheme',
+ './HeightmapTerrainData',
+ '../ThirdParty/when'
+ ], function(
+ defaultValue,
+ loadImage,
+ getImagePixels,
+ throttleRequestByServer,
+ writeTextToCanvas,
+ DeveloperError,
+ CesiumMath,
+ Ellipsoid,
+ Event,
+ TerrainProvider,
+ GeographicTilingScheme,
+ HeightmapTerrainData,
+ when) {
+ "use strict";
+
+ /**
+ * A {@link TerrainProvider} that produces terrain geometry by tessellating height maps
+ * retrieved from an ArcGIS ImageServer.
+ *
+ * @alias ArcGisImageServerTerrainProvider
+ * @constructor
+ *
+ * @param {String} description.url The URL of the ArcGIS ImageServer service.
+ * @param {String} [description.token] The authorization token to use to connect to the service.
+ * @param {Object} [description.proxy] A proxy to use for requests. This object is expected to have a getURL function which returns the proxied URL, if needed.
+ * @param {TilingScheme} [description.tilingScheme] The tiling scheme specifying how the terrain