Blenderの3DデータをMinecraftに送りこむ
2016/04/27
  • このエントリーをはてなブックマークに追加

カブクのエンジニアはこんなことしてます

こんにちは、カブクの唐揚げ担当の和田です。

「カブクのエンジニアが普段何をしているのか」ということを知ってもらうために始めたエンジニアブログですが、各エンジニアがもちまわりで書くということになり、今週もカブクのビジネスとは関係ない最近作ったものの話をいたします。

作ったもの

Blender内の3Dデータをブロック群に変換し、それをMinecraftに転送するというBlenderのアドオンを作りました。こちらのアドオンはgithubで公開しています。

そもそも

今回は、BlenderとMinecraftを組み合わせるわけですが、これらについてちょいとご説明いたします。

Blenderって

Blenderはオープンソースの無料で誰でも使える3DCGソフトウェアです。ここ何十年、3DCGや3Dプリンタがもてはやされておりますが、その中心にある要素の一つが「3Dデータの作成」であり、このようなツールを使って作成します。

Minecraftって

Minecraftは、スウェーデンのMojang ABという会社(現在はMicrosoftが買収)がつくったゲームで、仮想空間上にブロックやらパーツを積み上げて、建物やオブジェクトを作っていくゲームです。最近は お子様にも大変人気があり、いろいろな攻略本とかも販売されているみたいです。小さいころにボンバーマンの戦略本を読みふけっていた頃が思い出されます。

プログラムの構成

基本的な流れとしては、↓のようなかんじです。下図の2つの部分について詳細に見ていきましょう。

プログラム概要

ブロック化処理

ブロック化は、Octreeをつかって作成した各ブロックに元の3Dデータの色を彩色するという流れです。

ブロック化処理の流れ

前処理

ここではポリゴンの削減や、後々に使うデータの事前作成を行います。

  • ポリゴンの削減: メッシュ交錯判定時の計算量を減らすため、元データのポリゴンを削減します
  • kd木の作成: 色情報の取得に使用するkd木を作成します
  • 色データの収集: 彩色処理をやりやすくなるように、元データの色情報を変換しておきます

ソースコード的にはこの辺り↓ (convert2block.py)

# Initial procedure
self.__calc_decimated()
self.__build_src_kd()
self.__create_color_dict()

Octreeの作成とメッシュ交錯判定

Octreeは立方体領域を、xyz方向にそれぞれ2分割(合計8分割)し、8つの立方体領域に分割するという考え方です。プログラム内では、create_new_octree(box)というメソッドで行っています。

Octreeのイメージ
Octreeで立方体を作成しつつ、それぞれの立方体が元データのメッシュと交錯するかの判定を行います。交錯する場合にはその立方体を残し、その立方体をさらに8分割し同様の処理を繰り返します(再帰処理)。交錯しない場合には、その立方体は無視されます。

交錯判定はBlenderの BVHTreeユーティリティoverlapメソッドで可能です。プログラム内では、check_if_overlap(obj, box)というメソッドで行っています。 この部分の処理は立方体毎に独立した処理になるので、アドオン内部では並列処理されます(Pythonによるマルチプロセス処理)。また再帰的に行うことができる処理なので、Octreeの深さを引数で渡し、再帰処理を行います。

ソースコード的にはこの辺り↓ (convert2block.py)

def invoke_create_voxel(self, obj, box, max_depth):
# Calc unit length
self.unit = (box[1].z - box[0].z) / float(2 ** max_depth)

overlap = Converter.check_if_overlap(obj, box)
if overlap:
    boxes = Converter.create_new_octree(box)
    jobs = []
    for child in boxes:
        p = Process(
            target=self.create_voxel,
            args=(obj, child, 1, self.voxel_list, max_depth)
        )
        jobs.append(p)
        p.start()

    [job.join() for job in jobs]

各ブロックの色情報の取得

色情報の取得には、前処理で作成したkd木を使用します。こちらはBlenderの KDTreeユーティリティfindメソッドを利用します。Octree処理で作成された各立方体毎に元の3Dデータの近接点の色情報を取得します。 この処理も立方体毎に独立した処理になるので、アドオン内部では並列処理されます。

ソースコード的にはこの辺り↓ (convert2block.py)

