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

Billboard transparency #4886

Merged
merged 17 commits into from
Jan 26, 2017
Merged
Show file tree
Hide file tree
Changes from 14 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
1 change: 1 addition & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ Change Log
* `TerrainProvider` now optionally exposes an `availability` property that can be used to query the terrain level that is available at a location or in a rectangle. Currently only `CesiumTerrainProvider` exposes this property.
* Added `sampleTerrainMostDetailed` to sample the height of an array of positions using the best available terrain data at each point. This requires a `TerrainProvider` with the `availability` property.
* Added 2D and Columbus View support for models using the RTC extension or whose vertices are in WGS84 coordinates. [#4922](https://github.com/AnalyticalGraphicsInc/cesium/pull/4922)
* Transparent parts of billboards, labels, and points no longer overwrite parts of the scene behind them. [#4886](https://github.com/AnalyticalGraphicsInc/cesium/pull/4886)
Copy link
Contributor

Choose a reason for hiding this comment

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

Update this.


### 1.29 - 2017-01-02

Expand Down
301 changes: 184 additions & 117 deletions Source/Scene/BillboardCollection.js

Large diffs are not rendered by default.

37 changes: 37 additions & 0 deletions Source/Scene/BillboardRenderTechnique.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*global define*/
define([
'../Core/freezeObject'
], function(
freezeObject) {
'use strict';

/**
* Determines how billboards and points are rendered.
*
* @exports BillboardRenderTechnique
*/
var BillboardRenderTechnique = {
Copy link
Contributor

Choose a reason for hiding this comment

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

Given that this applies to points and labels as well, I don't think it should have Billboard in the name. I am also hesitant about having technique in the name since in glTF and computer graphics, this isn't really a technique in the material sense.

Perhaps throughout, this is better named BlendOption (too confusing with blend mode? probably not at this level of the API), ImageBlendOption, RenderPasses (again, too similar to the renderer?), or CompositeMode? Ignore the implementation and think about what would sound reasonable to the end user.

/**
* The billboards in the collection are completely opaque.
* @type {Number}
* @constant
*/
OPAQUE : 0,

/**
* The billboards in the collection are completely translucent.
* @type {Number}
* @constant
*/
TRANSLUCENT : 1,

/**
* The billboards in the collection are both opaque and translucent.
* @type {Number}
* @constant
*/
OPAQUE_AND_TRANSLUCENT : 2
};

return freezeObject(BillboardRenderTechnique);
});
231 changes: 149 additions & 82 deletions Source/Scene/PointPrimitiveCollection.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ define([
'../Renderer/VertexArrayFacade',
'../Shaders/PointPrimitiveCollectionFS',
'../Shaders/PointPrimitiveCollectionVS',
'./BillboardRenderTechnique',
'./BlendingState',
'./PointPrimitive',
'./SceneMode'
Expand Down Expand Up @@ -50,6 +51,7 @@ define([
VertexArrayFacade,
PointPrimitiveCollectionFS,
PointPrimitiveCollectionVS,
BillboardRenderTechnique,
BlendingState,
PointPrimitive,
SceneMode) {
Expand Down Expand Up @@ -87,6 +89,9 @@ define([
* @param {Object} [options] Object with the following properties:
* @param {Matrix4} [options.modelMatrix=Matrix4.IDENTITY] The 4x4 transformation matrix that transforms each point from model to world coordinates.
* @param {Boolean} [options.debugShowBoundingVolume=false] For debugging only. Determines if this primitive's commands' bounding spheres are shown.
* @param {BillboardRenderTechnique} [options.renderTechnique=BillboardRenderTechnique.OPAQUE_AND_TRANSLUCENT] The billboard rendering technique. The default
* is used for rendering both opaque and translucent points. However, if either all of the points are completely opaque or all are completely translucent,
* setting the technique to BillboardRenderTechnique.OPAQUE or BillboardRenderTechnique.TRANSLUCENT can improve performance by 2x.
*
* @performance For best performance, prefer a few collections, each with many points, to
* many collections with only a few points each. Organize collections so that points
Expand Down Expand Up @@ -115,9 +120,11 @@ define([
options = defaultValue(options, defaultValue.EMPTY_OBJECT);

this._sp = undefined;
this._rs = undefined;
this._vaf = undefined;
this._spTranslucent = undefined;
this._spPick = undefined;
this._rsOpaque = undefined;
this._rsTranslucent = undefined;
this._vaf = undefined;

this._pointPrimitives = [];
this._pointPrimitivesToUpdate = [];
Expand Down Expand Up @@ -197,6 +204,16 @@ define([
*/
this.debugShowBoundingVolume = defaultValue(options.debugShowBoundingVolume, false);

/**
* The billboard rendering technique. The default is used for rendering both opaque and translucent points.
* However, if either all of the points are completely opaque or all are completely translucent,
* setting the technique to BillboardRenderTechnique.OPAQUE or BillboardRenderTechnique.TRANSLUCENT can improve performance by 2x.
* @type {BillboardRenderTechnique}
* @default BillboardRenderTechnique.OPAQUE_AND_TRANSLUCENT
*/
this.renderTechnique = defaultValue(options.renderTechnique, BillboardRenderTechnique.OPAQUE_AND_TRANSLUCENT);
this._renderTechnique = undefined;

this._mode = SceneMode.SCENE3D;
this._maxTotalPointSize = 1;

Expand Down Expand Up @@ -835,79 +852,166 @@ define([
}
updateBoundingVolume(this, frameState, boundingVolume);

var va;
var vaLength;
var command;
var j;
var vs;
var fs;

var commandList = frameState.commandList;
var techniqueChanged = this._renderTechnique !== this.renderTechnique;
this._renderTechnique = this.renderTechnique;

if (pass.render) {
var colorList = this._colorCommands;
if (techniqueChanged) {
this._rsOpaque = RenderState.fromCache({
depthTest : {
enabled : true,
func : WebGLConstants.LEQUAL
},
depthMask : true
});

if (!defined(this._rs)) {
this._rs = RenderState.fromCache({
if (this._renderTechnique === BillboardRenderTechnique.TRANSLUCENT || this._renderTechnique === BillboardRenderTechnique.OPAQUE_AND_TRANSLUCENT) {
this._rsTranslucent = RenderState.fromCache({
depthTest : {
enabled : true,
func : WebGLConstants.LEQUAL
},
depthMask : false,
blending : BlendingState.ALPHA_BLEND
});
} else {
this._rsTranslucent = undefined;
}
}

if (!defined(this._sp) ||
(this._shaderScaleByDistance && !this._compiledShaderScaleByDistance) ||
(this._shaderTranslucencyByDistance && !this._compiledShaderTranslucencyByDistance) ||
(this._shaderDistanceDisplayCondition && !this._compiledShaderDistanceDisplayCondition)) {
if (techniqueChanged ||
(this._shaderScaleByDistance && !this._compiledShaderScaleByDistance) ||
(this._shaderTranslucencyByDistance && !this._compiledShaderTranslucencyByDistance) ||
(this._shaderDistanceDisplayCondition && !this._compiledShaderDistanceDisplayCondition)) {

vs = new ShaderSource({
sources : [PointPrimitiveCollectionVS]
});
if (this._shaderScaleByDistance) {
vs.defines.push('EYE_DISTANCE_SCALING');
}
if (this._shaderTranslucencyByDistance) {
vs.defines.push('EYE_DISTANCE_TRANSLUCENCY');
}
if (this._shaderDistanceDisplayCondition) {
vs.defines.push('DISTANCE_DISPLAY_CONDITION');
}
vs = new ShaderSource({
sources : [PointPrimitiveCollectionVS]
});
if (this._shaderScaleByDistance) {
vs.defines.push('EYE_DISTANCE_SCALING');
}
if (this._shaderTranslucencyByDistance) {
vs.defines.push('EYE_DISTANCE_TRANSLUCENCY');
}
if (this._shaderDistanceDisplayCondition) {
vs.defines.push('DISTANCE_DISPLAY_CONDITION');
}

if (this._renderTechnique === BillboardRenderTechnique.OPAQUE || this._renderTechnique === BillboardRenderTechnique.OPAQUE_AND_TRANSLUCENT) {
fs = new ShaderSource({
defines : ['OPAQUE'],
sources : [PointPrimitiveCollectionFS]
});
this._sp = ShaderProgram.replaceCache({
context : context,
shaderProgram : this._sp,
vertexShaderSource : vs,
fragmentShaderSource : PointPrimitiveCollectionFS,
fragmentShaderSource : fs,
attributeLocations : attributeLocations
});
} else {
this._sp = this._sp && this._sp.destroy();
this._sp = undefined;
}

this._compiledShaderScaleByDistance = this._shaderScaleByDistance;
this._compiledShaderTranslucencyByDistance = this._shaderTranslucencyByDistance;
this._compiledShaderDistanceDisplayCondition = this._shaderDistanceDisplayCondition;
if (this._renderTechnique === BillboardRenderTechnique.TRANSLUCENT || this._renderTechnique === BillboardRenderTechnique.OPAQUE_AND_TRANSLUCENT) {
fs = new ShaderSource({
defines : ['TRANSLUCENT'],
sources : [PointPrimitiveCollectionFS]
});
this._spTranslucent = ShaderProgram.replaceCache({
context : context,
shaderProgram : this._spTranslucent,
vertexShaderSource : vs,
fragmentShaderSource : fs,
attributeLocations : attributeLocations
});
} else {
this._spTranslucent = this._spTranslucent && this._spTranslucent.destroy();
this._spTranslucent = undefined;
}

this._compiledShaderScaleByDistance = this._shaderScaleByDistance;
this._compiledShaderTranslucencyByDistance = this._shaderTranslucencyByDistance;
this._compiledShaderDistanceDisplayCondition = this._shaderDistanceDisplayCondition;
}

if (!defined(this._spPick) ||
(this._shaderScaleByDistance && !this._compiledShaderScaleByDistancePick) ||
(this._shaderTranslucencyByDistance && !this._compiledShaderTranslucencyByDistancePick) ||
(this._shaderDistanceDisplayCondition && !this._compiledShaderDistanceDisplayConditionPick)) {

vs = new ShaderSource({
defines : ['RENDER_FOR_PICK'],
sources : [PointPrimitiveCollectionVS]
});

if (this._shaderScaleByDistance) {
vs.defines.push('EYE_DISTANCE_SCALING');
}
if (this._shaderTranslucencyByDistance) {
vs.defines.push('EYE_DISTANCE_TRANSLUCENCY');
}
if (this._shaderDistanceDisplayCondition) {
vs.defines.push('DISTANCE_DISPLAY_CONDITION');
}

fs = new ShaderSource({
defines : ['RENDER_FOR_PICK'],
sources : [PointPrimitiveCollectionFS]
});

this._spPick = ShaderProgram.replaceCache({
context : context,
shaderProgram : this._spPick,
vertexShaderSource : vs,
fragmentShaderSource : fs,
attributeLocations : attributeLocations
});

this._compiledShaderScaleByDistancePick = this._shaderScaleByDistance;
this._compiledShaderTranslucencyByDistancePick = this._shaderTranslucencyByDistance;
this._compiledShaderDistanceDisplayConditionPick = this._shaderDistanceDisplayCondition;
}

var va;
var vaLength;
var command;
var j;
var vs;
var fs;

var commandList = frameState.commandList;

if (pass.render) {
var colorList = this._colorCommands;

var opaque = this._renderTechnique === BillboardRenderTechnique.OPAQUE;
var opaqueAndTranslucent = this._renderTechnique === BillboardRenderTechnique.OPAQUE_AND_TRANSLUCENT;

va = this._vaf.va;
vaLength = va.length;

colorList.length = vaLength;
for (j = 0; j < vaLength; ++j) {
var totalLength = opaqueAndTranslucent ? vaLength * 2 : vaLength;
for (j = 0; j < totalLength; ++j) {
var opaqueCommand = opaque || (opaqueAndTranslucent && j % 2 === 0);

command = colorList[j];
if (!defined(command)) {
command = colorList[j] = new DrawCommand({
primitiveType : PrimitiveType.POINTS,
pass : Pass.OPAQUE,
owner : this
});
command = colorList[j] = new DrawCommand();
}

command.primitiveType = PrimitiveType.POINTS;
command.pass = opaqueCommand ? Pass.OPAQUE : Pass.TRANSLUCENT;
command.owner = this;

var index = opaqueAndTranslucent ? Math.floor(j / 2.0) : j;
command.boundingVolume = boundingVolume;
command.modelMatrix = modelMatrix;
command.shaderProgram = this._sp;
command.shaderProgram = opaqueCommand ? this._sp : this._spTranslucent;
command.uniformMap = this._uniforms;
command.vertexArray = va[j].va;
command.renderState = this._rs;
command.vertexArray = va[index].va;
command.renderState = opaqueCommand ? this._rsOpaque : this._rsTranslucent;
command.debugShowBoundingVolume = this.debugShowBoundingVolume;

commandList.push(command);
Expand All @@ -917,44 +1021,6 @@ define([
if (picking) {
var pickList = this._pickCommands;

if (!defined(this._spPick) ||
(this._shaderScaleByDistance && !this._compiledShaderScaleByDistancePick) ||
(this._shaderTranslucencyByDistance && !this._compiledShaderTranslucencyByDistancePick) ||
(this._shaderDistanceDisplayCondition && !this._compiledShaderDistanceDisplayConditionPick)) {

vs = new ShaderSource({
defines : ['RENDER_FOR_PICK'],
sources : [PointPrimitiveCollectionVS]
});

if (this._shaderScaleByDistance) {
vs.defines.push('EYE_DISTANCE_SCALING');
}
if (this._shaderTranslucencyByDistance) {
vs.defines.push('EYE_DISTANCE_TRANSLUCENCY');
}
if (this._shaderDistanceDisplayCondition) {
vs.defines.push('DISTANCE_DISPLAY_CONDITION');
}

fs = new ShaderSource({
defines : ['RENDER_FOR_PICK'],
sources : [PointPrimitiveCollectionFS]
});

this._spPick = ShaderProgram.replaceCache({
context : context,
shaderProgram : this._spPick,
vertexShaderSource : vs,
fragmentShaderSource : fs,
attributeLocations : attributeLocations
});

this._compiledShaderScaleByDistancePick = this._shaderScaleByDistance;
this._compiledShaderTranslucencyByDistancePick = this._shaderTranslucencyByDistance;
this._compiledShaderDistanceDisplayConditionPick = this._shaderDistanceDisplayCondition;
}

va = this._vaf.va;
vaLength = va.length;

Expand All @@ -974,7 +1040,7 @@ define([
command.shaderProgram = this._spPick;
command.uniformMap = this._uniforms;
command.vertexArray = va[j].va;
command.renderState = this._rs;
command.renderState = this._rsOpaque;

commandList.push(command);
}
Expand Down Expand Up @@ -1015,6 +1081,7 @@ define([
*/
PointPrimitiveCollection.prototype.destroy = function() {
this._sp = this._sp && this._sp.destroy();
this._spTranslucent = this._spTranslucent && this._spTranslucent.destroy();
this._spPick = this._spPick && this._spPick.destroy();
this._vaf = this._vaf && this._vaf.destroy();
destroyPointPrimitives(this._pointPrimitives);
Expand Down
Loading