🗾

好きな地図をマイクラの世界に生成してみる

2023/12/18に公開

これは GO Inc. Advent Calendar 2023 の 18 日目の記事です。

PEmugiです。普段はGO株式会社で地図周りのデータエンジニアをしています。
この記事ではマインクラフトと地図で遊んでみた話をしますが、会社の業務とは関係ありません。

はじめに

マイクラ楽しいですよね。エンドラ倒した後も建築したり、レッドストーン装置を作ったりとまったく飽きることなく子供と楽しんでいます。時間が溶ける。

遊んでいるとふと思うんです。現実の世界の地図をマイクラの世界に生成したいなと。
今日は、デジタル地図データにある土地被覆や道路をマイクラに再現できないか試してみました。

GIS、地図およびマインクラフトの基礎知識がある方向けの説明にあっており、QGISでの作業の細かい解説や、マインクラフト用語、地図用語の詳しい解説はしません。

やること

すでに、PLATEAU のCityGMLの建物形状をマイクラに取り込むプロジェクトや、デジタル標高データから地形をマイクラに取り込む試みを試されている方もいらっしゃいます。

ここではなるべく簡単に地図データの土地の状態や道路の情報をマイクラの地表面に再現することを目標にします。3次元的な建物や地形の再現ではなくあくまで土地被覆を地表に再現させてみます。

材料

マインクラフト

Java版の1.20.2を使用します。Fabricが入っていますが特に必須ではなくバニラでも再現できます。

地図

オープン ライセンスの下で自由に利用できる OpenStreetMap から地図のデータを取得して使います。

ツール類

  • QGIS
    • OSMのデータ取得、地図加工に使用します。
  • Python
    • マインクラフトのデータ生成は Python で行います。
  • anvil-parser
    • マインクラフトの世界のブロックの状態を格納しているAnvil形式のデータを読み書きするオープンソースの Python ライブラリ。

やってみた

マインクラフトの世界の座標系

導入としてマインクラフトの世界の座標系を簡単に説明します。
マインクラフトの世界は立方体のブロックの集合です。
配置されたブロックは X、Z、Y の3次元空間で管理されます。

X-Zの平面を16x16ブロックで区切った領域を Chunk そして、32x32 Chunk の集合を Region といいます。つまり1つの Region は1辺が16x32=512ブロックの領域です。
マインクラフトの世界のデータはこの Region を1ファイルとして管理します。

作業方針

地図データをラスター画像に変換し、1pixel = 1ブロックとしてマインクラフトのデータを作成することにします。
画像のピクセル値は道路、水域、草地などを表現するカテゴリ値として扱い、Pythonプログラムで画像のピクセル値を読み、対応するブロックを対応する場所に配置します。
より正確な形状の描画や、建物の立体構造の再現、階層等の属性情報を元にマインクラフトのデータを作成する場合は地図データをそのままベクターデータとして扱う方がいいでしょう。今回は、土地被覆の状態のみ扱いたい&プログラムの実装を簡単にするため、1pixel=1ブロックで分かりやすく扱えるラスター画像を入力にします。

地図の座標系と解像度

入力の地図データから作ったラスター画像の座標系はWeb Mercator(EPSG:3857)とします。マインクラフトはソフトウェアの表現として球体の地球のような世界観で描画されますが、球面座標系ではなくデカルト座標系です。なので地図側はあらかじめ投影座標系にしておくとマッピングしやすいです。座標の単位もメートルですし。
ただ、地図をこじらせている方にはお分かりかと思いますがより正確に形状を表現したいならローカルな投影座標系(日本の平面直角座標系のいずれかの系)を選ぶべきです。が、今回は簡単のため(めんどくさかった)&とりあえず単位がメートルになればよい&所詮ゲームということでWeb Mercatorにしています。

入力となるラスター画像の解像度は、1pixel=1ブロックの計算が簡単になるように1pixel=1メートルとします。つまりマインクラフト側では1ブロック=1辺1メートルの立方体としてあつかいます。

