Calmery.me

みっかぼうずにならないようがんばる

npm installで起こるnode-gypのエラーの対処方法

忘れそうなのでメモ.npm install すると node-gyp のエラーが出た.

$ npm install opencv

> opencv@6.0.0 install /Users/calmery/projects/opencv/node_modules/opencv
> node-pre-gyp install --fallback-to-build

node-pre-gyp ERR! Tried to download(403): https://node-opencv.s3.amazonaws.com/opencv/v6.0.0/Release/node-v51-darwin-x64.tar.gz 
node-pre-gyp ERR! Pre-built binaries not found for opencv@6.0.0 and node@7.1.0 (node-v51 ABI) (falling back to source compile with node-gyp) 
gyp ERR! configure error 
gyp ERR! stack Error: Command failed: /Users/calmery/.pyenv/shims/python2 -c import platform; print(platform.python_version());
gyp ERR! stack pyenv: python2: command not found
gyp ERR! stack 
gyp ERR! stack The `python2' command exists in these Python versions:
gyp ERR! stack   2.7.12
gyp ERR! stack 
gyp ERR! stack 
gyp ERR! stack     at ChildProcess.exithandler (child_process.js:211:12)
gyp ERR! stack     at emitTwo (events.js:106:13)
gyp ERR! stack     at ChildProcess.emit (events.js:191:7)
gyp ERR! stack     at maybeClose (internal/child_process.js:885:16)
gyp ERR! stack     at Socket.<anonymous> (internal/child_process.js:334:11)
gyp ERR! stack     at emitOne (events.js:96:13)
gyp ERR! stack     at Socket.emit (events.js:188:7)
gyp ERR! stack     at Pipe._handle.close [as _onclose] (net.js:501:12)
gyp ERR! System Darwin 15.6.0
gyp ERR! command "/usr/local/bin/node" "/Users/calmery/projects/opencv/node_modules/node-gyp/bin/node-gyp.js" "configure" "--fallback-to-build" "--module=/Users/calmery/projects/opencv/node_modules/opencv/build/opencv/v6.0.0/Release/node-v51-darwin-x64/opencv.node" "--module_name=opencv" "--module_path=/Users/calmery/projects/opencv/node_modules/opencv/build/opencv/v6.0.0/Release/node-v51-darwin-x64"
gyp ERR! cwd /Users/calmery/projects/opencv/node_modules/opencv
gyp ERR! node -v v7.1.0
gyp ERR! node-gyp -v v3.5.0
gyp ERR! not ok 
node-pre-gyp ERR! build error 
node-pre-gyp ERR! stack Error: Failed to execute '/usr/local/bin/node /Users/calmery/projects/opencv/node_modules/node-gyp/bin/node-gyp.js configure --fallback-to-build --module=/Users/calmery/projects/opencv/node_modules/opencv/build/opencv/v6.0.0/Release/node-v51-darwin-x64/opencv.node --module_name=opencv --module_path=/Users/calmery/projects/opencv/node_modules/opencv/build/opencv/v6.0.0/Release/node-v51-darwin-x64' (1)
node-pre-gyp ERR! stack     at ChildProcess.<anonymous> (/Users/calmery/projects/opencv/node_modules/opencv/node_modules/node-pre-gyp/lib/util/compile.js:83:29)
node-pre-gyp ERR! stack     at emitTwo (events.js:106:13)
node-pre-gyp ERR! stack     at ChildProcess.emit (events.js:191:7)
node-pre-gyp ERR! stack     at maybeClose (internal/child_process.js:885:16)
node-pre-gyp ERR! stack     at Process.ChildProcess._handle.onexit (internal/child_process.js:226:5)
node-pre-gyp ERR! System Darwin 15.6.0
node-pre-gyp ERR! command "/usr/local/bin/node" "/Users/calmery/projects/opencv/node_modules/opencv/node_modules/.bin/node-pre-gyp" "install" "--fallback-to-build"
node-pre-gyp ERR! cwd /Users/calmery/projects/opencv/node_modules/opencv
node-pre-gyp ERR! node -v v7.1.0
node-pre-gyp ERR! node-pre-gyp -v v0.6.32
node-pre-gyp ERR! not ok 
Failed to execute '/usr/local/bin/node /Users/calmery/projects/opencv/node_modules/node-gyp/bin/node-gyp.js configure --fallback-to-build --module=/Users/calmery/projects/opencv/node_modules/opencv/build/opencv/v6.0.0/Release/node-v51-darwin-x64/opencv.node --module_name=opencv --module_path=/Users/calmery/projects/opencv/node_modules/opencv/build/opencv/v6.0.0/Release/node-v51-darwin-x64' (1)
npm WARN enoent ENOENT: no such file or directory, open '/Users/calmery/projects/opencv/package.json'
npm WARN a No description
npm WARN a No repository field.
npm WARN a No README data
npm WARN a No license field.
npm WARN In opencv@6.0.0 replacing bundled version of node-pre-gyp with node-pre-gyp@0.6.32
npm ERR! Darwin 15.6.0
npm ERR! argv "/usr/local/bin/node" "/usr/local/bin/npm" "install" "opencv"
npm ERR! node v7.1.0
npm ERR! npm  v3.10.9
npm ERR! code ELIFECYCLE

npm ERR! opencv@6.0.0 install: `node-pre-gyp install --fallback-to-build`
npm ERR! Exit status 1
npm ERR! 
npm ERR! Failed at the opencv@6.0.0 install script 'node-pre-gyp install --fallback-to-build'.
npm ERR! Make sure you have the latest version of node.js and npm installed.
npm ERR! If you do, this is most likely a problem with the opencv package,
npm ERR! not with npm itself.
npm ERR! Tell the author that this fails on your system:
npm ERR!     node-pre-gyp install --fallback-to-build
npm ERR! You can get information on how to open an issue for this project with:
npm ERR!     npm bugs opencv
npm ERR! Or if that isn't available, you can get their info via:
npm ERR!     npm owner ls opencv
npm ERR! There is likely additional logging output above.

npm ERR! Please include the following file with any support request:
npm ERR!     /Users/calmery/projects/opencv/npm-debug.log

Windowsでnpm installしてnode-gypでつまずいた時対処方法 - Qiita によると

pythonも必要らしい。
そしてpython3.x系は未対応ということなので2.7系をインストールする。

ということみたい.エラーにもそう書いてある.

gyp ERR! stack Error: Command failed: /Users/calmery/.pyenv/shims/python2 -c import platform; print(platform.python_version());
gyp ERR! stack pyenv: python2: command not found
$ pyenv local 2.7.12
$ npm install opencv

> opencv@6.0.0 install /Users/calmery/projects/opencv/node_modules/opencv
> node-pre-gyp install --fallback-to-build

node-pre-gyp ERR! Tried to download(403): https://node-opencv.s3.amazonaws.com/opencv/v6.0.0/Release/node-v51-darwin-x64.tar.gz 
node-pre-gyp ERR! Pre-built binaries not found for opencv@6.0.0 and node@7.1.0 (node-v51 ABI) (falling back to source compile with node-gyp) 
  CXX(target) Release/obj.target/opencv/src/init.o
  CXX(target) Release/obj.target/opencv/src/Matrix.o
../src/Matrix.cc:335:59: warning: 'NewInstance' is deprecated
      [-Wdeprecated-declarations]
  v8::Local<v8::Object> actualBuffer = bufferConstructor->NewInstance(3...
                                                          ^
/Users/calmery/.node-gyp/7.1.0/include/node/v8.h:3288:31: note: 'NewInstance'
      has been explicitly marked deprecated here
                Local<Object> NewInstance(int argc, Local<Value> argv[]) const);
                              ^
...
                                                                   ^
/Users/calmery/.node-gyp/7.1.0/include/node/v8.h:3292:52: note: 'NewInstance'
      has been explicitly marked deprecated here
  V8_DEPRECATED("Use maybe version", Local<Object> NewInstance() const);
                                                   ^
2 warnings generated.
  SOLINK_MODULE(target) Release/opencv.node
  COPY /Users/calmery/projects/opencv/node_modules/opencv/build/opencv/v6.0.0/Release/node-v51-darwin-x64/opencv.node
  TOUCH Release/obj.target/action_after_build.stamp
  CXX(target) Release/obj.target/test_nativemat/test/nativemat.o
  SOLINK_MODULE(target) Release/test_nativemat.node
/Users/calmery/projects/a
└─┬ opencv@6.0.0 
  ├── buffers@0.1.1 
  ├─┬ istanbul@0.4.5 
  │ ├── async@1.5.2 
  │ ├─┬ escodegen@1.8.1 
  │ │ ├── estraverse@1.9.3 
  │ │ ├── esutils@2.0.2 
  │ │ ├─┬ optionator@0.8.2 
  │ │ │ ├── deep-is@0.1.3 
  │ │ │ ├── fast-levenshtein@2.0.6 
  │ │ │ ├── levn@0.3.0 
  │ │ │ ├── prelude-ls@1.1.2 
  │ │ │ └── type-check@0.3.2 
  │ │ └─┬ source-map@0.2.0 
  │ │   └── amdefine@1.0.1 
  │ ├── esprima@2.7.3 
  │ ├── glob@5.0.15 
  │ ├─┬ handlebars@4.0.6 
  │ │ ├─┬ optimist@0.6.1 
  │ │ │ └── wordwrap@0.0.3 
  │ │ ├── source-map@0.4.4 
  │ │ └─┬ uglify-js@2.7.5 
  │ │   ├── async@0.2.10 
  │ │   ├── source-map@0.5.6 
  │ │   ├── uglify-to-browserify@1.0.2 
  │ │   └─┬ yargs@3.10.0 
  │ │     ├── camelcase@1.2.1 
  │ │     ├─┬ cliui@2.1.0 
  │ │     │ ├─┬ center-align@0.1.3 
  │ │     │ │ ├─┬ align-text@0.1.4 
  │ │     │ │ │ ├─┬ kind-of@3.1.0 
  │ │     │ │ │ │ └── is-buffer@1.1.4 
  │ │     │ │ │ ├── longest@1.0.1 
  │ │     │ │ │ └── repeat-string@1.6.1 
  │ │     │ │ └── lazy-cache@1.0.4 
  │ │     │ ├── right-align@0.1.3 
  │ │     │ └── wordwrap@0.0.2 
  │ │     ├── decamelize@1.2.0 
  │ │     └── window-size@0.1.0 
  │ ├─┬ js-yaml@3.7.0 
  │ │ └─┬ argparse@1.0.9 
  │ │   └── sprintf-js@1.0.3 
  │ ├── resolve@1.1.7 
  │ ├─┬ supports-color@3.1.2 
  │ │ └── has-flag@1.0.0 
  │ └── wordwrap@1.0.0 
  ├── nan@2.5.0 
  └─┬ node-pre-gyp@0.6.32 
    ├─┬ rc@1.1.6 
    │ ├── deep-extend@0.4.1 
    │ ├── ini@1.3.4 
    │ ├── minimist@1.2.0 
    │ └── strip-json-comments@1.0.4 
    └─┬ tar-pack@3.3.0 
      ├─┬ debug@2.2.0 
      │ └── ms@0.7.1 
      ├── fstream-ignore@1.0.5 
      ├── once@1.3.3 
      ├── readable-stream@2.1.5 
      └── uid-number@0.0.6 

npm WARN enoent ENOENT: no such file or directory, open '/Users/calmery/projects/opencv/package.json'
npm WARN a No description
npm WARN a No repository field.
npm WARN a No README data
npm WARN a No license field.
npm WARN In opencv@6.0.0 replacing bundled version of node-pre-gyp with node-pre-gyp@0.6.32

出来た.

$ node
> require( 'opencv' )
{ version: '2.4',
  readImage: [Function: readImage],
  Point: [Function: Point],
  Matrix: 
   { [Function: Matrix]
     Zeros: [Function: Zeros],
     Ones: [Function: Ones],
     Eye: [Function: Eye],
     getRotationMatrix2D: [Function: getRotationMatrix2D] },
  CascadeClassifier: [Function: CascadeClassifier],
  VideoCapture: [Function: VideoCapture],
  Contours: [Function: Contours],
  TrackedObject: [Function: TrackedObject],
  NamedWindow: [Function: NamedWindow],
  ...
  FACE_CASCADE: '/Users/calmery/projects/opencv/node_modules/opencv/data/haarcascade_frontalface_alt.xml',
  EYE_CASCADE: '/Users/calmery/projects/opencv/node_modules/opencv/data/haarcascade_eye.xml',
  EYEGLASSES_CASCADE: '/Users/calmery/projects/opencv/node_modules/opencv/data/haarcascade_eye_tree_eyeglasses.xml',
  FULLBODY_CASCADE: '/Users/calmery/projects/opencv/node_modules/opencv/data/haarcascade_fullbody.xml',
  CAR_SIDE_CASCADE: '/Users/calmery/projects/opencv/node_modules/opencv/data/hogcascade_cars_sideview.xml' }

Blenderでモデルを作りthree.jsで表示する

Blender で作成したモデルとアニメーションを three.js を使いブラウザ上で表示できたのでメモ.今月の 17,18 日に開催された 林業応援ハッカソン でブラウザ上でモデルを動かすのに必要だった.

準備

Blender にアドオンを追加する.これは three.js が提供するもので,このアドオンを使用すると three.js で使用できる JSON 形式でモデルを書き出せるようになる.README か Three.js の JSONLoader のメモ - Qiita を参考にする.というか見た方が早いと思う.

$ cp -r three.js-master/utils/exporters/blender/addons/io_three /Users/calmery/Library/Application\ Support/Blender/2.77/scripts/addons/io_three

アドオンを追加後,Blender の User Performance から Add-ons を開き,Import-Export: Three.js Format にチェックを入れれば three.js 用の JSON 形式に書き出せるようになる.
f:id:calmery:20161224234440p:plain
Blender の他にも 3ds MAX や Maya,Revit 用のアドオンもあるみたい.どれも README に手順が書かれているのでそれを見ながらやればできそう.

書き出す

わかりやすいようにキューブに色をつけた.
f:id:calmery:20161225000501p:plain
Export から Three.js(json) を選択する.
f:id:calmery:20161225041940p:plain
Face materials にチェックを入れて書き出す必要があるみたい.チェックを入れずに書き出してマテリアルが表示されず大変だった.
f:id:calmery:20161224234922p:plain

読み込む

three.js の JSONLoader を使い,書き出した JSON からモデルを読み込む.

<body></body>

<script src="resources/js/three.min.js"></script>
<script src="resources/js/TrackballControls.js"></script>
<script>
    let scene = new THREE.Scene()

    let renderer = new THREE.WebGLRenderer( { antialias: true } )
    renderer.setSize( 600, 400 )
    renderer.setClearColor( 0xffffff, 1 )
    document.body.appendChild( renderer.domElement )

    let camera = new THREE.PerspectiveCamera( 60, ( 600 / 400 ), 1, 1000 )
    camera.position.set( 0, 0, 300 )

    let directionalLight = new THREE.DirectionalLight( 0xffffff, 0.5 )
    directionalLight.position.set( 0, 150, 1000 )
    scene.add( directionalLight )

    let trackball = new THREE.TrackballControls( camera )

    let loader = new THREE.JSONLoader()
    loader.load( 'blenderToThreejs.json', ( geometry, materials ) => {
        let faceMaterial = new THREE.MeshFaceMaterial( materials )
        mesh = new THREE.Mesh( geometry, faceMaterial )
        mesh.position.set( 0, 0, 0 )
        mesh.scale.set( 50, 50, 50 )
        scene.add( mesh )

        let animation = ( function(){
            requestAnimationFrame( arguments.callee )
            renderer.render( scene, camera )
            trackball.update()
        } )()
    } )
</script>

ちゃんと表示することができた.
f:id:calmery:20161225001648p:plain
もし,書き出したモデルが正しく表示されない場合は Blender Three.js エクスポート その3( テクスチャなどがエクスポート出来ない場合) を参考にする.人のモデルを作成したまでは良かったが,頭だけ表示されてないなんてことにならないようにしたい(なった)

アニメーション

キューブが下に落ちていくアニメーションを作成した.
f:id:calmery:20161225012147p:plain
同様に Export の Three.js(json) から保存する.このとき Animation の Morph Animation と Settings の Textures にチェックを入れる必要がある.
f:id:calmery:20161225012207p:plain
f:id:calmery:20161225012204p:plain
アニメーションを再生できるように修正する.ほとんど Blender Three.js エクスポート その4( モーフアニメーション) そのままなのは気にしてはいけない.

loader.load( 'animation.json', ( geometry, materials ) => {
    // 全てのマテリアルのモーフターゲットの値を true にする
    for( let i=0, l=materials.length; i<l; i++ ) materials[i].morphTargets = true;

    let faceMaterial = new THREE.MeshFaceMaterial( materials )
    mesh = new THREE.Mesh( geometry, faceMaterial )
    mesh.position.set( 0, 0, 0 )
    mesh.scale.set( 50, 50, 50 )
    scene.add( mesh )

    let current_frame = 0,
        total_frame   = 50

    let animation = ( function(){
        requestAnimationFrame( arguments.callee )

        last_frame = current_frame
        current_frame++

        // 現在のフレーム数が合計のフレーム数以上になったら現在のフレームを始めに戻す
        if( total_frame <= current_frame ) current_frame = 0

        mesh.morphTargetInfluences[last_frame] = 0
        mesh.morphTargetInfluences[current_frame] = 1

        renderer.render( scene, camera )
        trackball.update()
    } )()
} )

動かしてみた.
f:id:calmery:20161225034936g:plain

まとめ

Blender で作成したモデルやアニメーションを three.js 上で動かすことができた.

three.jsと標高タイルで3Dマップを生成する

今日はクリスマスイブですね.皆様いかがお過ごしでしょうか.かく言う私はお布団にくるまり http://qiita.com/advent-calendar/2016/no-girlfriend を眺めています.お察しください.

ブラウザ上で現在位置を中心とした 3D マップを 国土地理院の標高タイルthree.js で作ることができたのでメモ.今月の 17,18 日に開催された 林業応援ハッカソン で作った.
github.com
流れとしてはまず現在位置を取得し,その取得した現在位置からタイル座標を求める.ちなみに私は初めてタイル座標というものを知った.このタイル座標や後々利用するピクセル座標については TrailNote : 座標の変換(世界座標、ピクセル座標、タイル座標、緯度・経度) が参考になる.次に求めたタイル座標を元に 国土地理院の標高タイル から標高データを取得し three.js で描画する.

タイル座標を求める

緯度と経度からタイル座標を求める.Showing pixel and tile coordinates  |  Google Maps JavaScript API  |  Google Developers を参考にした.

const createCoordinate = ( lat, lng ) => {
    const TILE_SIZE  = 256,
          ZOOM_LEVEL = 14
    return createInfoWindowContent( ( new google.maps.LatLng( lat, lng ) ), ZOOM_LEVEL, TILE_SIZE )
}

const createInfoWindowContent = ( latLng, zoom, tileSize ) => {
    const scale = 1 << zoom
    
    const worldCoordinate = ( ( latLng, tileSize ) => {
        const siny = Math.min( Math.max( ( Math.sin(latLng.lat() * Math.PI / 180) ), -0.9999 ), 0.9999 )
        return new google.maps.Point( tileSize * ( 0.5 + latLng.lng() / 360 ), tileSize * ( 0.5 - Math.log( ( 1 + siny ) / ( 1 - siny ) ) / ( 4 * Math.PI ) ) )
    } )( latLng, tileSize )

    const pixelCoordinate = new google.maps.Point( Math.floor( worldCoordinate.x * scale ), Math.floor( worldCoordinate.y * scale ) ),
          tileCoordinate  = new google.maps.Point( Math.floor( worldCoordinate.x * scale / tileSize ), Math.floor( worldCoordinate.y * scale / tileSize ) )

    return {
        lat            : latLng.lat(),
        lng            : latLng.lng(),
        zoomLevel      : zoom,
        pixelCoordinate: { x: pixelCoordinate.x, y: pixelCoordinate.y },
        worldCoordinate: { x: worldCoordinate.x, y: worldCoordinate.y },
        tileCoordinate : { x: tileCoordinate.x, y: tileCoordinate.y }
    }
}

標高データを取得する

タイル座標を使い,標高データを CSV で取得する.また,タイル座標に対応したテクスチャも取得することができる.ただし,国土地理院の標高タイルではズームレベルが 14 で固定されており,他のズームレベルでは標高データを取得することができないことに注意する.

標高データ
http://cyberjapandata.gsi.go.jp/xyz/dem/ZOOM_LEVEL/TILE_COORDINATE_X/TILE_COORDINATE_Y.txt
http://cyberjapandata.gsi.go.jp/xyz/dem/14/14547/6463.txt
テクスチャ
http://cyberjapandata.gsi.go.jp/xyz/relief/ZOOM_LEVEL/TILE_COORDINATE_X/TILE_COORDINATE_Y.png
http://cyberjapandata.gsi.go.jp/xyz/relief/14/14547/6463.png

取得した標高データは適当に処理して配列に変換する.

mapData = mapData.substring( 0, mapData.length-1 ).split( '\n' ).map( ( row ) => {
    return row.split( ',' ).map( ( height ) => {
        return parseFloat( height ) || -1
    } )
} )

あとは three.js の PlaneGeometry で元となる Plane を作成し,取得した標高データを元に各点の高さを変更する.

let geometry = new THREE.PlaneGeometry( 0, 0, xLength-1, yLength-1 )

for( let y=0; y<yLength; y++ )
    for( let x=0; x<xLength; x++ )
        geometry.vertices[x + ( y * xLength )] = { x: x, y: y, z: mapData[y][x] }

自分を中心とした 3D マップを生成する

現在位置からタイル座標を求める場合,自分の現在位置に対応したタイル座標を得ることができる.だがタイル上のどの位置にいても同じタイル座標を得てしまう.まあタイル座標というくらいだし当たり前なのだろうけど.またまた TrailNote : 座標の変換(世界座標、ピクセル座標、タイル座標、緯度・経度) を参考にした.自分の現在位置を元に 3D マップを作成しても自分を中心としたマップは作成されないのでいい感じにゴニョゴニョする.

仕方がないので差分をとって取得した標高データを合成する.タイル座標からピクセル座標を求めて現在位置のピクセル座標と比較する.自分がタイルのどの辺りにいるのかを調べて足りない標高データを取得するようにした.
f:id:calmery:20161224164312p:plain
もっとスマートにやりたかった.恥ずかしい.mori_hack/main.js at master · calmery/mori_hack · GitHub に頑張ったあとがある.

const targetTile = createCoordinate( position.lat, position.lng )

const difference = ( ( targetTile ) => {
    let t = targetTile.tileCoordinate,
        p = targetTile.pixelCoordinate

    let tileToLatLng = ( tx, ty, zoom ) => {
        let numOfTiles = Math.pow( 2, zoom ),
            x = tx / numOfTiles,
            y = ty / numOfTiles,
            latRadians = ( y - ( 1 / 2 ) ) / - ( 1 / ( 2 * Math.PI ) )
        return { lat: ( 2 * Math.atan( Math.exp( latRadians ) ) - Math.PI / 2 ) / Math.PI * 180,  lng: ( x - ( 1 / 2 ) ) / ( 1 / 360 ) }
    }

    let latLng = tileToLatLng( t.x, t.y, t.z ),
        tile = createCoordinate( latLng.lat, latLng.lng )

    return { x: p.x - tile.pixelCoordinate.x, y: p.y - tile.pixelCoordinate.y }
} )( targetTile )

const essentialTile = ( ( targetTile, difference ) => {
    let tx = targetTile.tileCoordinate.x,
        ty = targetTile.tileCoordinate.y

    let tiles = [ [], [] ],
        differenceFromBase = {}

    if( difference.x <= 128 && difference.y <= 128 ){
        tiles[0][0] = { x: -1, y: -1 }
        tiles[0][1] = { x:  0, y: -1 }
        tiles[1][0] = { x: -1, y:  0 }
        tiles[1][1] = { x:  0, y:  0 }

        differenceFromBase.x = 256 + difference.x
        differenceFromBase.y = 256 + difference.y
    } else if( difference.x > 128 && difference.y <= 128 ){
        ...
    } else if( difference.x <= 128 && difference.y > 128 ){
        ...
    } else if( difference.x > 128 && difference.y > 128 ){
        ...
    }

    return { tiles: tiles, difference: differenceFromBase }
} )( targetTile, difference )

足りない標高データを補うため合計で 4 回,標高データを取得する必要がある.配列に現在位置より求めたタイル座標からどの程度ずれているかの情報を格納している.上の図の場合,こんな配列になる.

[
    [{ x: -1, y: -1 }, { x:  0, y: -1 }],
    [{ x: -1, y:  0 }, { x:  0, y:  0 }]
]

この配列を元に標高データを取得し,あとはタイル座標から求めたピクセル座標と,現在位置のピクセル座標の差分を元に,足りない標高データを補った配列を作る.テクスチャも同様に 4 枚取得し canvas に貼り付けて切り取る.人吉駅を中心とするとこんな感じの 3D マップができる.f:id:calmery:20161224165333p:plain
ちょっとわかりにくいが中心に人吉駅がある.Google Map で見るとちゃんと中心にきていることがわかるかも.

まとめ

Unity を使って OpenStreetMap Japan | 自由な地図をみんなの手に/The Free Wiki World Map とかと組み合わせると面白そうだと思った.mori_hack/sample at master · calmery/mori_hack · GitHub にすぐに動かせるものがあるのでお試しあれ.