cesium/Apps/Sandcastle/gallery/Procedural Terrain.html

172 lines
5.7 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="Generate procedural heightmap terrain." />
<meta name="cesium-sandcastle-labels" content="Showcases" />
<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
const width = 32;
const height = 32;
const noiseTerrainProvider = new Cesium.CustomHeightmapTerrainProvider({
width: width,
height: height,
callback: function (x, y, level) {
function fract(x) {
return x - Math.floor(x);
}
function smoothstep(x) {
return x * x * (3.0 - 2.0 * x);
}
function hash(x, y) {
const a = 50.0 * fract(x * 0.3183099 + 0.71);
const b = 50.0 * fract(y * 0.3183099 + 0.113);
const v = fract(a * b * (a + b));
return -1.0 + 2.0 * v; // -1 to +1
}
function lerp(x, y, t) {
return x * (1.0 - t) + y * t;
}
function noise(x, y) {
// Value noise: lerp between random values
const ix = Math.floor(x);
const iy = Math.floor(y);
const fx = fract(x);
const fy = fract(y);
const tx = smoothstep(fx);
const ty = smoothstep(fy);
const v00 = hash(ix, iy);
const v10 = hash(ix + 1, iy);
const v01 = hash(ix, iy + 1);
const v11 = hash(ix + 1, iy + 1);
const v = lerp(lerp(v00, v10, tx), lerp(v01, v11, tx), ty);
return v; // -1 to +1
}
function fbm(x, y) {
// Fractal brownian motion: accumulate octaves of self-similar noise
let v = 0.5 * noise(x * 1.0, y * 1.0);
v += 0.25 * noise(x * 0.4, y * 2.8);
v += 0.125 * noise(x * -2.72, y * 4.96);
v += 0.0625 * noise(x * -10.3, y * 4.67);
v += 0.03125 * noise(x * -22.09, y * -4.89);
v += 0.015625 * noise(x * -29.48, y * -34.33);
// v += 0.0078125 * noise(x * -5.97, y * -90.31);
// v += 0.00390625 * noise(x * 98.83, y * -151.66);
return v; // -1 to +1
}
function terrainNoise(x, y) {
let v = fbm(x, y);
// Move to 0 to 1 range, then make it pointier
v = Math.pow(v * 0.5 + 0.5, 2.0);
return v;
}
const buffer = new Float32Array(width * height);
for (let yy = 0; yy < height; yy++) {
for (let xx = 0; xx < width; xx++) {
const u = (x + xx / (width - 1)) / Math.pow(2, level);
const v = (y + yy / (height - 1)) / Math.pow(2, level);
const heightValue = 9000 * terrainNoise(u * 1750 - 10, v * 1500);
const index = yy * width + xx;
buffer[index] = heightValue;
}
}
return buffer;
},
});
const sineTerrainProvider = new Cesium.CustomHeightmapTerrainProvider({
width: width,
height: height,
callback: function (x, y, level) {
const buffer = new Float32Array(width * height);
for (let yy = 0; yy < height; yy++) {
for (let xx = 0; xx < width; xx++) {
const u = (x + xx / (width - 1)) / Math.pow(2, level);
const v = (y + yy / (height - 1)) / Math.pow(2, level);
const heightValue = 4000 * (Math.sin(8000 * v) * 0.5 + 0.5);
const index = yy * width + xx;
buffer[index] = heightValue;
}
}
return buffer;
},
});
const viewer = new Cesium.Viewer("cesiumContainer");
Sandcastle.addDefaultToolbarMenu([
{
text: "Noise",
onselect: function () {
viewer.terrainProvider = noiseTerrainProvider;
},
},
{
text: "Sine",
onselect: function () {
viewer.terrainProvider = sineTerrainProvider;
},
},
]);
viewer.scene.camera.setView({
destination: new Cesium.Cartesian3(
339907.1874329616,
5654554.279066735,
2936259.008266917,
),
orientation: new Cesium.HeadingPitchRoll(
5.473742192009368,
-0.2225518333236931,
6.28274245960864,
),
});
//Sandcastle_End
};
if (typeof Cesium !== "undefined") {
window.startupCalled = true;
window.startup(Cesium).catch((error) => {
"use strict";
console.error(error);
});
Sandcastle.finishedLoading();
}
</script>
</body>
</html>