1. OSMデータの取得

QGIS + QuickOSMプラグインで地図データを取得します。
今回は皇居を中心に1kmの範囲を取得しました。
QuickOSMで取得できるデータは道路や鉄道路線の形状を表すラインデータと行政界や公園、池などの領域を表すポリゴンデータ、POIを表すポイントデータで構成されます。

QuickOSM

2. データ加工

今回はポリゴンデータから森、草地、水域、歩行者専用地域等を、ラインデータからは高速道路以外の道路を抽出して使用します。
ラスター画像としては土地の被覆(森、草地等、水域)表すデータと、道路を表すデータの2つを作成すします。

データの加工として以下を実施しました。

  1. Web Mercatorに投影変換します。QuickOSMで取得後のデータはWGS84(EPSG:4326)になっているので、作業前にWeb Mercatorに変換しておきます。
  2. 森、草地、道路等の属性に応じてラスター画像のピクセル値となるカテゴリ値(整数)を割り当てます。 pixがカテゴリ値
  3. フィーチャの重なり順を定義しデータをソートします。草地のフィーチャの上に森のフィーチャが重なったりしていますが、ラスター画像変換後はレイヤ構造をとれませんので(マルチバンドにすればいけないこともないが)期待した描画できるようにカテゴリ値でソートしておきます。カテゴリ値を描画優先度も考慮して決めればカテゴリ値でソートすればOKです。
  4. 道路データのポリゴン化をします。道路データはラインデータですが、ラスター画像に変換する都合上、領域として表現できないとうまくいきません。なのでラインデータに道路の種類ごとに定義した太さを元にしたバッファーを発生させ、ポリゴン化します。

    赤線が変換前のライン、オレンジ領域が変換後のポリゴン

3. ラスタライズ

データ加工が終わったら、それぞれのデータをラスター画像に変換します。
QGISからラスタライズのツールで変換可能です。
ラスタ画像のフォーマットはなんでもいいと思いますが、ピクセル値を意味ある値として扱いたいので、素直にtifにしました。以下細かい出力設定になります。

  1. 座標系: Web Mercator(EPSG:3857)
  2. 解像度: 1m
  3. データ型: UInt16の単バンド


道路データのtif

土地被覆データのtif

4. マインクラフトのデータに変換

2つのtif画像を元にマインクラフトのデータを作成します。

  1. マインクラフトであらかじめスーパーフラットの世界を生成しておきます。生成された世界のデータはマインクラフトのデータディレクトリの ./saves/{worldname}/region にあります。
    windowsの場合
  2. データ変換
    以下のようなプログラムで変換します(anvil_parserのサンプルを元に作成)。今回は4つのRegionにまたがることが分かっていたため、Region生成はハードコードしていますが、本来なら座標に応じて動的的に生成すべきですね。
    サンプルなので許してください。
    ランダムで森に木が、草地に草が生えるようにしてみました。木の生成コードはGitHub Copilotさんに聞きました...
  1. データの配置
    できたr.0.0.mca~r.1.1mcaの4つのファイルを1のディレクトリに上書きします。

完成!

あまり手をかけずにデザインした割にはきれいにできたと思います。建物を追加したりすればさらに見栄えが良くなりそうですね。お堀の水域がいい感じですね。

皇居がマイクラに!
スライムかわいい

動画はこちら
https://drive.google.com/file/d/1KuAoqdoRJzf7cydYyDUYT2_G06W1KBkY/view?usp=sharing

最後に

地図データからマインクラフトの世界を作る紹介をしました。オープンなデータとオープンソースでマイクラの世界がさらに楽しくなりました。
地形の導入や多くのブロックを使った表現などこれからさらにいろいろ遊んで用と思います。GIS的な技術とマイクラの連携は応用範囲広そうです。
みなさんもぜひ試してみてくださいー。

Discussion