diff --git a/Source/Scene/Scene.js b/Source/Scene/Scene.js
index dc5a93041057..8bbbfcd457c7 100644
--- a/Source/Scene/Scene.js
+++ b/Source/Scene/Scene.js
@@ -3548,6 +3548,17 @@ define([
var scratchUp = new Cartesian3();
function pickFromRay(scene, ray, pickPosition, pickObject) {
+ //>>includeStart('debug', pragmas.debug);
+ Check.defined('ray', ray);
+ if (pickPosition && !this.pickPositionSupported) {
+ throw new DeveloperError('Picking from the depth buffer is not supported. Check pickPositionSupported.');
+ }
+ if (scene._mode === SceneMode.SCENE2D) {
+ throw new DeveloperError('Pick from ray is not supported in 2D.');
+ }
+ //>>includeEnd('debug');
+
+
var context = scene._context;
var uniformState = context.uniformState;
var frameState = scene._frameState;
@@ -3635,7 +3646,7 @@ define([
/**
* Returns an object with a `primitive` property that contains the first (top) primitive in the scene
* hit by the ray or undefined if nothing is hit. Other properties may potentially be set depending on the type
- * of primitive and may be used to further identify the picked object.
+ * of primitive and may be used to further identify the picked object. The ray must be given in world coordinates.
*
* When a feature of a 3D Tiles tileset is picked, pick
returns a {@link Cesium3DTileFeature} object.
*
@@ -3648,9 +3659,6 @@ define([
* @see Scene#pick
*/
Scene.prototype.pickFromRay = function(ray) {
- //>>includeStart('debug', pragmas.debug);
- Check.defined('ray', ray);
- //>>includeEnd('debug');
var pickResult = pickFromRay(this, ray, false, true);
if (defined(pickResult)) {
return pickResult.object;
@@ -3658,7 +3666,8 @@ define([
};
/**
- * Returns the cartesian position of the first intersection of the ray or undefined if nothing is hit.
+ * Returns the position, in world coordinates, of the first intersection of the ray or undefined if nothing is hit.
+ * The ray must be given in world coordinates.
*
* @private
*
@@ -3669,12 +3678,6 @@ define([
* @exception {DeveloperError} Picking from the depth buffer is not supported. Check pickPositionSupported.
*/
Scene.prototype.pickPositionFromRay = function(ray, result) {
- //>>includeStart('debug', pragmas.debug);
- Check.defined('ray', ray);
- if (!this.pickPositionSupported) {
- throw new DeveloperError('Picking from the depth buffer is not supported. Check pickPositionSupported.');
- }
- //>>includeEnd('debug');
var pickResult = pickFromRay(this, ray, true, false);
if (defined(pickResult)) {
return Cartesian3.clone(pickResult.position, result);
@@ -3684,7 +3687,7 @@ define([
/**
* Returns a list of objects, each containing a `primitive` property, for all primitives hit
* by the ray. Other properties may also be set depending on the type of primitive and may be
- * used to further identify the picked object.
+ * used to further identify the picked object. The ray must be given in world coordinates.
* The primitives in the list are ordered by their visual order in the scene (front to back).
*
* @private
@@ -3696,9 +3699,6 @@ define([
* @see Scene#drillPick
*/
Scene.prototype.drillPickFromRay = function(ray, limit) {
- //>>includeStart('debug', pragmas.debug);
- Check.defined('ray', ray);
- //>>includeEnd('debug');
var that = this;
var pickCallback = function() {
return pickFromRay(that, ray, false, true);
@@ -3710,7 +3710,7 @@ define([
};
/**
- * Returns a list of cartesian positions containing intersections of the ray in the scene.
+ * Returns a list of cartesian positions, in world coordinates, containing intersections of the ray in the scene.
*
* @private
*
@@ -3721,9 +3721,6 @@ define([
* @exception {DeveloperError} Picking from the depth buffer is not supported. Check pickPositionSupported.
*/
Scene.prototype.drillPickPositionFromRay = function(ray, limit) {
- //>>includeStart('debug', pragmas.debug);
- Check.defined('ray', ray);
- //>>includeEnd('debug');
if (!this.pickPositionSupported) {
throw new DeveloperError('Picking from the depth buffer is not supported. Check pickPositionSupported.');
}
@@ -3758,9 +3755,6 @@ define([
*
*/
Scene.prototype.drillPick = function(windowPosition, limit, width, height) {
- //>>includeStart('debug', pragmas.debug);
- Check.defined('windowPosition', windowPosition);
- //>>includeEnd('debug');
var that = this;
var pickCallback = function() {
var object = that.pick(windowPosition, width, height);
@@ -3804,9 +3798,6 @@ define([
Scene.prototype.sampleHeight = function(position, objectsToExclude) {
//>>includeStart('debug', pragmas.debug);
Check.defined('position', position);
- if (!this.pickPositionSupported) {
- throw new DeveloperError('Picking from the depth buffer is not supported. Check pickPositionSupported.');
- }
//>>includeEnd('debug');
var globe = this.globe;
var ellipsoid = defined(globe) ? globe.ellipsoid : this.mapProjection.ellipsoid;
@@ -3869,6 +3860,9 @@ define([
* @exception {DeveloperError} Picking from the depth buffer is not supported. Check pickPositionSupported.
*/
Scene.prototype.clampToHeight = function(cartesian, objectsToExclude, result) {
+ //>>includeStart('debug', pragmas.debug);
+ Check.defined('cartesian', cartesian);
+ //>>includeEnd('debug');
var globe = this.globe;
var ellipsoid = defined(globe) ? globe.ellipsoid : this.mapProjection.ellipsoid;
var cartographic = Cartographic.fromCartesian(cartesian, ellipsoid, scratchPickCartographic);
diff --git a/Specs/Scene/PickSpec.js b/Specs/Scene/PickSpec.js
index 03d2ae3964e7..5343dce4c007 100644
--- a/Specs/Scene/PickSpec.js
+++ b/Specs/Scene/PickSpec.js
@@ -1,29 +1,41 @@
defineSuite([
+ 'Core/Cartographic',
'Core/FeatureDetection',
'Core/GeometryInstance',
'Core/Math',
+ 'Core/Matrix4',
'Core/OrthographicFrustum',
'Core/PerspectiveFrustum',
+ 'Core/Ray',
'Core/Rectangle',
'Core/RectangleGeometry',
'Core/ShowGeometryInstanceAttribute',
+ 'Core/Transforms',
+ 'Scene/Cesium3DTileset',
'Scene/EllipsoidSurfaceAppearance',
'Scene/Primitive',
'Scene/SceneMode',
+ 'Specs/Cesium3DTilesTester',
'Specs/createCanvas',
'Specs/createScene'
], 'Scene/Pick', function(
+ Cartographic,
FeatureDetection,
GeometryInstance,
CesiumMath,
+ Matrix4,
OrthographicFrustum,
PerspectiveFrustum,
+ Ray,
Rectangle,
RectangleGeometry,
ShowGeometryInstanceAttribute,
+ Transforms,
+ Cesium3DTileset,
EllipsoidSurfaceAppearance,
Primitive,
SceneMode,
+ Cesium3DTilesTester,
createCanvas,
createScene) {
'use strict';
@@ -32,6 +44,9 @@ defineSuite([
var primitives;
var camera;
var primitiveRectangle = Rectangle.fromDegrees(-1.0, -1.0, 1.0, 1.0);
+ var otherRectangle = Rectangle.fromDegrees(-45.0, -1.0, -43.0, 1.0);
+ var primitiveRay;
+ var otherRay;
beforeAll(function() {
scene = createScene({
@@ -39,6 +54,16 @@ defineSuite([
});
primitives = scene.primitives;
camera = scene.camera;
+
+ camera.setView({
+ destination : primitiveRectangle
+ });
+ primitiveRay = new Ray(camera.positionWC, camera.directionWC);
+
+ camera.setView({
+ destination : otherRectangle
+ });
+ otherRay = new Ray(camera.positionWC, camera.directionWC);
});
afterAll(function() {
@@ -82,6 +107,20 @@ defineSuite([
return e;
}
+ function createTileset() {
+ var url = 'Data/Cesium3DTiles/Batched/BatchedWithTransformBox/tileset.json';
+ var options = {
+ maximumScreenSpaceError : 0
+ };
+ return Cesium3DTilesTester.loadTileset(scene, url, options).then(function(tileset) {
+ var cartographic = Rectangle.center(primitiveRectangle);
+ var cartesian = Cartographic.toCartesian(cartographic);
+ tileset.root.transform = Matrix4.IDENTITY;
+ tileset.modelMatrix = Transforms.eastNorthUpToFixedFrame(cartesian);
+ return Cesium3DTilesTester.waitForTilesLoaded(scene, tileset);
+ });
+ }
+
describe('pick', function() {
it('does not pick undefined window positions', function() {
expect(function() {
@@ -364,4 +403,82 @@ defineSuite([
});
});
});
+
+ describe('pickFromRay', function() {
+ it('picks a tileset', function() {
+ return createTileset().then(function(tileset) {
+ scene.renderForSpecs();
+ var picked = scene.pickFromRay(primitiveRay);
+ expect(picked.primitive).toBe(tileset);
+ });
+ });
+
+ it('picks a primitive', function() {
+ var rectangle = createRectangle();
+ var picked = scene.pickFromRay(primitiveRay);
+ expect(picked.primitive).toBe(rectangle);
+ });
+
+ it('does not pick primitive', function() {
+ createRectangle();
+ var picked = scene.pickFromRay(otherRay);
+ expect(picked).toBeUndefined();
+ });
+
+ it('does not pick primitives when show is false', function() {
+ var rectangle = createRectangle();
+ rectangle.show = false;
+ var picked = scene.pickFromRay(primitiveRay);
+ expect(picked).toBeUndefined();
+ });
+
+ it('does not pick primitives when alpha is zero', function() {
+ var rectangle = createRectangle();
+ rectangle.appearance.material.uniforms.color.alpha = 0.0;
+ var picked = scene.pickFromRay(primitiveRay);
+ expect(picked).toBeUndefined();
+ });
+
+ it('picks the top primitive', function() {
+ createRectangle();
+ var rectangle2 = createRectangle();
+ rectangle2.height = 0.01;
+
+ var picked = scene.pickFromRay(primitiveRay);
+ expect(picked.primitive).toBe(rectangle2);
+ });
+
+ it('picks when main camera is in 3D with orthographic projection', function() {
+ var frustum = new OrthographicFrustum();
+ frustum.aspectRatio = 1.0;
+ frustum.width = 20.0;
+ camera.frustum = frustum;
+
+ // force off center update
+ expect(frustum.projectionMatrix).toBeDefined();
+
+ camera.setView({ destination : primitiveRectangle });
+ var rectangle = createRectangle();
+ scene.initializeFrame();
+ var picked = scene.pickFromRay(primitiveRay);
+ expect(picked.primitive).toBe(rectangle);
+ });
+
+ it('picks when main camera is in CV', function() {
+ // TODO
+ });
+
+ it('throws if ray is undefined', function() {
+ expect(function() {
+ scene.pickFromRay(undefined);
+ }).toThrowDeveloperError();
+ });
+
+ // it('throws if main camera is in 2D', function() {
+ // scene.morphTo2D(0.0);
+ // expect(function() {
+ // scene.pickFromRay(primitiveRay);
+ // }).toThrowDeveloperError();
+ // });
+ });
}, 'WebGL');