Skip to content

Commit

Permalink
Initial commit for issue CesiumGS#1076. Added translucencyByDistance …
Browse files Browse the repository at this point in the history
…to billboard

and incorporated into Label.  SandCastle examples added for both label and
billboard fading based on camera distance.

Signed-off-by: Alex Wood <[email protected]>
  • Loading branch information
abwood committed Oct 1, 2013
1 parent 92babfa commit f9bf08c
Show file tree
Hide file tree
Showing 8 changed files with 274 additions and 24 deletions.
30 changes: 30 additions & 0 deletions Apps/Sandcastle/gallery/Billboards.html
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,26 @@
image.src = '../images/facility.gif';
}

function billboardTranslucencyByDistance(scene, ellipsoid) {
Sandcastle.declare(billboardTranslucencyByDistance); // For highlighting in Sandcastle.
var image = new Image();
image.onload = function() {
var billboards = new Cesium.BillboardCollection();
var textureAtlas = scene.getContext().createTextureAtlas({
image : image
});
billboards.setTextureAtlas(textureAtlas);

billboards.add({
position : ellipsoid.cartographicToCartesian(Cesium.Cartographic.fromDegrees(-75.59777, 40.03883)),
imageIndex : 0,
translucencyByDistance : new Cesium.NearFarScalar(1.5e2, 1.0, 1.5e7, 0.2)
});
scene.getPrimitives().add(billboards);
};
image.src = '../images/Cesium_Logo_overlay.gif';
}

function addPointBillboards(scene, ellipsoid) {
Sandcastle.declare(addPointBillboards); // For highlighting in Sandcastle.
// A white circle is drawn into a 2D canvas. The canvas is used as
Expand Down Expand Up @@ -430,6 +450,16 @@
};
button.textContent = 'Scale by viewer distance';
toolbar.appendChild(button);

button = document.createElement('button');
button.className = 'cesium-button';
button.onclick = function() {
primitives.removeAll();
billboardTranslucencyByDistance(scene, ellipsoid);
Sandcastle.highlight(billboardTranslucencyByDistance);
};
button.textContent = 'Fade by viewer distance';
toolbar.appendChild(button);
}

var widget = new Cesium.CesiumWidget('cesiumContainer');
Expand Down
39 changes: 39 additions & 0 deletions Apps/Sandcastle/gallery/Labels.html
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,35 @@
scene.getPrimitives().add(labels);
}

function labelTranslucencyByDistance(scene, ellipsoid) {
Sandcastle.declare(labelTranslucencyByDistance); // For highlighting in Sandcastle.
var labels = new Cesium.LabelCollection();
var l = labels.add({
position : ellipsoid.cartographicToCartesian(Cesium.Cartographic.fromDegrees(-75.10, 39.57)),
text : 'Philadelphia',
translucencyByDistance : new Cesium.NearFarScalar(1.5e2, 1.0, 1.5e7, 0.0),
pixelOffset : new Cesium.Cartesian2(0, 50)
});

var image = new Image();
image.onload = function() {
var billboards = new Cesium.BillboardCollection();
var textureAtlas = scene.getContext().createTextureAtlas({
image : image
});
billboards.setTextureAtlas(textureAtlas);

billboards.add({
position : ellipsoid.cartographicToCartesian(Cesium.Cartographic.fromDegrees(-75.10, 39.57)),
imageIndex : 0
});
scene.getPrimitives().add(billboards);
};
image.src = '../images/facility.gif';

scene.getPrimitives().add(labels);
}

function createButtons(widget) {
var ellipsoid = widget.centralBody.getEllipsoid();
var scene = widget.scene;
Expand Down Expand Up @@ -135,6 +164,16 @@
};
button.textContent = 'Add labels in reference frame';
toolbar.appendChild(button);

button = document.createElement('button');
button.className = 'cesium-button';
button.onclick = function() {
primitives.removeAll();
labelTranslucencyByDistance(scene, ellipsoid);
Sandcastle.highlight(labelTranslucencyByDistance);
};
button.textContent = 'Fade label by distance';
toolbar.appendChild(button);
}

