Skip to content

Commit

Permalink
Merge pull request #5019 from AnalyticalGraphicsInc/scale-by-distance
Browse files Browse the repository at this point in the history
Add label scale by distance
  • Loading branch information
pjcozzi authored Feb 22, 2017
2 parents ac09adf + 07d1f74 commit 913b253
Show file tree
Hide file tree
Showing 10 changed files with 219 additions and 29 deletions.
18 changes: 18 additions & 0 deletions Apps/Sandcastle/gallery/Labels.html
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down Expand Up @@ -139,6 +151,12 @@
fadeByDistance();
Sandcastle.highlight(fadeByDistance);
}
}, {
text : 'Scale label by distance',
onselect : function() {
scaleByDistance();
Sandcastle.highlight(scaleByDistance);
}
}]);

Sandcastle.reset = function() {
Expand Down
1 change: 1 addition & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ Change Log
* Fixed exception in 2D in certain cases with polylines 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)
* Add support for `Scene.pickPosition` in Columbus view and 2D. [#4990](https://github.com/AnalyticalGraphicsInc/cesium/pull/4990)
* Added `Label.scaleByDistance` to control minimum/maximum label size based on distance from the camera. [#5019](https://github.com/AnalyticalGraphicsInc/cesium/pull/5019)

### 1.30 - 2017-02-01

Expand Down
17 changes: 17 additions & 0 deletions Source/DataSources/LabelGraphics.js
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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;
};
Expand Down Expand Up @@ -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);
};

Expand Down
2 changes: 2 additions & 0 deletions Source/DataSources/LabelVisualizer.js
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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;
Expand Down
57 changes: 57 additions & 0 deletions Source/Scene/Label.js
Original file line number Diff line number Diff line change
Expand Up @@ -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');
}
Expand All @@ -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;

