Skip to content

Commit

Permalink
Merge pull request #6069 from likangning93/attenuation-and-EDL
Browse files Browse the repository at this point in the history
Geometric-error based point cloud attenuation and eye dome lighting
  • Loading branch information
lilleyse authored Jan 30, 2018
2 parents 51030d0 + 4400531 commit f1fad41
Show file tree
Hide file tree
Showing 17 changed files with 1,412 additions and 14 deletions.
275 changes: 275 additions & 0 deletions Apps/Sandcastle/gallery/3D Tiles Point Cloud Shading.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,275 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no">
<meta name="description" content="Point Cloud Attenuation and Eye Dome Lighting example.">
<meta name="cesium-sandcastle-labels" content="3D Tiles">
<title>Cesium Demo</title>
<script type="text/javascript" src="../Sandcastle-header.js"></script>
<script type="text/javascript" src="../../../ThirdParty/requirejs-2.1.20/require.js"></script>
<script type="text/javascript">
if(typeof require === "function") {
require.config({
baseUrl : '../../../Source',
waitSeconds : 120
});
}
</script>
</head>
<body class="sandcastle-loading" data-sandcastle-bucket="bucket-requirejs.html">
<style>
@import url(../templates/bucket.css);
#toolbar {
background: rgba(42, 42, 42, 0.8);
padding: 4px;
border-radius: 4px;
}
#toolbar input {
vertical-align: middle;
padding-top: 2px;
padding-bottom: 2px;
}
#toolbar .header {
font-weight: bold;
}
</style>
<div id="cesiumContainer" class="fullSize"></div>
<div id="loadingOverlay"><h1>Loading...</h1></div>
<div id="toolbar">
<select data-bind="options: exampleTypes, value: currentExampleType"></select>
<table><tbody>
<tr>
<td>Maximum Screen Space Error</td>
<td>
<input type="range" min="0.0" max="64.0" step="0.1" data-bind="value: maximumScreenSpaceError, valueUpdate: 'input'">
<input type="text" size="5" data-bind="value: maximumScreenSpaceError">
</td>
</tr>
<tr><td class="header">Attenuation</td></tr>
<tr>
<td>Geometric Error Scale</td>
<td>
<input type="range" min="0.0" max="2.0" step="0.1" data-bind="value: geometricErrorScale, valueUpdate: 'input'">
<input type="text" size="5" data-bind="value: geometricErrorScale">
</td>
</tr>
<tr>
<td>Maximum Attenuation</td>
<td>
<input type="range" min="0.0" max="32.0" step="1.0" data-bind="value: maximumAttenuation, valueUpdate: 'input'">
<input type="text" size="5" data-bind="value: maximumAttenuation">
</td>
</tr>
<tr>
<td>Base Resolution</td>
<td>
<input type="range" min="0.0" max="10.0" step="0.01" data-bind="value: baseResolution, valueUpdate: 'input'">
<input type="text" size="5" data-bind="value: baseResolution">
</td>
</tr>
<tr><td class="header">Eye Dome Lighting</td></tr>
<tr>
<td>Eye Dome Lighting Strength</td>
<td>
<input type="range" min="0.0" max="10.0" step="0.1" data-bind="value: eyeDomeLightingStrength, valueUpdate: 'input'">
<input type="text" size="5" data-bind="value: eyeDomeLightingStrength">
</td>
</tr>
<tr>
<td>Eye Dome Lighting Radius</td>
<td>
<input type="range" min="0.0" max="10.0" step="0.1" data-bind="value: eyeDomeLightingRadius, valueUpdate: 'input'">
<input type="text" size="5" data-bind="value: eyeDomeLightingRadius">
</td>
</tr>
</tbody></table>
</div>
<script id="cesium_sandcastle_script">
function startup(Cesium) {
'use strict';
//Sandcastle_Begin
var viewer = new Cesium.Viewer('cesiumContainer');

var scene = viewer.scene;
var viewModelTileset;

function reset() {
viewer.entities.removeAll();
viewer.scene.primitives.removeAll();
viewModelTileset = undefined;
}

// The viewModel tracks the state of our mini application.
var pointClouds = ['St. Helens', 'Church'];
var viewModel = {
exampleTypes : pointClouds,
currentExampleType : pointClouds[0],
maximumScreenSpaceError : 8.0,
geometricErrorScale : 1.0,
maximumAttenuation : 0, // Equivalent to undefined
baseResolution : 0, // Equivalent to undefined
eyeDomeLightingStrength : 1.0,
eyeDomeLightingRadius : 1.0
};

function tilesetToViewModel(tileset) {
viewModelTileset = tileset;

var pointCloudShading = tileset.pointCloudShading;
viewModel.maximumScreenSpaceError = tileset.maximumScreenSpaceError;
viewModel.geometricErrorScale = pointCloudShading.geometricErrorScale;
viewModel.maximumAttenuation = pointCloudShading.maximumAttenuation ? pointCloudShading.maximumAttenuation : 0;
viewModel.baseResolution = pointCloudShading.baseResolution ? pointCloudShading.baseResolution : 0;
viewModel.eyeDomeLightingStrength = pointCloudShading.eyeDomeLightingStrength;
viewModel.eyeDomeLightingRadius = pointCloudShading.eyeDomeLightingRadius;
}

function loadStHelens() {
// Set the initial camera view to look at Mt. St. Helens
var initialPosition = Cesium.Cartesian3.fromRadians(-2.1344873183780484, 0.8071380277370774, 5743.394497982162);
var initialOrientation = new Cesium.HeadingPitchRoll.fromDegrees(112.99596671210358, -21.34390550872461, 0.0716951918898415);
viewer.scene.camera.setView({
destination: initialPosition,
orientation: initialOrientation,
endTransform: Cesium.Matrix4.IDENTITY
});

// Mt. St. Helens 3D Tileset generated from LAS provided by https://www.liblas.org/samples/
// This tileset uses replacement refinement and has geometric error approximately equal to
// the average interpoint distance in each tile.
Cesium.CesiumIon.create3DTileset(3742, { accessToken: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiIxOGZjMjlhZC03MDE1LTQ3ZTAtODEyNy05YTU3M2MwYzQ0YmEiLCJpZCI6NDQsImFzc2V0cyI6WzM3NDJdLCJpYXQiOjE1MTcyNDI3NDJ9.TJAJctFXC1UyFMpxkA3cyKVAmnh72cLtfY1yKbaQsyk' })
.then(function(tileset) {
viewer.scene.primitives.add(tileset);

tileset.maximumScreenSpaceError = 8.0;
tileset.pointCloudShading.maximumAttenuation = undefined; // Will be based on maximumScreenSpaceError instead
tileset.pointCloudShading.baseResolution = undefined;
tileset.pointCloudShading.geometricErrorScale = 1.0;
tileset.pointCloudShading.attenuation = true;
tileset.pointCloudShading.eyeDomeLighting = true;

tilesetToViewModel(tileset);
})
.otherwise(function(error) {
console.log(error);
});
}

function loadChurch() {
// Point Cloud by Prof. Peter Allen, Columbia University Robotics Lab. Scanning by Alejandro Troccoli and Matei Ciocarlie.
// This tileset uses additive refinement and has geometric error based on the bounding box size for each tile.
Cesium.CesiumIon.create3DTileset(1460, { accessToken: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiIyMzk2YzJiOS1jZGFmLTRlZmYtYmQ4MS00NTA3NjEwMzViZTkiLCJpZCI6NDQsImFzc2V0cyI6WzE0NjBdLCJpYXQiOjE0OTkyNjQ3NTV9.oWjvN52CRQ-dk3xtvD4e8ZnOHZhoWSpJLlw115mbQJM' })
.then(function(tileset) {
viewer.scene.primitives.add(tileset);

tileset.maximumScreenSpaceError = 1024.0; // For better performance, due to how this tileset treats geometric error.
tileset.pointCloudShading.maximumAttenuation = 8.0; // Don't allow points larger than 8 pixels.
tileset.pointCloudShading.baseResolution = 0.05; // Assume an original capture resolution of 5 centimeters between neighboring points.
tileset.pointCloudShading.geometricErrorScale = 1.0; // Applies to both geometric error and the base resolution.
tileset.pointCloudShading.attenuation = true;
tileset.pointCloudShading.eyeDomeLighting = true;

tilesetToViewModel(tileset);
viewer.zoomTo(tileset);
})
.otherwise(function(error) {
console.log(error);
});
}

function checkZero(newValue) {
var newValueFloat = parseFloat(newValue);
return (newValueFloat === 0.0) ? undefined : newValueFloat;
}

loadStHelens();

// Convert the viewModel members into knockout observables.
Cesium.knockout.track(viewModel);

// Bind the viewModel to the DOM elements of the UI that call for it.
var toolbar = document.getElementById('toolbar');
Cesium.knockout.applyBindings(viewModel, toolbar);

Cesium.knockout.getObservable(viewModel, 'currentExampleType').subscribe(function(newValue) {
reset();
if (newValue === pointClouds[0]) {
loadStHelens();
} else if (newValue === pointClouds[1]) {
loadChurch();
}
});

Cesium.knockout.getObservable(viewModel, 'maximumScreenSpaceError').subscribe(
function(newValue) {
if (Cesium.defined(viewModelTileset)) {
viewModelTileset.maximumScreenSpaceError = parseFloat(newValue);
}
}
);

Cesium.knockout.getObservable(viewModel, 'geometricErrorScale').subscribe(
function(newValue) {
if (Cesium.defined(viewModelTileset)) {
viewModelTileset.pointCloudShading.geometricErrorScale = parseFloat(newValue);
}
}
);

Cesium.knockout.getObservable(viewModel, 'maximumAttenuation').subscribe(
function(newValue) {
if (Cesium.defined(viewModelTileset)) {
viewModelTileset.pointCloudShading.maximumAttenuation = checkZero(newValue);
}
}
);

Cesium.knockout.getObservable(viewModel, 'baseResolution').subscribe(
function(newValue) {
if (Cesium.defined(viewModelTileset)) {
viewModelTileset.pointCloudShading.baseResolution = checkZero(newValue);
}
}
);

Cesium.knockout.getObservable(viewModel, 'eyeDomeLightingStrength').subscribe(
function(newValue) {
if (Cesium.defined(viewModelTileset)) {
viewModelTileset.pointCloudShading.eyeDomeLightingStrength = parseFloat(newValue);
}
}
);

Cesium.knockout.getObservable(viewModel, 'eyeDomeLightingRadius').subscribe(
function(newValue) {
if (Cesium.defined(viewModelTileset)) {
viewModelTileset.pointCloudShading.eyeDomeLightingRadius = parseFloat(newValue);
}
}
);

Sandcastle.addToggleButton('Enable Attenuation', true, function(checked) {
if (Cesium.defined(viewModelTileset)) {
viewModelTileset.pointCloudShading.attenuation = checked;
}
});

Sandcastle.addToggleButton('Enable Eye Dome Lighting', true, function(checked) {
if (Cesium.defined(viewModelTileset)) {
viewModelTileset.pointCloudShading.eyeDomeLighting = checked;
}
});

//Sandcastle_End
Sandcastle.finishedLoading();
}
if (typeof Cesium !== "undefined") {
startup(Cesium);
} else if (typeof require === "function") {
require(["Cesium"], startup);
}
</script>
</body>
</html>
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ Change Log
* Fixed `Camera.moveStart` and `Camera.moveEnd` events not being raised when camera is close to the ground. [#4753](https://github.com/AnalyticalGraphicsInc/cesium/issues/4753)
* Fixed discrepancy between default value used and commented value for default value for halfAxes of OrientedBoundingBox. [#6147](https://github.com/AnalyticalGraphicsInc/cesium/pull/6147)
* Added `Cartographic.toCartesian` to convert from Cartographic to Cartesian3. [#6163](https://github.com/AnalyticalGraphicsInc/cesium/pull/6163)
* Added geometric-error-based point cloud attenuation and eye dome lighting for point clouds using replacement refinement. [#6069](https://github.com/AnalyticalGraphicsInc/cesium/pull/6069)
* Added `BoundingSphere.volume` for computing the volume of a `BoundingSphere`. [#6069](https://github.com/AnalyticalGraphicsInc/cesium/pull/6069)

### 1.41 - 2018-01-02

Expand Down
12 changes: 12 additions & 0 deletions Source/Core/BoundingSphere.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
define([
'./Cartesian3',
'./Cartographic',
'./Math',
'./Check',
'./defaultValue',
'./defined',
Expand All @@ -14,6 +15,7 @@ define([
], function(
Cartesian3,
Cartographic,
CesiumMath,
Check,
defaultValue,
defined,
Expand Down Expand Up @@ -66,6 +68,7 @@ define([
var fromPointsMinBoxPt = new Cartesian3();
var fromPointsMaxBoxPt = new Cartesian3();
var fromPointsNaiveCenterScratch = new Cartesian3();
var volumeConstant = (4.0 / 3.0) * CesiumMath.PI;

/**
* Computes a tight-fitting bounding sphere enclosing a list of 3D Cartesian points.
Expand Down Expand Up @@ -1302,5 +1305,14 @@ define([
return BoundingSphere.clone(this, result);
};

/**
* Computes the radius of the BoundingSphere.
* @returns {Number} The radius of the BoundingSphere.
*/
BoundingSphere.prototype.volume = function() {
var radius = this.radius;
return volumeConstant * radius * radius * radius;
};

return BoundingSphere;
});
22 changes: 21 additions & 1 deletion Source/Scene/Cesium3DTileset.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ define([
'./Cesium3DTileStyleEngine',
'./ClassificationType',
'./LabelCollection',
'./PointCloudShading',
'./PointCloudEyeDomeLighting',
'./SceneMode',
'./ShadowMode',
'./TileBoundingRegion',
Expand Down Expand Up @@ -79,6 +81,8 @@ define([
Cesium3DTileStyleEngine,
ClassificationType,
LabelCollection,
PointCloudShading,
PointCloudEyeDomeLighting,
SceneMode,
ShadowMode,
TileBoundingRegion,
Expand Down Expand Up @@ -124,6 +128,7 @@ define([
* @param {Boolean} [options.debugShowRenderingStatistics=false] For debugging only. When true, draws labels to indicate the number of commands, points, triangles and features for each tile.
* @param {Boolean} [options.debugShowMemoryUsage=false] For debugging only. When true, draws labels to indicate the texture and geometry memory in megabytes used by each tile.
* @param {Boolean} [options.debugShowUrl=false] For debugging only. When true, draws labels to indicate the url of each tile.
* @param {Object} [options.pointCloudShading] Options for constructing a {@link PointCloudShading} object to control point attenuation based on geometric error and lighting.
*
* @exception {DeveloperError} The tileset must be 3D Tiles version 0.0 or 1.0. See {@link https://github.com/AnalyticalGraphicsInc/3d-tiles#spec-status}
*
Expand Down Expand Up @@ -334,6 +339,14 @@ define([
*/
this.colorBlendAmount = 0.5;

/**
* Options for controlling point size based on geometric error and eye dome lighting.
* @type {PointCloudShading}
*/
this.pointCloudShading = new PointCloudShading(options.pointCloudShading);

this._pointCloudEyeDomeLighting = new PointCloudEyeDomeLighting();

/**
* The event fired to indicate progress of loading new tiles. This event is fired when a new tile
* is requested, when a requested tile is finished downloading, and when a downloaded tile has been
Expand Down Expand Up @@ -1632,6 +1645,7 @@ define([
}
}
var lengthAfterUpdate = commandList.length;
var addedCommandsLength = lengthAfterUpdate - lengthBeforeUpdate;

tileset._backfaceCommands.trim();

Expand Down Expand Up @@ -1661,7 +1675,6 @@ define([
*/

var backfaceCommands = tileset._backfaceCommands.values;
var addedCommandsLength = (lengthAfterUpdate - lengthBeforeUpdate);
var backfaceCommandsLength = backfaceCommands.length;

commandList.length += backfaceCommandsLength;
Expand All @@ -1680,6 +1693,13 @@ define([
// Number of commands added by each update above
statistics.numberOfCommands = (commandList.length - numberOfInitialCommands);

// Only run EDL if simple attenuation is on
if (tileset.pointCloudShading.attenuation &&
tileset.pointCloudShading.eyeDomeLighting &&
(addedCommandsLength > 0)) {
tileset._pointCloudEyeDomeLighting.update(frameState, numberOfInitialCommands, tileset);
}

if (tileset.debugShowGeometricError || tileset.debugShowRenderingStatistics || tileset.debugShowMemoryUsage || tileset.debugShowUrl) {
if (!defined(tileset._tileDebugLabels)) {
tileset._tileDebugLabels = new LabelCollection();
Expand Down
Loading

0 comments on commit f1fad41

Please sign in to comment.