9
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

FOSS4GAdvent Calendar 2018

Day 19

Mapbox GL JSで色別標高図

Last updated at Posted at 2018-12-25

Mapbox GL JSで、地理院地図の「自分で作る色別標高図」を実装してみる試みです。

自分で作る色別標高図とは

今年、地理院地図に追加された、自由に色を設定して色別標高図を作ることができるすごい機能です。

Leaflet.jsのTileLayerを拡張して、canvas上で標高に応じた色をつけるように実装されています。

同じことをMapbox GL JSで実現することを考えます。
ですが、現時点では色別標高図を作る機能はないため、自分で実装してみます。

地理院標高タイル

まず、地理院標高タイルをMapbox GL JSで扱えるようにします。
これは以前、Mapbox GL JSで地理院標高タイルという記事を書きました。

Relief Layer

hillshadeのように、色別標高図をRelief Layerとして追加できるようにします。

WebGLで標高に応じた色をつける

relief.fragment.glsl
#ifdef GL_ES
precision highp float;
#endif

uniform sampler2D u_image;
uniform sampler2D u_table;
varying vec2 v_pos;

uniform float u_color_len;
uniform float u_opacity;

float getElevation(sampler2D u_tex, vec2 coord, float bias) {
    // Convert encoded elevation value to meters
    vec4 data = texture2D(u_tex, coord) * 255.0;
    return (data.r + data.g * 256.0 + data.b * 256.0 * 256.0) / 4.0;
}

float getIndex(float el) {
    float prev;
    for (float i = 0.0; i < 128.0; i++){
        if (i >= u_color_len) return u_color_len;
        float v = getElevation(u_table, vec2((i + 0.5) / u_color_len, 1), 0.0);
        if (v >= el){
            if (i == 0.0) return i;
            return i + (el - prev) / (v - prev);
        }
        prev = v;
    }
}

void main() {
    float v = getElevation(u_image, v_pos, 0.0);
    float i = getIndex(v);

    vec4 color = texture2D(u_table, vec2(i / u_color_len, 0), 0.0);
    gl_FragColor = v > 0.0 ? vec4(color.rgb, u_opacity) : vec4(0.0, 0.0, 0.0, 0.0);
}

ざっくりと説明すると、

  1. WebGLで標高値getElevationに応じた階級getIndexを計算する
  2. 設定色のTextureから、階級に応じた色を取得して返す
    という感じです。

区分の標高値と設定色をTexture u_tableとして渡すところがポイントでしょうか。
このフラグメントシェーダーを実行するために、いろいろとコードを書きます。
https://github.com/tattii/mapbox-gl-js/pull/2

参考: Data-driven Raster Layer with Mapbox GL

Example

スクリーンショット 2018-12-26 6.16.05.png https://tattii.github.io/terrain-japan/relief/#9.06/35.511/139.1993
map.addLayer({
    "id": "relief",
    "source": "gsi-dem",
    "type": "relief",
    "paint": {
        "relief-opacity": 0.7,
        "relief-gradation": true,
        "relief-colors": [
            0, "#2db4b4",
            100, "#71b42d",
            300, "#b4a72d",
            1000, "#b4562d",
            2000, "#b4491b",
            4000, "#b43d09",
            null, "#b43d09"
        ]
    }
}, 'waterway-river-canal-shadow');

relief-colorsで標高と色を指定します。この設定例で、自分で作る色別標高図の初期状態と同じです。
スクリーンショット 2018-12-26 6.43.19.png

WIP: 自由に色を設定する

簡易的に、dat.guiを使ってリアルタイムに色の編集をできるようにしました。
スクリーンショット 2018-12-26 7.26.19.png
https://tattii.github.io/terrain-japan/relief/color.html#8.85/35.352/139.1404

標高の編集や区分数を増やすことができるようなアプリケーションとして作成中です...。

Mapbox GL JSで実装してみて

描画が速いため、リアルタイムに色の編集をできるのが良いところです。
また、Mapbox GL JSの陰影起伏hillshadeは重ねても暗くなりません。

一方、Mapbox GL JSをforkして独自の拡張をしているため、本体のバージョンアップについていくのは大変です。

まとめ

WebGLは難しいです。綺麗な色別標高図を作るのも難しいです。
地理院地図にある、URLでの共有や断面図といった機能も実装してみたいです。

9
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?