Skip to content
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

Added "GlTiles" Source #11810

Closed
wants to merge 41 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
39eaefa
WIP
IvanSanchez Nov 7, 2019
bf2ac29
WIP
IvanSanchez Nov 27, 2019
8da8860
WIP: mising files
IvanSanchez Dec 5, 2019
b2a3b2d
WIP: working RGBA textures
IvanSanchez Dec 18, 2019
845e5d2
WIP: Got right place for tileExtent calculation; lint
IvanSanchez Feb 10, 2020
fc5b65b
More WIP: working 8-bit geotiff!
IvanSanchez Dec 7, 2020
226158b
More WIP: working 8-bit geotiff!
IvanSanchez Feb 25, 2020
dabf225
WIP: Bit of linting and cleanup
IvanSanchez Feb 26, 2020
b103bbc
More WIP: fix tile size hack, first shot at uniforms
IvanSanchez Mar 6, 2020
03f3059
More WIP: GlTiles now re-render when changing an uniform.
IvanSanchez Mar 9, 2020
888d469
More WIP: Removed GeoTIFF.js-specific code from GlTiles, moved into G…
IvanSanchez Mar 11, 2020
30bbef4
WIP: Added example (but not data) for GL render of 8-bit indexed geotiff
IvanSanchez Jun 24, 2020
13580ec
Restore canvas-tiles example from main branch
IvanSanchez Jun 24, 2020
df2e8ff
WIP: packing 16-bit geotiffs as 2x8 luminance+alpha texture
IvanSanchez Sep 11, 2020
477720e
More WIP: async init of GlTiles, wait for textures' function defs.
IvanSanchez Sep 17, 2020
adbc0be
Do not empty textures during program init (fixes async bug)
IvanSanchez Sep 18, 2020
e352805
Prettify comments in one gltiles example
IvanSanchez Sep 18, 2020
28c134e
WIP: Working minimal Terrain-RGB GLTiles demo
IvanSanchez Nov 12, 2020
8f7c461
GlTiles "shaded relief" example deemed to be complete.
IvanSanchez Nov 13, 2020
a897065
Added a GlTiles example with hypsometric tint; tweaked terrain-rgb de…
IvanSanchez Nov 13, 2020
b1003e7
WIP: Half-working one-geotiff-per-tile example
IvanSanchez Nov 20, 2020
017082d
WIP: GlTiles supports non-square tiles; fixed projections in gltiles …
IvanSanchez Nov 27, 2020
2035229
Little bit of cleanup in GlTiles examples
IvanSanchez Nov 27, 2020
af81385
GlTiles: performance improvements for re-rendering.
IvanSanchez Nov 30, 2020
574034b
Update gltiles examples to geotiff.sj beta16; implemented geotidd ins…
IvanSanchez Dec 7, 2020
980a03c
Update gltiles examples to geotiff.sj beta16; implemented geotidd ins…
IvanSanchez Dec 4, 2020
e9067de
GlTiles: cleanup
IvanSanchez Dec 7, 2020
bd60212
GlTiles: tweak deps in package.json for some of the gltile examples
IvanSanchez Dec 7, 2020
eda26ad
GlTiles: Make eslint happier.
IvanSanchez Dec 8, 2020
5da9a09
Remove remaining lint
ahocevar Dec 8, 2020
6f19369
Make tsdoc happier.
IvanSanchez Dec 10, 2020
3876251
Fix typedef
ahocevar Dec 11, 2020
3494d0a
Fix module tags
ahocevar Dec 11, 2020
a15c4e2
GlTiles docstrings: adding a few "@api"s around
IvanSanchez Dec 11, 2020
0c7de5d
Cloak the maptiler API key in the gltiles examples
IvanSanchez Dec 21, 2020
9b72a60
rm tileSize/tileGrid from TileLayer in examples/gltiles-geotiff-tiles.js
IvanSanchez Dec 21, 2020
bba3ebf
Revert unnecessary package.json changes
ahocevar Dec 21, 2020
6a675a7
Fix API docs for class, constructor and options
ahocevar Dec 13, 2020
e5d338a
Make example code prettier
ahocevar Dec 21, 2020
f0621c3
WIP: GlTiles tries to get the projection and tilegrid from its textur…
IvanSanchez Jan 12, 2021
e46c780
Update package.json to fix merge conflict
IvanSanchez Jan 13, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions examples/gltiles-geotiff-tiles.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
layout: example.html
title: GeoTIFF tiles
shortdesc: WebGL shader for RGB+NIR GeoTIFF tiles
docs: >
This demo loads a tile pyramid of 16-bit RGB+NIR GeoTIFFs (one GeoTIFF file per tile, provided by <a href='https://eox.at/'>EOX</a>),
and displays the RGB+NIR data using a WebGL shader.
tags: "sentinel, canvas, webgl, geotiff, gltiles"
---
<script src="https://unpkg.com/geotiff@1.0.0-beta.16/dist-browser/geotiff.js"></script>
<div id="map" class="map"></div>
136 changes: 136 additions & 0 deletions examples/gltiles-geotiff-tiles.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
import GlTiledTextureGeoTiffTiles from '../src/ol/source/GlTiledTexture/GlTiledTextureGeoTiffTiles.js';
import Map from '../src/ol/Map.js';
import TileGrid from '../src/ol/tilegrid/TileGrid.js';
import TileLayer from '../src/ol/layer/Tile.js';
import TileWMS from '../src/ol/source/TileWMS.js';
import View from '../src/ol/View.js';
import {GlTiles, XYZ} from '../src/ol/source.js';