Expand Down Expand Up @@ -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 <code>x</code> points towards the viewer's right, <code>y</code> points up, and
Expand Down Expand Up @@ -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;
};
Expand Down
2 changes: 2 additions & 0 deletions Source/Scene/LabelCollection.js
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,7 @@ define([
backgroundBillboard.id = label._id;
backgroundBillboard.translucencyByDistance = label._translucencyByDistance;
backgroundBillboard.pixelOffsetScaleByDistance = label._pixelOffsetScaleByDistance;
backgroundBillboard.scaleByDistance = label._scaleByDistance;
backgroundBillboard.distanceDisplayCondition = label._distanceDisplayCondition;
}

Expand Down Expand Up @@ -263,6 +264,7 @@ define([
billboard.image = id;
billboard.translucencyByDistance = label._translucencyByDistance;
billboard.pixelOffsetScaleByDistance = label._pixelOffsetScaleByDistance;
billboard.scaleByDistance = label._scaleByDistance;
billboard.distanceDisplayCondition = label._distanceDisplayCondition;
}
}
Expand Down
60 changes: 31 additions & 29 deletions Source/Shaders/BillboardCollectionVS.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
attribute vec2 direction;
#endif
attribute vec4 positionHighAndScale;
attribute vec4 positionLowAndRotation;
attribute vec4 positionLowAndRotation;
attribute vec4 compressedAttribute0; // pixel offset, translate, horizontal origin, vertical origin, show, direction, texture coordinates (texture offset)
attribute vec4 compressedAttribute1; // aligned axis, translucency by distance, image width
attribute vec4 compressedAttribute2; // image height, color, pick color, size in meters, valid aligned axis, 13 bits free
Expand Down Expand Up @@ -44,7 +44,7 @@ vec4 computePositionWindowCoordinates(vec4 positionEC, vec2 imageSize, float sca
halfSize *= ((direction * 2.0) - 1.0);

vec2 originTranslate = origin * abs(halfSize);

#if defined(ROTATION) || defined(ALIGNED_AXIS)
if (validAlignedAxis || rotation != 0.0)
{
Expand All @@ -57,7 +57,7 @@ vec4 computePositionWindowCoordinates(vec4 positionEC, vec2 imageSize, float sca
tangent = czm_modelViewProjection * tangent;
angle += sign(-tangent.x) * acos(tangent.y / length(tangent.xy));
}

float cosTheta = cos(angle);
float sinTheta = sin(angle);
mat2 rotationMatrix = mat2(cosTheta, sinTheta, -sinTheta, cosTheta);
Expand All @@ -82,44 +82,44 @@ vec4 computePositionWindowCoordinates(vec4 positionEC, vec2 imageSize, float sca
{
positionWC.xy += halfSize;
}

positionWC.xy += translate;
positionWC.xy += (pixelOffset * czm_resolutionScale);

return positionWC;
}

void main()
void main()
{
// Modifying this shader may also require modifications to Billboard._computeScreenSpacePosition

// unpack attributes
vec3 positionHigh = positionHighAndScale.xyz;
vec3 positionLow = positionLowAndRotation.xyz;
float scale = positionHighAndScale.w;

#if defined(ROTATION) || defined(ALIGNED_AXIS)
float rotation = positionLowAndRotation.w;
#else
float rotation = 0.0;
#endif

float compressed = compressedAttribute0.x;

vec2 pixelOffset;
pixelOffset.x = floor(compressed * SHIFT_RIGHT7);
compressed -= pixelOffset.x * SHIFT_LEFT7;
pixelOffset.x -= UPPER_BOUND;

vec2 origin;
origin.x = floor(compressed * SHIFT_RIGHT5);
compressed -= origin.x * SHIFT_LEFT5;

origin.y = floor(compressed * SHIFT_RIGHT3);
compressed -= origin.y * SHIFT_LEFT3;

origin -= vec2(1.0);

float show = floor(compressed * SHIFT_RIGHT2);
compressed -= show * SHIFT_LEFT2;

Expand All @@ -134,30 +134,30 @@ void main()

vec2 textureCoordinates = czm_decompressTextureCoordinates(compressedAttribute0.w);
#endif

float temp = compressedAttribute0.y * SHIFT_RIGHT8;
pixelOffset.y = -(floor(temp) - UPPER_BOUND);

vec2 translate;
translate.y = (temp - floor(temp)) * SHIFT_LEFT16;

temp = compressedAttribute0.z * SHIFT_RIGHT8;
translate.x = floor(temp) - UPPER_BOUND;

translate.y += (temp - floor(temp)) * SHIFT_LEFT8;
translate.y -= UPPER_BOUND;

temp = compressedAttribute1.x * SHIFT_RIGHT8;

vec2 imageSize = vec2(floor(temp), compressedAttribute2.w);

#ifdef EYE_DISTANCE_TRANSLUCENCY
vec4 translucencyByDistance;
translucencyByDistance.x = compressedAttribute1.z;
translucencyByDistance.z = compressedAttribute1.w;

translucencyByDistance.y = ((temp - floor(temp)) * SHIFT_LEFT8) / 255.0;

temp = compressedAttribute1.y * SHIFT_RIGHT8;
translucencyByDistance.w = ((temp - floor(temp)) * SHIFT_LEFT8) / 255.0;
#endif
Expand All @@ -170,7 +170,7 @@ void main()
vec3 alignedAxis = vec3(0.0);
bool validAlignedAxis = false;
#endif

#ifdef RENDER_FOR_PICK
temp = compressedAttribute2.y;
#else
Expand All @@ -183,27 +183,27 @@ void main()
temp = floor(temp) * SHIFT_RIGHT8;
color.g = (temp - floor(temp)) * SHIFT_LEFT8;
color.r = floor(temp);

temp = compressedAttribute2.z * SHIFT_RIGHT8;
bool sizeInMeters = floor((temp - floor(temp)) * SHIFT_LEFT7) > 0.0;
temp = floor(temp) * SHIFT_RIGHT8;

#ifdef RENDER_FOR_PICK
color.a = (temp - floor(temp)) * SHIFT_LEFT8;
vec4 pickColor = color / 255.0;
#else
color.a = floor(temp);
color /= 255.0;
#endif

///////////////////////////////////////////////////////////////////////////

vec4 p = czm_translateRelativeToEye(positionHigh, positionLow);
vec4 positionEC = czm_modelViewRelativeToEye * p;
positionEC = czm_eyeOffset(positionEC, eyeOffset.xyz);
positionEC.xyz *= show;
///////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////

#if defined(EYE_DISTANCE_SCALING) || defined(EYE_DISTANCE_TRANSLUCENCY) || defined(EYE_DISTANCE_PIXEL_OFFSET) || defined(DISTANCE_DISPLAY_CONDITION)
float lengthSq;
Expand All @@ -220,7 +220,9 @@ void main()
#endif

#ifdef EYE_DISTANCE_SCALING
scale *= czm_nearFarScalar(scaleByDistance, lengthSq);
float distanceScale = czm_nearFarScalar(scaleByDistance, lengthSq);
scale *= distanceScale;
translate *= distanceScale;
// push vertex behind near plane for clipping
if (scale == 0.0)
{
Expand Down
Loading

0 comments on commit 913b253

Please sign in to comment.