diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 000000000000..85fb445c2db3 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,21 @@ +{ + // Use IntelliSense to learn about possible Node.js debug attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "type": "node", + "request": "launch", + "name": "Launch Program", + "program": "${workspaceRoot}\\server.js", + "cwd": "${workspaceRoot}" + }, + { + "type": "node", + "request": "attach", + "name": "Attach to Process", + "port": 5858 + } + ] +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 000000000000..f04ffafe314e --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,30 @@ +// Cesium project settings for VSCode. +{ + "files.exclude": { + "**/.git": true, + ".idea": true, + ".metadata": true, + "Build": true, + "Instrumented": true, + "**/Cesium-*.zip": true, + "**/cesium-*.tgz": true, + "**/.DS_Store": true, + "**/Thumbs.db": true, + + "Apps/Sandcastle/jsHintOption?.js": true, + "Apps/Sandcastle/gallery/gallery-inde?.js": true, + + "Source/Cesiu?.js": true, + "Source/Shaders/**/*.js": true, + + "Specs/SpecLis?.js": true, + "node_modules": true, + "npm-debu?.log": true + }, + "files.trimTrailingWhitespace": true, + "files.insertFinalNewline": true, + "editor.insertSpaces": true, + "editor.tabSize": 4, + "editor.detectIndentation": false, + "jshint.enable": true +} diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 000000000000..4befb021f0ca --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,32 @@ +{ + // See https://go.microsoft.com/fwlink/?LinkId=733558 + // for the documentation about the tasks.json format + "version": "0.1.0", + "command": "gulp", + "isShellCommand": true, + "args": [ + "--no-color" + ], + "tasks": [ + { + "taskName": "build", + "args": [], + "isBuildCommand": true, + "isBackground": false, + "problemMatcher": [ + "$lessCompile", + "$tsc", + "$jshint" + ] + }, + { + "taskName": "test", + "args": [], + "isTestCommand": true + }, + { + "taskName": "build-watch", + "isBackground": true + } + ] +} diff --git a/Apps/Sandcastle/gallery/Labels.html b/Apps/Sandcastle/gallery/Labels.html index 2c4b4b4b7f96..aaf32e0826d2 100644 --- a/Apps/Sandcastle/gallery/Labels.html +++ b/Apps/Sandcastle/gallery/Labels.html @@ -109,6 +109,18 @@ }); } +function scaleByDistance() { + Sandcastle.declare(scaleByDistance); + + viewer.entities.add({ + position : Cesium.Cartesian3.fromDegrees(-75.1641667, 39.9522222), + label : { + text : 'Philadelphia', + scaleByDistance : new Cesium.NearFarScalar(1.5e2, 2.0, 1.5e7, 0.5) + } + }); +} + Sandcastle.addToolbarMenu([{ text : 'Add label', onselect : function() { @@ -139,6 +151,12 @@ fadeByDistance(); Sandcastle.highlight(fadeByDistance); } +}, { + text : 'Scale label by distance', + onselect : function() { + scaleByDistance(); + Sandcastle.highlight(scaleByDistance); + } }]); Sandcastle.reset = function() { diff --git a/Apps/Sandcastle/gallery/Picking.html b/Apps/Sandcastle/gallery/Picking.html index 00e82620e44f..a976f27363ac 100644 --- a/Apps/Sandcastle/gallery/Picking.html +++ b/Apps/Sandcastle/gallery/Picking.html @@ -174,17 +174,16 @@ } }); - var sceneModeWarningPosted = false; - // Mouse over the globe to see the cartographic position handler = new Cesium.ScreenSpaceEventHandler(scene.canvas); handler.setInputAction(function(movement) { + var foundPosition = false; var scene = viewer.scene; - var pickedObject = scene.pick(movement.endPosition); - if (scene.pickPositionSupported && Cesium.defined(pickedObject) && pickedObject.id === modelEntity) { - if (scene.mode === Cesium.SceneMode.SCENE3D) { + if (scene.mode !== Cesium.SceneMode.MORPHING) { + var pickedObject = scene.pick(movement.endPosition); + if (scene.pickPositionSupported && Cesium.defined(pickedObject) && pickedObject.id === modelEntity) { var cartesian = viewer.scene.pickPosition(movement.endPosition); if (Cesium.defined(cartesian)) { @@ -200,14 +199,10 @@ '\nLat: ' + (' ' + latitudeString).slice(-7) + '\u00B0' + '\nAlt: ' + (' ' + heightString).slice(-7) + 'm'; - var camera = scene.camera; - labelEntity.label.eyeOffset = new Cesium.Cartesian3(0.0, 0.0, camera.frustum.near * 1.5 - Cesium.Cartesian3.distance(cartesian, camera.position)); + labelEntity.label.eyeOffset = new Cesium.Cartesian3(0.0, 0.0, -cartographic.height * (scene.mode === Cesium.SceneMode.SCENE2D ? 1.5 : 1.0)); foundPosition = true; } - } else if (!sceneModeWarningPosted) { - sceneModeWarningPosted = true; - console.log("pickPosition is currently only supported in 3D mode."); } } diff --git a/CHANGES.md b/CHANGES.md index eed35940b2bb..b5e58bc021d5 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -12,28 +12,41 @@ Change Log * `Cesium3DTilesInspector` * `Cesium3DTilesInspectorViewModel` +### 1.32 - 2017-04-03 + +* Added the event `Viewer.trackedEntityChanged`, which is raised when the value of `viewer.trackedEntity` changes. [#5060](https://github.com/AnalyticalGraphicsInc/cesium/pull/5060) +* Fix crunch compressed textures in IE11. [#5057](https://github.com/AnalyticalGraphicsInc/cesium/pull/5057) + ### 1.31 - 2017-03-01 * Deprecated - * The function `Quaternion.fromHeadingPitchRoll(heading, pitch, roll,result)` will be removed in 1.33. Use `Quaternion.fromHeadingPitchRoll(hpr,result)` instead where hpr is a HeadingPitchRoll. - * The function `Transforms.headingPitchRollToFixedFrame(origin, headingPitchRoll, ellipsoid, result)` will be removed in 1.33. Use `Transforms.headingPitchRollToFixedFrame(origin, headingPitchRoll, ellipsoid, fixedFrameTransform, result)` instead where fixedFrameTransform is a a 4x4 transformation matrix (see Transforms.localFrameToFixedFrameGenerator). - * The function `Transforms.headingPitchRollQuaternion(origin, headingPitchRoll, ellipsoid, result)` will be removed in 1.33. Use `Transforms.headingPitchRollQuaternion(origin, headingPitchRoll, ellipsoid, fixedFrameTransform, result)` instead where fixedFrameTransform is a a 4x4 transformation matrix (see Transforms.localFrameToFixedFrameGenerator). - * `ArcGisImageServerTerrainProvider` will be removed in 1.32 due to missing TIFF support in web browsers. + * The function `Quaternion.fromHeadingPitchRoll(heading, pitch, roll, result)` will be removed in 1.33. Use `Quaternion.fromHeadingPitchRoll(hpr, result)` instead where `hpr` is a `HeadingPitchRoll`. [#4896](https://github.com/AnalyticalGraphicsInc/cesium/pull/4896) + * The function `Transforms.headingPitchRollToFixedFrame(origin, headingPitchRoll, ellipsoid, result)` will be removed in 1.33. Use `Transforms.headingPitchRollToFixedFrame(origin, headingPitchRoll, ellipsoid, fixedFrameTransform, result)` instead where `fixedFrameTransform` is a a 4x4 transformation matrix (see `Transforms.localFrameToFixedFrameGenerator`). [#4896](https://github.com/AnalyticalGraphicsInc/cesium/pull/4896) + * The function `Transforms.headingPitchRollQuaternion(origin, headingPitchRoll, ellipsoid, result)` will be removed in 1.33. Use `Transforms.headingPitchRollQuaternion(origin, headingPitchRoll, ellipsoid, fixedFrameTransform, result)` instead where `fixedFrameTransform` is a a 4x4 transformation matrix (see `Transforms.localFrameToFixedFrameGenerator`). [#4896](https://github.com/AnalyticalGraphicsInc/cesium/pull/4896) + * `ArcGisImageServerTerrainProvider` will be removed in 1.32 due to missing TIFF support in web browsers. [#4981](https://github.com/AnalyticalGraphicsInc/cesium/pull/4981) * Breaking changes * Corrected spelling of `Color.FUCHSIA` from `Color.FUSCHIA`. [#4977](https://github.com/AnalyticalGraphicsInc/cesium/pull/4977) -* Added support to `DebugCameraPrimitive` to draw multifrustum planes. The attribute `debugShowFrustumPlanes` of `Scene` and `frustumPlanes` of `CesiumInspector` toggles this. `FrameState` has been augmented to include `frustumSplits` which is a `Number[]` of the near/far planes of the camera frustums. -* Enable rendering `GroundPrimitives` on hardware without the `EXT_frag_depth` extension; however, this could cause artifacts for certain viewing angles. -* Always outline KML line extrusions so that they show up properly in 2D and other straight down views. + * The enums `MIDDLE_DOUBLE_CLICK` and `RIGHT_DOUBLE_CLICK` from `ScreenSpaceEventType` have been removed. [#5052](https://github.com/AnalyticalGraphicsInc/cesium/pull/5052) + * Removed the function `GeometryPipeline.computeBinormalAndTangent`. Use `GeometryPipeline.computeTangentAndBitangent` instead. [#5053](https://github.com/AnalyticalGraphicsInc/cesium/pull/5053) + * Removed the `url` and `key` properties from `GeocoderViewModel`. [#5056](https://github.com/AnalyticalGraphicsInc/cesium/pull/5056) + * `BingMapsGeocoderServices` now requires `options.scene`. [#5056](https://github.com/AnalyticalGraphicsInc/cesium/pull/5056) * Added compressed texture support. [#4758](https://github.com/AnalyticalGraphicsInc/cesium/pull/4758) * glTF models and imagery layers can now reference [KTX](https://www.khronos.org/opengles/sdk/tools/KTX/) textures and textures compressed with [crunch](https://github.com/BinomialLLC/crunch). * Added `loadKTX`, to load KTX textures, and `loadCRN` to load crunch compressed textures. * Added new `PixelFormat` and `WebGLConstants` enums from WebGL extensions `WEBGL_compressed_s3tc`, `WEBGL_compressed_texture_pvrtc`, and `WEBGL_compressed_texture_etc1`. * Added `CompressedTextureBuffer`. -* Improved `RectangleGeometry` by skipping unecessary logic in the code [#4948](https://github.com/AnalyticalGraphicsInc/cesium/pull/4948) -* Added `Transforms.localFrameToFixedFrameGenerator` to generate a function that computes a 4x4 transformation matrix from a local reference frame to fixed reference frame. +* Added support for `Scene.pickPosition` in Columbus view and 2D. [#4990](https://github.com/AnalyticalGraphicsInc/cesium/pull/4990) +* Added support for depth picking translucent primitives when `Scene.pickTranslucentDepth` is `true`. [#4979](https://github.com/AnalyticalGraphicsInc/cesium/pull/4979) * Fixed an issue where the camera would zoom past an object and flip to the other side of the globe. [#4967](https://github.com/AnalyticalGraphicsInc/cesium/pull/4967) and [#4982](https://github.com/AnalyticalGraphicsInc/cesium/pull/4982) -* Fixed exception in 2D in certain cases with polylines when rotating the map. [#4619](https://github.com/AnalyticalGraphicsInc/cesium/issues/4619) +* Enable rendering `GroundPrimitives` on hardware without the `EXT_frag_depth` extension; however, this could cause artifacts for certain viewing angles. [#4930](https://github.com/AnalyticalGraphicsInc/cesium/pull/4930) +* Added `Transforms.localFrameToFixedFrameGenerator` to generate a function that computes a 4x4 transformation matrix from a local reference frame to fixed reference frame. [#4896](https://github.com/AnalyticalGraphicsInc/cesium/pull/4896) +* Added `Label.scaleByDistance` to control minimum/maximum label size based on distance from the camera. [#5019](https://github.com/AnalyticalGraphicsInc/cesium/pull/5019) +* Added support to `DebugCameraPrimitive` to draw multifrustum planes. The attribute `debugShowFrustumPlanes` of `Scene` and `frustumPlanes` of `CesiumInspector` toggle this. [#4932](https://github.com/AnalyticalGraphicsInc/cesium/pull/4932) +* Added fix to always outline KML line extrusions so that they show up properly in 2D and other straight down views. [#4961](https://github.com/AnalyticalGraphicsInc/cesium/pull/4961) +* Improved `RectangleGeometry` by skipping unnecessary logic in the code. [#4948](https://github.com/AnalyticalGraphicsInc/cesium/pull/4948) +* Fixed exception for polylines in 2D when rotating the map. [#4619](https://github.com/AnalyticalGraphicsInc/cesium/issues/4619) * Fixed an issue with constant `VertexArray` attributes not being set correctly. [#4995](https://github.com/AnalyticalGraphicsInc/cesium/pull/4995) +* Added the event `Viewer.selectedEntityChanged`, which is raised when the value of `viewer.selectedEntity` changes. [#5043](https://github.com/AnalyticalGraphicsInc/cesium/pull/5043) ### 1.30 - 2017-02-01 diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 681280e6a60c..a6503618995e 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -132,3 +132,4 @@ See [CONTRIBUTING.md](CONTRIBUTING.md) for details on how to contribute to Cesiu * [Jane Minghui Guo](https://github.com/Jane-Of-Art) * [Prasanna Natarajan](https://github.com/PrasannaNatarajan) * [Joseph Klinger](https://github.com/klingerj) +* [Grace Lee](https://github.com/glee2244) diff --git a/Documentation/Contributors/README.md b/Documentation/Contributors/README.md index 11ba10f61036..d783cee68e4a 100644 --- a/Documentation/Contributors/README.md +++ b/Documentation/Contributors/README.md @@ -5,6 +5,7 @@ * **IDEs** - use any IDE you want for Cesium development. Most contributors use WebStorm (commercial) or Eclipse (open source). * [WebStorm Guide](WebStormGuide/README.md) - How to set up WebStorm. * [Eclipse Guide](EclipseGuide/README.md) - How to set up Eclipse. + * [VSCode Guide](VSCodeGuide/README.md) - How to set up VSCode. * [Coding Guide](CodingGuide/README.md) - JavaScript and GLSL coding conventions and best practices for design, maintainability, and performance. * [Testing Guide](TestingGuide/README.md) - How to run the Cesium tests and write awesome tests. * [Documentation Guide](DocumentationGuide/README.md) - How to write great reference documentation. diff --git a/Documentation/Contributors/VSCodeGuide/README.md b/Documentation/Contributors/VSCodeGuide/README.md new file mode 100644 index 000000000000..61cedd85f973 --- /dev/null +++ b/Documentation/Contributors/VSCodeGuide/README.md @@ -0,0 +1,76 @@ +# VSCode Guide + +1. Install [VSCode](https://code.visualstudio.com/). + +2. If you haven't already, install `gulp-cli` globally, with +`npm install -g gulp-cli` from a bash prompt. This does not require +administrative rights, and places a `gulp` shim into your path that will +invoke a copy of gulp from the local project folder. This is needed for +VSCode's build tasks to work with Cesium. + +3. Click `File -> Open Folder...` and open the Cesium root folder. + +## Shell Integration (optional) + +VSCode has an integrated shell, exposed on Windows by pressing CTRL-\` (CTRL-backtick). +You may want to switch this to be a git bash shell by default. If so, click +File -> Preferences -> Settings... and enter `integrated.shell` into the search +box. Choose the appropriate key for your operating system, for example +`terminal.integrated.shell.windows` for Windows, and click the edit icon. +The default setting will be copied to your user settings. The default for +Windows is `"C:\\Windows\\system32\\cmd.exe"`. Change this to point to your +git bash install. For example: + +``` +{ + "terminal.integrated.shell.windows": "C:\\Program Files\\Git\\bin\\bash.exe" +} +``` + +Note that on Windows, the git bash desktop icon points at a different exe file, +one that forces a separate (non-integrated) window to pop open outside of VSCode. +Make sure you are pointed at the correct exe as shown above, with Git 2.0.0 or +higher installed, to get the correct integrated shell behavior. + +## VSCode Plugins (mostly optional) + +Click on the extensions icon, or press CTRL-SHIFT-X to see the list of installed +VSCode extensions. While we don't officially endorse any particular 3rd-party +plugin, there are some that appear to be quite useful to Cesium. Just enter +the desired plugin name in the search box and click install. You will need to +restart VSCode after you are done installing plugins. + +* **jshint** by Dirk Baeumer -- This plugin picks up on Cesium's own jsHint settings, +and will warn of any violations. The Cesium main repository should pass jsHint +using the Cesium jsHint settings with no warnings and no errors. Proposed +contributions to Cesium that introduce jsHint warnings will need to be corrected +before they are accepted. + +* **Shader languages support for VS Code** by slevesque -- This plugin provides +syntax highlighting for Cesium's shader code. + +* **Prettify JSON** by Mohsen Azimi -- This seems generally useful. + +## VSCode Tasks and Files + +You can launch any of Cesium's npm tasks from within VSCode by pressing +CTRL-P and typing `task ` (with a trailing space). Autocomplete will +offer the list of npm tasks for you to run. The first time you do this, +allow a moment for it to read the available tasks from the gulpfile. + +You can also jump to any source file with the same CTRL-P keypress +followed by the name of the file. + +## Building Cesium + +Cesium has a number of GLSL shaders and auto-generated files that must be +built before Cesium can be used. The simplest way in VSCode is to type +`CTRL-P` `task build` to trigger a single build. + +You can also start the build watcher with `CTRL-P` `task build-watch`. This +leaves a watcher running until you exit VSCode, that will automatically +update any shaders or auto-generated files to reflect changes to Cesium as +you save them. + +Keep in mind that `build-watch` will quietly terminate when +you quit VSCode, so should be restarted manually on next launch. diff --git a/README.md b/README.md index d75994100c97..7b1531411335 100644 --- a/README.md +++ b/README.md @@ -46,6 +46,10 @@ We appreciate attribution by including the Cesium logo and link in your app. ### Demos ###
+
+
+
+
@@ -94,7 +98,6 @@ We appreciate attribution by including the Cesium logo and link in your app.
-
@@ -134,7 +137,6 @@ We appreciate attribution by including the Cesium logo and link in your app.
-
@@ -143,7 +145,6 @@ We appreciate attribution by including the Cesium logo and link in your app.
-
diff --git a/Source/Core/BingMapsGeocoderService.js b/Source/Core/BingMapsGeocoderService.js
index 7f9c4fc4ced8..e4130d8ed61a 100644
--- a/Source/Core/BingMapsGeocoderService.js
+++ b/Source/Core/BingMapsGeocoderService.js
@@ -17,7 +17,7 @@ define([
Rectangle) {
'use strict';
- var url = 'https://dev.virtualearth.net/REST/v1/Locations';
+ var url = 'https://dev.virtualearth.net/REST/v1/Locations';
/**
* Provides geocoding through Bing Maps.
@@ -25,12 +25,26 @@ define([
* @constructor
*
* @param {Object} options Object with the following properties:
+ * @param {String} options.scene The scene
* @param {String} [options.key] A key to use with the Bing Maps geocoding service
*/
function BingMapsGeocoderService(options) {
options = defaultValue(options, defaultValue.EMPTY_OBJECT);
- this._url = 'https://dev.virtualearth.net/REST/v1/Locations';
- this._key = BingMapsApi.getKey(options.key);
+ //>>includeStart('debug', pragmas.debug);
+ if (!defined(options.scene)) {
+ throw new DeveloperError('options.scene is required.');
+ }
+ //>>includeEnd('debug');
+
+ var key = options.key;
+ this._key = BingMapsApi.getKey(key);
+
+ if (defined(key)) {
+ var errorCredit = BingMapsApi.getErrorCredit(key);
+ if (defined(errorCredit)) {
+ options.scene._frameState.creditDisplay.addDefaultCredit(errorCredit);
+ }
+ }
}
defineProperties(BingMapsGeocoderService.prototype, {
@@ -42,7 +56,7 @@ define([
*/
url : {
get : function () {
- return this._url;
+ return url;
}
},
diff --git a/Source/Core/CesiumTerrainProvider.js b/Source/Core/CesiumTerrainProvider.js
index 90e78b5370bc..6f19508b7929 100644
--- a/Source/Core/CesiumTerrainProvider.js
+++ b/Source/Core/CesiumTerrainProvider.js
@@ -19,11 +19,9 @@ define([
'./Math',
'./OrientedBoundingBox',
'./QuantizedMeshTerrainData',
- './Rectangle',
'./Request',
'./RequestScheduler',
'./RequestType',
- './RuntimeError',
'./TerrainProvider',
'./TileAvailability',
'./TileProviderError'
@@ -47,11 +45,9 @@ define([
CesiumMath,
OrientedBoundingBox,
QuantizedMeshTerrainData,
- Rectangle,
Request,
RequestScheduler,
RequestType,
- RuntimeError,
TerrainProvider,
TileAvailability,
TileProviderError) {
diff --git a/Source/Core/CircleGeometry.js b/Source/Core/CircleGeometry.js
index ddcf17d57532..4a3e87dfdaf6 100644
--- a/Source/Core/CircleGeometry.js
+++ b/Source/Core/CircleGeometry.js
@@ -5,7 +5,6 @@ define([
'./defaultValue',
'./defined',
'./defineProperties',
- './DeveloperError',
'./EllipseGeometry',
'./Ellipsoid',
'./VertexFormat'
@@ -15,7 +14,6 @@ define([
defaultValue,
defined,
defineProperties,
- DeveloperError,
EllipseGeometry,
Ellipsoid,
VertexFormat) {
diff --git a/Source/Core/CircleOutlineGeometry.js b/Source/Core/CircleOutlineGeometry.js
index 9a6aab62dc12..fa5e78ade493 100644
--- a/Source/Core/CircleOutlineGeometry.js
+++ b/Source/Core/CircleOutlineGeometry.js
@@ -4,7 +4,6 @@ define([
'./Check',
'./defaultValue',
'./defined',
- './DeveloperError',
'./EllipseOutlineGeometry',
'./Ellipsoid'
], function(
@@ -12,7 +11,6 @@ define([
Check,
defaultValue,
defined,
- DeveloperError,
EllipseOutlineGeometry,
Ellipsoid) {
'use strict';
diff --git a/Source/Core/GeocoderService.js b/Source/Core/GeocoderService.js
index c15982213a0f..08bbdb3f6d66 100644
--- a/Source/Core/GeocoderService.js
+++ b/Source/Core/GeocoderService.js
@@ -1,9 +1,7 @@
/*global define*/
define([
- './defineProperties',
'./DeveloperError'
], function(
- defineProperties,
DeveloperError) {
'use strict';
diff --git a/Source/Core/GeometryPipeline.js b/Source/Core/GeometryPipeline.js
index ed8427ec4602..b689f6e8ecc4 100644
--- a/Source/Core/GeometryPipeline.js
+++ b/Source/Core/GeometryPipeline.js
@@ -10,7 +10,6 @@ define([
'./ComponentDatatype',
'./defaultValue',
'./defined',
- './deprecationWarning',
'./DeveloperError',
'./EncodedCartesian3',
'./GeographicProjection',
@@ -37,7 +36,6 @@ define([
ComponentDatatype,
defaultValue,
defined,
- deprecationWarning,
DeveloperError,
EncodedCartesian3,
GeographicProjection,
@@ -1173,20 +1171,28 @@ define([
for (i = 0; i < numVertices; i++) {
var i3 = i * 3;
vertexNormalData = normalsPerVertex[i];
+ Cartesian3.clone(Cartesian3.ZERO, normal);
if (vertexNormalData.count > 0) {
- Cartesian3.clone(Cartesian3.ZERO, normal);
for (j = 0; j < vertexNormalData.count; j++) {
Cartesian3.add(normal, normalsPerTriangle[normalIndices[vertexNormalData.indexOffset + j]], normal);
}
- Cartesian3.normalize(normal, normal);
- normalValues[i3] = normal.x;
- normalValues[i3 + 1] = normal.y;
- normalValues[i3 + 2] = normal.z;
- } else {
- normalValues[i3] = 0.0;
- normalValues[i3 + 1] = 0.0;
- normalValues[i3 + 2] = 1.0;
+
+ // We can run into an issue where a vertex is used with 2 primitives that have opposite winding order.
+ if (Cartesian3.equalsEpsilon(Cartesian3.ZERO, normal, CesiumMath.EPSILON10)) {
+ Cartesian3.clone(normalsPerTriangle[normalIndices[vertexNormalData.indexOffset]], normal);
+ }
}
+
+ // We end up with a zero vector probably because of a degenerate triangle
+ if (Cartesian3.equalsEpsilon(Cartesian3.ZERO, normal, CesiumMath.EPSILON10)) {
+ // Default to (0,0,1)
+ normal.z = 1.0;
+ }
+
+ Cartesian3.normalize(normal, normal);
+ normalValues[i3] = normal.x;
+ normalValues[i3 + 1] = normal.y;
+ normalValues[i3 + 2] = normal.z;
}
geometry.attributes.normal = new GeometryAttribute({
@@ -1344,34 +1350,6 @@ define([
return geometry;
};
- /**
- * Computes per-vertex binormal and tangents for a geometry containing TRIANGLES
.
- * The result is new binormal
and tangent
attributes added to the geometry.
- * This assumes a counter-clockwise winding order.
- *
- * Based on Computing Tangent Space Basis Vectors - * for an Arbitrary Mesh by Eric Lengyel. - *
- * - * @param {Geometry} geometry The geometry to modify. - * @returns {Geometry} The modifiedgeometry
argument with the computed binormal
and tangent
attributes.
- *
- * @exception {DeveloperError} geometry.indices length must be greater than 0 and be a multiple of 3.
- * @exception {DeveloperError} geometry.primitiveType must be {@link PrimitiveType.TRIANGLES}.
- *
- * @example
- * Cesium.GeometryPipeline.computeBinormalAndTangent(geometry);
- *
- * @see GeometryPipeline.computeTangentAndBitangent
- */
- GeometryPipeline.computeBinormalAndTangent = function(geometry) {
- deprecationWarning('computeBinormalAndTangent', 'computeBinormalAndTangent was deprecated in 1.30. It will be removed in 1.31. Use a computeTangentAndBitangent.');
- GeometryPipeline.computeTangentAndBitangent(geometry);
- geometry.attributes.binormal = geometry.attributes.bitangent;
-
- return geometry;
- };
-
var scratchCartesian2 = new Cartesian2();
var toEncode1 = new Cartesian3();
var toEncode2 = new Cartesian3();
diff --git a/Source/Core/Matrix2.js b/Source/Core/Matrix2.js
index 86f0e3597a9d..b7e717685487 100644
--- a/Source/Core/Matrix2.js
+++ b/Source/Core/Matrix2.js
@@ -5,7 +5,6 @@ define([
'./defaultValue',
'./defined',
'./defineProperties',
- './DeveloperError',
'./freezeObject'
], function(
Cartesian2,
@@ -13,7 +12,6 @@ define([
defaultValue,
defined,
defineProperties,
- DeveloperError,
freezeObject) {
'use strict';
diff --git a/Source/Core/Matrix4.js b/Source/Core/Matrix4.js
index 67de77b5a76b..13e4ba5d9c69 100644
--- a/Source/Core/Matrix4.js
+++ b/Source/Core/Matrix4.js
@@ -6,7 +6,6 @@ define([
'./defaultValue',
'./defined',
'./defineProperties',
- './DeveloperError',
'./freezeObject',
'./Math',
'./Matrix3',
@@ -18,7 +17,6 @@ define([
defaultValue,
defined,
defineProperties,
- DeveloperError,
freezeObject,
CesiumMath,
Matrix3,
diff --git a/Source/Core/Quaternion.js b/Source/Core/Quaternion.js
index cd19446e2fc8..8eac4c7de49c 100644
--- a/Source/Core/Quaternion.js
+++ b/Source/Core/Quaternion.js
@@ -5,7 +5,6 @@ define([
'./defaultValue',
'./defined',
'./deprecationWarning',
- './DeveloperError',
'./FeatureDetection',
'./freezeObject',
'./HeadingPitchRoll',
@@ -17,7 +16,6 @@ define([
defaultValue,
defined,
deprecationWarning,
- DeveloperError,
FeatureDetection,
freezeObject,
HeadingPitchRoll,
diff --git a/Source/Core/Rectangle.js b/Source/Core/Rectangle.js
index 24d3efaf2c40..0f451aae3d2e 100644
--- a/Source/Core/Rectangle.js
+++ b/Source/Core/Rectangle.js
@@ -5,7 +5,6 @@ define([
'./defaultValue',
'./defined',
'./defineProperties',
- './DeveloperError',
'./Ellipsoid',
'./freezeObject',
'./Math'
@@ -15,7 +14,6 @@ define([
defaultValue,
defined,
defineProperties,
- DeveloperError,
Ellipsoid,
freezeObject,
CesiumMath) {
diff --git a/Source/Core/RectangleGeometry.js b/Source/Core/RectangleGeometry.js
index 58738ccf7c7e..034e8d4fa45d 100644
--- a/Source/Core/RectangleGeometry.js
+++ b/Source/Core/RectangleGeometry.js
@@ -18,7 +18,6 @@ define([
'./GeometryPipeline',
'./IndexDatatype',
'./Math',
- './Matrix2',
'./Matrix3',
'./PolygonPipeline',
'./PrimitiveType',
@@ -45,7 +44,6 @@ define([
GeometryPipeline,
IndexDatatype,
CesiumMath,
- Matrix2,
Matrix3,
PolygonPipeline,
PrimitiveType,
diff --git a/Source/Core/ScreenSpaceEventHandler.js b/Source/Core/ScreenSpaceEventHandler.js
index a22670eb7688..ba63e2e20f02 100644
--- a/Source/Core/ScreenSpaceEventHandler.js
+++ b/Source/Core/ScreenSpaceEventHandler.js
@@ -4,7 +4,6 @@ define([
'./Cartesian2',
'./defaultValue',
'./defined',
- './deprecationWarning',
'./destroyObject',
'./DeveloperError',
'./FeatureDetection',
@@ -16,7 +15,6 @@ define([
Cartesian2,
defaultValue,
defined,
- deprecationWarning,
destroyObject,
DeveloperError,
FeatureDetection,
@@ -272,10 +270,6 @@ define([
var screenSpaceEventType;
if (button === MouseButton.LEFT) {
screenSpaceEventType = ScreenSpaceEventType.LEFT_DOUBLE_CLICK;
- } else if (button === MouseButton.MIDDLE) {
- screenSpaceEventType = ScreenSpaceEventType.MIDDLE_DOUBLE_CLICK;
- } else if (button === MouseButton.RIGHT) {
- screenSpaceEventType = ScreenSpaceEventType.RIGHT_DOUBLE_CLICK;
} else {
return;
}
@@ -686,14 +680,6 @@ define([
registerListeners(this);
}
- function checkForDoubleClick(type) {
- if (type === ScreenSpaceEventType.MIDDLE_DOUBLE_CLICK) {
- deprecationWarning('MIDDLE_DOUBLE_CLICK', 'ScreenSpaceEventType.MIDDLE_DOUBLE_CLICK was deprecated in Cesium 1.30. It will be removed in 1.31.');
- } else if (type === ScreenSpaceEventType.RIGHT_DOUBLE_CLICK) {
- deprecationWarning('RIGHT_DOUBLE_CLICK', 'ScreenSpaceEventType.RIGHT_DOUBLE_CLICK was deprecated in Cesium 1.30. It will be removed in 1.31.');
- }
- }
-
/**
* Set a function to be executed on an input event.
*
@@ -715,8 +701,6 @@ define([
}
//>>includeEnd('debug');
- checkForDoubleClick(type);
-
var key = getInputEventKey(type, modifier);
this._inputEvents[key] = action;
};
@@ -738,8 +722,6 @@ define([
}
//>>includeEnd('debug');
- checkForDoubleClick(type);
-
var key = getInputEventKey(type, modifier);
return this._inputEvents[key];
};
@@ -761,8 +743,6 @@ define([
}
//>>includeEnd('debug');
- checkForDoubleClick(type);
-
var key = getInputEventKey(type, modifier);
delete this._inputEvents[key];
};
diff --git a/Source/Core/ScreenSpaceEventType.js b/Source/Core/ScreenSpaceEventType.js
index 9cc2428da497..3c4388123f91 100644
--- a/Source/Core/ScreenSpaceEventType.js
+++ b/Source/Core/ScreenSpaceEventType.js
@@ -67,16 +67,6 @@ define([
*/
RIGHT_CLICK : 7,
- /**
- * Represents a mouse right double click event.
- *
- * @type {Number}
- * @constant
- *
- * @deprecated
- */
- RIGHT_DOUBLE_CLICK : 8,
-
/**
* Represents a mouse middle button down event.
*
@@ -101,16 +91,6 @@ define([
*/
MIDDLE_CLICK : 12,
- /**
- * Represents a mouse middle double click event.
- *
- * @type {Number}
- * @constant
- *
- * @deprecated
- */
- MIDDLE_DOUBLE_CLICK : 13,
-
/**
* Represents a mouse move event.
*
diff --git a/Source/Core/SphereGeometry.js b/Source/Core/SphereGeometry.js
index a30873a61512..18d9b74d56ef 100644
--- a/Source/Core/SphereGeometry.js
+++ b/Source/Core/SphereGeometry.js
@@ -4,7 +4,6 @@ define([
'./Check',
'./defaultValue',
'./defined',
- './DeveloperError',
'./EllipsoidGeometry',
'./VertexFormat'
], function(
@@ -12,7 +11,6 @@ define([
Check,
defaultValue,
defined,
- DeveloperError,
EllipsoidGeometry,
VertexFormat) {
'use strict';
diff --git a/Source/Core/SphereOutlineGeometry.js b/Source/Core/SphereOutlineGeometry.js
index fa025b9c99f5..0dbff9a8017a 100644
--- a/Source/Core/SphereOutlineGeometry.js
+++ b/Source/Core/SphereOutlineGeometry.js
@@ -4,14 +4,12 @@ define([
'./Check',
'./defaultValue',
'./defined',
- './DeveloperError',
'./EllipsoidOutlineGeometry'
], function(
Cartesian3,
Check,
defaultValue,
defined,
- DeveloperError,
EllipsoidOutlineGeometry) {
'use strict';
diff --git a/Source/Core/Spherical.js b/Source/Core/Spherical.js
index 4f79d5871e9e..5eecf7e6b1a4 100644
--- a/Source/Core/Spherical.js
+++ b/Source/Core/Spherical.js
@@ -2,13 +2,11 @@
define([
'./Check',
'./defaultValue',
- './defined',
- './DeveloperError'
+ './defined'
], function(
Check,
defaultValue,
- defined,
- DeveloperError) {
+ defined) {
'use strict';
/**
diff --git a/Source/Core/TileAvailability.js b/Source/Core/TileAvailability.js
index 22f6853716da..066ee2639b31 100644
--- a/Source/Core/TileAvailability.js
+++ b/Source/Core/TileAvailability.js
@@ -1,20 +1,16 @@
/*global define*/
define([
- '../ThirdParty/when',
'./binarySearch',
'./Cartographic',
'./defined',
'./defineProperties',
- './sampleTerrain',
'./DeveloperError',
'./Rectangle'
], function(
- when,
binarySearch,
Cartographic,
defined,
defineProperties,
- sampleTerrain,
DeveloperError,
Rectangle) {
"use strict";
diff --git a/Source/Core/Transforms.js b/Source/Core/Transforms.js
index 41483f28b6e1..27edaabc93ec 100644
--- a/Source/Core/Transforms.js
+++ b/Source/Core/Transforms.js
@@ -13,7 +13,6 @@ define([
'./EarthOrientationParameters',
'./EarthOrientationParametersSample',
'./Ellipsoid',
- './HeadingPitchRoll',
'./Iau2006XysData',
'./Iau2006XysSample',
'./JulianDate',
@@ -36,7 +35,6 @@ define([
EarthOrientationParameters,
EarthOrientationParametersSample,
Ellipsoid,
- HeadingPitchRoll,
Iau2006XysData,
Iau2006XysSample,
JulianDate,
diff --git a/Source/Core/sampleTerrainMostDetailed.js b/Source/Core/sampleTerrainMostDetailed.js
index 1416474cefb3..027fd8de22c8 100644
--- a/Source/Core/sampleTerrainMostDetailed.js
+++ b/Source/Core/sampleTerrainMostDetailed.js
@@ -3,14 +3,12 @@ define([
'../ThirdParty/when',
'./defined',
'./sampleTerrain',
- './DeveloperError',
- './Rectangle'
+ './DeveloperError'
], function(
when,
defined,
sampleTerrain,
- DeveloperError,
- Rectangle) {
+ DeveloperError) {
"use strict";
/**
diff --git a/Source/DataSources/KmlDataSource.js b/Source/DataSources/KmlDataSource.js
index f5be3bdd5baf..1f84db071fbf 100644
--- a/Source/DataSources/KmlDataSource.js
+++ b/Source/DataSources/KmlDataSource.js
@@ -2259,11 +2259,12 @@ define([
*
* @example
* var viewer = new Cesium.Viewer('cesiumContainer');
- * viewer.dataSources.add(Cesium.KmlDataSource.load('../../SampleData/facilities.kmz'),
+ * viewer.dataSources.add(Cesium.KmlDataSource.load('../../SampleData/facilities.kmz',
* {
- * camera: viewer.scene.camera,
- * canvas: viewer.scene.canvas
- * });
+ * camera: viewer.scene.camera,
+ * canvas: viewer.scene.canvas
+ * })
+ * );
*/
function KmlDataSource(options) {
options = defaultValue(options, {});
diff --git a/Source/DataSources/LabelGraphics.js b/Source/DataSources/LabelGraphics.js
index 3377176256cf..bb7b8b004444 100644
--- a/Source/DataSources/LabelGraphics.js
+++ b/Source/DataSources/LabelGraphics.js
@@ -45,6 +45,7 @@ define([
* @param {Property} [options.pixelOffset=Cartesian2.ZERO] A {@link Cartesian2} Property specifying the pixel offset.
* @param {Property} [options.translucencyByDistance] A {@link NearFarScalar} Property used to set translucency based on distance from the camera.
* @param {Property} [options.pixelOffsetScaleByDistance] A {@link NearFarScalar} Property used to set pixelOffset based on distance from the camera.
+ * @param {Property} [options.scaleByDistance] A {@link NearFarScalar} Property used to set scale based on distance from the camera.
* @param {Property} [options.heightReference=HeightReference.NONE] A Property specifying what the height is relative to.
* @param {Property} [options.distanceDisplayCondition] A Property specifying at what distance from the camera that this label will be displayed.
*
@@ -87,6 +88,8 @@ define([
this._translucencyByDistanceSubscription = undefined;
this._pixelOffsetScaleByDistance = undefined;
this._pixelOffsetScaleByDistanceSubscription = undefined;
+ this._scaleByDistance = undefined;
+ this._scaleByDistanceSubscription = undefined;
this._distanceDisplayCondition = undefined;
this._distanceDisplayConditionSubscription = undefined;
this._definitionChanged = new Event();
@@ -289,6 +292,18 @@ define([
*/
pixelOffsetScaleByDistance : createPropertyDescriptor('pixelOffsetScaleByDistance'),
+ /**
+ * Gets or sets near and far scaling properties of a Label based on the label's distance from the camera.
+ * A label's scale will interpolate between the {@link NearFarScalar#nearValue} and
+ * {@link NearFarScalar#farValue} while the camera distance falls within the upper and lower bounds
+ * of the specified {@link NearFarScalar#near} and {@link NearFarScalar#far}.
+ * Outside of these ranges the label's scale remains clamped to the nearest bound. If undefined,
+ * scaleByDistance will be disabled.
+ * @memberof LabelGraphics.prototype
+ * @type {Property}
+ */
+ scaleByDistance : createPropertyDescriptor('scaleByDistance'),
+
/**
* Gets or sets the {@link DistanceDisplayCondition} Property specifying at what distance from the camera that this label will be displayed.
* @memberof LabelGraphics.prototype
@@ -325,6 +340,7 @@ define([
result.pixelOffset = this.pixelOffset;
result.translucencyByDistance = this.translucencyByDistance;
result.pixelOffsetScaleByDistance = this.pixelOffsetScaleByDistance;
+ result.scaleByDistance = this.scaleByDistance;
result.distanceDisplayCondition = this.distanceDisplayCondition;
return result;
};
@@ -360,6 +376,7 @@ define([
this.pixelOffset = defaultValue(this.pixelOffset, source.pixelOffset);
this.translucencyByDistance = defaultValue(this._translucencyByDistance, source.translucencyByDistance);
this.pixelOffsetScaleByDistance = defaultValue(this._pixelOffsetScaleByDistance, source.pixelOffsetScaleByDistance);
+ this.scaleByDistance = defaultValue(this._scaleByDistance, source.scaleByDistance);
this.distanceDisplayCondition = defaultValue(this.distanceDisplayCondition, source.distanceDisplayCondition);
};
diff --git a/Source/DataSources/LabelVisualizer.js b/Source/DataSources/LabelVisualizer.js
index 019e8527fc77..3ec353a13fc9 100644
--- a/Source/DataSources/LabelVisualizer.js
+++ b/Source/DataSources/LabelVisualizer.js
@@ -59,6 +59,7 @@ define([
var pixelOffset = new Cartesian2();
var translucencyByDistance = new NearFarScalar();
var pixelOffsetScaleByDistance = new NearFarScalar();
+ var scaleByDistance = new NearFarScalar();
var distanceDisplayCondition = new DistanceDisplayCondition();
function EntityData(entity) {
@@ -161,6 +162,7 @@ define([
label.verticalOrigin = Property.getValueOrDefault(labelGraphics._verticalOrigin, time, defaultVerticalOrigin);
label.translucencyByDistance = Property.getValueOrUndefined(labelGraphics._translucencyByDistance, time, translucencyByDistance);
label.pixelOffsetScaleByDistance = Property.getValueOrUndefined(labelGraphics._pixelOffsetScaleByDistance, time, pixelOffsetScaleByDistance);
+ label.scaleByDistance = Property.getValueOrUndefined(labelGraphics._scaleByDistance, time, scaleByDistance);
label.distanceDisplayCondition = Property.getValueOrUndefined(labelGraphics._distanceDisplayCondition, time, distanceDisplayCondition);
}
return true;
diff --git a/Source/DataSources/dynamicGeometryGetBoundingSphere.js b/Source/DataSources/dynamicGeometryGetBoundingSphere.js
index 09e277d811c3..d79b6b3fd6a3 100644
--- a/Source/DataSources/dynamicGeometryGetBoundingSphere.js
+++ b/Source/DataSources/dynamicGeometryGetBoundingSphere.js
@@ -1,17 +1,13 @@
/*global define*/
define([
'../Core/BoundingSphere',
- '../Core/defaultValue',
'../Core/defined',
'../Core/DeveloperError',
- '../Core/Matrix4',
'./BoundingSphereState'
], function(
BoundingSphere,
- defaultValue,
defined,
DeveloperError,
- Matrix4,
BoundingSphereState) {
'use strict';
diff --git a/Source/Renderer/ShaderCache.js b/Source/Renderer/ShaderCache.js
index d4ed90bd9f7d..d02724bdfedc 100644
--- a/Source/Renderer/ShaderCache.js
+++ b/Source/Renderer/ShaderCache.js
@@ -55,7 +55,7 @@ define([
* fragmentShaderSource : fs,
* attributeLocations : attributeLocations
* });
- *
+ *
* @see ShaderCache#getShaderProgram
*/
ShaderCache.prototype.replaceShaderProgram = function(options) {
@@ -103,7 +103,7 @@ define([
var keyword = vertexShaderText + fragmentShaderText + JSON.stringify(attributeLocations);
var cachedShader;
- if (this._shaders[keyword]) {
+ if (defined(this._shaders[keyword])) {
cachedShader = this._shaders[keyword];
// No longer want to release this if it was previously released.
@@ -125,6 +125,7 @@ define([
cache : this,
shaderProgram : shaderProgram,
keyword : keyword,
+ derivedKeywords : [],
count : 0
};
@@ -138,14 +139,86 @@ define([
return cachedShader.shaderProgram;
};
+ ShaderCache.prototype.getDerivedShaderProgram = function(shaderProgram, keyword) {
+ var cachedShader = shaderProgram._cachedShader;
+ var derivedKeyword = keyword + cachedShader.keyword;
+ var cachedDerivedShader = this._shaders[derivedKeyword];
+ if (!defined(cachedDerivedShader)) {
+ return undefined;
+ }
+
+ return cachedDerivedShader.shaderProgram;
+ };
+
+ ShaderCache.prototype.createDerivedShaderProgram = function(shaderProgram, keyword, options) {
+ var cachedShader = shaderProgram._cachedShader;
+ var derivedKeyword = keyword + cachedShader.keyword;
+
+ var vertexShaderSource = options.vertexShaderSource;
+ var fragmentShaderSource = options.fragmentShaderSource;
+ var attributeLocations = options.attributeLocations;
+
+ if (typeof vertexShaderSource === 'string') {
+ vertexShaderSource = new ShaderSource({
+ sources : [vertexShaderSource]
+ });
+ }
+
+ if (typeof fragmentShaderSource === 'string') {
+ fragmentShaderSource = new ShaderSource({
+ sources : [fragmentShaderSource]
+ });
+ }
+
+ var vertexShaderText = vertexShaderSource.createCombinedVertexShader();
+ var fragmentShaderText = fragmentShaderSource.createCombinedFragmentShader();
+
+ var context = this._context;
+ var derivedShaderProgram = new ShaderProgram({
+ gl : context._gl,
+ logShaderCompilation : context.logShaderCompilation,
+ debugShaders : context.debugShaders,
+ vertexShaderSource : vertexShaderSource,
+ vertexShaderText : vertexShaderText,
+ fragmentShaderSource : fragmentShaderSource,
+ fragmentShaderText : fragmentShaderText,
+ attributeLocations : attributeLocations
+ });
+
+ var derivedCachedShader = {
+ cache : this,
+ shaderProgram : derivedShaderProgram,
+ keyword : derivedKeyword,
+ derivedKeywords : [],
+ count : 0
+ };
+
+ cachedShader.derivedKeywords.push(keyword);
+ derivedShaderProgram._cachedShader = derivedCachedShader;
+ this._shaders[derivedKeyword] = derivedCachedShader;
+ return derivedShaderProgram;
+ };
+
+ function destroyShader(cache, cachedShader) {
+ var derivedKeywords = cachedShader.derivedKeywords;
+ var length = derivedKeywords.length;
+ for (var i = 0; i < length; ++i) {
+ var keyword = derivedKeywords[i] + cachedShader.keyword;
+ var derivedCachedShader = cache._shaders[keyword];
+ destroyShader(cache, derivedCachedShader);
+ }
+
+ delete cache._shaders[cachedShader.keyword];
+ cachedShader.shaderProgram.finalDestroy();
+ }
+
ShaderCache.prototype.destroyReleasedShaderPrograms = function() {
var shadersToRelease = this._shadersToRelease;
for ( var keyword in shadersToRelease) {
if (shadersToRelease.hasOwnProperty(keyword)) {
var cachedShader = shadersToRelease[keyword];
- delete this._shaders[cachedShader.keyword];
- cachedShader.shaderProgram.finalDestroy();
+ destroyShader(this, cachedShader);
--this._numberOfShaders;
}
}
@@ -168,13 +241,11 @@ define([
ShaderCache.prototype.destroy = function() {
var shaders = this._shaders;
-
- for ( var keyword in shaders) {
+ for (var keyword in shaders) {
if (shaders.hasOwnProperty(keyword)) {
shaders[keyword].shaderProgram.finalDestroy();
}
}
-
return destroyObject(this);
};
diff --git a/Source/Scene/BatchTable.js b/Source/Scene/BatchTable.js
index 71b31e3d6ce0..29a0542ce97b 100644
--- a/Source/Scene/BatchTable.js
+++ b/Source/Scene/BatchTable.js
@@ -12,7 +12,6 @@ define([
'../Core/FeatureDetection',
'../Core/Math',
'../Core/PixelFormat',
- '../Core/RuntimeError',
'../Renderer/ContextLimits',
'../Renderer/PixelDatatype',
'../Renderer/Sampler',
@@ -32,7 +31,6 @@ define([
FeatureDetection,
CesiumMath,
PixelFormat,
- RuntimeError,
ContextLimits,
PixelDatatype,
Sampler,
diff --git a/Source/Scene/Batched3DModel3DTileContent.js b/Source/Scene/Batched3DModel3DTileContent.js
index a245d2337a85..bf112209c694 100644
--- a/Source/Scene/Batched3DModel3DTileContent.js
+++ b/Source/Scene/Batched3DModel3DTileContent.js
@@ -85,6 +85,15 @@ define([
}
},
+ /**
+ * Part of the {@link Cesium3DTileContent} interface.
+ */
+ pointsLength : {
+ get : function() {
+ return 0;
+ }
+ },
+
/**
* Part of the {@link Cesium3DTileContent} interface.
*/
@@ -307,12 +316,13 @@ define([
gltf : gltfView,
cull : false, // The model is already culled by the 3D tiles
releaseGltfJson : true, // Models are unique and will not benefit from caching so save memory
- basePath : getBaseUri(this._url),
+ basePath : getBaseUri(this._url, true),
modelMatrix : this._tile.computedTransform,
upAxis : this._tileset._gltfUpAxis,
shadows: this._tileset.shadows,
debugWireframe: this._tileset.debugWireframe,
incrementallyLoadTextures : false,
+ pickPrimitive : this._tileset,
vertexShaderLoaded : getVertexShaderCallback(this),
fragmentShaderLoaded : getFragmentShaderCallback(this),
uniformMapLoaded : batchTable.getUniformMapCallback(),
diff --git a/Source/Scene/Cesium3DTile.js b/Source/Scene/Cesium3DTile.js
index dd2e7436aa94..5f6b9441f3f6 100644
--- a/Source/Scene/Cesium3DTile.js
+++ b/Source/Scene/Cesium3DTile.js
@@ -5,6 +5,7 @@ define([
'../Core/Cartesian3',
'../Core/Color',
'../Core/ColorGeometryInstanceAttribute',
+ '../Core/clone',
'../Core/defaultValue',
'../Core/defined',
'../Core/defineProperties',
@@ -22,8 +23,11 @@ define([
'../Core/RequestScheduler',
'../Core/SphereOutlineGeometry',
'../ThirdParty/Uri',
+ './Cesium3DTileChildrenVisibility',
'./Cesium3DTileContentFactory',
'./Cesium3DTileContentState',
+ './Cesium3DTileOptimizations',
+ './Cesium3DTileOptimizationHint',
'./Cesium3DTileRefine',
'./Empty3DTileContent',
'./PerInstanceColorAppearance',
@@ -38,6 +42,7 @@ define([
Cartesian3,
Color,
ColorGeometryInstanceAttribute,
+ clone,
defaultValue,
defined,
defineProperties,
@@ -55,8 +60,11 @@ define([
RequestScheduler,
SphereOutlineGeometry,
Uri,
+ Cesium3DTileChildrenVisibility,
Cesium3DTileContentFactory,
Cesium3DTileContentState,
+ Cesium3DTileOptimizations,
+ Cesium3DTileOptimizationHint,
Cesium3DTileRefine,
Empty3DTileContent,
PerInstanceColorAppearance,
@@ -305,6 +313,15 @@ define([
* @private
*/
this.visibilityPlaneMask = true;
+
+ /**
+ * Flag to mark children visibility
+ *
+ * @type {Cesium3DTileChildrenVisibility}
+ *
+ * @private
+ */
+ this.childrenVisibility = Cesium3DTileChildrenVisibility.VISIBLE;
/**
* The last frame number the tile was selected in.
@@ -329,6 +346,13 @@ define([
this._debugViewerRequestVolume = undefined;
this._debugColor = new Color.fromRandom({ alpha : 1.0 });
this._debugColorizeTiles = false;
+
+ /**
+ * Marks whether the tile's children bounds are fully contained within the tile's bounds
+ *
+ * @type {Cesium3DTileOptimizationHint}
+ */
+ this._optimChildrenWithinParent = Cesium3DTileOptimizationHint.NOT_COMPUTED;
}
defineProperties(Cesium3DTile.prototype, {
diff --git a/Source/Scene/Cesium3DTileChildrenVisibility.js b/Source/Scene/Cesium3DTileChildrenVisibility.js
new file mode 100644
index 000000000000..5715f0375818
--- /dev/null
+++ b/Source/Scene/Cesium3DTileChildrenVisibility.js
@@ -0,0 +1,19 @@
+/*global define*/
+define([
+ '../Core/freezeObject'
+ ], function(
+ freezeObject) {
+ 'use strict';
+
+ /**
+ * @private
+ */
+ var Cesium3DTileChildrenVisibility = {
+ NONE : 0, // No children visbile
+ VISIBLE : 1, // At least one child visible
+ IN_REQUEST_VOLUME : 2, // At least one child in viewer request volume
+ VISIBLE_IN_REQUEST_VOLUME : 4 // At least one child both visible and in viewer request volume
+ };
+
+ return freezeObject(Cesium3DTileChildrenVisibility);
+});
diff --git a/Source/Scene/Cesium3DTileContent.js b/Source/Scene/Cesium3DTileContent.js
index e63d77075858..7db1cffd2afe 100644
--- a/Source/Scene/Cesium3DTileContent.js
+++ b/Source/Scene/Cesium3DTileContent.js
@@ -78,6 +78,20 @@ define([
}
},
+ /**
+ * Gets the number of points in the tile.
+ *
+ * @memberof Cesium3DTileContent.prototype
+ *
+ * @type {Number}
+ * @readonly
+ */
+ pointsLength : {
+ get : function() {
+ DeveloperError.throwInstantiationError();
+ }
+ },
+
/**
* Gets the array of {@link Cesium3DTileContent} objects that represent the
* content a composite's inner tiles, which can also be composites.
diff --git a/Source/Scene/Cesium3DTileOptimizationHint.js b/Source/Scene/Cesium3DTileOptimizationHint.js
new file mode 100644
index 000000000000..9665c56a7da0
--- /dev/null
+++ b/Source/Scene/Cesium3DTileOptimizationHint.js
@@ -0,0 +1,22 @@
+/*global define*/
+define([
+ '../Core/freezeObject'
+ ], function(
+ freezeObject) {
+ 'use strict';
+
+ /**
+ * @private
+ *
+ * @exports Cesium3DTileOptimizationHint
+ *
+ * Hint defining optimization support for a 3D tile
+ */
+ var Cesium3DTileOptimizationHint = {
+ NOT_COMPUTED: -1,
+ USE_OPTIMIZATION: 1,
+ SKIP_OPTIMIZATION: 0
+ };
+
+ return freezeObject(Cesium3DTileOptimizationHint);
+});
diff --git a/Source/Scene/Cesium3DTileOptimizations.js b/Source/Scene/Cesium3DTileOptimizations.js
new file mode 100644
index 000000000000..89515676e088
--- /dev/null
+++ b/Source/Scene/Cesium3DTileOptimizations.js
@@ -0,0 +1,116 @@
+/*global define*/
+define([
+ '../Core/Cartesian3',
+ '../Core/Check',
+ '../Core/defaultValue',
+ '../Core/freezeObject',
+ './Cesium3DTileOptimizationHint',
+ './TileBoundingRegion',
+ './TileOrientedBoundingBox'
+ ], function(
+ Cartesian3,
+ Check,
+ defaultValue,
+ freezeObject,
+ Cesium3DTileOptimizationHint,
+ TileBoundingRegion,
+ TileOrientedBoundingBox) {
+ 'use strict';
+
+ /**
+ * Utility functions for computing optimization hints for a {@link Cesium3DTileset}.
+ *
+ * @private
+ *
+ * @exports Cesium3DTileOptimizations
+ */
+ var Cesium3DTileOptimizations = {};
+
+ var scratchAxis = new Cartesian3();
+
+ /**
+ * Checks and optionally evaluates support for the childrenWithinParent optimization. This is used to more tightly cull tilesets if children bounds are
+ * fully contained within the parent. Currently, support for the optimization only works for oriented bounding boxes, so both the child and parent tile
+ * must be either a {@link TileOrientedBoundingBox} or {@link TileBoundingRegion}. The purpose of this check is to prevent use of a culling optimization
+ * when the child bounds exceed those of the parent. If the child bounds are greater, it is more likely that the optimization will waste CPU cycles. Bounding
+ * spheres are not supported for the reason that the child bounds can very often be partially outside of the parent bounds.
+ *
+ * @param {Cesium3DTile} tile The tile to check.
+ * @param {Boolean} [evaluate=false] Whether to evaluate support if support for the childrenWithinParent optimization is Cesium3DTileOptimizationHints.NOT_COMPUTED
+ * @param {Boolean} [force=false] Whether to always evaluate support for the childrenWithinParent optimization
+ * @returns {Boolean} Whether the childrenWithinParent optimization is supported.
+ */
+ Cesium3DTileOptimizations.checkChildrenWithinParent = function(tile, evaluate, force) {
+ //>>includeStart('debug', pragmas.debug);
+ Check.typeOf.object('tile', tile);
+ //>>includeEnd('debug');
+
+ evaluate = defaultValue(evaluate, false);
+ force = defaultValue(force, false);
+
+ if ((tile._optimChildrenWithinParent === Cesium3DTileOptimizationHint.NOT_COMPUTED && evaluate) || force) {
+ var children = tile.children;
+ var length = children.length;
+
+ // Check if the parent has an oriented bounding box.
+ var boundingVolume = tile._boundingVolume;
+ if (boundingVolume instanceof TileOrientedBoundingBox || boundingVolume instanceof TileBoundingRegion) {
+ var orientedBoundingBox = boundingVolume._orientedBoundingBox;
+ tile._optimChildrenWithinParent = Cesium3DTileOptimizationHint.USE_OPTIMIZATION;
+ for (var i = 0; i < length; ++i) {
+ var child = children[i];
+
+ // Check if the child has an oriented bounding box.
+ var childBoundingVolume = child._boundingVolume;
+ if (childBoundingVolume instanceof TileOrientedBoundingBox || childBoundingVolume instanceof TileBoundingRegion) {
+ var childOrientedBoundingBox = childBoundingVolume._orientedBoundingBox;
+
+ // Compute the axis from the parent to the child.
+ var axis = Cartesian3.subtract(childOrientedBoundingBox.center, orientedBoundingBox.center, scratchAxis);
+ var axisLength = Cartesian3.magnitude(axis);
+ Cartesian3.divideByScalar(axis, axisLength, axis);
+
+ // Project the bounding box of the parent onto the axis. Because the axis is a ray from the parent to the child,
+ // the projection parameterized along the ray will be (+/- proj1).
+ var proj1 = Math.abs(orientedBoundingBox.halfAxes[0] * axis.x) +
+ Math.abs(orientedBoundingBox.halfAxes[1] * axis.y) +
+ Math.abs(orientedBoundingBox.halfAxes[2] * axis.z) +
+ Math.abs(orientedBoundingBox.halfAxes[3] * axis.x) +
+ Math.abs(orientedBoundingBox.halfAxes[4] * axis.y) +
+ Math.abs(orientedBoundingBox.halfAxes[5] * axis.z) +
+ Math.abs(orientedBoundingBox.halfAxes[6] * axis.x) +
+ Math.abs(orientedBoundingBox.halfAxes[7] * axis.y) +
+ Math.abs(orientedBoundingBox.halfAxes[8] * axis.z);
+
+ // Project the bounding box of the child onto the axis. Because the axis is a ray from the parent to the child,
+ // the projection parameterized along the ray will be (+/- proj2) + axis.length.
+ var proj2 = Math.abs(childOrientedBoundingBox.halfAxes[0] * axis.x) +
+ Math.abs(childOrientedBoundingBox.halfAxes[1] * axis.y) +
+ Math.abs(childOrientedBoundingBox.halfAxes[2] * axis.z) +
+ Math.abs(childOrientedBoundingBox.halfAxes[3] * axis.x) +
+ Math.abs(childOrientedBoundingBox.halfAxes[4] * axis.y) +
+ Math.abs(childOrientedBoundingBox.halfAxes[5] * axis.z) +
+ Math.abs(childOrientedBoundingBox.halfAxes[6] * axis.x) +
+ Math.abs(childOrientedBoundingBox.halfAxes[7] * axis.y) +
+ Math.abs(childOrientedBoundingBox.halfAxes[8] * axis.z);
+
+ // If the child extends the parent's bounds, the optimization is not valid and we skip it.
+ if (proj1 <= proj2 + axisLength) {
+ tile._optimChildrenWithinParent = Cesium3DTileOptimizationHint.SKIP_OPTIMIZATION;
+ break;
+ }
+
+ } else {
+ // Do not support if the parent and child both do not have oriented bounding boxes.
+ tile._optimChildrenWithinParent = Cesium3DTileOptimizationHint.SKIP_OPTIMIZATION;
+ break;
+ }
+ }
+ }
+ }
+
+ return tile._optimChildrenWithinParent === Cesium3DTileOptimizationHint.USE_OPTIMIZATION;
+ };
+
+ return Cesium3DTileOptimizations;
+});
diff --git a/Source/Scene/Cesium3DTileset.js b/Source/Scene/Cesium3DTileset.js
index d352f5d15191..c6378d9cd5a3 100644
--- a/Source/Scene/Cesium3DTileset.js
+++ b/Source/Scene/Cesium3DTileset.js
@@ -3,6 +3,7 @@ define([
'../Core/Cartesian3',
'../Core/Cartographic',
'../Core/Color',
+ '../Core/clone',
'../Core/defaultValue',
'../Core/defined',
'../Core/defineProperties',
@@ -26,11 +27,15 @@ define([
'../ThirdParty/when',
'./Axis',
'./Cesium3DTile',
+ './Cesium3DTileChildrenVisibility',
'./Cesium3DTileColorBlendMode',
+ './Cesium3DTileOptimizations',
+ './Cesium3DTileOptimizationHint',
'./Cesium3DTileRefine',
'./Cesium3DTileStyleEngine',
'./CullingVolume',
'./DebugCameraPrimitive',
+ './LabelCollection',
'./SceneMode',
'./ShadowMode',
'./TileBoundingRegion',
@@ -40,6 +45,7 @@ define([
Cartesian3,
Cartographic,
Color,
+ clone,
defaultValue,
defined,
defineProperties,
@@ -63,11 +69,15 @@ define([
when,
Axis,
Cesium3DTile,
+ Cesium3DTileChildrenVisibility,
Cesium3DTileColorBlendMode,
+ Cesium3DTileOptimizations,
+ Cesium3DTileOptimizationHint,
Cesium3DTileRefine,
Cesium3DTileStyleEngine,
CullingVolume,
DebugCameraPrimitive,
+ LabelCollection,
SceneMode,
ShadowMode,
TileBoundingRegion,
@@ -88,6 +98,7 @@ define([
* @param {Matrix4} [options.modelMatrix=Matrix4.IDENTITY] A 4x4 transformation matrix that transforms the tileset's root tile.
* @param {Number} [options.maximumScreenSpaceError=16] The maximum screen-space error used to drive level-of-detail refinement.
* @param {Boolean} [options.refineToVisible=false] Whether replacement refinement should refine when all visible children are ready. An experimental optimization.
+ * @param {Boolean} [options.cullWithChildrenBounds=true] Whether to cull tiles using the union of their children bounding volumes.
* @param {Boolean} [options.dynamicScreenSpaceError=false] Reduce the screen space error for tiles that are further away from the camera.
* @param {Number} [options.dynamicScreenSpaceErrorDensity=0.00278] Density used to adjust the dynamic screen space error, similar to fog density.
* @param {Number} [options.dynamicScreenSpaceErrorFactor=4.0] A factor used to increase the computed dynamic screen space error.
@@ -98,6 +109,7 @@ define([
* @param {Boolean} [options.debugShowBoundingVolume=false] For debugging only. When true, renders the bounding volume for each tile.
* @param {Boolean} [options.debugShowContentBoundingVolume=false] For debugging only. When true, renders the bounding volume for each tile's content.
* @param {Boolean} [options.debugShowViewerRequestVolume=false] For debugging only. When true, renders the viewer request volume for each tile.
+ * @param {Boolean} [options.debugShowGeometricError=false] For debugging only. When true, draws labels to indicate the geometric error of each tile
* @param {ShadowMode} [options.shadows=ShadowMode.ENABLED] Determines whether the tileset casts or receives shadows from each light source.
*
* @example
@@ -123,7 +135,7 @@ define([
if (getExtensionFromUri(url) === 'json') {
tilesetUrl = url;
- baseUrl = getBaseUri(url);
+ baseUrl = getBaseUri(url, true);
} else if (isDataUri(url)) {
tilesetUrl = url;
baseUrl = '';
@@ -156,6 +168,8 @@ define([
this._refineToVisible = defaultValue(options.refineToVisible, false);
+ this._cullWithChildrenBounds = defaultValue(options.cullWithChildrenBounds, true);
+
/**
* Whether the tileset should should refine based on a dynamic screen space error. Tiles that are further
* away will be rendered with lower detail than closer tiles. This improves performance by rendering fewer
@@ -266,9 +280,16 @@ define([
numberProcessing : 0,
numberContentReady : 0, // Number of tiles with content loaded, does not include empty tiles
numberTotal : 0, // Number of tiles in tileset.json (and other tileset.json files as they are loaded)
+ // Features stats
+ numberOfFeaturesSelected : 0, // number of features rendered
+ numberOfFeaturesLoaded : 0, // number of features in memory
+ numberOfPointsSelected: 0,
+ numberOfPointsLoaded: 0,
// Styling stats
numberOfTilesStyled : 0,
numberOfFeaturesStyled : 0,
+ // Optimization stats
+ numberOfTilesCulledWithChildrenUnion : 0,
lastColor : new Cesium3DTilesetStatistics(),
lastPick : new Cesium3DTilesetStatistics()
@@ -348,6 +369,18 @@ define([
*/
this.debugShowViewerRequestVolume = defaultValue(options.debugShowViewerRequestVolume, false);
+ /**
+ * This property is for debugging only; it is not optimized for production use.
+ * + * When true, draws labels to indicate the geometric error of each tile. + *
+ * + * @type {Boolean} + * @default false + */ + this.debugShowGeometricError = defaultValue(options.debugShowGeometricError, false); + this._geometricErrorLabels = undefined; + /** * The event fired to indicate progress of loading new tiles. This event is fired when a new tile * is requested, when a requested tile is finished downloading, and when a downloaded tile has been @@ -468,8 +501,13 @@ define([ this.numberProcessing = 0; this.numberContentReady = 0; this.numberTotal = 0; + this.numberOfFeaturesSelected = 0; + this.numberOfFeaturesLoaded = 0; + this.numberOfPointsSelected = 0; + this.numberOfPointsLoaded = 0; this.numberOfTilesStyled = 0; this.numberOfFeaturesStyled = 0; + this.numberOfTilesCulledWithChildrenUnion = 0; } defineProperties(Cesium3DTileset.prototype, { @@ -860,13 +898,16 @@ define([ var stats = that._statistics; // Append the version to the baseUrl - var versionQuery = '?v=' + defaultValue(tilesetJson.asset.tilesetVersion, '0.0'); - that._baseUrl = joinUrls(that._baseUrl, versionQuery); + var hasVersionQuery = /[?&]v=/.test(tilesetUrl); + if (!hasVersionQuery) { + var versionQuery = '?v=' + defaultValue(tilesetJson.asset.tilesetVersion, '0.0'); + that._baseUrl = joinUrls(that._baseUrl, versionQuery); + tilesetUrl = joinUrls(tilesetUrl, versionQuery, false); + } // A tileset.json referenced from a tile may exist in a different directory than the root tileset. // Get the baseUrl relative to the external tileset. var baseUrl = getBaseUri(tilesetUrl, true); - baseUrl = joinUrls(baseUrl, versionQuery); var rootTile = new Cesium3DTile(that, baseUrl, tilesetJson.root, parentTile); var refiningTiles = []; @@ -913,6 +954,7 @@ define([ } } } + Cesium3DTileOptimizations.checkChildrenWithinParent(tile3D, true); if (tile3D.hasContent && hasEmptyChild && (tile3D.refine === Cesium3DTileRefine.REPLACE)) { // Tiles that use replacement refinement and have empty child tiles need to keep track of // descendants with content in order to refine correctly. @@ -1159,6 +1201,39 @@ define([ var scratchStack = []; var scratchRefiningTiles = []; + function computeChildrenVisibility(tile, frameState, checkViewerRequestVolume) { + var flag = Cesium3DTileChildrenVisibility.NONE; + var children = tile.children; + var childrenLength = children.length; + var visibilityPlaneMask = tile.visibilityPlaneMask; + for (var k = 0; k < childrenLength; ++k) { + var child = children[k]; + + var visibilityMask = child.visibility(frameState, visibilityPlaneMask); + + if (isVisible(visibilityMask)) { + flag |= Cesium3DTileChildrenVisibility.VISIBLE; + } + + if (checkViewerRequestVolume) { + if (!child.insideViewerRequestVolume(frameState)) { + visibilityMask = CullingVolume.MASK_OUTSIDE; + } else { + flag |= Cesium3DTileChildrenVisibility.IN_REQUEST_VOLUME; + if (isVisible(visibilityMask)) { + flag |= Cesium3DTileChildrenVisibility.VISIBLE_IN_REQUEST_VOLUME; + } + } + } + + child.visibilityPlaneMask = visibilityMask; + } + + tile.childrenVisibility = flag; + + return flag; + } + function selectTiles(tileset, frameState, outOfCore) { if (tileset.debugFreezeFrame) { return; @@ -1291,10 +1366,30 @@ define([ // is not sufficient, its children (or ancestors) are // rendered instead - if ((sse <= maximumScreenSpaceError) || (childrenLength === 0)) { - // This tile meets the SSE so add its commands. + // This optimization may cause issues if the parent's content exceeds the bounds of the childrens` content. + // In these case nothing will be selected to fill the empty space. This is possible if occlusion-preserving + // decimation is not used, but it is arguably better to cull in this way because in the cases where we cull + // when the parent content is visible, if the object were to be drawn at full resolution, the geometry would + // not be visible. + var useChildrenBoundUnion = tileset._cullWithChildrenBounds && t._optimChildrenWithinParent === Cesium3DTileOptimizationHint.USE_OPTIMIZATION; + + var childrenVisibility; + + if (childrenLength === 0) { // Select tile if it's a leaf (childrenLength === 0) selectTile(tileset, t, fullyVisible, frameState); + } else if (sse <= maximumScreenSpaceError) { + // This tile meets the SSE so add its commands. + if (useChildrenBoundUnion) { + childrenVisibility = computeChildrenVisibility(t, frameState, false); + if (childrenVisibility & Cesium3DTileChildrenVisibility.VISIBLE) { + selectTile(tileset, t, fullyVisible, frameState); + } else { + ++stats.numberOfTilesCulledWithChildrenUnion; + } + } else { + selectTile(tileset, t, fullyVisible, frameState); + } } else if (!tileset._refineToVisible) { // Tile does not meet SSE. // Refine when all children (visible or not) are loaded. @@ -1316,37 +1411,38 @@ define([ } if (!allChildrenLoaded) { - // Tile does not meet SSE. Add its commands since it is the best we have and request its children. - selectTile(tileset, t, fullyVisible, frameState); + if (useChildrenBoundUnion) { + childrenVisibility = computeChildrenVisibility(t, frameState, false); + } + if (!useChildrenBoundUnion || (childrenVisibility & Cesium3DTileChildrenVisibility.VISIBLE)) { + // Tile does not meet SSE. Add its commands since it is the best we have and request its children. + selectTile(tileset, t, fullyVisible, frameState); - if (outOfCore) { - for (k = 0; (k < childrenLength) && t.canRequestContent(); ++k) { - child = children[k]; - // PERFORMANCE_IDEA: we could spin a bit less CPU here by keeping separate lists for unloaded/ready children. - if (child.contentUnloaded) { - requestContent(tileset, child, outOfCore); - } else { - // Touch loaded child even though it is not selected this frame since - // we want to keep it in the cache for when all children are loaded - // and this tile can refine to them. - touch(tileset, child, outOfCore); + if (outOfCore) { + for (k = 0; k < childrenLength; ++k) { + child = children[k]; + // PERFORMANCE_IDEA: we could spin a bit less CPU here by keeping separate lists for unloaded/ready children. + if (child.contentUnloaded) { + requestContent(tileset, child, outOfCore); + } else { + // Touch loaded child even though it is not selected this frame since + // we want to keep it in the cache for when all children are loaded + // and this tile can refine to them. + touch(tileset, child, outOfCore); + } } } + } else if (useChildrenBoundUnion) { + ++stats.numberOfTilesCulledWithChildrenUnion; } } else { // Tile does not meet SSE and its children are loaded. Refine to them in front-to-back order. - var anyChildrenVisible = false; + childrenVisibility = computeChildrenVisibility(t, frameState, true); for (k = 0; k < childrenLength; ++k) { child = children[k]; - if (child.insideViewerRequestVolume(frameState)) { - child.visibilityPlaneMask = child.visibility(frameState, visibilityPlaneMask); - } else { - child.visibilityPlaneMask = CullingVolume.MASK_OUTSIDE; - } if (isVisible(child.visibilityPlaneMask)) { stack.push(child); - anyChildrenVisible = true; } else { // Touch the child tile even if it is not visible. Since replacement refinement // requires all child tiles to be loaded to refine to them, we want to keep it in the cache. @@ -1354,15 +1450,17 @@ define([ } } - if (anyChildrenVisible) { + if (childrenVisibility & Cesium3DTileChildrenVisibility.VISIBLE_IN_REQUEST_VOLUME) { t.replaced = true; if (defined(t.descendantsWithContent)) { scratchRefiningTiles.push(t); } - } else { + } else if (!useChildrenBoundUnion || (childrenVisibility & Cesium3DTileChildrenVisibility.VISIBLE)) { // Even though the children are all loaded they may not be visible if the camera // is not inside their request volumes. selectTile(tileset, t, fullyVisible, frameState); + } else if (useChildrenBoundUnion) { + ++stats.numberOfTilesCulledWithChildrenUnion; } } } else { @@ -1371,16 +1469,13 @@ define([ // Get visibility for all children. Check if any visible children are not loaded. // PERFORMANCE_IDEA: exploit temporal coherence to avoid checking visibility every frame + updateTransforms(children, t.computedTransform); + childrenVisibility = computeChildrenVisibility(t, frameState, true); + var allVisibleChildrenLoaded = true; var someVisibleChildrenLoaded = false; for (k = 0; k < childrenLength; ++k) { child = children[k]; - child.updateTransform(t.computedTransform); - if (child.insideViewerRequestVolume(frameState)) { - child.visibilityPlaneMask = child.visibility(frameState, visibilityPlaneMask); - } else { - child.visibilityPlaneMask = CullingVolume.MASK_OUTSIDE; - } if (isVisible(child.visibilityPlaneMask)) { if (child.contentReady) { someVisibleChildrenLoaded = true; @@ -1390,6 +1485,13 @@ define([ } } + if (useChildrenBoundUnion && childrenVisibility === Cesium3DTileChildrenVisibility.NONE) { + if (allVisibleChildrenLoaded && !someVisibleChildrenLoaded) { + ++stats.numberOfTilesCulledWithChildrenUnion; + } + continue; + } + if (allVisibleChildrenLoaded && !someVisibleChildrenLoaded) { // No children are visible, select this tile selectTile(tileset, t, fullyVisible, frameState); @@ -1466,6 +1568,7 @@ define([ for (j = 0; j < descendantsLength; ++j) { descendant = refiningTile.descendantsWithContent[j]; if (!descendant.selected && !descendant.replaced && + ((descendant.childrenVisibility & Cesium3DTileChildrenVisibility.VISIBLE) || descendant.children.length === 0) && (frameState.cullingVolume.computeVisibility(descendant.contentBoundingVolume) !== Intersect.OUTSIDE)) { refinable = false; break; @@ -1503,6 +1606,7 @@ define([ // RESEARCH_IDEA: ability to unload tiles (without content) for an // external tileset when all the tiles are unloaded. ++tileset._statistics.numberContentReady; + incrementPointAndFeatureLoadCounts(tileset, tile.content); tile.replacementNode = tileset._replacementList.add(tile); } } else { @@ -1533,6 +1637,9 @@ define([ stats.numberOfAttemptedRequests = 0; stats.numberOfTilesStyled = 0; stats.numberOfFeaturesStyled = 0; + stats.numberOfTilesCulledWithChildrenUnion = 0; + stats.numberOfFeaturesSelected = 0; + stats.numberOfPointsSelected = 0; } function updateLastStats(tileset, isPick) { @@ -1547,8 +1654,79 @@ define([ last.numberProcessing = stats.numberProcessing; last.numberContentReady = stats.numberContentReady; last.numberTotal = stats.numberTotal; + last.numberOfFeaturesSelected = stats.numberOfFeaturesSelected; + last.numberOfFeaturesLoaded = stats.numberOfFeaturesLoaded; + last.numberOfPointsSelected = stats.numberOfPointsSelected; + last.numberOfPointsLoaded = stats.numberOfPointsLoaded; last.numberOfTilesStyled = stats.numberOfTilesStyled; last.numberOfFeaturesStyled = stats.numberOfFeaturesStyled; + last.numberOfTilesCulledWithChildrenUnion = stats.numberOfTilesCulledWithChildrenUnion; + } + + function updatePointAndFeatureCounts(tileset, content, decrement, load) { + var stats = tileset._statistics; + var contents = content.innerContents; + var pointsLength = content.pointsLength; + var featuresLength = content.featuresLength; + + if (load) { + stats.numberOfFeaturesLoaded += decrement ? -featuresLength : featuresLength; + stats.numberOfPointsLoaded += decrement ? -pointsLength : pointsLength; + } else { + stats.numberOfFeaturesSelected += decrement ? -featuresLength : featuresLength; + stats.numberOfPointsSelected += decrement ? -pointsLength : pointsLength; + } + + if (defined(contents)) { + var length = contents.length; + for (var i = 0; i < length; ++i) { + updatePointAndFeatureCounts(tileset, contents[i], decrement, load); + } + } + } + + function incrementPointAndFeatureSelectionCounts(tileset, content) { + updatePointAndFeatureCounts(tileset, content, false, false); + } + + function incrementPointAndFeatureLoadCounts(tileset, content) { + updatePointAndFeatureCounts(tileset, content, false, true); + } + + function decrementPointAndFeatureLoadCounts(tileset, content) { + updatePointAndFeatureCounts(tileset, content, true, true); + } + + var scratchCartesian = new Cartesian3(); + + function updateGeometricErrorLabels(tileset, frameState) { + var selectedTiles = tileset._selectedTiles; + var length = selectedTiles.length; + tileset._geometricErrorLabels.removeAll(); + for (var i = 0; i < length; ++i) { + var tile = selectedTiles[i]; + if (tile.selected) { + var boundingVolume = tile._boundingVolume.boundingVolume; + var halfAxes = boundingVolume.halfAxes; + var radius = boundingVolume.radius; + + var position = Cartesian3.clone(boundingVolume.center, scratchCartesian); + if (defined(halfAxes)) { + position.x += 0.75 * (halfAxes[0] + halfAxes[3] + halfAxes[6]); + position.y += 0.75 * (halfAxes[1] + halfAxes[4] + halfAxes[7]); + position.z += 0.75 * (halfAxes[2] + halfAxes[5] + halfAxes[8]); + } else if (defined(radius)) { + var normal = Cartesian3.normalize(boundingVolume.center, scratchCartesian); + normal = Cartesian3.multiplyByScalar(normal, 0.75 * radius, scratchCartesian); + position = Cartesian3.add(normal, boundingVolume.center, scratchCartesian); + } + tileset._geometricErrorLabels.add({ + text: tile.geometricError.toString(), + position: position + }); + } + } + tileset._geometricErrorLabels.update(frameState); } function updateTiles(tileset, frameState) { @@ -1566,11 +1744,21 @@ define([ // makes changes that update needs to apply to WebGL resources tileVisible.raiseEvent(tile); tile.update(tileset, frameState); + incrementPointAndFeatureSelectionCounts(tileset, tile.content); } } // Number of commands added by each update above tileset._statistics.numberOfCommands = (commandList.length - numberOfInitialCommands); + + if (tileset.debugShowGeometricError) { + if (!defined(tileset._geometricErrorLabels)) { + tileset._geometricErrorLabels = new LabelCollection(); + } + updateGeometricErrorLabels(tileset, frameState); + } else { + tileset._geometricErrorLabels = tileset._geometricErrorLabels && tileset._geometricErrorLabels.destroy(); + } } function unloadTiles(tileset, frameState) { @@ -1591,6 +1779,7 @@ define([ while ((node !== sentinel) && ((replacementList.length > maximumNumberOfLoadedTiles) || trimTiles)) { var tile = node.item; + decrementPointAndFeatureLoadCounts(tileset, tile.content); tileUnload.raiseEvent(tile); tile.unloadContent(); @@ -1747,7 +1936,6 @@ define([ } this._root = undefined; - this._debugCameraFrustum = this._debugCameraFrustum && this._debugCameraFrustum.destroy(); return destroyObject(this); }; diff --git a/Source/Scene/Composite3DTileContent.js b/Source/Scene/Composite3DTileContent.js index 6dd61495b387..0d16968063f4 100644 --- a/Source/Scene/Composite3DTileContent.js +++ b/Source/Scene/Composite3DTileContent.js @@ -89,6 +89,16 @@ define([ } }, + /** + * Part of the {@link Cesium3DTileContent} interface.Composite3DTileContent
+ * always returns 0
. Instead call pointsLength
for a tile in the composite.
+ */
+ pointsLength : {
+ get : function() {
+ return 0;
+ }
+ },
+
/**
* Gets the array of {@link Cesium3DTileContent} objects that represent the
* content of the composite's inner tiles, which can also be composites.
diff --git a/Source/Scene/FrameState.js b/Source/Scene/FrameState.js
index 82644c105d9e..e362ccd26b35 100644
--- a/Source/Scene/FrameState.js
+++ b/Source/Scene/FrameState.js
@@ -133,7 +133,14 @@ define([
* @type {Boolean}
* @default false
*/
- pick : false
+ pick : false,
+
+ /**
+ * true
if the primitive should update for a depth only pass, false
otherwise.
+ * @type {Boolean}
+ * @default false
+ */
+ depth : false
};
/**
diff --git a/Source/Scene/Globe.js b/Source/Scene/Globe.js
index bb92954ec673..f947b21caaf5 100644
--- a/Source/Scene/Globe.js
+++ b/Source/Scene/Globe.js
@@ -14,7 +14,6 @@ define([
'../Core/Event',
'../Core/IntersectionTests',
'../Core/loadImage',
- '../Core/Math',
'../Core/Ray',
'../Core/Rectangle',
'../Renderer/ShaderSource',
@@ -44,7 +43,6 @@ define([
Event,
IntersectionTests,
loadImage,
- CesiumMath,
Ray,
Rectangle,
ShaderSource,
diff --git a/Source/Scene/GroundPrimitive.js b/Source/Scene/GroundPrimitive.js
index 4818e1e11bc0..e3d239ef9320 100644
--- a/Source/Scene/GroundPrimitive.js
+++ b/Source/Scene/GroundPrimitive.js
@@ -5,8 +5,6 @@ define([
'../Core/Cartesian2',
'../Core/Cartesian3',
'../Core/Cartographic',
- '../Core/clone',
- '../Core/Color',
'../Core/ColorGeometryInstanceAttribute',
'../Core/defaultValue',
'../Core/defined',
@@ -41,8 +39,6 @@ define([
Cartesian2,
Cartesian3,
Cartographic,
- clone,
- Color,
ColorGeometryInstanceAttribute,
defaultValue,
defined,
diff --git a/Source/Scene/Instanced3DModel3DTileContent.js b/Source/Scene/Instanced3DModel3DTileContent.js
index 2c42fe564875..d3542eabae66 100644
--- a/Source/Scene/Instanced3DModel3DTileContent.js
+++ b/Source/Scene/Instanced3DModel3DTileContent.js
@@ -101,7 +101,20 @@ define([
*/
featuresLength : {
get : function() {
- return this._modelInstanceCollection.length;
+ if (defined(this._modelInstanceCollection)) {
+ return this._modelInstanceCollection.length;
+ } else {
+ return 0;
+ }
+ }
+ },
+
+ /**
+ * Part of the {@link Cesium3DTileContent} interface.
+ */
+ pointsLength : {
+ get : function() {
+ return 0;
}
},
@@ -311,11 +324,10 @@ define([
if (gltfFormat === 0) {
var gltfUrl = getStringFromTypedArray(gltfView);
- var baseUrl = defaultValue(this._tileset.baseUrl, '');
- collectionOptions.url = joinUrls(baseUrl, gltfUrl);
+ collectionOptions.url = joinUrls(getBaseUri(this._url, true), gltfUrl);
} else {
collectionOptions.gltf = gltfView;
- collectionOptions.basePath = getBaseUri(this._url);
+ collectionOptions.basePath = getBaseUri(this._url, true);
}
var eastNorthUp = featureTable.getGlobalProperty('EAST_NORTH_UP');
diff --git a/Source/Scene/Label.js b/Source/Scene/Label.js
index 67502ac5d74c..3fe84a1b5057 100644
--- a/Source/Scene/Label.js
+++ b/Source/Scene/Label.js
@@ -75,6 +75,9 @@ define([
if (defined(options.pixelOffsetScaleByDistance) && options.pixelOffsetScaleByDistance.far <= options.pixelOffsetScaleByDistance.near) {
throw new DeveloperError('pixelOffsetScaleByDistance.far must be greater than pixelOffsetScaleByDistance.near.');
}
+ if (defined(options.scaleByDistance) && options.scaleByDistance.far <= options.scaleByDistance.near) {
+ throw new DeveloperError('scaleByDistance.far must be greater than scaleByDistance.near.');
+ }
if (defined(options.distanceDisplayCondition) && options.distanceDisplayCondition.far <= options.distanceDisplayCondition.near) {
throw new DeveloperError('distanceDisplayCondition.far must be greater than distanceDisplayCondition.near');
}
@@ -99,6 +102,7 @@ define([
this._id = options.id;
this._translucencyByDistance = options.translucencyByDistance;
this._pixelOffsetScaleByDistance = options.pixelOffsetScaleByDistance;
+ this._scaleByDistance = options.scaleByDistance;
this._heightReference = defaultValue(options.heightReference, HeightReference.NONE);
this._distanceDisplayCondition = options.distanceDisplayCondition;
@@ -613,6 +617,58 @@ define([
}
},
+ /**
+ * Gets or sets near and far scaling properties of a Label based on the label's distance from the camera.
+ * A label's scale will interpolate between the {@link NearFarScalar#nearValue} and
+ * {@link NearFarScalar#farValue} while the camera distance falls within the upper and lower bounds
+ * of the specified {@link NearFarScalar#near} and {@link NearFarScalar#far}.
+ * Outside of these ranges the label's scale remains clamped to the nearest bound. If undefined,
+ * scaleByDistance will be disabled.
+ * @memberof Label.prototype
+ * @type {NearFarScalar}
+ *
+ * @example
+ * // Example 1.
+ * // Set a label's scaleByDistance to scale by 1.5 when the
+ * // camera is 1500 meters from the label and disappear as
+ * // the camera distance approaches 8.0e6 meters.
+ * label.scaleByDistance = new Cesium.NearFarScalar(1.5e2, 1.5, 8.0e6, 0.0);
+ *
+ * @example
+ * // Example 2.
+ * // disable scaling by distance
+ * label.scaleByDistance = undefined;
+ */
+ scaleByDistance : {
+ get : function() {
+ return this._scaleByDistance;
+ },
+ set : function(value) {
+ //>>includeStart('debug', pragmas.debug);
+ if (defined(value) && value.far <= value.near) {
+ throw new DeveloperError('far distance must be greater than near distance.');
+ }
+ //>>includeEnd('debug');
+
+ var scaleByDistance = this._scaleByDistance;
+ if (!NearFarScalar.equals(scaleByDistance, value)) {
+ this._scaleByDistance = NearFarScalar.clone(value, scaleByDistance);
+
+ var glyphs = this._glyphs;
+ for (var i = 0, len = glyphs.length; i < len; i++) {
+ var glyph = glyphs[i];
+ if (defined(glyph.billboard)) {
+ glyph.billboard.scaleByDistance = value;
+ }
+ }
+ var backgroundBillboard = this._backgroundBillboard;
+ if (defined(backgroundBillboard)) {
+ backgroundBillboard.scaleByDistance = value;
+ }
+ }
+ }
+ },
+
/**
* Gets and sets the 3D Cartesian offset applied to this label in eye coordinates. Eye coordinates is a left-handed
* coordinate system, where x
points towards the viewer's right, y
points up, and
@@ -1066,6 +1122,7 @@ define([
Cartesian3.equals(this._eyeOffset, other._eyeOffset) &&
NearFarScalar.equals(this._translucencyByDistance, other._translucencyByDistance) &&
NearFarScalar.equals(this._pixelOffsetScaleByDistance, other._pixelOffsetScaleByDistance) &&
+ NearFarScalar.equals(this._scaleByDistance, other._scaleByDistance) &&
DistanceDisplayCondition.equals(this._distanceDisplayCondition, other._distanceDisplayCondition) &&
this._id === other._id;
};
diff --git a/Source/Scene/LabelCollection.js b/Source/Scene/LabelCollection.js
index 1d4665ef4a32..9f3763f94586 100644
--- a/Source/Scene/LabelCollection.js
+++ b/Source/Scene/LabelCollection.js
@@ -2,7 +2,6 @@
define([
'../Core/BoundingRectangle',
'../Core/Cartesian2',
- '../Core/Color',
'../Core/defaultValue',
'../Core/defined',
'../Core/defineProperties',
@@ -20,7 +19,6 @@ define([
], function(
BoundingRectangle,
Cartesian2,
- Color,
defaultValue,
defined,
defineProperties,
@@ -171,6 +169,7 @@ define([
backgroundBillboard.id = label._id;
backgroundBillboard.translucencyByDistance = label._translucencyByDistance;
backgroundBillboard.pixelOffsetScaleByDistance = label._pixelOffsetScaleByDistance;
+ backgroundBillboard.scaleByDistance = label._scaleByDistance;
backgroundBillboard.distanceDisplayCondition = label._distanceDisplayCondition;
}
@@ -263,6 +262,7 @@ define([
billboard.image = id;
billboard.translucencyByDistance = label._translucencyByDistance;
billboard.pixelOffsetScaleByDistance = label._pixelOffsetScaleByDistance;
+ billboard.scaleByDistance = label._scaleByDistance;
billboard.distanceDisplayCondition = label._distanceDisplayCondition;
}
}
diff --git a/Source/Scene/Model.js b/Source/Scene/Model.js
index 263a151e827d..95b696603681 100644
--- a/Source/Scene/Model.js
+++ b/Source/Scene/Model.js
@@ -1549,13 +1549,15 @@ define([
++model._loadResources.pendingTextureLoads;
var imagePath = joinUrls(model._baseUri, gltfImage.uri);
+ var promise;
if (ktxRegex.test(imagePath)) {
- loadKTX(imagePath).then(imageLoad(model, id)).otherwise(getFailedLoadFunction(model, 'image', imagePath));
+ promise = RequestScheduler.request(imagePath, loadKTX, undefined, model._requestType);
} else if (crnRegex.test(imagePath)) {
- loadCRN(imagePath).then(imageLoad(model, id)).otherwise(getFailedLoadFunction(model, 'image', imagePath));
+ promise = RequestScheduler.request(imagePath, loadCRN, undefined, model._requestType);
} else {
- loadImage(imagePath).then(imageLoad(model, id)).otherwise(getFailedLoadFunction(model, 'image', imagePath));
+ promise = RequestScheduler.request(imagePath, loadImage, undefined, model._requestType);
}
+ promise.then(imageLoad(model, id)).otherwise(getFailedLoadFunction(model, 'image', imagePath));
}
}
}
@@ -1848,7 +1850,7 @@ define([
// the normal attribute.
for (i = 1; i < length; ++i) {
var attribute = attributes[i];
- if (/position/i.test(attribute)) {
+ if (/pos/i.test(attribute)) {
attributes[i] = attributes[0];
attributes[0] = attribute;
break;
@@ -2332,6 +2334,7 @@ define([
// Retrieve the compiled shader program to assign index values to attributes
var attributeLocations = {};
+ var location;
var index;
var technique = techniques[materials[primitive.material].technique];
var parameters = technique.parameters;
@@ -2340,23 +2343,27 @@ define([
var programVertexAttributes = program.vertexAttributes;
var programAttributeLocations = program._attributeLocations;
- // Note: WebGL shader compiler may have optimized and removed some attributes from programAttributeLocations
- for (var location in programAttributeLocations){
- if (programAttributeLocations.hasOwnProperty(location)) {
+ // Note: WebGL shader compiler may have optimized and removed some attributes from programVertexAttributes
+ for (location in programVertexAttributes){
+ if (programVertexAttributes.hasOwnProperty(location)) {
var attribute = attributes[location];
+ index = programVertexAttributes[location].index;
if (defined(attribute)) {
- var vertexAttribute = programVertexAttributes[location];
- if (defined(vertexAttribute)) {
- index = vertexAttribute.index;
- var parameter = parameters[attribute];
- attributeLocations[parameter.semantic] = index;
- }
- } else {
- // Pre-created attributes.
- // Some pre-created attributes, like per-instance pickIds, may be compiled out of the draw program
- // but should be included in the list of attribute locations for the pick program.
- // This is safe to do since programVertexAttributes and programAttributeLocations are equivalent except
- // that programVertexAttributes optimizes out unused attributes.
+ var parameter = parameters[attribute];
+ attributeLocations[parameter.semantic] = index;
+ }
+ }
+ }
+
+ // Always add pre-created attributes.
+ // Some pre-created attributes, like per-instance pickIds, may be compiled out of the draw program
+ // but should be included in the list of attribute locations for the pick program.
+ // This is safe to do since programVertexAttributes and programAttributeLocations are equivalent except
+ // that programVertexAttributes optimizes out unused attributes.
+ var precreatedAttributes = model._precreatedAttributes;
+ if (defined(precreatedAttributes)) {
+ for (location in precreatedAttributes) {
+ if (precreatedAttributes.hasOwnProperty(location)) {
index = programAttributeLocations[location];
attributeLocations[location] = index;
}
diff --git a/Source/Scene/ModelInstanceCollection.js b/Source/Scene/ModelInstanceCollection.js
index c11760ee9fc0..5935432bc27d 100644
--- a/Source/Scene/ModelInstanceCollection.js
+++ b/Source/Scene/ModelInstanceCollection.js
@@ -789,8 +789,8 @@ define([
for (var i = 0; i < commandsLength; ++i) {
for (var j = 0; j < instancesLength; ++j) {
var drawCommand = DrawCommand.shallowClone(drawCommands[i]);
- drawCommand.modelMatrix = new Matrix4(); // Updated in updateNonInstancedCommands
- drawCommand.boundingVolume = new BoundingSphere(); // Updated in updateNonInstancedCommands
+ drawCommand.modelMatrix = new Matrix4(); // Updated in updateCommandsNonInstanced
+ drawCommand.boundingVolume = new BoundingSphere(); // Updated in updateCommandsNonInstanced
drawCommand.cull = cull;
drawCommand.uniformMap = clone(drawCommand.uniformMap);
if (usesBatchTable) {
@@ -800,8 +800,8 @@ define([
if (allowPicking) {
var pickCommand = DrawCommand.shallowClone(pickCommands[i]);
- pickCommand.modelMatrix = new Matrix4(); // Updated in updateNonInstancedCommands
- pickCommand.boundingVolume = new BoundingSphere(); // Updated in updateNonInstancedCommands
+ pickCommand.modelMatrix = new Matrix4(); // Updated in updateCommandsNonInstanced
+ pickCommand.boundingVolume = new BoundingSphere(); // Updated in updateCommandsNonInstanced
pickCommand.cull = cull;
pickCommand.uniformMap = clone(pickCommand.uniformMap);
if (usesBatchTable) {
@@ -919,8 +919,9 @@ define([
this._state = LoadState.LOADED;
this._ready = true;
- // Expand bounding volume to fit the radius of the loaded model
- this._boundingSphere.radius += model.boundingSphere.radius;
+ // Expand bounding volume to fit the radius of the loaded model including the model's offset from the center
+ var modelRadius = model.boundingSphere.radius + Cartesian3.magnitude(model.boundingSphere.center);
+ this._boundingSphere.radius += modelRadius;
var modelCommands = getModelCommands(model);
this._modelCommands = modelCommands.draw;
diff --git a/Source/Scene/OIT.js b/Source/Scene/OIT.js
index eba923512306..c74b7e945611 100644
--- a/Source/Scene/OIT.js
+++ b/Source/Scene/OIT.js
@@ -11,7 +11,6 @@ define([
'../Renderer/Framebuffer',
'../Renderer/PixelDatatype',
'../Renderer/RenderState',
- '../Renderer/ShaderProgram',
'../Renderer/ShaderSource',
'../Renderer/Texture',
'../Shaders/AdjustTranslucentFS',
@@ -30,7 +29,6 @@ define([
Framebuffer,
PixelDatatype,
RenderState,
- ShaderProgram,
ShaderSource,
Texture,
AdjustTranslucentFS,
@@ -82,8 +80,6 @@ define([
this._translucentRenderStateCache = {};
this._alphaRenderStateCache = {};
- this._translucentShaderCache = {};
- this._alphaShaderCache = {};
this._compositeCommand = undefined;
this._adjustTranslucentCommand = undefined;
@@ -411,9 +407,8 @@ define([
' float ai = czm_gl_FragColor.a;\n' +
' gl_FragColor = vec4(ai);\n';
- function getTranslucentShaderProgram(context, shaderProgram, cache, source) {
- var id = shaderProgram.id;
- var shader = cache[id];
+ function getTranslucentShaderProgram(context, shaderProgram, keyword, source) {
+ var shader = context.shaderCache.getDerivedShaderProgram(shaderProgram, keyword);
if (!defined(shader)) {
var attributeLocations = shaderProgram._attributeLocations;
@@ -446,29 +441,26 @@ define([
source +
'}\n');
- shader = ShaderProgram.fromCache({
- context : context,
+ shader = context.shaderCache.createDerivedShaderProgram(shaderProgram, keyword, {
vertexShaderSource : shaderProgram.vertexShaderSource,
fragmentShaderSource : fs,
attributeLocations : attributeLocations
});
-
- cache[id] = shader;
}
return shader;
}
- function getTranslucentMRTShaderProgram(oit, context, shaderProgram) {
- return getTranslucentShaderProgram(context, shaderProgram, oit._translucentShaderCache, mrtShaderSource);
+ function getTranslucentMRTShaderProgram(context, shaderProgram) {
+ return getTranslucentShaderProgram(context, shaderProgram, 'translucentMRT', mrtShaderSource);
}
- function getTranslucentColorShaderProgram(oit, context, shaderProgram) {
- return getTranslucentShaderProgram(context, shaderProgram, oit._translucentShaderCache, colorShaderSource);
+ function getTranslucentColorShaderProgram(context, shaderProgram) {
+ return getTranslucentShaderProgram(context, shaderProgram, 'translucentMultipass', colorShaderSource);
}
- function getTranslucentAlphaShaderProgram(oit, context, shaderProgram) {
- return getTranslucentShaderProgram(context, shaderProgram, oit._alphaShaderCache, alphaShaderSource);
+ function getTranslucentAlphaShaderProgram(context, shaderProgram) {
+ return getTranslucentShaderProgram(context, shaderProgram, 'alphaMultipass', alphaShaderSource);
}
OIT.prototype.createDerivedCommands = function(command, context, result) {
@@ -487,7 +479,7 @@ define([
result.translucentCommand = DrawCommand.shallowClone(command, result.translucentCommand);
if (!defined(translucentShader) || result.shaderProgramId !== command.shaderProgram.id) {
- result.translucentCommand.shaderProgram = getTranslucentMRTShaderProgram(this, context, command.shaderProgram);
+ result.translucentCommand.shaderProgram = getTranslucentMRTShaderProgram(context, command.shaderProgram);
result.translucentCommand.renderState = getTranslucentMRTRenderState(this, context, command.renderState);
result.shaderProgramId = command.shaderProgram.id;
} else {
@@ -510,9 +502,9 @@ define([
result.alphaCommand = DrawCommand.shallowClone(command, result.alphaCommand);
if (!defined(colorShader) || result.shaderProgramId !== command.shaderProgram.id) {
- result.translucentCommand.shaderProgram = getTranslucentColorShaderProgram(this, context, command.shaderProgram);
+ result.translucentCommand.shaderProgram = getTranslucentColorShaderProgram(context, command.shaderProgram);
result.translucentCommand.renderState = getTranslucentColorRenderState(this, context, command.renderState);
- result.alphaCommand.shaderProgram = getTranslucentAlphaShaderProgram(this, context, command.shaderProgram);
+ result.alphaCommand.shaderProgram = getTranslucentAlphaShaderProgram(context, command.shaderProgram);
result.alphaCommand.renderState = getTranslucentAlphaRenderState(this, context, command.renderState);
result.shaderProgramId = command.shaderProgram.id;
} else {
@@ -639,23 +631,6 @@ define([
this._adjustAlphaCommand.shaderProgram = this._adjustAlphaCommand.shaderProgram && this._adjustAlphaCommand.shaderProgram.destroy();
}
- var name;
- var cache = this._translucentShaderCache;
- for (name in cache) {
- if (cache.hasOwnProperty(name) && defined(cache[name])) {
- cache[name].destroy();
- }
- }
- this._translucentShaderCache = {};
-
- cache = this._alphaShaderCache;
- for (name in cache) {
- if (cache.hasOwnProperty(name) && defined(cache[name])) {
- cache[name].destroy();
- }
- }
- this._alphaShaderCache = {};
-
return destroyObject(this);
};
diff --git a/Source/Scene/PointCloud3DTileContent.js b/Source/Scene/PointCloud3DTileContent.js
index 91749ec79b18..5b47a0a09a2d 100644
--- a/Source/Scene/PointCloud3DTileContent.js
+++ b/Source/Scene/PointCloud3DTileContent.js
@@ -139,6 +139,7 @@ define([
this._contentReadyToProcessPromise = when.defer();
this._readyPromise = when.defer();
this._features = undefined;
+ this._pointsLength = 0;
}
defineProperties(PointCloud3DTileContent.prototype, {
@@ -154,6 +155,15 @@ define([
}
},
+ /**
+ * Part of the {@link Cesium3DTileContent} interface.
+ */
+ pointsLength : {
+ get : function() {
+ return this._pointsLength;
+ }
+ },
+
/**
* Part of the {@link Cesium3DTileContent} interface.
*/
@@ -459,13 +469,13 @@ define([
}
this._parsedContent = {
- pointsLength : pointsLength,
positions : positions,
colors : colors,
normals : normals,
batchIds : batchIds,
styleableProperties : styleableProperties
};
+ this._pointsLength = pointsLength;
this._isQuantized = isQuantized;
this._isOctEncoded16P = isOctEncoded16P;
@@ -487,7 +497,7 @@ define([
function createResources(content, frameState) {
var context = frameState.context;
var parsedContent = content._parsedContent;
- var pointsLength = parsedContent.pointsLength;
+ var pointsLength = content._pointsLength;
var positions = parsedContent.positions;
var colors = parsedContent.colors;
var normals = parsedContent.normals;
diff --git a/Source/Scene/QuadtreePrimitive.js b/Source/Scene/QuadtreePrimitive.js
index 9149b60359e4..78c09c7be8a4 100644
--- a/Source/Scene/QuadtreePrimitive.js
+++ b/Source/Scene/QuadtreePrimitive.js
@@ -9,7 +9,6 @@ define([
'../Core/Event',
'../Core/getTimestamp',
'../Core/Math',
- '../Core/Queue',
'../Core/Ray',
'../Core/Rectangle',
'../Core/Visibility',
@@ -28,7 +27,6 @@ define([
Event,
getTimestamp,
CesiumMath,
- Queue,
Ray,
Rectangle,
Visibility,
diff --git a/Source/Scene/Scene.js b/Source/Scene/Scene.js
index c46d0f8fd57c..33433a159671 100644
--- a/Source/Scene/Scene.js
+++ b/Source/Scene/Scene.js
@@ -28,6 +28,7 @@ define([
'../Core/Matrix4',
'../Core/mergeSort',
'../Core/Occluder',
+ '../Core/PixelFormat',
'../Core/RequestScheduler',
'../Core/ShowGeometryInstanceAttribute',
'../Core/Transforms',
@@ -36,10 +37,14 @@ define([
'../Renderer/Context',
'../Renderer/ContextLimits',
'../Renderer/DrawCommand',
+ '../Renderer/Framebuffer',
'../Renderer/Pass',
'../Renderer/PassState',
+ '../Renderer/PixelDatatype',
+ '../Renderer/RenderState',
'../Renderer/ShaderProgram',
'../Renderer/ShaderSource',
+ '../Renderer/Texture',
'./Camera',
'./CreditDisplay',
'./CullingVolume',
@@ -98,6 +103,7 @@ define([
Matrix4,
mergeSort,
Occluder,
+ PixelFormat,
RequestScheduler,
ShowGeometryInstanceAttribute,
Transforms,
@@ -106,10 +112,14 @@ define([
Context,
ContextLimits,
DrawCommand,
+ Framebuffer,
Pass,
PassState,
+ PixelDatatype,
+ RenderState,
ShaderProgram,
ShaderSource,
+ Texture,
Camera,
CreditDisplay,
CullingVolume,
@@ -299,6 +309,12 @@ define([
this._pickDepths = [];
this._debugGlobeDepths = [];
+ this._pickDepthPassState = undefined;
+ this._pickDepthFramebuffer = undefined;
+ this._pickDepthFramebufferWidth = undefined;
+ this._pickDepthFramebufferHeight = undefined;
+ this._depthOnlyRenderStateCache = {};
+
this._transitioner = new SceneTransitioner(this);
this._renderError = new Event();
@@ -553,6 +569,18 @@ define([
*/
this.useDepthPicking = true;
+ /**
+ * When true
, enables picking translucent geometry using the depth buffer.
+ * {@link Scene#useDepthPicking} must also be true to enable picking the depth buffer.
+ * + * There is a decrease in performance when enabled. There are extra draw calls to write depth for + * translucent geometry. + *
+ * @type {Boolean} + * @default false + */ + this.pickTranslucentDepth = false; + /** * The time in milliseconds to wait before checking if the camera has not moved and fire the cameraMoveEnd event. * @type {Number} @@ -1167,11 +1195,10 @@ define([ shadowsDirty = true; } - if (command.dirty) { + var derivedCommands = command.derivedCommands; + if (command.dirty && defined(derivedCommands)) { command.dirty = false; - var derivedCommands = command.derivedCommands; - if (shadowsEnabled && (command.receiveShadows || command.castShadows)) { derivedCommands.shadows = ShadowMap.createDerivedCommands(shadowMaps, lightShadowMaps, command, shadowsDirty, context, derivedCommands.shadows); } @@ -1185,6 +1212,8 @@ define([ derivedCommands.oit = oit.createDerivedCommands(command, context, derivedCommands.oit); } } + + derivedCommands.depth = createDepthOnlyDerivedCommand(scene, command, context, derivedCommands.depth); } } @@ -1208,6 +1237,7 @@ define([ function clearPasses(passes) { passes.render = false; passes.pick = false; + passes.depth = false; } function updateFrameState(scene, frameNumber, time) { @@ -1582,6 +1612,8 @@ define([ // Some commands, such as OIT derived commands, do not have derived shadow commands themselves // and instead shadowing is built-in. In this case execute the command regularly below. command.derivedCommands.shadows.receiveCommand.execute(context, passState); + } else if (scene.frameState.passes.depth && defined(command.derivedCommands.depth)) { + command.derivedCommands.depth.depthOnlyCommand.execute(context, passState); } else { command.execute(context, passState); } @@ -1709,7 +1741,7 @@ define([ var scratchPerspectiveOffCenterFrustum = new PerspectiveOffCenterFrustum(); var scratchOrthographicFrustum = new OrthographicFrustum(); - function executeCommands(scene, passState, picking) { + function executeCommands(scene, passState) { var camera = scene._camera; var context = scene.context; var us = context.uniformState; @@ -1734,6 +1766,9 @@ define([ us.updatePass(Pass.ENVIRONMENT); var useWebVR = scene._useWebVR && scene.mode !== SceneMode.SCENE2D; + var passes = scene._frameState.passes; + var picking = passes.pick; + var depthOnly = passes.depth; var environmentState = scene._environmentState; // Do not render environment primitives during a pick pass since they do not generate picking commands. @@ -1882,10 +1917,11 @@ define([ commands.length = frustumCommands.indices[Pass.TRANSLUCENT]; executeTranslucentCommands(scene, executeCommand, passState, commands); - if (defined(globeDepth) && environmentState.useGlobeDepthFramebuffer && scene.useDepthPicking) { + if (defined(globeDepth) && (environmentState.useGlobeDepthFramebuffer || depthOnly) && scene.useDepthPicking) { // PERFORMANCE_IDEA: Use MRT to avoid the extra copy. + var depthStencilTexture = depthOnly ? passState.framebuffer.depthStencilTexture : globeDepth.framebuffer.depthStencilTexture; var pickDepth = getPickDepth(scene, index); - pickDepth.update(context, globeDepth.framebuffer.depthStencilTexture); + pickDepth.update(context, depthStencilTexture); pickDepth.executeCopyDepth(context, passState); } } @@ -2004,7 +2040,7 @@ define([ } } - function updateAndExecuteCommands(scene, passState, backgroundColor, picking) { + function updateAndExecuteCommands(scene, passState, backgroundColor) { var context = scene._context; var viewport = passState.viewport; @@ -2012,13 +2048,20 @@ define([ var frameState = scene._frameState; var camera = frameState.camera; var mode = frameState.mode; + var depthOnly = frameState.passes.depth; if (scene._useWebVR && mode !== SceneMode.SCENE2D) { - updatePrimitives(scene); + if (!depthOnly) { + updatePrimitives(scene); + } + createPotentiallyVisibleSet(scene); - updateAndClearFramebuffers(scene, passState, backgroundColor, picking); - executeComputeCommands(scene); - executeShadowMapCastCommands(scene); + updateAndClearFramebuffers(scene, passState, backgroundColor); + + if (!depthOnly) { + executeComputeCommands(scene); + executeShadowMapCastCommands(scene); + } // Based on Calculating Stereo pairs by Paul Bourke // http://paulbourke.net/stereographics/stereorender/ @@ -2042,14 +2085,14 @@ define([ Cartesian3.add(savedCamera.position, eyeTranslation, camera.position); camera.frustum.xOffset = offset; - executeCommands(scene, passState, picking); + executeCommands(scene, passState); viewport.x = passState.viewport.width; Cartesian3.subtract(savedCamera.position, eyeTranslation, camera.position); camera.frustum.xOffset = -offset; - executeCommands(scene, passState, picking); + executeCommands(scene, passState); Camera.clone(savedCamera, camera); } else { @@ -2059,9 +2102,9 @@ define([ viewport.height = context.drawingBufferHeight; if (mode !== SceneMode.SCENE2D || scene._mapMode2D === MapMode2D.ROTATE) { - executeCommandsInViewport(true, scene, passState, backgroundColor, picking); + executeCommandsInViewport(true, scene, passState, backgroundColor); } else { - execute2DViewportCommands(scene, passState, backgroundColor, picking); + execute2DViewportCommands(scene, passState, backgroundColor); } } } @@ -2074,7 +2117,7 @@ define([ var scratch2DViewportEyePoint = new Cartesian3(); var scratch2DViewportWindowCoords = new Cartesian3(); - function execute2DViewportCommands(scene, passState, backgroundColor, picking) { + function execute2DViewportCommands(scene, passState, backgroundColor) { var context = scene.context; var frameState = scene.frameState; var camera = scene.camera; @@ -2105,7 +2148,7 @@ define([ var viewportWidth = viewport.width; if (x === 0.0 || windowCoordinates.x <= 0.0 || windowCoordinates.x >= context.drawingBufferWidth) { - executeCommandsInViewport(true, scene, passState, backgroundColor, picking); + executeCommandsInViewport(true, scene, passState, backgroundColor); } else if (Math.abs(context.drawingBufferWidth * 0.5 - windowCoordinates.x) < 1.0) { viewport.width = windowCoordinates.x; @@ -2116,7 +2159,7 @@ define([ frameState.cullingVolume = camera.frustum.computeCullingVolume(camera.positionWC, camera.directionWC, camera.upWC); context.uniformState.update(frameState); - executeCommandsInViewport(true, scene, passState, backgroundColor, picking); + executeCommandsInViewport(true, scene, passState, backgroundColor); viewport.x = viewport.width; @@ -2128,7 +2171,7 @@ define([ frameState.cullingVolume = camera.frustum.computeCullingVolume(camera.positionWC, camera.directionWC, camera.upWC); context.uniformState.update(frameState); - executeCommandsInViewport(false, scene, passState, backgroundColor, picking); + executeCommandsInViewport(false, scene, passState, backgroundColor); } else if (windowCoordinates.x > context.drawingBufferWidth * 0.5) { viewport.width = windowCoordinates.x; @@ -2138,7 +2181,7 @@ define([ frameState.cullingVolume = camera.frustum.computeCullingVolume(camera.positionWC, camera.directionWC, camera.upWC); context.uniformState.update(frameState); - executeCommandsInViewport(true, scene, passState, backgroundColor, picking); + executeCommandsInViewport(true, scene, passState, backgroundColor); viewport.x += windowCoordinates.x; viewport.width = context.drawingBufferWidth - windowCoordinates.x; @@ -2151,7 +2194,7 @@ define([ frameState.cullingVolume = camera.frustum.computeCullingVolume(camera.positionWC, camera.directionWC, camera.upWC); context.uniformState.update(frameState); - executeCommandsInViewport(false, scene, passState, backgroundColor, picking); + executeCommandsInViewport(false, scene, passState, backgroundColor); } else { viewport.x = windowCoordinates.x; viewport.width = context.drawingBufferWidth - windowCoordinates.x; @@ -2162,7 +2205,7 @@ define([ frameState.cullingVolume = camera.frustum.computeCullingVolume(camera.positionWC, camera.directionWC, camera.upWC); context.uniformState.update(frameState); - executeCommandsInViewport(true, scene, passState, backgroundColor, picking); + executeCommandsInViewport(true, scene, passState, backgroundColor); viewport.x = 0; viewport.width = windowCoordinates.x; @@ -2175,7 +2218,7 @@ define([ frameState.cullingVolume = camera.frustum.computeCullingVolume(camera.positionWC, camera.directionWC, camera.upWC); context.uniformState.update(frameState); - executeCommandsInViewport(false, scene, passState, backgroundColor, picking); + executeCommandsInViewport(false, scene, passState, backgroundColor); } camera._setTransform(transform); @@ -2186,21 +2229,28 @@ define([ viewport.width = viewportWidth; } - function executeCommandsInViewport(firstViewport, scene, passState, backgroundColor, picking) { - if (!firstViewport) { + function executeCommandsInViewport(firstViewport, scene, passState, backgroundColor) { + var depthOnly = scene.frameState.passes.depth; + + if (!firstViewport && !depthOnly) { scene.frameState.commandList.length = 0; } - updatePrimitives(scene); + if (!depthOnly) { + updatePrimitives(scene); + } + createPotentiallyVisibleSet(scene); if (firstViewport) { - updateAndClearFramebuffers(scene, passState, backgroundColor, picking); - executeComputeCommands(scene); - executeShadowMapCastCommands(scene); + updateAndClearFramebuffers(scene, passState, backgroundColor); + if (!depthOnly) { + executeComputeCommands(scene); + executeShadowMapCastCommands(scene); + } } - executeCommands(scene, passState, picking); + executeCommands(scene, passState); } function updateEnvironment(scene) { @@ -2310,10 +2360,12 @@ define([ } } - function updateAndClearFramebuffers(scene, passState, clearColor, picking) { + function updateAndClearFramebuffers(scene, passState, clearColor) { var context = scene._context; var environmentState = scene._environmentState; + var passes = scene._frameState.passes; + var picking = passes.pick; var useWebVR = scene._useWebVR && scene.mode !== SceneMode.SCENE2D; // Preserve the reference to the original framebuffer. @@ -2696,7 +2748,7 @@ define([ var passState = this._pickFramebuffer.begin(scratchRectangle); - updateAndExecuteCommands(this, passState, scratchColorZero, true); + updateAndExecuteCommands(this, passState, scratchColorZero); resolveFramebuffers(this, passState); var object = this._pickFramebuffer.end(scratchRectangle); @@ -2705,20 +2757,170 @@ define([ return object; }; + var fragDepthRegex = /\bgl_FragDepthEXT\b/; + var discardRegex = /\bdiscard\b/; + + function getDepthOnlyShaderProgram(context, shaderProgram) { + var shader = context.shaderCache.getDerivedShaderProgram(shaderProgram, 'depthOnly'); + if (!defined(shader)) { + var attributeLocations = shaderProgram._attributeLocations; + var fs = shaderProgram.fragmentShaderSource; + + var writesDepthOrDiscards = false; + var sources = fs.sources; + var length = sources.length; + for (var i = 0; i < length; ++i) { + if (fragDepthRegex.test(sources[i]) || discardRegex.test(sources[i])) { + writesDepthOrDiscards = true; + break; + } + } + + if (!writesDepthOrDiscards) { + fs = new ShaderSource({ + sources : ['void main() { gl_FragColor = vec4(1.0); }'] + }); + } + + shader = context.shaderCache.createDerivedShaderProgram(shaderProgram, 'depthOnly', { + vertexShaderSource : shaderProgram.vertexShaderSource, + fragmentShaderSource : fs, + attributeLocations : attributeLocations + }); + } + + return shader; + } + + function getDepthOnlyRenderState(scene, renderState) { + var cache = scene._depthOnlyRenderStateCache; + var depthOnlyState = cache[renderState.id]; + if (!defined(depthOnlyState)) { + var rs = RenderState.getState(renderState); + rs.depthMask = true; + rs.colorMask = { + red : false, + green : false, + blue : false, + alpha : false + }; + + depthOnlyState = RenderState.fromCache(rs); + cache[renderState.id] = depthOnlyState; + } + + return depthOnlyState; + } + + function createDepthOnlyDerivedCommand(scene, command, context, result) { + // For a depth only pass, we bind a framebuffer with only a depth attachment (no color attachments), + // do not write color, and write depth. If the fragment shader doesn't modify the fragment depth + // or discard, the driver can replace the fragment shader with a pass-through shader. We're unsure if this + // actually happens so we modify the shader to use a pass-through fragment shader. + + if (!defined(result)) { + result = {}; + } + + var shader; + var renderState; + if (defined(result.depthOnlyCommand)) { + shader = result.depthOnlyCommand.shaderProgram; + renderState = result.depthOnlyCommand.renderState; + } + + result.depthOnlyCommand = DrawCommand.shallowClone(command, result.depthOnlyCommand); + + if (!defined(shader) || result.shaderProgramId !== command.shaderProgram.id) { + result.depthOnlyCommand.shaderProgram = getDepthOnlyShaderProgram(context, command.shaderProgram); + result.depthOnlyCommand.renderState = getDepthOnlyRenderState(scene, command.renderState); + result.shaderProgramId = command.shaderProgram.id; + } else { + result.depthOnlyCommand.shaderProgram = shader; + result.depthOnlyCommand.renderState = renderState; + } + + return result; + } + + function renderTranslucentDepthForPick(scene, drawingBufferPosition) { + // PERFORMANCE_IDEA: render translucent only and merge with the previous frame + var context = scene._context; + var frameState = scene._frameState; + + clearPasses(frameState.passes); + frameState.passes.pick = true; + frameState.passes.depth = true; + frameState.cullingVolume = getPickCullingVolume(scene, drawingBufferPosition, 1, 1); + + var passState = scene._pickDepthPassState; + if (!defined(passState)) { + passState = scene._pickDepthPassState = new PassState(context); + passState.scissorTest = { + enabled : true, + rectangle : new BoundingRectangle() + }; + passState.viewport = new BoundingRectangle(); + } + + var width = context.drawingBufferWidth; + var height = context.drawingBufferHeight; + + var framebuffer = scene._pickDepthFramebuffer; + var pickDepthFBWidth = scene._pickDepthFramebufferWidth; + var pickDepthFBHeight = scene._pickDepthFramebufferHeight; + if (!defined(framebuffer) || pickDepthFBWidth !== width || pickDepthFBHeight !== height) { + scene._pickDepthFramebuffer = scene._pickDepthFramebuffer && scene._pickDepthFramebuffer.destroy(); + framebuffer = scene._pickDepthFramebuffer = new Framebuffer({ + context : context, + depthStencilTexture : new Texture({ + context : context, + width : width, + height : height, + pixelFormat : PixelFormat.DEPTH_STENCIL, + pixelDatatype : PixelDatatype.UNSIGNED_INT_24_8 + }) + }); + + scene._pickDepthFramebufferWidth = width; + scene._pickDepthFramebufferHeight = height; + } + + passState.framebuffer = framebuffer; + passState.viewport.width = width; + passState.viewport.height = height; + passState.scissorTest.rectangle.x = drawingBufferPosition.x; + passState.scissorTest.rectangle.y = height - drawingBufferPosition.y; + passState.scissorTest.rectangle.width = 1; + passState.scissorTest.rectangle.height = 1; + + updateAndExecuteCommands(scene, passState, scratchColorZero); + resolveFramebuffers(scene, passState); + + context.endFrame(); + } + var scratchPackedDepth = new Cartesian4(); var packedDepthScale = new Cartesian4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 16581375.0); /** * Returns the cartesian position reconstructed from the depth buffer and window position. + * The returned position is in world coordinates. Used internally by camera functions to + * prevent conversion to projected 2D coordinates and then back. + *
+ * Set {@link Scene#pickTranslucentDepth} to true
to include the depth of
+ * translucent primitives; otherwise, this essentially picks through translucent primitives.
+ *
+ * The position reconstructed from the depth buffer in 2D may be slightly different from those + * reconstructed in 3D and Columbus view. This is caused by the difference in the distribution + * of depth values of perspective and orthographic projection. + *
+ *
+ * Set {@link Scene#pickTranslucentDepth} to true
to include the depth of
+ * translucent primitives; otherwise, this essentially picks through translucent primitives.
+ *