cesium/Apps/Sandcastle/gallery/3D Tiles 1.1 Photogrammetry...

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>