読者です 読者をやめる 読者になる 読者になる

S.F. Page

Programming,Music,etc...

Overpass API + three.jsを使って建物を3D化して表示してみる(2)

スカイボックスを追加し、ビルにテクスチャを貼り付けてみた。リアルとは言えないが、雰囲気は出てきた。

大きい範囲を描画しようとすると相当に処理が重い。最適化しないといかんかな。。まあでも縦スクロールシューティングではかなり狭い範囲を描画するので、パフォーマンス的にはそんなに問題にはならなそうだが。

屋根の面には屋根用のテクスチャを貼らないといけないんだけど、どうやればいいかまだわかっていない。テクスチャの貼り方にはさらに工夫が必要だ。

デモ:(相当処理が重いので注意

Open Street Map のデータをthree.jsにインポートする

ソースコード&デモ:(相当処理が重いので注意

Open Street Mapのデータを使用してthree.jsで可視化する(2)テクスチャーマップ - bl.ocks.org

ちょっとはまったのは、ShapeExtrudeGeometryで立体化しているのだけれども、ExtrudeGeometryで作成されたジオメトリに普通にテクスチャを貼り付けようとしてもできないというところ。

このことはThree.jsのISSUEにも載っていた。

github.com

回避策としては、UVGeneratorにBoundingUVGeneratorをセットしてExtrudeGeometryする。だがこの記事で載っているBoundingUVGeneratorは最新バージョンでは動作しないので、改良版を作った。

class BoundingUVGenerator {
  constructor(extrudedShape, extrudedOptions) {
    this.extrudedShape = extrudedShape;
    this.bb = new THREE.Box2();

    this.bb.setFromPoints(this.extrudedShape.extractAllPoints().shape);
    this.extrudedOptions = extrudedOptions;
  }
  generateTopUV(geometry, indexA, indexB, indexC) {
    var ax = geometry.vertices[indexA].x,
      ay = geometry.vertices[indexA].y,

      bx = geometry.vertices[indexB].x,
      by = geometry.vertices[indexB].y,

      cx = geometry.vertices[indexC].x,
      cy = geometry.vertices[indexC].y,

      bb = this.bb,//extrudedShape.getBoundingBox(),
      bbx = bb.max.x - bb.min.x,
      bby = bb.max.y - bb.min.y;

    return [
      new THREE.Vector2((ax - bb.min.x) / bbx, 1 - (ay - bb.min.y) / bby),
      new THREE.Vector2((bx - bb.min.x) / bbx, 1 - (by - bb.min.y) / bby),
      new THREE.Vector2((cx - bb.min.x) / bbx, 1 - (cy - bb.min.y) / bby)
    ];
  }

  generateBottomUV(geometry, indexA, indexB, indexC) {
    return this.generateTopUV(geometry, indexA, indexB, indexC);
  }

  generateSideWallUV(geometry, indexA, indexB, indexC, indexD) {
    var ax = geometry.vertices[indexA].x,
      ay = geometry.vertices[indexA].y,
      az = geometry.vertices[indexA].z,

      bx = geometry.vertices[indexB].x,
      by = geometry.vertices[indexB].y,
      bz = geometry.vertices[indexB].z,

      cx = geometry.vertices[indexC].x,
      cy = geometry.vertices[indexC].y,
      cz = geometry.vertices[indexC].z,

      dx = geometry.vertices[indexD].x,
      dy = geometry.vertices[indexD].y,
      dz = geometry.vertices[indexD].z;

    var amt = this.extrudedOptions.amount,
      bb = this.bb,//extrudedShape.getBoundingBox(),
      bbx = bb.max.x - bb.min.x,
      bby = bb.max.y - bb.min.y;

    if (Math.abs(ay - by) < 0.01) {
      return [
        new THREE.Vector2(ax / bbx, az / amt),
        new THREE.Vector2(bx / bbx, bz / amt),
        new THREE.Vector2(cx / bbx, cz / amt),
        new THREE.Vector2(dx / bbx, dz / amt)
      ];
    } else {
      return [
        new THREE.Vector2(ay / bby, az / amt),
        new THREE.Vector2(by / bby, bz / amt),
        new THREE.Vector2(cy / bby, cz / amt),
        new THREE.Vector2(dy / bby, dz / amt)
      ];
    }
  }
};

Overpass API + three.jsを使って建物を3D化して表示してみる。

下の記事のコードをベースに、OverPass APIとthree.jsを使って、建物を3D化して表示してみた。

qiita.com

表示してみた結果は以下の通り。

参考にしたコードは、建物の高さデータを利用していなかったので、利用するようにしたのと、高さデータがないものは乱数で高さを与えてみている。またunderscoreやjqueryも除去し、ES6コードを加えたりした。 上の結果は大阪の中心部を表示したものであるが、建物高さが乱数によっている部分があるので、実際とは異なっているが、かなり都会的な街並みが再現されているのではなかろうか。

サンプルはこちら。ちなみに下のサンプルで表示されるのは東京の中心部分。一応マウスでぐりぐりできる。PCによっては処理が重いかもしれない。

Open Street Map のデータをthree.jsにインポートする

ソースコードはこちら:

OverPass APIを使って建物データを3D化してみる · GitHub

Open Street Map(OSM)周りのJSライブラリを調べる

背景の描画を省力化するために地図データから街並みを作ることを試みようとしている。OSMであれば建物を上から見た形状データがあるので、それをY方向に膨らまして屋根と壁にテクスチャを貼り付ければ、手っ取り早く背景マップができるのではないか。Googleマップの3Dのように実際の地形や建物を3D化するわけではないので、比較的簡単に実現できるのではないかと考えているわけだ。

地図情報をスクロール背景に使おうと考える輩は少数派だと思うけれど、地図データをthree.jsで立体化しようとする人は結構いるのではないかと思ってググると、いくつかすでに実装が存在していた。

googlemapsmania.blogspot.jp

github.com

OSM Buildings

github.com

qiita.com

このあたりのコードを1つ1つ調べて、コードを書いてみようと思っている。