tangrams / tangram

WebGL map rendering engine for creative cartography
https://tangram.city
MIT License
2.21k stars 290 forks source link

Debug flag to visualize tile boundaries #354

Open bcamper opened 8 years ago

bcamper commented 8 years ago

It would be useful to be able to visualize tile boundaries consistently. We often use the tile_edges: true flag for this when drawing land or water layers, but this both requires polygon geometry to be present in the source data covering the tile boundaries, and for additional draw blocks to add lines. We've also looked at highlighting Leaflet <div>s, but they do not follow Tangram's zoom conventions and so they are not an accurate depiction of the currently visible Tangram tiles.

This debug should just be built into the library. The most straightforward way to do this is probably to generate a simple GL quad geometry for each tile using GL_LINES, and include it in the tile rendering process. I believe this is similar to the technique used in ES - @karimnaaji? Note that we aren't actually using GL_LINES anywhere else in our render process, though the VBOMesh class was written with this use case in mind; it' possible some clean-up is needed to get it up to speed. Another option would be to actually tesselate polylines for the tile boundaries, like we do for other lines.

Because tiles are rendered with meshes grouped by style rather than all in one render call, we may need to add an additional call for this type of tile-wide drawing/debugging, somewhere in the main tile draw loop.

nvkelso commented 8 years ago

+1

On Tue, Jul 12, 2016 at 8:57 AM, Brett Camper notifications@github.com wrote:

It would be useful to be able to visualize tile boundaries consistently. We often use the tile_edges: true flag for this when drawing land or water layers, but this both requires polygon geometry to be present in the source data covering the tile boundaries, and for additional draw blocks to add lines. We've also looked at highlighting Leaflet

s, but they do not follow Tangram's zoom conventions and so they are not an accurate depiction of the currently visible Tangram tiles.

This debug should just be built into the library. The most straightforward way to do this is probably to generate a simple GL quad geometry for each tile using GL_LINES, and include it in the tile rendering process. I believe this is similar to the technique used in ES - @karimnaaji https://github.com/karimnaaji? Note that we aren't actually using GL_LINES anywhere else in our render process, though the VBOMesh class was written with this use case in mind; it' possible some clean-up is needed to get it up to speed. Another option would be to actually tesselate polylines for the tile boundaries, like we do for other lines.

Because tiles are rendered with meshes grouped by style rather than all in one render call, we may need to add an additional call for this type of tile-wide drawing/debugging, somewhere in the main tile draw loop https://github.com/tangrams/tangram/blob/master/src/scene.js#L518.

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/tangrams/tangram/issues/354, or mute the thread https://github.com/notifications/unsubscribe/AA0EO3tjF1HoV0c-CBug7CLyXjGu2sY7ks5qU7lmgaJpZM4JKi9C .

karimnaaji commented 8 years ago

We have two ways to draw debug on -es:

  1. Screen space polygons called primitives using immediate rendering mode available with glVertexAttribPointer of Opengl ES. It uses client side buffer data instead of a buffered vbo, it's faster to implement (no need of setting up vbos/vaos) but much slower on rendering, so it's a good fit for debug. I doubt that WebGL has something similar since client data is more protected but would be worth looking at. Otherwise everything is drawn using GL_LINES like mentioned. Those are not rendered in the tile drawing process and are used for labels, debug stats.
  2. Regular meshes drawn with GL_LINES for tile boundaries where each geometry is the 4 corners of a tile. Those are drawn in the tile drawing process.
bcamper commented 8 years ago

Ah, yeah there's no "client data" in WebGL. Making regular meshes with GL_LINES is probably going to be the simplest (will use existing code and fit into the rendering pipeline cleanly).

bcamper commented 8 years ago

Here are some notes on a couple possible paths:

1. Hook into the existing tile building pipeline This is kind of a hack, but you could generate an extra data layer for each tile, that is rendered just for debug purposes.

For example, you could hook into the NetworkTileSource class, and override the internal _load() method to add extra data after the tile loads. Here's a proof of concept:

    _load (tile) {
        // First load tile from network
        return super._load(tile).then(tile => {
            // Generate a polygon around the tile's edges
            let scale = Geo.tile_scale;
            tile.source_data.layers._tile_edges = {
                type: 'FeatureCollection',
                features: [{
                    geometry: {
                        type: 'Polygon',
                        coordinates: [[
                            [0, 0], [scale,0],
                            [scale, scale], [0, scale], [0, 0]
                        ]]
                    },
                    properties: {
                        name: tile.key,
                        x: tile.coords.x,
                        y: tile.coords.y,
                        z: tile.coords.z,
                        style_zoom: tile.style_zoom,
                        source: tile.source.name
                    }
                }]
            };
            return tile;
        });
    }

Then, you could add a corresponding layer to the scene to draw that feature. In scene file form it would look like this:

layers:
    _tile_edges:
        data: { source: mapzen } # note the data source shouldn't actually be hardcoded
        draw:
            lines:
                color: yellow
                width: 4px
                order: 1000 # find a suitable max value for this
                tile_edges: true

That could be programmatically added to the scene.config.layers object, probably in the updateConfig() method (which does some preparation on the config before it is sent to the worker). Alternatively it could maybe go in the finalize() method of the SceneLoader.

2. Create a separate GL buffer to draw tile borders This is probably the more correct way to do this, since it doesn't hijack any user-facing functionality, but may be more code than it's worth for a debug feature. Theoretically, the VBOMesh class should be able to render other GL types, such as GL_LINES (see the draw_mode parameter). That said we haven't used that functionality in years so who knows if it still works :) Since all tiles have the same local coordinate space, it may be possible to build a single mesh object with a fixed scale (same as the GeoJSON example above), and then render it for each tile.

To minimize GL state changes, rendering is actually grouped by style (shader program) rather than by tile, so rendering these tile boundary objects might need to be a separate loop, somewhere around here. You'd also need to figure out what shader program / vertex layout to render them with; probably the existing polygons style, which I think would work as-is when applied to a GL_LINES buffer. (Since this process would skip the polyline builder, it wouldn't work to use the lines style since it expects extra vertex attributes for line extrusion, etc.)

burritojustice commented 8 years ago

+1