Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix billboard on terrain and Globe.getHeight #4622

Merged
merged 21 commits into from
Dec 26, 2016
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
Change Log
==========
* Fixed issue where billboards on terrain had some offset. [#4598](https://github.com/AnalyticalGraphicsInc/cesium/issues/4598)
* Fixed issue where `globe.getHeight` randomly returned 'undefined'. [#3411](https://github.com/AnalyticalGraphicsInc/cesium/issues/3411)

### 1.28 - 2016-12-01

Expand Down
40 changes: 38 additions & 2 deletions Source/Scene/Globe.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ define([
'../Core/Event',
'../Core/IntersectionTests',
'../Core/loadImage',
'../Core/Math',
'../Core/Ray',
'../Core/Rectangle',
'../Renderer/ShaderSource',
Expand Down Expand Up @@ -43,6 +44,7 @@ define([
Event,
IntersectionTests,
loadImage,
CesiumMath,
Ray,
Rectangle,
ShaderSource,
Expand Down Expand Up @@ -424,10 +426,44 @@ define([
}

var ellipsoid = this._surface._tileProvider.tilingScheme.ellipsoid;
var cartesian = ellipsoid.cartographicToCartesian(cartographic, scratchGetHeightCartesian);

//cartesian has to be on the ellipsoid surface for `ellipsoid.geodeticSurfaceNormal`
var cartesian = Cartesian3.fromRadians(cartographic.longitude, cartographic.latitude, 0.0, ellipsoid, scratchGetHeightCartesian);

var ray = scratchGetHeightRay;
Cartesian3.normalize(cartesian, ray.direction);
var surfaceNormal = ellipsoid.geodeticSurfaceNormal(cartesian, ray.direction);

// compute origin point

// Try to find the intersection point between the surface normal and z-axis.
// Ellipsoid is a surface of revolution, so surface normal intersects the rotation axis (z-axis)

// compute the magnitude required to bring surface normal to x=0, y=0, from cartesian
var magnitude;

// avoid dividing by zero
if (Math.abs(surfaceNormal.x) > CesiumMath.EPSILON16){
magnitude = cartesian.x / surfaceNormal.x;
} else if (Math.abs(surfaceNormal.y) > CesiumMath.EPSILON16){
magnitude = cartesian.y / surfaceNormal.y;
} else if (Math.abs(surfaceNormal.z) > CesiumMath.EPSILON16){ //surface normal is (0,0,1) | (0,0,-1) | (0,0,0)
magnitude = cartesian.z / surfaceNormal.z;
} else { //(0,0,0), just for case
magnitude = 0;
}

var vectorToMinimumPoint = Cartesian3.multiplyByScalar(surfaceNormal, magnitude, scratchGetHeightIntersection);
Cartesian3.subtract(cartesian, vectorToMinimumPoint, ray.origin);

// Theoretically, the intersection point can be outside the ellipsoid, so we have to check if the result's 'z' is inside the ellipsoid (with some buffer)
if (Math.abs(ray.origin.z) >= ellipsoid.radii.z -11500.0){
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of hard coding -11500.0 here and below, can this use some percentage of ellipsoid.radii.maximumComponent? Or does the buffer need to be this big? Instead, can it be a much smaller epsilon?

// intersection point is outside the ellipsoid, try other value
magnitude = Math.min(defaultValue(tile.data.minimumHeight, 0.0),-11500.0);

// multiply by the *positive* value of the magnitude
vectorToMinimumPoint = Cartesian3.multiplyByScalar(surfaceNormal, Math.abs(magnitude) + 1, scratchGetHeightIntersection);
Cartesian3.subtract(cartesian, vectorToMinimumPoint, ray.origin);
}

var intersection = tile.data.pick(ray, undefined, undefined, false, scratchGetHeightIntersection);
if (!defined(intersection)) {
Expand Down
45 changes: 39 additions & 6 deletions Source/Scene/QuadtreePrimitive.js
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,7 @@ define([
QuadtreePrimitive.prototype.updateHeight = function(cartographic, callback) {
var primitive = this;
var object = {
position : undefined,
positionOnEllipsoidSurface : undefined,
positionCartographic : cartographic,
level : -1,
callback : callback
Expand Down Expand Up @@ -455,7 +455,7 @@ define([
customDataRemoved.length = 0;
}

// Our goal with load ordering is to first load all of the tiles we need to
// Our goal with load ordering is to first load all of the tiles we need to
// render the current scene at full detail. Loading any other tiles is just
// a form of prefetching, and we need not do it at all (other concerns aside). This
// simple and obvious statement gets more complicated when we realize that, because
Expand Down Expand Up @@ -761,13 +761,46 @@ define([
var data = customData[i];

if (tile.level > data.level) {
if (!defined(data.position)) {
data.position = ellipsoid.cartographicToCartesian(data.positionCartographic);
if (!defined(data.positionOnEllipsoidSurface)) {
// cartesian has to be on the ellipsoid surface for `ellipsoid.geodeticSurfaceNormal`
data.positionOnEllipsoidSurface = Cartesian3.fromRadians(data.positionCartographic.longitude, data.positionCartographic.latitude, 0.0, ellipsoid);
}

if (mode === SceneMode.SCENE3D) {
Cartesian3.clone(Cartesian3.ZERO, scratchRay.origin);
Cartesian3.normalize(data.position, scratchRay.direction);
var surfaceNormal = ellipsoid.geodeticSurfaceNormal(data.positionOnEllipsoidSurface, scratchRay.direction);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this duplicate code belong in a utility function for Ray or Ellipsoid? That would also be more testable so we could add unit tests.


// compute origin point

// Try to find the intersection point between the surface normal and z-axis.
// Ellipsoid is a surface of revolution, so surface normal intersects the rotation axis (z-axis)

// compute the magnitude required to bring surface normal to x=0, y=0, from data.position
var magnitude;

// avoid dividing by zero
if (Math.abs(surfaceNormal.x) > CesiumMath.EPSILON16){
magnitude = data.positionOnEllipsoidSurface.x / surfaceNormal.x;
} else if (Math.abs(surfaceNormal.y) > CesiumMath.EPSILON16){
magnitude = data.positionOnEllipsoidSurface.y / surfaceNormal.y;
} else if (Math.abs(surfaceNormal.z) > CesiumMath.EPSILON16){ //surface normal is (0,0,1) | (0,0,-1) | (0,0,0)
magnitude = data.positionOnEllipsoidSurface.z / surfaceNormal.z;
} else { //(0,0,0), just for case
magnitude = 0;
}

var vectorToMinimumPoint = Cartesian3.multiplyByScalar(surfaceNormal, magnitude, scratchPosition);
Cartesian3.subtract(data.positionOnEllipsoidSurface, vectorToMinimumPoint, scratchRay.origin);

// Theoretically, the intersection point can be outside the ellipsoid, so we have to check if the result's 'z' is inside the ellipsoid (with some buffer)
if (Math.abs(scratchRay.origin.z) >= ellipsoid.radii.z -11500.0){
// intersection point is outside the ellipsoid, try other value
magnitude = Math.min(defaultValue(tile.data.minimumHeight, 0.0),-11500.0);

// multiply by the *positive* value of the magnitude
vectorToMinimumPoint = Cartesian3.multiplyByScalar(surfaceNormal, Math.abs(magnitude) + 1, scratchPosition);
Cartesian3.subtract(data.positionOnEllipsoidSurface, vectorToMinimumPoint, scratchRay.origin);
}

} else {
Cartographic.clone(data.positionCartographic, scratchCartographic);

Expand Down