Skip to content

Commit

Permalink
Configurable frustum width for ray-pick functions
Browse files Browse the repository at this point in the history
  • Loading branch information
lilleyse committed Nov 26, 2018
1 parent 05c44f4 commit e70d371
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 38 deletions.
4 changes: 4 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ Change Log
##### Breaking Changes :mega:
* `TerrainProviders` that implement `availability` must now also implement the `loadTileDataAvailability` method.

##### Deprecated :hourglass_flowing_sand:
* `Scene.clampToHeight` now takes an optional `width` argument before the `result` argument. The previous function definition will no longer work in 1.53. [#7287](https://github.com/AnalyticalGraphicsInc/cesium/pull/7287)

##### Additions :tada:
* Added functions to get the most detailed height of 3D Tiles on-screen or off-screen. [#7115](https://github.com/AnalyticalGraphicsInc/cesium/pull/7115)
* Added `Scene.sampleHeightMostDetailed`, an asynchronous version of `Scene.sampleHeight` that uses the maximum level of detail for 3D Tiles.
Expand All @@ -15,6 +18,7 @@ Change Log
* Added `computeLineSegmentLineSegmentIntersection` to `Intersections2D`. [#7228](https://github.com/AnalyticalGraphicsInc/Cesium/pull/7228)
* Added ability to load availability progressively from a quantized mesh extension instead of upfront. This will speed up load time and reduce memory usage. [#7196](https://github.com/AnalyticalGraphicsInc/cesium/pull/7196)
* Added the ability to apply styles to 3D Tilesets that don't contain features. [#7255](https://github.com/AnalyticalGraphicsInc/Cesium/pull/7255)
* Added the ability to specify the width of the intersection volume for `Scene.sampleHeight`, `Scene.clampToHeight`, `Scene.sampleHeightMostDetailed`, and `Scene.clampToHeightMostDetailed`. [#7287](https://github.com/AnalyticalGraphicsInc/cesium/pull/7287)

##### Fixes :wrench:
* Fixed issue causing polyline to look wavy depending on the position of the camera [#7209](https://github.com/AnalyticalGraphicsInc/cesium/pull/7209)
Expand Down
97 changes: 59 additions & 38 deletions Source/Scene/Scene.js
Original file line number Diff line number Diff line change
Expand Up @@ -170,8 +170,9 @@ define([
};
};

function AsyncRayPick(ray, primitives) {
function AsyncRayPick(ray, width, primitives) {
this.ray = ray;
this.width = width;
this.primitives = primitives;
this.ready = false;
this.deferred = when.defer();
Expand Down Expand Up @@ -775,16 +776,18 @@ define([
camera.frustum.far = 10000000000.0;
}

var pickOffscreenDefaultWidth = 0.1;
var pickOffscreenViewport = new BoundingRectangle(0, 0, 1, 1);
var pickOffscreenCamera = new Camera(this);
pickOffscreenCamera.frustum = new OrthographicFrustum({
width: 0.01,
width: pickOffscreenDefaultWidth,
aspectRatio: 1.0,
near: 0.1
});

this._view = new View(this, camera, viewport);
this._pickOffscreenView = new View(this, pickOffscreenCamera, pickOffscreenViewport);
this._pickOffscreenDefaultWidth = pickOffscreenDefaultWidth;

this._defaultView = new View(this, camera, viewport);
this._view = this._defaultView;
Expand Down Expand Up @@ -3758,7 +3761,7 @@ define([
var scratchRight = new Cartesian3();
var scratchUp = new Cartesian3();

function updateCameraFromRay(ray, camera) {
function updateOffscreenCameraFromRay(scene, ray, width, camera) {
var direction = ray.direction;
var orthogonalAxis = Cartesian3.mostOrthogonalAxis(direction, scratchRight);
var right = Cartesian3.cross(direction, orthogonalAxis, scratchRight);
Expand All @@ -3768,6 +3771,8 @@ define([
camera.direction = direction;
camera.up = up;
camera.right = right;

camera.frustum.width = defaultValue(width, scene._pickOffscreenDefaultWidth);
}

function updateAsyncRayPick(scene, asyncRayPick) {
Expand All @@ -3779,9 +3784,10 @@ define([
scene._view = view;

var ray = asyncRayPick.ray;
var width = asyncRayPick.width;
var primitives = asyncRayPick.primitives;

updateCameraFromRay(ray, view.camera);
updateOffscreenCameraFromRay(scene, ray, width, view.camera);

updateFrameState(scene);
frameState.passes.offscreen = true;
Expand Down Expand Up @@ -3826,7 +3832,7 @@ define([
}
}

function launchAsyncRayPick(scene, ray, objectsToExclude, callback) {
function launchAsyncRayPick(scene, ray, objectsToExclude, width, callback) {
var asyncPrimitives = [];
var primitives = scene.primitives;
var length = primitives.length;
Expand All @@ -3842,7 +3848,7 @@ define([
return when.resolve(callback());
}

var asyncRayPick = new AsyncRayPick(ray, asyncPrimitives);
var asyncRayPick = new AsyncRayPick(ray, width, asyncPrimitives);
scene._asyncRayPicks.push(asyncRayPick);
return asyncRayPick.promise.then(function() {
return callback();
Expand All @@ -3858,15 +3864,15 @@ define([
(objectsToExclude.indexOf(object.id) > -1);
}

function getRayIntersection(scene, ray, objectsToExclude, requirePosition, async) {
function getRayIntersection(scene, ray, objectsToExclude, width, requirePosition, async) {
var context = scene._context;
var uniformState = context.uniformState;
var frameState = scene._frameState;

var view = scene._pickOffscreenView;
scene._view = view;

updateCameraFromRay(ray, view.camera);
updateOffscreenCameraFromRay(scene, ray, width, view.camera);

scratchRectangle = BoundingRectangle.clone(view.viewport, scratchRectangle);

Expand Down Expand Up @@ -3917,22 +3923,22 @@ define([
}
}

function getRayIntersections(scene, ray, limit, objectsToExclude, requirePosition, async) {
function getRayIntersections(scene, ray, limit, objectsToExclude, width, requirePosition, async) {
var pickCallback = function() {
return getRayIntersection(scene, ray, objectsToExclude, requirePosition, async);
return getRayIntersection(scene, ray, objectsToExclude, width, requirePosition, async);
};
return drillPick(limit, pickCallback);
}

function pickFromRay(scene, ray, objectsToExclude, requirePosition, async) {
var results = getRayIntersections(scene, ray, 1, objectsToExclude, requirePosition, async);
function pickFromRay(scene, ray, objectsToExclude, width, requirePosition, async) {
var results = getRayIntersections(scene, ray, 1, objectsToExclude, width, requirePosition, async);
if (results.length > 0) {
return results[0];
}
}

function drillPickFromRay(scene, ray, limit, objectsToExclude, requirePosition, async) {
return getRayIntersections(scene, ray, limit, objectsToExclude, requirePosition, async);
function drillPickFromRay(scene, ray, limit, objectsToExclude, width, requirePosition, async) {
return getRayIntersections(scene, ray, limit, objectsToExclude, width, requirePosition, async);
}

/**
Expand All @@ -3949,18 +3955,19 @@ define([
*
* @param {Ray} ray The ray.
* @param {Object[]} [objectsToExclude] A list of primitives, entities, or 3D Tiles features to exclude from the ray intersection.
* @param {Number} [width=0.1] Width of the intersection volume in meters.
* @returns {Object} An object containing the object and position of the first intersection.
*
* @exception {DeveloperError} Ray intersections are only supported in 3D mode.
*/
Scene.prototype.pickFromRay = function(ray, objectsToExclude) {
Scene.prototype.pickFromRay = function(ray, objectsToExclude, width) {
//>>includeStart('debug', pragmas.debug);
Check.defined('ray', ray);
if (this._mode !== SceneMode.SCENE3D) {
throw new DeveloperError('Ray intersections are only supported in 3D mode.');
}
//>>includeEnd('debug');
return pickFromRay(this, ray, objectsToExclude, false, false);
return pickFromRay(this, ray, objectsToExclude, width, false, false);
};

/**
Expand All @@ -3979,18 +3986,19 @@ define([
* @param {Ray} ray The ray.
* @param {Number} [limit=Number.MAX_VALUE] If supplied, stop finding intersections after this many intersections.
* @param {Object[]} [objectsToExclude] A list of primitives, entities, or 3D Tiles features to exclude from the ray intersection.
* @param {Number} [width=0.1] Width of the intersection volume in meters.
* @returns {Object[]} List of objects containing the object and position of each intersection.
*
* @exception {DeveloperError} Ray intersections are only supported in 3D mode.
*/
Scene.prototype.drillPickFromRay = function(ray, limit, objectsToExclude) {
Scene.prototype.drillPickFromRay = function(ray, limit, objectsToExclude, width) {
//>>includeStart('debug', pragmas.debug);
Check.defined('ray', ray);
if (this._mode !== SceneMode.SCENE3D) {
throw new DeveloperError('Ray intersections are only supported in 3D mode.');
}
//>>includeEnd('debug');
return drillPickFromRay(this, ray, limit, objectsToExclude, false, false);
return drillPickFromRay(this, ray, limit, objectsToExclude, width,false, false);
};

/**
Expand All @@ -4001,11 +4009,12 @@ define([
*
* @param {Ray} ray The ray.
* @param {Object[]} [objectsToExclude] A list of primitives, entities, or 3D Tiles features to exclude from the ray intersection.
* @param {Number} [width=0.1] Width of the intersection volume in meters.
* @returns {Promise.<Object>} A promise that resolves to an object containing the object and position of the first intersection.
*
* @exception {DeveloperError} Ray intersections are only supported in 3D mode.
*/
Scene.prototype.pickFromRayMostDetailed = function(ray, objectsToExclude) {
Scene.prototype.pickFromRayMostDetailed = function(ray, objectsToExclude, width) {
//>>includeStart('debug', pragmas.debug);
Check.defined('ray', ray);
if (this._mode !== SceneMode.SCENE3D) {
Expand All @@ -4015,8 +4024,8 @@ define([
var that = this;
ray = Ray.clone(ray);
objectsToExclude = defined(objectsToExclude) ? objectsToExclude.slice() : objectsToExclude;
return launchAsyncRayPick(this, ray, objectsToExclude, function() {
return pickFromRay(that, ray, objectsToExclude, false, true);
return launchAsyncRayPick(this, ray, objectsToExclude, width, function() {
return pickFromRay(that, ray, objectsToExclude, width, false, true);
});
};

Expand All @@ -4029,11 +4038,12 @@ define([
* @param {Ray} ray The ray.
* @param {Number} [limit=Number.MAX_VALUE] If supplied, stop finding intersections after this many intersections.
* @param {Object[]} [objectsToExclude] A list of primitives, entities, or 3D Tiles features to exclude from the ray intersection.
* @param {Number} [width=0.1] Width of the intersection volume in meters.
* @returns {Promise.<Object[]>} A promise that resolves to a list of objects containing the object and position of each intersection.
*
* @exception {DeveloperError} Ray intersections are only supported in 3D mode.
*/
Scene.prototype.drillPickFromRayMostDetailed = function(ray, limit, objectsToExclude) {
Scene.prototype.drillPickFromRayMostDetailed = function(ray, limit, objectsToExclude, width) {
//>>includeStart('debug', pragmas.debug);
Check.defined('ray', ray);
if (this._mode !== SceneMode.SCENE3D) {
Expand All @@ -4043,8 +4053,8 @@ define([
var that = this;
ray = Ray.clone(ray);
objectsToExclude = defined(objectsToExclude) ? objectsToExclude.slice() : objectsToExclude;
return launchAsyncRayPick(this, ray, objectsToExclude, function() {
return drillPickFromRay(that, ray, limit, objectsToExclude, false, true);
return launchAsyncRayPick(this, ray, objectsToExclude, width, function() {
return drillPickFromRay(that, ray, limit, objectsToExclude, width, false, true);
});
};

Expand Down Expand Up @@ -4082,20 +4092,20 @@ define([
return cartographic.height;
}

function sampleHeightMostDetailed(scene, cartographic, objectsToExclude) {
function sampleHeightMostDetailed(scene, cartographic, objectsToExclude, width) {
var ray = getRayForSampleHeight(scene, cartographic);
return launchAsyncRayPick(scene, ray, objectsToExclude, function() {
var pickResult = pickFromRay(scene, ray, objectsToExclude, true, true);
return launchAsyncRayPick(scene, ray, objectsToExclude, width, function() {
var pickResult = pickFromRay(scene, ray, objectsToExclude, width, true, true);
if (defined(pickResult)) {
return getHeightFromCartesian(scene, pickResult.position);
}
});
}

function clampToHeightMostDetailed(scene, cartesian, objectsToExclude, result) {
function clampToHeightMostDetailed(scene, cartesian, objectsToExclude, width, result) {
var ray = getRayForClampToHeight(scene, cartesian);
return launchAsyncRayPick(scene, ray, objectsToExclude, function() {
var pickResult = pickFromRay(scene, ray, objectsToExclude, true, true);
return launchAsyncRayPick(scene, ray, objectsToExclude, width, function() {
var pickResult = pickFromRay(scene, ray, objectsToExclude, width, true, true);
if (defined(pickResult)) {
return Cartesian3.clone(pickResult.position, result);
}
Expand All @@ -4113,6 +4123,7 @@ define([
*
* @param {Cartographic} position The cartographic position to sample height from.
* @param {Object[]} [objectsToExclude] A list of primitives, entities, or 3D Tiles features to not sample height from.
* @param {Number} [width=0.1] Width of the intersection volume in meters.
* @returns {Number} The height. This may be <code>undefined</code> if there was no scene geometry to sample height from.
*
* @example
Expand All @@ -4127,7 +4138,7 @@ define([
* @exception {DeveloperError} sampleHeight is only supported in 3D mode.
* @exception {DeveloperError} sampleHeight requires depth texture support. Check sampleHeightSupported.
*/
Scene.prototype.sampleHeight = function(position, objectsToExclude) {
Scene.prototype.sampleHeight = function(position, objectsToExclude, width) {
//>>includeStart('debug', pragmas.debug);
Check.defined('position', position);
if (this._mode !== SceneMode.SCENE3D) {
Expand All @@ -4138,7 +4149,7 @@ define([
}
//>>includeEnd('debug');
var ray = getRayForSampleHeight(this, position);
var pickResult = pickFromRay(this, ray, objectsToExclude, true, false);
var pickResult = pickFromRay(this, ray, objectsToExclude, width, true, false);
if (defined(pickResult)) {
return getHeightFromCartesian(this, pickResult.position);
}
Expand All @@ -4155,6 +4166,7 @@ define([
*
* @param {Cartesian3} cartesian The cartesian position.
* @param {Object[]} [objectsToExclude] A list of primitives, entities, or 3D Tiles features to not clamp to.
* @param {Number} [width=0.1] Width of the intersection volume in meters.
* @param {Cartesian3} [result] An optional object to return the clamped position.
* @returns {Cartesian3} The modified result parameter or a new Cartesian3 instance if one was not provided. This may be <code>undefined</code> if there was no scene geometry to clamp to.
*
Expand All @@ -4170,7 +4182,7 @@ define([
* @exception {DeveloperError} clampToHeight is only supported in 3D mode.
* @exception {DeveloperError} clampToHeight requires depth texture support. Check clampToHeightSupported.
*/
Scene.prototype.clampToHeight = function(cartesian, objectsToExclude, result) {
Scene.prototype.clampToHeight = function(cartesian, objectsToExclude, width, result) {
//>>includeStart('debug', pragmas.debug);
Check.defined('cartesian', cartesian);
if (this._mode !== SceneMode.SCENE3D) {
Expand All @@ -4180,8 +4192,15 @@ define([
throw new DeveloperError('clampToHeight requires depth texture support. Check clampToHeightSupported.');
}
//>>includeEnd('debug');

if (width instanceof Cartesian3) {
result = width;
width = undefined;
deprecationWarning('clampToHeight-parameter-change', 'clampToHeight now takes an optional width argument before the result argument in Cesium 1.52. The previous function definition will no longer work in 1.53.');
}

var ray = getRayForClampToHeight(this, cartesian);
var pickResult = pickFromRay(this, ray, objectsToExclude, true, false);
var pickResult = pickFromRay(this, ray, objectsToExclude, width, true, false);
if (defined(pickResult)) {
return Cartesian3.clone(pickResult.position, result);
}
Expand All @@ -4196,6 +4215,7 @@ define([
*
* @param {Cartographic[]} positions The cartographic positions to update with sampled heights.
* @param {Object[]} [objectsToExclude] A list of primitives, entities, or 3D Tiles features to not sample height from.
* @param {Number} [width=0.1] Width of the intersection volume in meters.
* @returns {Promise.<Number[]>} A promise that resolves to the provided list of positions when the query has completed.
*
* @example
Expand All @@ -4214,7 +4234,7 @@ define([
* @exception {DeveloperError} sampleHeightMostDetailed is only supported in 3D mode.
* @exception {DeveloperError} sampleHeightMostDetailed requires depth texture support. Check sampleHeightSupported.
*/
Scene.prototype.sampleHeightMostDetailed = function(positions, objectsToExclude) {
Scene.prototype.sampleHeightMostDetailed = function(positions, objectsToExclude, width) {
//>>includeStart('debug', pragmas.debug);
Check.defined('positions', positions);
if (this._mode !== SceneMode.SCENE3D) {
Expand All @@ -4228,7 +4248,7 @@ define([
var length = positions.length;
var promises = new Array(length);
for (var i = 0; i < length; ++i) {
promises[i] = sampleHeightMostDetailed(this, positions[i], objectsToExclude);
promises[i] = sampleHeightMostDetailed(this, positions[i], objectsToExclude, width);
}
return when.all(promises).then(function(heights) {
var length = heights.length;
Expand All @@ -4247,6 +4267,7 @@ define([
*
* @param {Cartesian3[]} cartesians The cartesian positions to update with clamped positions.
* @param {Object[]} [objectsToExclude] A list of primitives, entities, or 3D Tiles features to not clamp to.
* @param {Number} [width=0.1] Width of the intersection volume in meters.
* @returns {Promise.<Cartesian3[]>} A promise that resolves to the provided list of positions when the query has completed.
*
* @example
Expand All @@ -4265,7 +4286,7 @@ define([
* @exception {DeveloperError} clampToHeightMostDetailed is only supported in 3D mode.
* @exception {DeveloperError} clampToHeightMostDetailed requires depth texture support. Check clampToHeightSupported.
*/
Scene.prototype.clampToHeightMostDetailed = function(cartesians, objectsToExclude) {
Scene.prototype.clampToHeightMostDetailed = function(cartesians, objectsToExclude, width) {
//>>includeStart('debug', pragmas.debug);
Check.defined('cartesians', cartesians);
if (this._mode !== SceneMode.SCENE3D) {
Expand All @@ -4279,7 +4300,7 @@ define([
var length = cartesians.length;
var promises = new Array(length);
for (var i = 0; i < length; ++i) {
promises[i] = clampToHeightMostDetailed(this, cartesians[i], objectsToExclude, cartesians[i]);
promises[i] = clampToHeightMostDetailed(this, cartesians[i], objectsToExclude, width, cartesians[i]);
}
return when.all(promises).then(function(clampedCartesians) {
var length = clampedCartesians.length;
Expand Down

0 comments on commit e70d371

Please sign in to comment.