import {Worker} from 'threads';

// This example depends on a global variable "GeoTIFF" being defined.
// This is done via a <script src="https://unpkg.com/geotiff..."> tag
// It'd be also possible to do a "import * as GeoTIFF from 'geotiff';"
/* global GeoTIFF */

// Creating a GeoTIFF worker Pool is not needed, but makes decoding feel faster
const pool = new GeoTIFF.Pool(
navigator.hardwareConcurrency,
new Worker(
'https://unpkg.com/geotiff@1.0.0-beta.16/dist-browser/decoder.worker.1936c0d9.js'
)
);

// These non-square GeoTIFF tiles need a custom tilegrid - forcing level 0 for
// the top-level 512x256px tile, and limiting the number of available zoom levels.

const tileGrid = new TileGrid({
extent: [-180, -90, 180, 90],
origin: [-180, 90],
resolutions: [360 / 512, 180 / 512, 90 / 512, 45 / 512, 22.5 / 512],
tileSizes: [
[512, 256],
[1024, 512],
[1024, 1024],
[1024, 1024],
[1024, 1024],
],
});

const tiffTiles = new XYZ({
url:
'https://s2downloads.eox.at/demo/EOxCloudless/2019/rgbnir_16bit/{z}/{y}/{x}.tif',
tileGrid: tileGrid,
projection: 'EPSG:4326',
});

// tcr, tcg, tcb = True Colour Red/Green/Blue
// nir = Near InfraRed
// These tiles are 16-bit 4-sample RGB+NIR geotiff
const tcr = new GlTiledTextureGeoTiffTiles({
xyz: tiffTiles,
geotiffFactory: GeoTIFF.fromUrl,
sample: 0,
fillValue: -999,
fetchFuncName: 'getTCR',
pool: pool,
});
const tcg = new GlTiledTextureGeoTiffTiles({
xyz: tiffTiles,
geotiffFactory: GeoTIFF.fromUrl,
sample: 1,
fillValue: -999,
fetchFuncName: 'getTCG',
pool: pool,
});
const tcb = new GlTiledTextureGeoTiffTiles({
xyz: tiffTiles,
geotiffFactory: GeoTIFF.fromUrl,
sample: 2,
fillValue: -999,
fetchFuncName: 'getTCB',
pool: pool,
});
const nir = new GlTiledTextureGeoTiffTiles({
xyz: tiffTiles,
geotiffFactory: GeoTIFF.fromUrl,
sample: 3,
fillValue: -999,
fetchFuncName: 'getNIR',
pool: pool,
});

const rgbnirShader =
'#line 1 \n' +
'void main(void) { \n' +
' // Fetch texel values for different bands \n' +
' // in the current texel coordinate (vTextureCoords.st) \n' +
' // These values are in ranges like 0..4000, and must be \n' +
' // normalized into the 0..1 range for display in GL. \n' +
' float tcr = getTCR(vTextureCoords.st); \n' +
' float tcg = getTCG(vTextureCoords.st); \n' +
' float tcb = getTCB(vTextureCoords.st); \n' +
' float nir = getNIR(vTextureCoords.st); \n' +
' \n' +
' if (tcr < 30.) { gl_FragColor = vec4(0.0); } else \n' +
' { \n' +
' gl_FragColor = vec4( \n' +
' tcr / 4000., \n' +
' tcg / 3000., \n' +
' tcb / 2000., \n' +
' 1.0); \n' +
' } \n' +
'} \n';

