この記事は、STYLY Advent Calendar 2025の12/9の記事です。
GeoTileLoaderとは?
STYLYでは、World Canvasという名称で、スマホアプリで現実空間にオブジェクトを重畳するときに、現実の地図との位置合わせをWebブラウザで行うことができるようにする機能が利用できるようになっています。
このための3D地図の表示を行うために利用されているのが、GeoTileLoaderになります。GeoTileLoaderは、Unityで、緯度経度を指定すると周辺の地図メッシュを読み込んでくれるオープンソースのライブラリです。(拙作)
GeoTileLoaderの主な特徴は以下になります。
- Unity標準のC#で記述されている
- 3D Tiles形式のデータをロードできる
- 3Dモデルのロードに、Unity公式のGlTFastライブラリを用いている
- 並列ロードによる高速な3D地図の表示
- WebGLでの動作に対応
GeoTileLoader を利用すると、Unityで 3D Tiles形式 のデータを読み込んでロードできます。Googleが、Photorealistic 3D Tiles API を公開しており、このAPIを通じて地球全体の3D Tiles形式の3D地図を取得、表示できます。また、PLATEAU Streaming の3D Tilesも表示可能です。
とりあえず使ってみたいという方は、「導入方法」のところをご覧ください。
3D Tiles形式 のデータソースについて
3D Tiles形式は、Cesium社によって推進された仕様ですが、オープンな仕様であり、他の会社なども利用することができます。基本的には、URLに配置されたJSONファイルおよび3Dモデルファイルによって構成されています。JSONファイル内から、配下のノード(JSON)や、3Dモデルファイル(GLTF等)にリンクされています。
3D Tiles形式の地図メッシュデータは、以下のようなサービスによって提供されています。
- Google Photorealistic 3D Tiles API
- PLATEAU Streaming
- Cesium社
仕様に従っているといっても、各データソースで特徴や構成が異なります。そのあたりを以下で触れます。
Google Photorealistic 3D Tiles API について
テクスチャ付きで、Google Mapの3Dモードに近いようなメッシュデータが取得できますし、1つのタイルセットURLの指定で、全世界の情報が取得できます。非常にクオリティが高く有用といえます。
悩ましいこととしては、Googleの Photorealistic 3D Tiles API はGoogle APIに 課金登録しないと使えない ということがあります。
Photorealistic 3D Tiles APIの課金について
残念なことに、Photorealistic 3D Tiles APIは、Map APIの中で課金は結構高い部類であることに注意が必要です。
ルートURLの読み込みが月間1000回まで無料ですが、それをこえると1000回あたり6ドル(1000円程度)かかります。万回単位の大量アクセスがあるとAPI死しかねないので注意しましょう。APIには呼び出し制約を設けることができるので、活用しましょう。
なお、上記はあくまでルートURLの読み込みですので、枝葉のノードを何度読み込んでも特に課金には影響しないと思われます。詳細は以下などを参照してください。
※ 日本語ページでは、課金の単位が「正方形タイルリクエスト」のようになっていますが、英語版では "Root Tile Request" となっているので、ルート(一番根本)のJSONの呼び出しあたり1回、と考えられます。
Photorealistic 3D Tiles APIの利用規約・著作権表示について
APIから取得されたメッシュデータを加工して別用途に利用する、などは基本的に許されないことに注意が必要です。また、地図データを表示するアプリなどを公開する場合は、Googleロゴの表示と、タイルデータの帰属表示が必要です。
https://developers.google.com/maps/documentation/tile/create-renderer?#display-attributions
GeoTileLoaderは上記の帰属表示にも対応していますが、利用アプリ側で若干の実装が必要です。
Photorealistic 3D Tiles APIの3D Tilesデータの特徴
- 1つのタイルに含まれる3Dモデルデータは、ばっさりと境界で切られている
- 個々のタイルの範囲はおおよそ立方体になっている
- BoundingVolumeの形状はboxになっている
- 3Dモデルファイルには、GLBファイル(GLTFのバイナリ形式)を直接利用している
- ベースは 3D Tiles v1.1形式のように思われる
各JSONロードにはAPIキーおよびセッション情報を渡す
Photorealistic 3D Tiles API は課金APIであり、すべてのJSON情報の読み出しにはセッション情報およびAPI Keyを含める必要があります。ルートJSONを読み出したときに取得されたセッション情報を、それ以降の読み出し時にも利用するというようにコードを書く必要があります。
これは3D Tilesの必須仕様ではなく、Googleの拡張仕様といえると思われます。
PLATEAU Streaming について
現状無料で利用できる 3D Tiles データとしては、PLATEAU Streaming があります。
無料で嬉しいですが、以下の点に注意が必要です。
- 地域・情報種別ごとにデータ(タイルセットURL)が分かれており、表示したい地域・種別・詳細度(LOD)ごとに異なるルートURLをセットする必要があります
- テクスチャつきとテクスチャなしのデータセットが別に存在しています
- カバー範囲は日本限定で、主に都市周辺となっています
- GeoTileLoaderではテクスチャ付きのデータは表示できません
- テクスチャつきデータセットのテクスチャ情報がWebP形式で保存されており、GeoTileLoaderで利用しているGlTFastライブラリがWebP形式テクスチャに対応していないためです
- 地面の地形は3D Tilesデータに含まれておらず、表示されません
- 別形式で提供されていますが、GeoTileLoaderでは対応していません
PLATEAU Streamingの3D Tilesデータの特徴
- 形状はわりと不定形
- BoundingVolumeの指定はregion形式になっている
- 3Dモデルデータにb3dm形式が利用されている
- b3dmの内部にGLTFが埋め込まれている
- 3D Tiles v1.0形式(古いほう)のように思われる
PLATEAU Streamingの利用規約について
国土交通省のPLATEAUの規約に従います。このため、PLATEAUデータを利用しているという表示などは必要になりますが、比較的自由に利用できるのが良いところです。
GeoTileLoader と Cesium for Unity との違い
3D Tiles表示という同様の目的を持つライブラリとして、Cesium for Unityがあります。比較すると以下のようになります。
| GeoTileLoader | Cesium for Unity | |
|---|---|---|
| 3D Tiles標準準拠 | △低 | ⚪︎高 |
| 地図のスクロール | ×現状不可 | ⚪︎可能 |
| 遠景対応 | ×現状非対応 | ⚪︎対応 |
| GLTF Draco圧縮 | ⚪︎対応 | ⚪︎対応 |
| GLTF WebPテクスチャ | ×非対応 | ⚪︎対応 |
| WebGLビルド対応 | ⚪︎対応 | △対応中? |
非常に大雑把な比較ですが、機能性ではCesium for Unityが良いです。GeoTileLoaderの良いところは、WebGLビルド可能な点にあります。
Cesium for Unityは、C++等で書かれた部分が多い関係もあるせいか、現状はWebGLに対応していません。と思っていましたが、今調べてみたら、CesiumもUnityのWebGL動作に向けて動いているようです・・・!
GeoTileLoader の導入方法
Google Photorealistic 3D Tiles API を利用する場合を例として、導入方法を紹介します。
Google API Keyの準備
3D Map Tiles API を有効化したGoogle API Keyを作成します。
https://console.cloud.google.com/apis/library/browse?hl=ja&q=tile のあたりでtileを検索すると、以下のように Map Tiles API が出てきます。
「有効にする」を押すと、現在のプロジェクトでAPIが有効になります。
このとき、おそらくプロジェクトの課金設定がされていないと有効化できないと思いますので、課金設定を追加してください。

