TOPIC 24|3D都市モデルを使って全国で使えるシステムを作る
PLATEAUの3D都市モデルは、全国的に提供されています。そのため、全国規模に展開するシステムを作ることも可能です。しかし地理情報はデータ量が大きくなるので、実際に作るとなるとデータ分割やサイズの縮小、そして検索などでさまざまな工夫が必要です。本トピックでは、広範囲の地理情報を扱う際に意識すべきポイントを解説します。
PLATEAUの3D都市モデルは、全国的に提供されています。そのため、全国規模に展開するシステムを作ることも可能です。しかし地理情報はデータ量が大きくなるので、実際に作るとなるとデータ分割やサイズの縮小、そして検索などでさまざまな工夫が必要です。本トピックでは、広範囲の地理情報を扱う際に意識すべきポイント、活用できるアルゴリズムやデータ構造を解説します。より深く地理情報を理解し、高度なシステム・サービスを構築するヒントになればと思います。
【目次】
24.3.1 無限PLATEAUのデータ処理と空間分割について
24.1 _ このトピックの見どころ
地理情報は、さまざまな用途に使える便利なものです。
しかし便利な一方で、データのサイズは意外と大きく、広範囲を扱おうとすると、現代のコンピューターでも簡単には扱えないほど巨大になります。そこでこれまで、地理情報を適切なアルゴリズムやデータ構造で扱うための、数多くの研究開発が行われてきました。
PLATEAUの3D都市モデルは、3次元の詳細なデータとして構成されていることもあり、従来の2次元の地図に比べて、さらに巨大なデータの扱いに気を付けなければなりません。そして、それに加えて3次元コンピュータグラフィックス特有の最適化なども考慮しなければなりません。
また現代では、クラウドなどのオンラインリソースを上手に使ったシステムをいかに構築するかという、サーバーやネットワーク特性まで考慮しなければならないケースも増えています。
本トピックでは、これらの一般的な考え方を解説し、いくつか筆者がこれまでに作った事例を取り上げつつ、読者の皆さんの課題解決のヒントになるように説明します。
主な見どころは、以下のとおりです。
・巨大な地理情報の扱い方
地理情報を効率良く扱うための手法を解説します。データの分割や階層化による分割、そして、検索性を高めるための空間インデックスの扱い方などを解説します。
・地理情報を活用した実例
実際に、どのようにして地理情報を効率良く扱えばよいのか、実例から、その実装例を紹介します。
実例は、以下の2本があります。どちらも全国を対象としたシステムなので、それらを扱う工夫が必要な構成です。
①無限PLATEAU
「無限PLATEAU」は、サーバーに置いたPLATEAUのLOD1の3D都市モデルをインターネット経由で位置を指定してUnityアプリに動的にロードする仕組みです。
3D都市モデルは、そもそもデータサイズが大きいため、全国のデータを端末内に持つのは現実的ではありません。そこで、Cesiumのように、必要な場所のデータだけを必要になったときにネットワークを介してサーバーから取得することができれば、アプリのインストール容量も少なくなり、大きなメリットとなります。
「無限PLATEAU」は、PLATEAUの3D都市モデルをUnityでのARのユースケースに最適化した空間分割を行ったうえで、3D圧縮フォーマットのDracoを使って圧縮し、ネットワーク配信しています。クライアント側ではそのデータを使って自分の今いる位置から必要な3DモデルのURLを生成し、必要になるデータを都度ダウンロードして表示する仕組みになっています。Cesiumのようなオンライン地図を、用途を限定してPLATEAUで自作したようなものになります。全国規模でPLATEAUの3D都市モデルをオンラインサービスで扱う実例として参考にしてください。
②Orthoverse
多くのARコンテンツは、特定の場所で特別なアプリを起動しないと体験できないものです。「Orthoverse」は、筆者が開発した地球上のどこにでもコンテンツを配置して見ることのできるARアプリです。
コンテンツの地理座標をそのままデータベースに記録し、空間検索で同様の仕組みを作ることもできますが、位置座標から一意の空間IDを計算し、それとコンテンツを紐付けることで、シンプルで扱いやすい仕組みとして構成します。空間IDの利用方法として事例紹介します。
24.2 _ 巨大な地理情報の扱い方
これまで地理情報を効率的に扱う、さまざまなアルゴリズムやデータ構造が考案されてきました。
どのようなものがあるのか、そして、どのように適用していけばよいのかを解説します。
24.2.1 _ 地理情報のデータの大きさ
効率化の話に入る前に、まず、地理情報をそのまま扱うと、いったいどのくらいの大きさになるのかを確認しておきましょう。
◾️ラスターデータの場合
まずは、ラスターデータで考えてみます。
例えば、地球表面を1平方メートルに区切った画像データを作るとします。1ピクセルが1平方メートルになる地球表面の画像データという想定です。衛星写真を思い浮かべるとよいでしょう。
地球の表面積は、おおよそ、4×π×6,371㎢=510,049,428,806,000㎡です。
1ピクセルを3バイト(=RGB各色1バイト)として換算すると、510,049,428,806,000×3=1,530,148,286,418,000バイト≒1.5ペタバイトのデータサイズになります。
これが月ごと週ごとなどで蓄積されることを考えると、なかなかのデータサイズです。
◾️ベクターデータの場合
それでは、ベクターデータは、どうでしょうか?
OpenStreetMapというプロジェクトでは、オープンな汎用地図のベクターデータを作成しています。このOpenStreetMapの全球データは、2023年10月時点において、圧縮されたものでおよそ70GBあります。
ちなみに、PLATEAUの東京都のデータは、圧縮ファイルで5.5GBです。PLATEAUの情報量で全球データを作るとすれば、相当大きなデータになりそうです。
ベクターデータのほうが少ないとはいえ、手元のパソコンで処理するには少し尻込みするレベルの大きさのデータです。そのため、さまざまなアルゴリズムやデータ構造の工夫で高速に扱えるようにしていかなければ実用的なシステムを作れません。
以下では、このような巨大な地理情報を扱うときに有効ないくつかの考え方を説明します。
PLATEAUの地理情報を使った全国規模のシステムを作る際のヒントになれば幸いです。
24.2.2 _ 局所化をうまく使う
巨大なデータを扱うときの基本は、データの局在性をうまく使い、そもそも一度に処理するデータの量を減らすことです。
地理情報データの場合、一度に同時に全データを処理しなければならないことはまれです。
注目しているデータ(例えばいま自分が居る場所の周辺)が、地球の裏側のデータを参照しないと処理できないことはほとんどないので、おおよそ注目点の周囲の限定的な範囲のデータを参照するだけで十分なケースがほとんどです。
このようなケースでは、ダウンロードしたりメモリに展開したりしなければならないデータは、周辺の狭い範囲だけとなるので、処理量、メモリ使用量などが、全体を処理するのに比べて圧倒的に少なく済み、現実的に処理できます。
これは、データ処理だけでなく、表示する場面でも、有効な考え方です。
2次元の地図を表示することを考えた場合、表示している枠の範囲外のデータは、基本的に必要ありません。
またゲームエンジンでも、FarClipなどのレンダリングする最大距離が決められており、それ以遠のオブジェクトについては描画されません。であれば、全データを用意せずに、レンダリングに必要な範囲のデータを用意するだけで問題ないということになります。
このように、処理しなければならないデータの範囲を狭めることは、現実に動作する仕組みを作る際に必須の思考と言えます。
しかし、全体のデータから必要な範囲のデータを検索・抽出するのに時間がかかってしまったりするようでは、本末転倒です。
24.2.3 _ 分割をうまく使う
そこで次に考慮するのが、データの分割です。
都度、全データから検索・抽出するのではなく、あらかじめデータ全体を適切な範囲に分割しておいて、分割単位ごとに処理する考え方です。
◾️グリッドによる分割
最も簡単な分割は、グリッドです。全データ範囲を格子状に区切り、任意の座標からその所属するマス目を計算できるようにする仕組みです。
簡単な例を示します。
例として、100キロメートル×100キロメートルの地域を対象とするとします。
これを1キロメートル四方のグリッドで区切り、処理単位とします。
座標系は図のとおりです。
ここで、任意の座標から所属するグリッドを求めるプログラムを書くと、以下のようになります。
import math
def grid(x: float, y: float):
return (int(math.floor(x)),int(math.floor(y)))
リスト 24-1 任意の座標から、所属するグリッドを求める
この仕組みだと、境界条件さえ正しく考慮すれば、隣接グリッドを求めるのも簡単です。
この例では、単純な平面上の分割を取り上げましたが、実際には地球が球体であることの考慮や基本とする座標系をどのようにするかなど、考え方や用途によってさまざまな分割が考えられます。
矩形ではなく、六角形を用いた分割なども提案されています。
24.2.4 _ 階層化をうまく使う
しかし、単純な分割では、難しいユースケースがあります。
例えば、地図がズームするケースです。
ズームするということは、どんどん(離れた視点に)縮小していくと、結局、広範囲を扱わなければならなくなります。結果、大量のグリッドを処理しなければならなくなり、前節のように、単純に分割しただけでは破綻します。
そこで使われるのが、階層化の考え方です。
◾️ピラミッドデータ構造
オンラインの地図で、拡大縮小していると、地図の雰囲気が切り替わるのにお気づきでしょうか。
次の図は、国土地理院の地理院地図をさまざまな縮尺で表示したものですが、縮尺が変わるごとに表示されるものが変わっているのがわかります。
【大縮尺】
【中縮尺】
【小縮尺】
これは、ズームのレベルごとに異なるデータを表示しているからです。
「ピラミッドデータ構造」という名称でも呼ばれることもありますが、データを階層的に管理し、上の階層は下の階層のデータをまとめたデータを持つようなデータ構造になっており、縮尺に合わせて、適切な階層のデータを表示しています。
各階層のデータは、その階層に適した粒度で簡略化することで(遠くから見ている場合、細かい部分は、どのみち見えないので省略するなど)、どのズームレベルのデータでも、クライアントが扱えるデータ量に収まるように調整されています。
このように階層化することで、縮尺を変えた場合でも、計算量をあまり変えずに処理や描画ができます。
またデータ構造を工夫することで、データが存在しない場所のデータ量を削減できます。図のように、上位の階層から下位の階層への参照情報を処理する際に、参照がないことを正しく扱うデータ構造とロジックを用意すると、それ以下の階層の詳細情報を保存しないようにできます。これにより、データが存在しない地域(例えば道路地図や地形図で海の部分など、主題から必要ない地域)が範囲内で大きな領域を占める場合などには、大きくデータ量を削減できます。
◾️XYZタイル
Web地図でよく使われるXYZタイルは、Webメルカトル座標系で表した経緯度を四分木で分割し、分割数に応じたズームレベルで階層化したものです。
また、3Dコンピュータグラフィックスにおいても、階層化をLODの異なるデータととらえることで、視点に近い部分は詳細モデルを使い、遠い部分で簡略化したモデルを使うなど、有効に使うことができます。
コラム:「LOD」という用語の違い
LOD(Level of Detail)という言葉は、PLATEAUのコンテキストとゲームエンジンのコンテキストの両方で使われています。どちらも「詳細度」という基本の意味は同じですが、明確に違う文脈で使われているので、注意してください。
・PLATEAUにおけるLOD
データが記述している内容の詳細度を表します。LODレベルが上がるごとに、より詳細なデータが追加されていきます。
・ゲームエンジンにおけるLOD
見た目をなるべく維持しながら遠くのものは簡略化して表示するという考え方で使われます。LODレベルが上がるごとに、元のモデルから簡略化されたモデルとなります。しかし、PLATEAUのLODと違い、データは簡略化されるだけで、要素は増減しません。
文中にLODという言葉が出てきたときは、どちらのコンテキストで使われているか注意して読んでください。
24.2.5 _ 空間分割
ここまで説明してきた分割と階層化の両者をうまく使って、空間全体を分割していくと、処理の効率化ができます。
もちろん、用途によって適するもの適さないものがあるので、性質をよく理解して使うことが重要です。
空間分割は、特性や用途により、さまざまな方法があります。
考慮すべきポイントとして、データ自身の性質、分布、データ構造の更新の頻度や負荷要件、メモリ使用量、各種検索における計算量などがあります。
以下に、よく使われる空間分割を簡単に解説します。
◾️Quadtree・Octree
四分木(Quadtree)、八分木(Octree)とも呼ばれるデータ構造で、2次元の場合は四分木を、3次元の場合八分木を、それぞれ使います。
次元ごとに二分割ずつしながら空間分割するデータ構造です。Web地図で使われているほか、点群の管理にも使われることがあります。
◾️kd-tree
領域の中央値を持つ点に対して、座標軸に沿った直線や平面で空間を分割し、ツリー構造を構築するデータ構造です。注目点が分割線・面のどちら側にあるかを判断し、検索などを行います。
◾️R-tree
幾何形状(ジオメトリ)そのものではなく、包括する矩形で木を構成するデータ構造です。
矩形を基に、最近傍や内包を探索します。多くの空間インデックスの実装で使われています。例えば、最近傍点の探索では、すべての点と最近傍計算をするのと比べ、木構造をたどりながら範囲計算をすることで検索できるので、少ない計算量で解を得られます。
24.2.6 _ 空間インデックス
空間分割を使うと、地物の検索なども効率化できます。
地理空間データベースなどでこのために構築されるデータ構造を、「空間インデックス」と呼びます。
一般的なリレーショナルデータベースシステムでは、データの検索クエリの高速化のために、インデックスというデータ構造が作られます。
よく使われるものとして、B-Treeやその変種のデータ構造があり、データベースシステムの利用に必須の仕組みとなっています。
しかし、一般的な行と列で構成されるデータベースで使われるインデックスのアルゴリズムは、地理情報の検索には向きません。そこで地理情報検索に向いた空間インデックスが考案され、実装されています。
◾️R-Tree
PostgreSQLの地理情報拡張であるPostGISでは、R-Treeの空間インデックスを使うことができます。
◾️モートン符号とZ階数曲線
モートン符号やZ階数曲線は、各次元の座標値をビット列として前方から交互に配置し直したビット列にすることで、範囲検索や内包の判定が前方一致のみで計算できます(https://ja.wikipedia.org/wiki/Z%E9%9A%8E%E6%95%B0%E6%9B%B2%E7%B7%9A)。
四分木や八分木のデータ構造を含み、また数字として近いビット列が表す場所は近い場所に存在することが保証されるなど、データの局所化の観点から見ても効率の良い空間インデックスです。また、ひとつの値のみの検索で範囲検索ができるので、Key Value Storeなどでの利用も有利です。
◾️ジオハッシュ(Geohash)
モートン符号を文字列化したインデックスです(https://ja.wikipedia.org/wiki/%E3%82%B8%E3%82%AA%E3%83%8F%E3%83%83%E3%82%B7%E3%83%A5)。クラウドのmBaaSなどで地理情報の検索のために使われています。
24.2.7 _ 空間ID
空間分割や空間インデックスのデータ構造をもとにして計算されたIDを使った「空間ID」という考え方があります。
空間IDの考え方を使うと、地理的な位置を一意のIDで表して、データと紐付けることができます。
空間IDは、作成するサービスやアプリケーションに適したものにすることが多いですが、これを標準化して、地球上の場所を一意に表せる仕組みを作り、地理空間データの相互活用がしやすい環境を作ろうという試みもあります。
・空間IDの取り組み
デジタル庁の「4次元時空間情報基盤」(旧「3次元空間ID」)は、政府が扱う地理空間情報を統一的なIDで取り扱う仕組みとして提案されています。
なお、Project PLATEAUでは検討段階から空間IDの取組に協力しており、PLATEAUが提供する3D都市モデルの情報を保持した空間IDを生成するツールなども公開しています(https://github.com/Project-PLATEAU/PLATEAU-generator-for-spatialid)。
・Whats3words
「What3words」は、複雑な住所システムを簡易な3単語だけで表す、新しい空間IDベースの住所システムを提案しています。
24.2.8 _ クラウドの活用
現代では、オンラインサービスにおいて、クラウドを有効に活用することが一般的です。
巨大な地理情報データを扱う場合、都度データをサーバー側のプログラムで計算して配信すると、処理負荷が大きくなります。そこで、あらかじめ処理してキャッシュしておいたファイル単位で配信する工夫をすることが多いです。
◾️オブジェクトストレージの活用
その際に選択肢にあがるのが、オブジェクトストレージです。AWSのS3やGoogle CloudのCloud Storageなどがあります。また、CDN(Contents Delivery Network)の使用も重要です。
近年は、こうしたクラウドを基盤とした配信システムに最適化したファイル形式も登場してきました。
例えば、Cesiumで利用されている3DTilesは、あらかじめ空間分割と階層化したデータを、ファイルの形でオブジェクトストレージに配置して配信することで、効率良く大規模な地図データを利用可能にしています。
◾️Cloud Optimize
最近では、Cloud Optimizeというキーワードが流行していて、クラウドのオブジェクトストレージサービス(S3など)の特徴である、HTTP(S)での配信に特化したファイル形式が提案されています。
オブジェクトストレージサービスでは、HTTPのレンジリクエストを使い、「何バイト目から何バイト目までを受信する」というように、巨大なファイルの一部だけをリクエストできます。
そのため、これまで複数ファイルに対して、複数のリクエストを行っていたのを、複数の範囲を指定したリクエストだけで同じデータを取得できます。
この仕組みを活用すれば、データ管理が容易になりますし、低コスト、効率の良い通信を実現できます。また、CDNを有効活用して、ユーザーに近いところにキャッシュして高速化することも容易です。
こうした方向性のデータ形式として、COG(Cloud Optimized GeoTIFF)、COPC(Cloud Optimized Point Cloud)、PMTilesなどがあります。
24.2.9 _ データの圧縮
圧縮アルゴリズムは、巨大なデータを扱うときに、とても強力な武器となります。
公開されている地理情報データは、データの相互利用のために汎用的な読みやすいフォーマットで配布されていることが多く、それらのフォーマットは、一般的にはデータ容量が大きくなりがちな冗長なフォーマットになっています。そのため、実際に使うデータを、どのように圧縮するかが重要になってきます。
◾️バイナリ形式への変換
例えば、PLATEAUのCityGMLデータは、テキストのXMLによる非常に冗長なデータとなっているため、かなり大きな容量です。意味的に同じデータを、ProtocolBufferなどの事前に構造を定義したバイナリ形式で保存すると、容量を大幅に削減できます。
また、データ形式をバイナリ形式にすることで、読み込み時のパースの処理などを高速化できる利点もあります。
◾️属性データのデータベース化
属性データの部分をSQLiteなどのファイルベースのデータベースに変換すれば、検索が容易になります。
◾️Draco圧縮
一方で3Dモデルの幾何形状(ジオメトリ)の圧縮に使えるのが、Dracoという圧縮フォーマットです。テキストをベースとしたOBJや、複雑なFBXと比べると、ファイルサイズと読み込み速度で利点があります。
◾️DXTCとASTC、BasisU
テクスチャをゲームエンジンで扱う場合には、JPEGやPNGなどの一般的な画像圧縮形式ではなく、DXTCやASTCのようなGPU専用のテクスチャ圧縮形式を使ったほうが効率的です。
しかし、GPUごとに扱うことのできる形式が異なっていることが多いため、配信用の形式とするには課題があります。
近年、BasisUという中間形式にすることで、複数のテクスチャ圧縮形式にクライアント側で容易かつ高速に変換可能なフォーマットが提案されており、利用が進むことが期待されます。
いずれにせよ、使う目的に合わせて最適化したデータ形式を使うことで、多くのメリットがあります。
PLATEAUを使ったシステムを構築する際に、こうした最適化した専用データ構造を検討することは一考の価値があると思います。
24.3 _ 無限PLATEAUの仕組み詳解
「無限PLATEAU」は、筆者が構築したPLATEAUの3D都市モデルデータのWeb配信システムです。
公開されているPLATEAUのデータの中から建築物のCityGMLのデータをもとにして、LOD0の平面形状と高さを抽出し、軽量な3D形式に変換してWeb配信するシステムです。
これにより、あらかじめモデルデータをアプリ内に入れておかなくても「PLATEAUの3D都市モデルが提供されているところならどこでもランタイムにオンラインでモデルが表示される」=「無限にPLATEAUが表示され続ける」ということで、「無限PLATEAU」と名付けています。
想定している利用用途は、ARでのオクルージョンなどです。Cesiumの3D地図配信や、GoogleがARCoreで提供しているStreetscape Geometry APIと同様のことをPLATEAUの3D都市モデルを使って限定的に実現しました。この仕組みをGoogleのGeospatial APIなどを使ったARアプリに組み込むと、自分のいる場所から判断して、必要なPLATEAUの3D都市モデルをダウンロードし、表示してくれます。
この仕組みではあらかじめすべてのデータを変換しておくことで、ランタイムでの軽量高速な動作を実現しています。
本項では、この仕組みを簡単に解説します。広範囲でスケールする3Dモデルの配信の仕組みとして、参考になれば幸いです。
なお、より詳細な仕組みについては、筆者の所属する株式会社ホロラボの有志で作成した「ホロらぼん Vol.01」の第1章をご参照ください。
24.3.1 _ 無限PLATEAUのデータ処理と空間分割について
まず無限PLATEAUを作るにあたって採用した、空間分割を説明します。
無限PLATEAUでは、前項で説明した空間分割の中で、最もシンプルなパターンである、1レベルのグリッドを採用しました。
これは、ARなどで実際にその場に居るときに、その場の3D都市モデルを歩行者視点で表示することを目的にしているため、複数のズームレベルに対応する階層化の必要がなかったことからの選択です。また検索についても、自分が居るまさにその地点のグリッドを計算できればよいため、範囲の検索など複雑な処理が必要なく、空間インデックスなども必要としないという判断です。
グリッドの分割は、多くのWeb地図が準拠しているWebメルカトルをベースとしたXYZタイルの分割としました。
24.3.2 _ データ圧縮
無限PLATEAUでは、Googleが開発した「Draco」という3Dデータ圧縮を使っています。
Draco圧縮は、点群や3Dモデルのデータを劇的に圧縮できるデータフォーマットです。非可逆圧縮で、圧縮率もモデルに依存しますが、モデルによっては1/10以下のサイズに圧縮できます。Draco形式への変換は、Googleが公開している「エンコードツール」を使います。対応するデータ形式は、OBJ、STLとPLYです。
無限PLATEAUでは、CityGMLから建造物ごとに幾何形状(ジオメトリ)を切り出し、それぞれの建造物ごとの重心に基づいてグリッドに分割しています。
その後、CityGMLの座標からグリッドの中心を原点とする座標系に変換したうえで幾何形状(ジオメトリ)をOBJファイルに書き出します。
こうして作成したOBJファイル群を、前述のDracoのコマンドラインツールを使ってDraco形式に変換し、配信用のデータファイルとしています。
24.3.3 _ URL設計
無限PLATEAUのフォルダ構造は、XとYのグリッド番号を上から2桁ずつ区切って交互に並べたものとしています。これは、XYZタイルのURL設計とは違いますが、一つのフォルダに入る子フォルダ・ファイルの数が必要以上に多くならないように独自のURL設計としました。
この理由としてWebサーバーでファイル配信を運用することを考えると、ひとつのフォルダにあまりに多くのファイルを置くことは性能の劣化につながるので避けるべきです。そこで、分割して深めのフォルダ階層にすることでひとつのフォルダのファイル数を抑えました。
また、クライアント側で与えられた地理座標から、計算でURLを求められるようにすることで、サーバー側は単純なファイル配信Webサーバーで構成できるようにしました。
24.3.4 _ グリッド移動判定の工夫
クライアント側では、ユーザーの移動に伴って、動的に必要なデータをロードしなければなりません。
そこでその判定のために、グリッドのXとYの数字を結合した「空間コード」というひとつの数字を作り、それとのイコール判定でグリッドの移動を判定しました。直前の空間コードと現在の空間コードを比較し、異なっていればロード処理をします。
24.4 _ スケールする地理情報システムでサービスを作る
続いて解説するOrthoverseは、PLATEAUデータを活用したARコンテンツの配信システムです。
特定の場所に固定されない、どこにでもロケーションARのコンテンツを配置できる仕組みとして筆者が個人で開発しているものです。現時点ではNFTと結び付けてコンテンツを管理するような仕組みになっていますが、ここでは空間IDを使ってコンテンツの配置を管理する仕組みの実例として仕組みを紹介します。
図 24-10のように、コンテンツ作成者は自分が配信するコンテンツを自分が管理するWebサーバーで公開します。NFT上には、このコンテンツのURLとコンテンツの場所を表す空間IDが1対1で記録されており、空間IDからコンテンツのURLを取得することができるようになっています。
ユーザーのスマホアプリでは、Geospatial APIで端末位置を取得し、ブロックチェーンのAPIを利用して、自分がいる場所に対応する空間IDに紐付くURLを取得します。このURLからコンテンツをダウンロードしてAR表示するという仕組みになっています。
ここで重要なのが、空間IDがインデックスとなってコンテンツと1対1で紐付け、NFTは単なるキーバリューストアとして使用している点です。
一般的に想像されるコンテンツを場所に紐付ける方法として、例えば経緯度をコンテンツのメタデータとして記録するなどが考えられますが、この場合周辺のコンテンツを表示するために自分の位置から範囲検索をする必要があります。
空間IDであれば、クライアントアプリで自己位置がわかれば、所定の計算をすることで一意に空間IDが得られるため、コンテンツを直接取得することができます。このため、システムをシンプルかつスケーラブルなものにできます。
ユーザーは、どこででもスマホをかざすとその場所にコンテンツが配置されていれば、自動的にダウンロードされて表示されるため、場所ごとの特定のアプリをインストールしたりする必要がありません。
本項では、この場所とコンテンツを紐付ける仕組みについて解説します。
24.4.1 _ 空間IDの設計について
無限PLATEAUと同様に、Orthoverseでも、経緯度を所定のズームレベルのXYZタイル互換のグリッドの分割を採用しています。ズームレベルは20を採用し、日本周辺では、およそ数10m四方の空間を最小単位としています。このグリッドのXとYの座標が10進で最大7桁の数字になるので、XとYを結合して14桁の数字にしたものを、空間IDとしています。この数字一つでグリッドを一意に特定できます。
経緯度からタイル座標への変換は以下のコードを使っています。
using System;
public class SpatialCode
{
private const long XMUL = 10000000;
public static (int x, int y, int z) deg2tile(double lon, double lat, int zoom)
{
int min = 1, max = 20;
int z = Math.Max(min, zoom);
z = Math.Min(max, z);
return (
(int)(Math.Floor(((lon + 180.0) / 360.0) * Math.Pow(2.0,z))),
(int)(Math.Floor(((1.0 - Math.Log(Math.Tan((lat * Math.PI) / 180.0)
+ 1.0 / Math.Cos((lat * Math.PI) / 180.0)) / Math.PI)
/ 2.0) * Math.Pow(2.0, z))),
z
);
}
public static (double lon, double lat) tile2deg(int x,int y,int z)
{
double n = Math.PI - 2.0 * Math.PI * y / Math.Pow(2.0, z);
return (
(x / Math.Pow(2.0, z) * 360.0 - 180.0),
(180.0 / Math.PI * Math.Atan(0.5 * (Math.Exp(n) - Math.Exp(-n))))
);
}
public static long toSpatialCode(int x, int y)
{
return (long)x * XMUL + (long)y;
}
public static (int x, int y) fromSpatialCode(long spatialCode)
{
return ((int)(spatialCode / XMUL), (int)(spatialCode % XMUL));
}
}
リスト 24-2 経緯度とタイル座標の相互変換と空間コード計算のプログラム
deg2tileで経緯度をタイル座標に変換します。いわゆるWebメルカトル座標系への変換とそこからタイルの座標への変換をしています。tile2degでは、その逆変換をしています。空間IDへの計算は、Xに10000000をかけてYと足すだけです。タイル座標への逆変換も下7桁と上7桁を分離するだけです。
このように、経緯度から計算した空間IDを使っています。
空間IDの設計は、用途によってさまざまにあります。用途に合わせた適切な空間IDを設計することで、大きなメリットを得られます。
24.4.2 _ KVSで空間情報を管理する仕組みについて
空間IDによって、IDと場所が一意に紐づくため、シンプルなKeyValueStore(以下KVS)を用いて、空間を管理できます。
OrthoverseではKVSとして、Etherium上にNFTとして構築したコントラクトに情報を保存しています。NFTのアドレスがそのまま空間IDの格納先となり、アドレスに紐付くデータとしてURLを格納しています。
こうすることで、非常にシンプルに、場所に紐付く情報の管理ができるようになっています。
経緯度から空間IDを計算すれば、その場所のコンテンツを一意に特定できるだけでなく、周辺のグリッドを表す空間IDも簡単に計算できます。空間検索で一定距離の近傍を検索するよりも大幅に少ない計算コストで、同等のことができるわけです。また、ほとんどの処理をクライアント側だけで行うことができるため、管理サーバー側への負荷が少なくなります。
24.4.3 _ コンテンツの配信の仕組みについて
URLの先のWebサーバーには、マークアップテキストとして、コンテンツが配置されています。
マークアップテキストは、MozillaのA-Frameを参考にした独自形式で、3Dコンテンツを表現できます。このデータを読み込むクライアントアプリでは、マークアップテキストをパースし対応したUnityの3Dオブジェクトを実行時に構築して表示できるようにしています。
<!DOCTYPE html>
<html>
<head>
<meta charset='utf-8'>
<title>Orthoverse Test</title>
<meta name='description' content='Orthoverse Test'>
<script type='text/lua'>
i = 0;
function start()
return
end
function update()
i=i+1
document:GetEntityByID('test'):GetComponentBase('rotation'):Set('x',''..i)
return
end
</script>
</head>
<body>
<a-scene scale="0.1 0.1 0.1">
<a-box color='red' depth='2' height='4' width='0.5'>
<a-entity geometry='primitive: cone; radiusBottom: 1; radiusTop: 0.1; height: 2;'></a-entity>
<a-entity geometry='primitive: cylinder; height: 3; radius: 2;' link='href: https://oho-sugu.github.io/ovtestpages/Test2.homl; title: My Homepage; target: _self;'></a-entity>
<a-entity geometry='primitive: cylinder; openEnded: true;'></a-entity>
<a-entity geometry='primitive: torus; radius: 2; radiusTubular: 0.2; arc: 180;'></a-entity>
<a-box id='test' color='blue' depth='1' height='1' width='1' position='1 1 1' rotation='30 0 30' scale='1.5 1.5 1.5'>
<a-sphere color='yellow' radius='0.5' position='2 1 1' link='href: https://oho-sugu.github.io/ovtestpages/Test2.homl; title: My Homepage; target: _self;'></a-sphere></a-box>
<a-box animation='property: object3D.position.z; to: 2; dur: 1000; loop: true' animation__2='property: object3D.position.x; to: 2; dur: 100; loop: true' color='green' depth='0.5' height='0.5' width='0.5' position='-1 -1 -1'></a-box>
</a-box>
</a-scene>
</body>
リスト 24-3 マークアップテキストの例
24.4.4 _ Orthoverseまとめ
このような仕組みにすることで、地球上のどこにでもコンテンツを配置できるようになっています。
もちろん、PLATEAUの3D都市モデルが提供されていない地域では、建造物の3Dモデルは表示されませんが、今後提供地域が増えることで表示できる範囲を更新していくことができます。
地理情報は広範囲を大規模に扱っていくことで、大きな価値を生み出します。現状のように一部の限定された地域でのアプリではなく、より広範囲のサービスという形でPLATEAUや地理情報を活用するものが出てくる一助になれば幸いです。
【文】
於保俊(株式会社ホロラボ)
【協力】
大澤文孝