-
Notifications
You must be signed in to change notification settings - Fork 3.5k
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
Geometric-error based point cloud attenuation and eye dome lighting #6069
Changes from 14 commits
501de27
095e152
dccefeb
aad2105
9659688
b77963d
d3367bf
e754963
9f9ebd1
4c7231b
0750c83
4e765ac
6041751
314355c
1484470
c4a3f6b
4400531
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
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; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just to be sure, does the code still work without this function? For example, if a developer sets There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. All computations will be done with 0.0 instead of with the "defaults." For |
||
} | ||
|
||
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> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,7 @@ | ||
define([ | ||
'./Cartesian3', | ||
'./Cartographic', | ||
'./Math', | ||
'./Check', | ||
'./defaultValue', | ||
'./defined', | ||
|
@@ -14,6 +15,7 @@ define([ | |
], function( | ||
Cartesian3, | ||
Cartographic, | ||
CesiumMath, | ||
Check, | ||
defaultValue, | ||
defined, | ||
|
@@ -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. | ||
|
@@ -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() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add this to CHANGES.md. |
||
var radius = this.radius; | ||
return volumeConstant * radius * radius * radius; | ||
}; | ||
|
||
return BoundingSphere; | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This demo might look better with terrain on.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I gave it a quick try, but it looks like Chappes church is below terrain, and the terrain also doesn't perfectly align with the Mt. St. Helens points, it punches through in some views.