const glSource = new GlTiles({
fragmentShader: rgbnirShader,
textureSources: [tcr, tcg, tcb, nir],
attributions:
"<a href='https://s2maps.eu'>Sentinel-2 cloudless</a> by <a href='https://eox.at/'>EOX IT Services GmbH</a> (Contains modified Copernicus Sentinel data 2019)",
uniforms: {},
});

const map = new Map({
layers: [
new TileLayer({
source: new TileWMS({
url: 'https://ahocevar.com/geoserver/wms',
params: {
'LAYERS': 'ne:NE1_HR_LC_SR_W_DR',
'TILED': true,
},
}),
opacity: 0.5,
}),

new TileLayer({
source: glSource,
}),
],
target: 'map',
view: new View({
projection: 'EPSG:4326',
center: [16, 46],
zoom: 0,
}),
});
36 changes: 36 additions & 0 deletions examples/gltiles-hypsometric-relief.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
---
layout: example.html
title: WebGL hypsometric tint
shortdesc: WebGL shader for Terrain-RGB hypsometric tint and shaded relief
docs: >
<p>
Similar to the <code>gltiles-shaded-relief</code> example, uses an
eleation model to calculate both a hypsometric tint and a shaded relief.
</p>
<p>
This loads elevation data from
<a href='https://cloud.maptiler.com/tiles/terrain-rgb/'>MapTiler's Terrain-RGB tiles</a>,
then calculates both the colour for the hypsometric tint and the shaded
relief parameters. All the heavy lifting of pixel algebra is done in the
GPU via WebGL.
</p>
tags: "raster, shaded relief, canvas, webgl, gltiles, hypsometric"
cloak:
- key: get_your_own_D6rA4zTHduk6KOKTXzGB
value: Get your own API key at https://www.maptiler.com/cloud/
---
<div id="map" class="map"></div>
<table class="controls">
<tr>
<td>vertical exaggeration: <span id="vertOut">1</span>x</td>
<td><input id="vert" type="range" min="1" max="5" value="1"/></td>
</tr>
<tr>
<td>sun elevation: <span id="sunElOut">45</span>°</td>
<td><input id="sunEl" type="range" min="0" max="90" value="45"/></td>
</tr>
<tr>
<td>sun azimuth: <span id="sunAzOut">45</span>°</td>
<td><input id="sunAz" type="range" min="0" max="360" value="45"/></td>
</tr>
</table>
140 changes: 140 additions & 0 deletions examples/gltiles-hypsometric-relief.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
import GlTiledTextureTerrainRGB from '../src/ol/source/GlTiledTexture/GlTiledTextureTerrainRGB.js';
import Map from '../src/ol/Map.js';
import TileLayer from '../src/ol/layer/Tile.js';
import View from '../src/ol/View.js';
import {GlTiles, XYZ} from '../src/ol/source.js';
import {fromLonLat} from '../src/ol/proj.js';

const maptilerKey = 'get_your_own_D6rA4zTHduk6KOKTXzGB';

const terrainTexture = new GlTiledTextureTerrainRGB({
xyz: new XYZ({
url:
'https://api.maptiler.com/tiles/terrain-rgb/{z}/{x}/{y}.png?key=' +
maptilerKey,
crossOrigin: 'anonymous',
tileSize: 512,
}),
fetchFuncName: 'getElevation',
});