var widget = new Cesium.CesiumWidget('cesiumContainer');
Expand Down
1 change: 1 addition & 0 deletions Source/DynamicScene/DynamicBillboard.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ define(['../Core/defaultValue',
this._eyeOffset = undefined;
this._pixelOffset = undefined;
this._show = undefined;
this._nearFarScalar = undefined;
this._propertyChanged = new Event();
};

Expand Down
65 changes: 63 additions & 2 deletions Source/Scene/Billboard.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ define([
* and add new billboards instead of modifying each one.
*
* @exception {DeveloperError} scaleByDistance.far must be greater than scaleByDistance.near
* @exception {DeveloperError} translucencyByDistance.far must be greater than translucencyByDistance.near
*
* @see BillboardCollection
* @see BillboardCollection#add
Expand All @@ -66,6 +67,10 @@ define([
if (defined(description.scaleByDistance) && description.scaleByDistance.far <= description.scaleByDistance.near) {
throw new DeveloperError('scaleByDistance.far must be greater than scaleByDistance.near.');
}
if (defined(description.translucencyByDistance) &&
description.translucencyByDistance.far <= description.translucencyByDistance.near) {
throw new DeveloperError('translucencyByDistance.far must be greater than translucencyByDistance.near.');
}

this._show = defaultValue(description.show, true);

Expand All @@ -84,6 +89,7 @@ define([
this._width = description.width;
this._height = description.height;
this._scaleByDistance = description.scaleByDistance;
this._translucencyByDistance = description.translucencyByDistance;

this._pickId = undefined;
this._pickIdThis = description._pickIdThis;
Expand All @@ -104,7 +110,8 @@ define([
var ROTATION_INDEX = Billboard.ROTATION_INDEX = 9;
var ALIGNED_AXIS_INDEX = Billboard.ALIGNED_AXIS_INDEX = 10;
var SCALE_BY_DISTANCE_INDEX = Billboard.SCALE_BY_DISTANCE_INDEX = 11;
Billboard.NUMBER_OF_PROPERTIES = 12;
var TRANSLUCENCY_BY_DISTANCE_INDEX = Billboard.TRANSLUCENCY_BY_DISTANCE_INDEX = 12;
Billboard.NUMBER_OF_PROPERTIES = 13;

function makeDirty(billboard, propertyChanged) {
var billboardCollection = billboard._billboardCollection;
Expand Down Expand Up @@ -330,6 +337,59 @@ define([
this._scaleByDistance = NearFarScalar.clone(scale, this._scaleByDistance);
};

/**
* Returns the near and far translucency properties of a Billboard based on the billboard's distance from the camera.
*
* @memberof Billboard
*
* @returns {NearFarScalar} The near/far translucency values based on camera distance to the billboard
*
* @see Billboard#setTranslucencyByDistance
*/
Billboard.prototype.getTranslucencyByDistance = function() {
return this._translucencyByDistance;
};

/**
* Sets near and far translucency properties of a Billboard based on the billboard's distance from the camera.
* A billboard's translucency 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 billboard's translucency remains clamped to the nearest bound. If undefined,
* translucencyByDistance will be disabled.
*
* @memberof Billboard
*
* @param {NearFarScalar} translucency The configuration of near and far distances and their respective translucency values
*
* @exception {DeveloperError} far distance must be greater than near distance.
*
* @see Billboard#getTranslucencyByDistance
*
* @example
* // Example 1.
* // Set a billboard's translucencyByDistance to 1.0 when the
* // camera is 1500 meters from the billboard and disappear as
* // the camera distance approaches 8.0e6 meters.
* b.setTranslucencyByDistance(new NearFarScalar(1.5e2, 1.0, 8.0e6, 0.0));
*
* // Example 2.
* // disable translucency by distance
* b.setTranslucencyByDistance(undefined);
*/
Billboard.prototype.setTranslucencyByDistance = function(translucency) {
if (NearFarScalar.equals(this._translucencyByDistance, translucency)) {
return;
}

if (translucency.far <= translucency.near) {
throw new DeveloperError('far distance must be greater than near distance.');
}

makeDirty(this, TRANSLUCENCY_BY_DISTANCE_INDEX);
this._translucencyByDistance = NearFarScalar.clone(translucency, this._translucencyByDistance);
};

/**
* Returns the 3D Cartesian offset applied to this billboard in eye coordinates.
*
Expand Down Expand Up @@ -886,7 +946,8 @@ define([
Color.equals(this._color, other._color) &&
Cartesian2.equals(this._pixelOffset, other._pixelOffset) &&
Cartesian3.equals(this._eyeOffset, other._eyeOffset) &&
NearFarScalar.equals(this._scaleByDistance, other._scaleByDistance);
NearFarScalar.equals(this._scaleByDistance, other._scaleByDistance) &&
NearFarScalar.equals(this._translucencyByDistance, other._translucencyByDistance);
};

Billboard.prototype._destroy = function() {
Expand Down
68 changes: 61 additions & 7 deletions Source/Scene/BillboardCollection.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ define([
var ROTATION_INDEX = Billboard.ROTATION_INDEX;
var ALIGNED_AXIS_INDEX = Billboard.ALIGNED_AXIS_INDEX;
var SCALE_BY_DISTANCE_INDEX = Billboard.SCALE_BY_DISTANCE_INDEX;
var TRANSLUCENCY_BY_DISTANCE_INDEX = Billboard.TRANSLUCENCY_BY_DISTANCE_INDEX;
var NUMBER_OF_PROPERTIES = Billboard.NUMBER_OF_PROPERTIES;

// PERFORMANCE_IDEA: Use vertex compression so we don't run out of
Expand All @@ -78,7 +79,8 @@ define([
pickColor : 7, // pickColor and color shared an index because pickColor is only used during
color : 7, // the 'pick' pass and 'color' is only used during the 'color' pass.
rotationAndAlignedAxis : 8,
scaleByDistance : 9
scaleByDistance : 9,
translucencyByDistance : 10
};

// Identifies to the VertexArrayFacade the attributes that are used only for the pick
Expand Down Expand Up @@ -156,6 +158,10 @@ define([
this._compiledShaderScaleByDistance = false;
this._compiledShaderScaleByDistancePick = false;

this._shaderTranslucencyByDistance = false;
this._compiledShaderTranslucencyByDistance = false;
this._compiledShaderTranslucencyByDistancePick = false;

this._propertiesChanged = new Uint32Array(NUMBER_OF_PROPERTIES);

this._maxSize = 0.0;
Expand Down Expand Up @@ -213,7 +219,8 @@ define([
BufferUsage.STATIC_DRAW, // COLOR_INDEX
BufferUsage.STATIC_DRAW, // ROTATION_INDEX
BufferUsage.STATIC_DRAW, // ALIGNED_AXIS_INDEX
BufferUsage.STATIC_DRAW // SCALE_BY_DISTANCE_INDEX
BufferUsage.STATIC_DRAW, // SCALE_BY_DISTANCE_INDEX
BufferUsage.STATIC_DRAW // TRANSLUCENCY_BY_DISTANCE_INDEX
];

var that = this;
Expand Down Expand Up @@ -256,6 +263,7 @@ define([
* verticalOrigin : VerticalOrigin.CENTER,
* scale : 1.0,
* scaleByDistance : new NearFarScalar(5e6, 1.0, 2e7, 0.0),
* translucencyByDistance : new NearFarScalar(5e6, 1.0, 2e7, 0.0),
* imageIndex : 0,
* color : Color.WHITE
* });
Expand Down Expand Up @@ -685,6 +693,11 @@ define([
componentsPerAttribute : 4,
componentDatatype : ComponentDatatype.FLOAT,
usage : buffersUsage[SCALE_BY_DISTANCE_INDEX]
}, {
index : attributeIndices.translucencyByDistance,
componentsPerAttribute : 4,
componentDatatype : ComponentDatatype.FLOAT,
usage : buffersUsage[TRANSLUCENCY_BY_DISTANCE_INDEX]
}], 4 * numberOfBillboards); // 4 vertices per billboard
}

Expand Down Expand Up @@ -893,6 +906,35 @@ define([
writer(i + 3, near, nearValue, far, farValue);
}

function writeTranslucencyByDistance(billboardCollection, context, textureAtlasCoordinates, vafWriters, billboard) {
var i = billboard._index * 4;
var allPurposeWriters = vafWriters[allPassPurpose];
var writer = allPurposeWriters[attributeIndices.translucencyByDistance];
var near = 0.0;
var nearValue = 0.0;
var far = 0.0;
var farValue = 0.0;

var translucency = billboard.getTranslucencyByDistance();
if (defined(translucency)) {
near = translucency.near;
nearValue = translucency.nearValue;
far = translucency.far;
farValue = translucency.farValue;

if (nearValue !== 1.0 || farValue !== 1.0) {
// translucency by distance calculation in shader need not be enabled
// until a billboard with near and far !== 1.0 is found
billboardCollection._shaderTranslucencyByDistance = true;
}
}

writer(i + 0, near, nearValue, far, farValue);
writer(i + 1, near, nearValue, far, farValue);
writer(i + 2, near, nearValue, far, farValue);
writer(i + 3, near, nearValue, far, farValue);
}

function writeBillboard(billboardCollection, context, textureAtlasCoordinates, vafWriters, billboard) {
writePosition(billboardCollection, context, textureAtlasCoordinates, vafWriters, billboard);
writePixelOffset(billboardCollection, context, textureAtlasCoordinates, vafWriters, billboard);
Expand All @@ -903,6 +945,7 @@ define([
writeTextureCoordinatesAndImageSize(billboardCollection, context, textureAtlasCoordinates, vafWriters, billboard);
writeRotationAndAlignedAxis(billboardCollection, context, textureAtlasCoordinates, vafWriters, billboard);
writeScaleByDistance(billboardCollection, context, textureAtlasCoordinates, vafWriters, billboard);
writeTranslucencyByDistance(billboardCollection, context, textureAtlasCoordinates, vafWriters, billboard);
}

function recomputeActualPositions(billboardCollection, billboards, length, frameState, modelMatrix, recomputeBoundingVolume) {
Expand Down Expand Up @@ -1091,6 +1134,10 @@ define([
writers.push(writeScaleByDistance);
}

if (properties[TRANSLUCENCY_BY_DISTANCE_INDEX]) {
writers.push(writeTranslucencyByDistance);
}

vafWriters = this._vaf.writers;

if ((billboardsToUpdateLength / billboardsLength) > 0.1) {
Expand Down Expand Up @@ -1165,19 +1212,23 @@ define([
});
}

if (!defined(this._sp) || (this._shaderRotation && !this._compiledShaderRotation) ||
(this._shaderScaleByDistance && !this._compiledShaderScaleByDistance)) {
if (!defined(this._sp) ||
(this._shaderRotation && !this._compiledShaderRotation) ||
(this._shaderScaleByDistance && !this._compiledShaderScaleByDistance) ||
(this._shaderTranslucencyByDistance && !this._compiledShaderTranslucencyByDistance)) {
this._sp = context.getShaderCache().replaceShaderProgram(
this._sp,
createShaderSource({
defines : [this._shaderRotation ? 'ROTATION' : '',
this._shaderScaleByDistance ? 'EYE_DISTANCE_SCALING' : ''],
this._shaderScaleByDistance ? 'EYE_DISTANCE_SCALING' : '',
this._shaderTranslucencyByDistance ? 'EYE_DISTANCE_TRANSLUCENCY' : ''],
sources : [BillboardCollectionVS]
}),
BillboardCollectionFS,
attributeIndices);
this._compiledShaderRotation = this._shaderRotation;
this._compiledShaderScaleByDistance = this._shaderScaleByDistance;
this._compiledShaderTranslucencyByDistance = this._shaderTranslucencyByDistance;
}

va = this._vaf.vaByPurpose[colorPassPurpose];
Expand Down Expand Up @@ -1207,13 +1258,15 @@ define([

if (!defined(this._spPick) ||
(this._shaderRotation && !this._compiledShaderRotationPick) ||
(this._shaderScaleByDistance && !this._compiledShaderScaleByDistancePick)) {
(this._shaderScaleByDistance && !this._compiledShaderScaleByDistancePick) ||
(this._shaderTranslucencyByDistance && !this._compiledShaderTranslucencyByDistancePick)) {
this._spPick = context.getShaderCache().replaceShaderProgram(
this._spPick,
createShaderSource({
defines : ['RENDER_FOR_PICK',
this._shaderRotation ? 'ROTATION' : '',
this._shaderScaleByDistance ? 'EYE_DISTANCE_SCALING' : ''],
this._shaderScaleByDistance ? 'EYE_DISTANCE_SCALING' : '',
this._shaderTranslucencyByDistance ? 'EYE_DISTANCE_TRANSLUCENCY' : ''],
sources : [BillboardCollectionVS]
}),
createShaderSource({
Expand All @@ -1223,6 +1276,7 @@ define([
attributeIndices);
this._compiledShaderRotationPick = this._shaderRotation;
this._compiledShaderScaleByDistancePick = this._shaderScaleByDistance;
this._compiledShaderTranslucencyByDistancePick = this._shaderTranslucencyByDistance;
}

va = this._vaf.vaByPurpose[pickPassPurpose];
Expand Down
Loading

0 comments on commit f9bf08c

Please sign in to comment.