-
Notifications
You must be signed in to change notification settings - Fork 2.1k
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
Add Experimental Layer: TerrainLayer #3984
Conversation
I tested the example and got these errors in the console:
|
Thanks for posting the error, that’s the same runtime error I’m getting right now too. We’re going to try to fix it soon (seems to have come from some recent updates) |
Regarding Martini, I think the main difference would be that you'd need to pass the image data to the geometry generator. It looks like right now, you're calculating the grid geometry just from the x and y resolutions and the bounding box. For its optimizations, Martini needs the elevation data when creating the geometry. I think a basic import GL from "@luma.gl/constants";
import { Geometry } from "@luma.gl/core";
import Martini from '@mapbox/martini'
export default class MartiniGeometry extends Geometry {
constructor(opts = {}) {
const { id = "martini-geometry" } = opts;
const mesh = runMartini(opts);
const indices = mesh.triangles
const positions = mesh.vertices
super(
Object.assign({}, opts, {
id,
drawMode: GL.TRIANGLES,
attributes: {
// No size/type information is needed for known vertex names
indices,
positions
},
vertexCount: indices.length
})
);
}
}
// From Martini demo
// https://observablehq.com/@mourner/martin-real-time-rtin-terrain-mesh
function runMartini({ pngData, xResolution }) {
const tileSize = xResolution;
const gridSize = tileSize + 1
const terrain = new Float32Array(gridSize * gridSize);
let R, G, B, height;
for (let x = 0; x < tileSize; x++) {
for (let y = 0; y < tileSize; y++) {
// .get method is from ndarray, which is how I had queried the png files
// https://github.com/scijs/ndarray
R = pngData.get(x, y, 0)
G = pngData.get(x, y, 1)
B = pngData.get(x, y, 2)
height = -10000 + ((R * 256 * 256 + G * 256 + B) * 0.1)
terrain[y * gridSize + x] = height;
}
}
// backfill right and bottom borders
for (let x = 0; x < gridSize - 1; x++) {
terrain[gridSize * (gridSize - 1) + x] = terrain[gridSize * (gridSize - 2) + x];
}
for (let y = 0; y < gridSize; y++) {
terrain[gridSize * y + gridSize - 1] = terrain[gridSize * y + gridSize - 2];
}
const martini = new Martini(gridSize);
const tile = martini.createTile(terrain);
const mesh = tile.getMesh(10);
return mesh;
} I'm also curious if you've tested this with vector layers as well as raster layers. Anyways, this is really exciting stuff. |
I did some research into using Mapbox vector map tiles, rendering them with the GeoJsonLayer without any terrain awareness. My primary goal was to customize the styles, and when I unable to get the result I was looking for I abandoned the idea. Off topic of terrain, but it seems like a part I’m missing there is a parser/mapper function between a mapbox style JSON, and the vector file data (the mapping isn’t intuitive). I guess that’s a long way of saying I didn’t test terrain mesh with vector tiles yet. Is a raster layer different from satellite imagery? This layer renders satellite map tiles or any bitmap tile on the terrain mesh (This PR also demos rendering Aviation navigation charts on the mesh). In the future I’d like to add a LayerExtension to bring “terrain awareness” to any layer. We have some ideas on how that might be done. |
In a style JSON, the You can have as many sources as you want. For example, with the map I'm currently developing, right now I have 5. Raster is the same thing as satellite imagery. Or more specifically, satellite is a type of raster data. You do set Another reason I asked about the vector layer is that tiles conforming to Mapbox's Terrain RGB spec can also be used for on-device hillshading. If the terrain-rgb tiles are used both for hillshading and for the TerrainLayer, it would be nice if they weren't loaded twice. |
@chrisgervang Would love to see a screenshot... |
Instead of This seems to work well: |
As someone who doesn't know WebGL, is there anything I can do to help move this along? |
@infospark I tried this out and got this error:
Is there something else I need to change? |
I created a fork with the changes I made here. https://github.com/infospark/deck.gl/tree/terrain-layer. The fork is now also upgraded to deck.gl 8 (uses positions64Low). Still doesn't work in Safari unfortunately. |
|
examples/experimental/terrain/src/terrain-layer/TerrainLayer.js
Outdated
Show resolved
Hide resolved
3a5bc92
to
9074c92
Compare
f5bec76
to
c669a73
Compare
Background
Many transportation projects, such as UAM network planning projects, need to be able to represent terrain and the real world. This layer is the first demonstration of loading global elevation data with deck.gl. It opens the door to more exploration, such as offsetting any layer by terrain. Eventually, it'd be amazing to correctly rendering entire cities, the buildings within them, and the aviation layers defined above them in AGL (above ground level) units.
This TerrainLayer is able to produce textured terrain meshes out of any rectangular image with elevation encoded as RGB values. It produces an optimal mesh using the Martini library. It asynchronously loads the terrain texture and will render an colored mesh by default, unless a surface texture is supplied.
Terrain Layer Props
For demonstration purposes, we've implemented an example application to load global terrain and satellite imagery provided by Mapbox.
Change List