mirror of https://github.com/CesiumGS/cesium.git
357 lines
12 KiB
HTML
357 lines
12 KiB
HTML
<!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="Load a photogrammetry dataset with feature ID textures from EXT_mesh_features."
|
|
/>
|
|
<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="../../../Build/CesiumUnminified/Cesium.js"
|
|
nomodule
|
|
></script>
|
|
<script type="module" src="../load-cesium-es6.js"></script>
|
|
</head>
|
|
<body class="sandcastle-loading" data-sandcastle-bucket="bucket-requirejs.html">
|
|
<style>
|
|
@import url(../templates/bucket.css);
|
|
</style>
|
|
<div id="cesiumContainer" class="fullSize"></div>
|
|
<div id="loadingOverlay"><h1>Loading...</h1></div>
|
|
<div id="toolbar"></div>
|
|
<script id="cesium_sandcastle_script">
|
|
window.startup = async function (Cesium) {
|
|
"use strict";
|
|
//Sandcastle_Begin
|
|
// San Francisco Ferry Building photogrammetry model provided by Aerometrex
|
|
const viewer = new Cesium.Viewer("cesiumContainer", {
|
|
infoBox: false,
|
|
orderIndependentTranslucency: false,
|
|
terrain: Cesium.Terrain.fromWorldTerrain(),
|
|
});
|
|
|
|
viewer.clock.currentTime = Cesium.JulianDate.fromIso8601(
|
|
"2021-11-09T20:27:37.016064475348684937Z",
|
|
);
|
|
|
|
const scene = viewer.scene;
|
|
|
|
// Fly to a nice overview of the city.
|
|
viewer.camera.flyTo({
|
|
destination: new Cesium.Cartesian3(
|
|
-2703640.80485846,
|
|
-4261161.990345464,
|
|
3887439.511104276,
|
|
),
|
|
orientation: new Cesium.HeadingPitchRoll(
|
|
0.22426651143535548,
|
|
-0.2624145362506527,
|
|
0.000006972977223185239,
|
|
),
|
|
duration: 0,
|
|
});
|
|
|
|
let tileset;
|
|
try {
|
|
tileset = await Cesium.Cesium3DTileset.fromIonAssetId(2333904);
|
|
|
|
const translation = new Cesium.Cartesian3(
|
|
-1.398521324920626,
|
|
0.7823052871729486,
|
|
0.7015244410592609,
|
|
);
|
|
tileset.modelMatrix = Cesium.Matrix4.fromTranslation(translation);
|
|
|
|
tileset.maximumScreenSpaceError = 8.0;
|
|
scene.pickTranslucentDepth = true;
|
|
scene.light.intensity = 7.0;
|
|
|
|
viewer.scene.primitives.add(tileset);
|
|
} catch (error) {
|
|
console.log(`Error loading tileset: ${error}`);
|
|
}
|
|
|
|
// Styles =============================================================================
|
|
|
|
const classificationStyle = new Cesium.Cesium3DTileStyle({
|
|
color: "color(${color})",
|
|
});
|
|
|
|
const translucentWindowsStyle = new Cesium.Cesium3DTileStyle({
|
|
color: {
|
|
conditions: [["${component} === 'Windows'", "color('gray', 0.7)"]],
|
|
},
|
|
});
|
|
|
|
// Shaders ============================================================================
|
|
|
|
// Dummy shader that sets the UNLIT lighting mode. For use with the classification style
|
|
const emptyFragmentShader =
|
|
"void fragmentMain(FragmentInput fsInput, inout czm_modelMaterial material) {}";
|
|
const unlitShader = new Cesium.CustomShader({
|
|
lightingModel: Cesium.LightingModel.UNLIT,
|
|
fragmentShaderText: emptyFragmentShader,
|
|
});
|
|
|
|
const materialShader = new Cesium.CustomShader({
|
|
lightingModel: Cesium.LightingModel.PBR,
|
|
fragmentShaderText: `
|
|
const int WINDOW = 0;
|
|
const int FRAME = 1;
|
|
const int WALL = 2;
|
|
const int ROOF = 3;
|
|
const int SKYLIGHT = 4;
|
|
const int AIR_CONDITIONER_WHITE = 5;
|
|
const int AIR_CONDITIONER_BLACK = 6;
|
|
const int AIR_CONDITIONER_TALL = 7;
|
|
const int CLOCK = 8;
|
|
const int PILLARS = 9;
|
|
const int STREET_LIGHT = 10;
|
|
const int TRAFFIC_LIGHT = 11;
|
|
|
|
void fragmentMain(FragmentInput fsInput, inout czm_modelMaterial material) {
|
|
int featureId = fsInput.featureIds.featureId_0;
|
|
|
|
if (featureId == CLOCK) {
|
|
// Shiny brass
|
|
material.specular = vec3(0.98, 0.90, 0.59);
|
|
material.roughness = 0.1;
|
|
} else if (
|
|
featureId == STREET_LIGHT ||
|
|
featureId == AIR_CONDITIONER_BLACK ||
|
|
featureId == AIR_CONDITIONER_WHITE ||
|
|
featureId == AIR_CONDITIONER_TALL ||
|
|
featureId == ROOF
|
|
) {
|
|
// dull aluminum
|
|
material.specular = vec3(0.91, 0.92, 0.92);
|
|
material.roughness = 0.5;
|
|
} else if (featureId == WINDOW || featureId == SKYLIGHT) {
|
|
// make translucent, but also set an orange emissive color so it looks like
|
|
// it's lit from inside
|
|
material.emissive = vec3(1.0, 0.3, 0.0);
|
|
material.alpha = 0.5;
|
|
} else if (featureId == WALL || featureId == FRAME || featureId == PILLARS) {
|
|
// paint the walls and pillars white to contrast the brass clock
|
|
material.diffuse = mix(material.diffuse, vec3(1.0), 0.8);
|
|
material.roughness = 0.9;
|
|
} else {
|
|
// brighten everything else
|
|
material.diffuse += 0.05;
|
|
material.roughness = 0.9;
|
|
}
|
|
}
|
|
`,
|
|
});
|
|
|
|
const NOTHING_SELECTED = 12;
|
|
const selectFeatureShader = new Cesium.CustomShader({
|
|
uniforms: {
|
|
u_selectedFeature: {
|
|
type: Cesium.UniformType.INT,
|
|
value: NOTHING_SELECTED,
|
|
},
|
|
},
|
|
lightingModel: Cesium.LightingModel.PBR,
|
|
fragmentShaderText: `
|
|
const int NOTHING_SELECTED = 12;
|
|
void fragmentMain(FragmentInput fsInput, inout czm_modelMaterial material) {
|
|
int featureId = fsInput.featureIds.featureId_0;
|
|
|
|
if (u_selectedFeature < NOTHING_SELECTED && featureId == u_selectedFeature) {
|
|
material.specular = vec3(1.00, 0.85, 0.57);
|
|
material.roughness = 0.1;
|
|
}
|
|
}
|
|
`,
|
|
});
|
|
|
|
const multipleFeatureIdsShader = new Cesium.CustomShader({
|
|
uniforms: {
|
|
u_selectedFeature: {
|
|
type: Cesium.UniformType.FLOAT,
|
|
value: NOTHING_SELECTED,
|
|
},
|
|
},
|
|
lightingModel: Cesium.LightingModel.UNLIT,
|
|
fragmentShaderText: `
|
|
const int IDS0_WINDOW = 0;
|
|
const int IDS1_FACADE = 2;
|
|
const int IDS1_ROOF = 3;
|
|
const vec3 PURPLE = vec3(0.5, 0.0, 1.0);
|
|
const vec3 YELLOW = vec3(1.0, 1.0, 0.0);
|
|
const vec3 NO_TINT = vec3(1.0);
|
|
|
|
void fragmentMain(FragmentInput fsInput, inout czm_modelMaterial material) {
|
|
int featureId0 = fsInput.featureIds.featureId_0; // fine features
|
|
int featureId1 = fsInput.featureIds.featureId_1; // coarse features
|
|
|
|
// use both feature ID sets to determine where the features are
|
|
float isWindow = float(featureId0 == IDS0_WINDOW);
|
|
float isFacade = float(featureId1 == IDS1_FACADE);
|
|
float isRoof = float(featureId1 == IDS1_ROOF);
|
|
|
|
// Tint the roof windows yellow and facade windows purple
|
|
vec3 tint = NO_TINT;
|
|
tint = mix(tint, YELLOW, isWindow * isRoof);
|
|
tint = mix(tint, PURPLE, isWindow * isFacade);
|
|
material.diffuse *= tint;
|
|
}
|
|
`,
|
|
});
|
|
|
|
// Demo Functions =====================================================================
|
|
|
|
function defaults() {
|
|
tileset.style = undefined;
|
|
tileset.customShader = unlitShader;
|
|
tileset.colorBlendMode = Cesium.Cesium3DTileColorBlendMode.HIGHLIGHT;
|
|
tileset.colorBlendAmount = 0.5;
|
|
tileset.featureIdLabel = 0;
|
|
}
|
|
|
|
const showPhotogrammetry = defaults;
|
|
|
|
function showClassification() {
|
|
defaults();
|
|
tileset.style = classificationStyle;
|
|
tileset.colorBlendMode = Cesium.Cesium3DTileColorBlendMode.MIX;
|
|
}
|
|
|
|
function showAlternativeClassification() {
|
|
showClassification();
|
|
// This dataset has a second feature ID texture.
|
|
tileset.featureIdLabel = 1;
|
|
}
|
|
|
|
function translucentWindows() {
|
|
defaults();
|
|
tileset.style = translucentWindowsStyle;
|
|
}
|
|
|
|
function pbrMaterials() {
|
|
defaults();
|
|
tileset.customShader = materialShader;
|
|
}
|
|
|
|
function goldenTouch() {
|
|
defaults();
|
|
tileset.customShader = selectFeatureShader;
|
|
}
|
|
|
|
function multipleFeatureIds() {
|
|
defaults();
|
|
tileset.customShader = multipleFeatureIdsShader;
|
|
}
|
|
|
|
// Pick Handlers ======================================================================
|
|
|
|
// HTML overlay for showing feature name on mouseover
|
|
const nameOverlay = document.createElement("div");
|
|
viewer.container.appendChild(nameOverlay);
|
|
nameOverlay.className = "backdrop";
|
|
nameOverlay.style.display = "none";
|
|
nameOverlay.style.position = "absolute";
|
|
nameOverlay.style.bottom = "0";
|
|
nameOverlay.style.left = "0";
|
|
nameOverlay.style["pointer-events"] = "none";
|
|
nameOverlay.style.padding = "4px";
|
|
nameOverlay.style.backgroundColor = "black";
|
|
nameOverlay.style.whiteSpace = "pre-line";
|
|
nameOverlay.style.fontSize = "12px";
|
|
|
|
let enablePicking = true;
|
|
const handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);
|
|
handler.setInputAction(function (movement) {
|
|
if (enablePicking) {
|
|
const pickedObject = viewer.scene.pick(movement.endPosition);
|
|
if (pickedObject instanceof Cesium.Cesium3DTileFeature) {
|
|
nameOverlay.style.display = "block";
|
|
nameOverlay.style.bottom = `${
|
|
viewer.canvas.clientHeight - movement.endPosition.y
|
|
}px`;
|
|
nameOverlay.style.left = `${movement.endPosition.x}px`;
|
|
const component = pickedObject.getProperty("component");
|
|
const message = `Component: ${component}\nFeature ID: ${pickedObject.featureId}`;
|
|
nameOverlay.textContent = message;
|
|
} else {
|
|
nameOverlay.style.display = "none";
|
|
}
|
|
} else {
|
|
nameOverlay.style.display = "none";
|
|
}
|
|
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
|
|
|
|
const clickHandler = new Cesium.ScreenSpaceEventHandler(scene.canvas);
|
|
handler.setInputAction(function (movement) {
|
|
if (enablePicking) {
|
|
const pickedObject = scene.pick(movement.position);
|
|
if (Cesium.defined(pickedObject) && Cesium.defined(pickedObject.featureId)) {
|
|
selectFeatureShader.setUniform("u_selectedFeature", pickedObject.featureId);
|
|
} else {
|
|
selectFeatureShader.setUniform("u_selectedFeature", NOTHING_SELECTED);
|
|
}
|
|
}
|
|
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);
|
|
|
|
// UI ============================================================================
|
|
|
|
Sandcastle.addToggleButton("Enable picking", enablePicking, function (checked) {
|
|
enablePicking = checked;
|
|
});
|
|
|
|
const demos = [
|
|
{
|
|
text: "Show Classification",
|
|
onselect: showClassification,
|
|
},
|
|
{
|
|
text: "Show Alternative Classification",
|
|
onselect: showAlternativeClassification,
|
|
},
|
|
{
|
|
text: "Translucent Windows",
|
|
onselect: translucentWindows,
|
|
},
|
|
{
|
|
text: "Stylized PBR Materials",
|
|
onselect: pbrMaterials,
|
|
},
|
|
{
|
|
text: "Golden Touch",
|
|
onselect: goldenTouch,
|
|
},
|
|
{
|
|
text: "Multiple Feature ID Sets",
|
|
onselect: multipleFeatureIds,
|
|
},
|
|
{
|
|
text: "No Classification",
|
|
onselect: showPhotogrammetry,
|
|
},
|
|
];
|
|
Sandcastle.addDefaultToolbarMenu(demos);
|
|
showClassification();
|
|
//Sandcastle_End
|
|
};
|
|
if (typeof Cesium !== "undefined") {
|
|
window.startupCalled = true;
|
|
window.startup(Cesium).catch((error) => {
|
|
"use strict";
|
|
console.error(error);
|
|
});
|
|
Sandcastle.finishedLoading();
|
|
}
|
|
</script>
|
|
</body>
|
|
</html>
|