認証情報ページの、認証情報を作成のあたりからAPIキーを作成してください。

後からわかりやすいキー名をつけておきましょう。
作成したら、APIキーの文字列を控えておきましょう。(後から見ることもできます)
Unityプロジェクトの準備
Unity2022.3またはUnity6で、基本的な3Dプロジェクトを作成してください。
UniTaskのインストール
以下のURLを Package Manager の Add package from git URL... から入れると良いでしょう。
https://github.com/Cysharp/UniTask.git?path=src/UniTask/Assets/Plugins/UniTask#2.5.10
次に、GeoTileLoader を入れましょう
パッケージ化されており、上記と同様に Package Manager の Add package from git URL... からインストールできます。
https://github.com/mhama/GeoTileLoader.git?path=Assets/GeoTileLoader#v0.6.0
サンプルシーン
GeoTileLoaderSettingアセット
- Google APIの設定情報を持つアセットです
- Project Viewから、Create -> GeoTileLoader -> GeoTileLoaderSettings を選んで、
GeoTileLoaderSettingsアセットを作成します -
Google Api Key For 3d Map Tilesというフィールドがあるので、前の項目で作成した Google API Key をセットしてください
TileSetManagerゲームオブジェクト
GeoTileLoaderの中心的コンポーネントです。
- Empty Objectとして "TileSetManager" という名前のゲームオブジェクトを追加します
-
TileSetManagerコンポーネントを追加します -
Settingsフィールドに、先程作成したGeoTileLoaderSettingsアセットを設定します - 任意ですが、
Tile Set Titleフィールドを設定しておくと、作成したマップデータのGameObjectに名前が入ります -
Tile Set Json Urlフィールドには、https://tile.googleapis.com/v1/3dtiles/root.jsonと入れます。これは、Google 3D Photorealistic Tiles API の一番根っこのjsonです
MapRootゲームオブジェクト
マップデータの親を作成します。
- Empty Objectとして "MapRoot" という名前のゲームオブジェクトを追加します
- Positionは (0,0,0) にします
- これを、上記
TileSetManagerコンポーネントのTile Set Parentフィールドにセットします - これにより、読み込まれたマップデータは MapRootゲームオブジェクト配下に追加されます
表示制限用Collider
表示範囲を制約するColliderを追加します。
- Cylinder を追加します。Positionは0,0,0としましょう
- Scaleを、(X: 300, Y: 1000, Z: 300) のようにしましょう。これによって、中心地点から、半径150m以内の地図を表示対象にします
- Cylinderのメッシュが見えている必要はないので、Mesh Rendererは非Activeにしましょう
表示場所と半径の指定
3D地図を表示する対象となる緯度経度、範囲を設定しましょう
-
TileSetManagerコンポーネントのCulling Infoフィールド内を変更することで、表示場所を指定できます -
表示したい緯度経度を
Culling Lat Degree, Culling Lon Degree フィールドにそれぞれ設定します -
Cull Colliderフィールドには、さきほど作成したCylinderゲームオブジェクトをセットします -
現状、
Culling Radius Metersフィールドは参照されませんのでご注意ください
サンプルコードの追加
BasicSample GameObjectの追加
- Empty GameObjectを追加し、"BasicSample" という名前にします
- Add Componentから"BasicSample"という名前で New Scriptを追加します
- 内容は以下のようにします
サンプルコード
using System;
using System.Threading;
using Cysharp.Threading.Tasks;
using GeoTile;
using UnityEngine;
public class BasicSample : MonoBehaviour
{
[SerializeField] private TileSetManager manager;
void Start()
{
Load(this.GetCancellationTokenOnDestroy()).Forget();
}
private void OnDestroy()
{
JsonLoadScheduler.Instance?.StopAllTasks();
ModelLoadScheduler.Instance?.StopAllTasks();
}
async UniTask Load(CancellationToken token)
{
// Tile SetのJSONを読み込む
var hierarchyTrans = await manager.ReadJsonAsync(null, token);
if (hierarchyTrans == null)
{
throw new Exception("Read tile set hierarchy failed.");
}
var hierarchy = hierarchyTrans.GetComponent<TileSetHierarchy>();
if (hierarchy == null)
{
throw new Exception("No hierarchy exist.");
}
// JSONツリーを再帰的に読み込む
await hierarchy.LoadSubTrees(100, 1500, token);
// 3Dモデルをロード、表示する
await hierarchy.Load3DModels(1000, token);
}
}
BasicSampleのフィールド設定
-
Managerフィールドに、TileSetManagerコンポーネントのGameObjectをセットします
実行
UnityでPLAYしたとき、以下のように、3D地図メッシュが表示されたら成功です。
表示されない場合の確認事項
コンソールに、UnityWebRequestException: HTTP/1.1 403 Forbidden などと出る場合は、以下を確認してください。
- GeoTileLoaderSettingsにAPIキーがセットされているか
- TileSetManagerに、GeoTileLoaderSettingsがセットされているか
- APIキーに対して、3D Map Tiles APIが有効化されているかどうか
座標(高度)について
GeoTileLoaderでロードされた3Dモデルの高さ0の場所とは、どういう高さに相当するのでしょうか?
Unity座標で高さ0の平面が、3D地図上では、WGS84楕円体 表面にあたります。耳慣れないかとは思いますが、これは、地球を楕円体として近似したときの表面、ということになり、標高0の高さからも若干ずれている(数m〜数十m)ので注意が必要です。
いずれにしても、たとえば高い山の緯度経度を指定したら、Unityシーン内での座標は数千mなどになるでしょう。ちょっと扱いづらい場面も想定されます。
このため、利用時、その場所の地形での高さに相当するところをY座標=0にしたいことがあると思います。そのような場合、以下の式で求めた距離(楕円体高という)分、生成されたモデルを下げてやると、ちょうど地表面がY座標=0となります。
その緯度経度における楕円体高 = (その緯度経度におけるジオイド高 + その緯度経度における地面の標高)
参考: https://www.gsi.go.jp/buturisokuchi/grageo_geoid.html
地図タイルの著作権表示について
Google の Photorealistic 3D Tiles を利用する場合、地図の著作権表示が必要になります。
実装方法としては、 TileSetHierarchy.OnCopyrightAttributionTextChanged イベントで通知を取得して、変化時にテキスト内容を表示する必要があります。
実用的なサンプルについて
GeoTileLoaderリポジトリ内の以下のシーンに、任意の緯度経度をロードできる、より実践的なサンプルがありますので見てみてください。
https://github.com/mhama/GeoTileLoader/blob/main/Assets/GeoTileLoader.Samples/Google3DMapTiles.unity