const reliefShader = `
const float pxSize = 1./512.;

void main(void) {
// Fetch data from texture source 0 using the named GLSL function
// (which has been set up in the GlTiledTexture)
// Note that this shader fetches data from neighboring pixels
float elevation = getElevation(vTextureCoords.st);

float elevationNorth = getElevation(vTextureCoords.st + vec2(0., pxSize));
float elevationSouth = getElevation(vTextureCoords.st + vec2(0., -pxSize));
float elevationEast = getElevation(vTextureCoords.st + vec2(pxSize, 0.));
float elevationWest = getElevation(vTextureCoords.st + vec2(-pxSize, 0.));

float deltaSN = (elevationNorth - elevationSouth) * uVerticalExaggeration * pxSize;
float deltaWE = (elevationWest - elevationEast) * uVerticalExaggeration * pxSize;

// Both 'slope' and 'aspect' are in the range of -pi/2 to pi/2
float slope = atan( length( vec2(deltaSN, deltaWE)) );
float aspect = atan( deltaSN, deltaWE );

float cosIncidence =
uSinSunElevation * cos(slope) +
uCosSunElevation * sin(slope) * cos( uSunAzimuth - aspect ) ;

// This would output a shaded relief grayscale raster
//gl_FragColor = vec4(vec3(cosIncidence), 1.);

// The format of the data table for the colour stops is: R,G,B,elevation (in meters)
vec4 colours[6];
colours[0] = vec4(0., 0., 0., -10.);
colours[1] = vec4(.2, .2, .5, -.01);
colours[2] = vec4(.4, .55, .3, .01);
colours[3] = vec4(.9, .9, .6, 500.);
colours[4] = vec4(.6, .4, .3, 2000.);
colours[5] = vec4(1., 1., 1., 4000.);

vec4 tintColour = colours[0];
for (int i=0; i < 5; i++) {
// Do a smoothstep of the heights between steps. If the result is > 0
// (meaning "the height is higher than the lower bound of this step"),
// then replace the colour with a linear blend of the step.
// If the result is 1, this means that the real colour will be applied
// in a later loop.

tintColour.rgb = mix(
tintColour.rgb,
colours[i+1].rgb,
smoothstep( colours[i].a, colours[i+1].a, elevation )
);
}

gl_FragColor = vec4(tintColour.rgb * (1. + cosIncidence - uSinSunElevation), 1.);

// Special case for zero elevation, since GPUs seems to handle this particular
// colour differently when using mix(), for whatever low-level reason.
if (elevation > -.001 && elevation < .001) {
gl_FragColor = vec4(colours[1].rgb, 1.);
}
}
`;

const glSource = new GlTiles({
fragmentShader: reliefShader,
textureSources: [terrainTexture],
attributions:
'Terrain-RGB data by <a href="https://www.maptiler.com/copyright/" target="_blank">&copy; MapTiler</a>',
uniforms: {
uVerticalExaggeration: 1,
// uSunElevation: 45,
uSinSunElevation: Math.sin((45 * Math.PI) / 180),
uCosSunElevation: Math.cos((45 * Math.PI) / 180),
uSunAzimuth: (45 * Math.PI) / 180,
},
tileSize: 512,
maxZoom: 10,
});

const map = new Map({
layers: [
new TileLayer({
source: glSource,
}),
],
target: 'map',
view: new View({
center: fromLonLat([-5, 40]),
maxZoom: 16,
zoom: 5,
}),
});

const sliderExaggeration = document.getElementById('vert');
sliderExaggeration.addEventListener('input', function () {
glSource.setUniform(
'uVerticalExaggeration',
Number(sliderExaggeration.value)
);
document.getElementById('vertOut').innerText = sliderExaggeration.value;
});

const sliderSunEl = document.getElementById('sunEl');
sliderSunEl.addEventListener('input', function () {
glSource.setUniform(
'uSinSunElevation',
Math.sin((sliderSunEl.value * Math.PI) / 180),
false
);
glSource.setUniform(
'uCosSunElevation',
Math.cos((sliderSunEl.value * Math.PI) / 180)
);
document.getElementById('sunElOut').innerText = sliderSunEl.value;
});

const sliderSunAz = document.getElementById('sunAz');
sliderSunAz.addEventListener('input', function () {
glSource.setUniform('uSunAzimuth', (sliderSunAz.value * Math.PI) / 180);
document.getElementById('sunAzOut').innerText = sliderSunAz.value;
});
15 changes: 15 additions & 0 deletions examples/gltiles-sentinel-ndvi.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
---
layout: example.html
title: Sentinel NDVI+NDWI
shortdesc: WebGL shader for NDVI & NDWI on Sentinel-2 data
docs: >
A demo of how a GLTiles source works:

Data from <a href='https://www.cogeo.org/'>COGs (Cloud-Optimized Geotiffs)</a>
from a Sentinel-2 granule (provided by <a href='https://eox.at/'>EOX</a>) is fetched
through instances of <a href='https://github.com/geotiffjs/geotiff.js'>geotiff.js</a>,
then passed to a WebGL shader to calculate NDVI (shown as green) and NDWI (shown as blue).
tags: "sentinel, canvas, webgl, geotiff, gltiles"
---
<script src="https://unpkg.com/geotiff@1.0.0-beta.16/dist-browser/geotiff.js"></script>
<div id="map" class="map"></div>
Loading