# Find closest color
co, index, dist = self.src_kd.find(voxel[0])
if self.decimated.data.vertex_colors:
    rgb = self.decimated.data.vertex_colors["Col"].data[self.color_dict[index]].color
else:
    rgb = (1.0, 1.0, 1.0)  # White

ブロックの描画

ここでは前のプロセスで計算された立方体の頂点と色情報をもとに、実際の3Dデータとしての色付き立方体を作成します。並行して、のちのちMinecraftに送信しやすいような形でデータ作成して戻り値として返します。また、ここの処理はBlenderの表示系に関わる部分となり、並列化出来ないので、描画する立方体の数に比例して処理時間がかかります。

Octreeを変更してブロック化処理を実行してみた結果が↓です。(ちなみに元データは メンバーページで閲覧できる僕です)既にみなさまお気づきかと思いますが、Octreeの数はtreeの深さに対して指数関数的に増大するので、増えるに従って計算量もアヒィーってなります。

ブロック処理の実行
アニGIF版

転送処理

Minecraftへの転送にあたっては、mcpiというpythonモジュールを使用してBlenderからデータを送ります。サーバ側は、 Raspberry JuiceというSpigot(MinecraftのModサーバ)向けプラグインでmcpiからのリクエストを受け取ります。

  • ※ mcpiはMinecraft PI Edition用にMojang ABが作成したPythonのモジュール。BlenderのPythonインタプリタはPython3系なので、今回のプログラムではPython3向けに移植された py3minepiを使用します。
  • ※ Raspberry Juiceは、mcpiに対応するAPIをSpigotに埋め込むためのプラグイン
転送処理の概要

ブロックの選定

ブロック化処理で彩色された色を、Minecraftのどのブロックで再現するかにあたっては、プログラム内に予めMinecraftのブロック定義と色情報を持っておき、欲しい色に最も近い色をもつブロック(RGBベクトルの距離が最小となるブロック)を選定するという方法にしています。

ブロック定義的な部分↓(block_def.py

_BlockItem(
    "White Wool",
    Vector((0.95, 0.95, 0.95)),
    (35, None)
),
_BlockItem(
    "Orange Wool",
    Vector((0.92, 0.53, 0.25)),
    (35, 1)
),
_BlockItem(
    "Magenta Wool",
    Vector((0.73, 0.31, 0.77)),
    (35, 2)
)

mcpiによる転送

mcpiを使えば簡単にブロックを設置可能です。具体的には、setBlockというメソッドに設置したいブロックの位置と種類を渡せば、Minecraft上に任意のブロックを設置できます。 あとはブロック化処理で作成したブロック定義に対して、このメソッドを呼べばブロック化されたオブジェクトを転送できます。

ソースコード的にはこの辺り↓ (convert2block.py)

for this_block in block_map:
	if this_block.color:
	    self.mc.setBlock(
	        pos.x + this_block.pos[0]/2.0,
	        pos.y + this_block.pos[2]/2.0,
	        pos.z - this_block.pos[1]/2.0,
	        this_block.block_type,
	        this_block.color
	    )

結果

転送結果は下記のようになりました。

転送できたッ!\(^o^)/
普通のブロックなので勿論住めます
天空の顔群

上記の写真をご覧いただければ分かるように、若干色がおかしな感じになっております。こちらは、Minecraftのブロックて表現できる限界なのか?という気もしておりますが、もしかしたらバグかもしれないので要継続調査です。ともあれ転送できてヨカッタ\(^o^)/。ちなみにMinecraftのブロックのサイズは変えることが出来ないので、Octreeが深いモデルほど、Minecraftに転送した時の全体のサイズは大きくなります。

ちなみに

ほぼ同等の内容ですが、4/16のBlender発表会@カブクで発表した資料を貼っつけておきます。ここには僕がチェーン芸人を卒業したざっくりした理由が書いてあります。

おまけ

3Dプリントするとこうなります↓。これはデスクトッププリンタで出力したので、色はつきません…グヌヌ

サポート材の除去はかなり面倒でした

おわりに

自分が書いたコードの結果が可視化されるというのは非常に楽しく、 昔はFlash厨だったのですが、最近はプログラムによる3Dモデリングにドハマリしてます。3Dモデルの場合、3Dプリントすれば実体化もできるという特典付きです!読者の皆様も是非!

あわせて読みたいカブクエンジニアブログ