三次元フラクタルを3Dプリントする

数学とコンピュータ Advent Calendar 2017 - Qiita
数学とコンピュータアドベントカレンダー23日目の記事です.(30分ほど遅れました.申し訳ありません.)

近年,3Dプリント技術の広まりとともに数学的なオブジェクトを3Dプリントによって造形する活動が広まっています.最近ではVisualizing Mathematics with 3D Printingという本も出ました.三次元フラクタルの3DプリントにはJeremie Brunet氏という先駆者がいます.とてもクオリティの高い作品を数多く公開しており,いつか自分でも試して見たいと思っていました.
www.shapeways.comThe Beauty of Math! These 3D Printed Fractals Will Blow Your Mind | 3DPrint.com | The Voice of 3D Printing / Additive Manufacturing

試行錯誤の結果,最近ようやくそれなりのものを出力できるようになりました.Twitterに投稿したものをまとめたのがこちらになります.
twitter.com


それぞれのオブジェクトの造形には10~20時間ほどの時間がかかりました.これらの3DプリントデータはDMM 3DプリントやShapewaysで公開する予定です.

このフラクタルはQuasi-Fuchsian 3D Fractalと呼ばれるフラクタルです.これに関してはこちらの記事で少しだけ触れました.
自作フラクタルレンダラとシェーダの取り回しについて - 心鏡曼荼羅
この記事ではこれらのフラクタルを3Dプリントするために必要な事項を簡単にまとめます.

モデリング・描画

数学的なオブジェクトをモデリングをするツールは様々にあります.こちらの記事に色々まとまっています.
3Dプリンター用の多彩なデザインの3Dモデルがつくれる計算幾何学アプリが楽しい!
しかし,三次元フラクタルはこういったソフトで計算,出力することは難しいです.多くの三次元フラクタルオブジェクトは,距離関数(Signed Distance Function)で表現されます.距離関数は与えられた点とオブジェクトの表面までの最短距離を返す関数です.たとえば,球の距離関数は次のようになります.

float distSphere(vec3 p){
    return distance(p, centerOfSphere) - r;
}

この関数は与えられた点から球の表面までの距離を返します.また,内側の点に関しては負の値を返します.
距離関数を用いた描画についてはこちらの記事にまとまっています.
全能感UP! GLSLで進めレイマーチング « demoscene.jp

3Dプリントを行うためには,出力したい物体のメッシュデータが必要なので,距離関数で表現されるフラクタルをボリュームデータ(ボクセルデータ)として出力し,これをメッシュ化していくことになります.三次元フラクタルに限らず,距離関数で定義できる(Sphere tracing. ray marhcingで描画できる)形状ならばこれから紹介する方法でメッシュ化してプリントすることができます.先述のJeremie Brunet氏もmandelbulbというソフトウェアで出力したフラクタルのボリュームデータをメッシュ化してプリントしているようです.

メッシュ化

ボクセルデータをメッシュ化する方法,ツールは様々にありますが,今回はParaviewとOpenVDBという二種類の方法を試しました.

ParaViewによるメッシュ化

Paraviewはオープンソースのデータ分析,可視化ソフトウェアです.ボリュームデータを読みこんで可視化,メッシュ化することができます.ボリュームデータはvtkと呼ばれるフォーマットで扱うため,データをこの形式で出力します.

vtkにはレガシーなASCIIフォーマットと,バイナリデータを扱うxmlフォーマットが存在しています.簡単のためにASCIIフォーマットを扱うことにします.vtkファイルに関してはこちらの記事が詳しいです.
ParaViewでVTKレガシーフォーマットを使う その1 - Qiita

フラクタルでない部分とフラクタル内部に分かれた二値のボリュームデータをvtk出力するプログラム例がこちらになります.(ビルドにはnanortが必要です)
Generate vtk file of fractal. · GitHub
テキストファイルなので,格子数によっては巨大ファイルになってしまいますが,一応はフラクタルをボリュームデータにすることができます.

次にParaviewで可視化,メッシュ化してみます.Paraviewを起動し,vtkファイルを投げ込んだらProperties tabからApplyをクリックします.RepresentationのドロップダウンリストからVolumeを選択するとボリュームデータが表示されます.
f:id:soma_arc:20171222124436p:plain

ボリュームデータをメッシュに変換します.画面上部のContourツールボタン(もしくはメニューのFilters -> Common -> Contour)をクリックします.
f:id:soma_arc:20171222124944p:plain
画面左のPipeline BrowserにContourというデータができます.これをクリックし,PropertiesタブのApplyをクリックしてやるとメッシュ化されます.あらかじめデータが二値であればデータの境界をメッシュにしてくれます.もしもデータが二値でないのならば,Isosurfacesパラメータを操作する必要があります.
f:id:soma_arc:20171222125119p:plain
フラクタルのボリュームデータをメッシュに変換することができました.データの保存はContourを選択した状態でFile-> Save Data... からファイル形式を.stlに指定して出力してやります.

変換はそれなりに高速で結果も綺麗です.しかし,データサイズが大きくなりがちなので,別のモデリングソフト等でデータを削減する必要があります.この例で使用したデータは比較的小さいですが,簡単に数百MBのデータになってしまうので注意が必要です.

Paraviewによるメッシュ化は非常に手軽にできるので,お勧めです.しかし,なるべくならレンダラにメッシュデータ生成機能を組み込みたいところです.そこで,次に試したのがOpenVDBです.

OpenVDBによるメッシュ化

OpenVDBはボリュームデータを効率よく扱うことのできるオープンソースライブラリです.ボリュームデータからメッシュを生成するような機能も備えています.
OpenVDBでは距離関数によるデータをメッシュ化することができます.OpenVDBのデータ表現に関する情報は次の記事に詳しく書いてあります.
Level sets with OpenVDB. Quick introduction. Part 1 - K. Lykov Blog
データ生成のコード片を置いておきます.メッシュ化処理の呼び出し等を含んだ実際のプログラムはまだ整理できていないため,後で公開します.
genFractalLevelSet.cpp · GitHub

f:id:soma_arc:20171223213220j:plain
Paraviewと比べて遜色ないメッシュデータを作成することができました.また, ボリュームデータフォーマットのvdbファイルはそれなりに小さいので,Houdiniなどの別のレンダラに持って行ってレンダリングするのも面白いかもしれません.Adaptive meshingやsmooth level setなど,試せていない機能もあるので今後の課題です.

OpenVDBの例は少ないですが,このあたりが参考になるかと思います.

メッシュ削減(Mesh Decimation)

生成したメッシュデータ(.obj or .stl)のサイズが大きい場合はメッシュを削減してやる必要があります.多くのモデリングソフトにこのような機能が搭載されています.だいたい頂点数が100万個あたりになるまで減らしています.自分でプリントする分にはデータサイズが大きめでも問題ありませんが,外部のプリントサービスを利用する場合は制限があるので注意が必要です.例えば,DMM3Dプリントだと,100MBを超えるデータはアップロードすることができません

MeshLabによるメッシュ削減

MeshLabはオープンソースのメッシュ処理ソフトです.Jérémie Brunet氏もMeshLabを使用してメッシュの最適化を行っているようです.しかし,今回は処理に時間がかかりすぎて使用を断念しました.データが悪かったのか,処理のパラメータが悪かったのかはわかりませんが,使いこなせればメッシュのクオリティアップに繋がるかもしれません.
MeshLabを使ったメッシュ削減の方法はshapewaysに記事がありました.
Polygon Reduction with Meshlab - Shapeways

Blenderによるメッシュ削減

Blenderオープンソースモデリングソフトです.ModifierのDecimationでメッシュを減らすことができます.

手順は次のようになります.Blenderでメッシュを読み込んだら,そのメッシュを選択し,ModifierタブからAdd Modifier -> Decimationを選択します.
f:id:soma_arc:20171223221751p:plain
0~1の範囲でメッシュを削減する割合を指定します.一度に大きく減らしすぎると,処理に時間がかかって応答しなくなるので,0.2くらいずつ減らしていくと良いかと思います.三種類処理の手法があるようですが,あまり違いはわかっていません.とりあえずCollapseでよいかと思います.
f:id:soma_arc:20171223221818p:plain
ほどほどの数のメッシュになったらApplyで処理を確定し,File->Exportから修正したデータをエクスポートします.ここまでくると,このデータを3Dプリントすることができます.

ZBrushを用いたメッシュ削減

ZBrushはスカルプトモデリングツールと呼ばれる種類のモデリングツールです.粘土をこねるような形でモデリングを行っていくツールで,大量の頂点を効率よく扱うことができます.有償のソフトですが,メッシュの最適化に関する優れた機能をもっています.Blenderでも機能的には十分ですが,やはり時間がかかるのと,後述するUV展開はうまく行えなかったので,ZBrushを使ってみました.ZBrushはなかなかクセのあるソフトですので,作業の流れを紹介するだけにとどめておきます.

ZBrushではDecimation MasterとDynameshという機能を使います.Decimation Masterを使うことで,メッシュの細部を保ったまま,高速にメッシュを減らす事ができます.もしも処理の途中でエラーが発生したらDynameshを使って,メッシュ全体を均一なメッシュに直します.
このあたりの手順はこちらの記事にまとまっています.
デジタル造形の時代〜基本的なワークフローについてわかりやすく解説〜 | 特集 | CGWORLD.jp

ZBrushにも3Dプリント用にデータをエクスポートする機能がついているので,削減した後はデータを出力してプリントできます.

テクスチャデータ生成の試み

ここまでで,3Dプリントデータ生成を見てきました.生成したデータは家庭用(?)の3Dプリンタでプリントする他に3Dプリントサービスを利用してプリントしてもらうことも出来ます.3Dプリントサービスで提供されているプリント素材にはフルカラーのものも存在しています.DMM3Dプリントではフルカラー石膏とフルカラープラスチックという素材を提供しています.カラーリングもフラクタルの見た目において,重要な要素です.フルカラーの3Dプリントデータの作成にも挑戦してみました.

DMM3Dプリントのカラープリントはモデルデータ(.obj)に紐ついた.mtlとテクスチャデータが必要です.そのため,メッシュデータにUV座標をつけ,テクスチャデータを用意する必要があります.

UV展開

まず,三次元空間上の頂点をテクスチャ平面の座標にマッピングする作業である,UV展開を行う必要があります.当初Blenderで試したのですが,メッシュが複雑でデータが大きいためか,うまく行きませんでした.色々試してみましたが,最終的にZBrushで成功しました.

ZBrushではUVMasterという機能でUV展開を行う事ができます.
【UnityAction & ZBrush】UV Masterを使ってみる。: Karasuのアプリ奮闘記
UV展開前のDecimation Masterによるメッシュ削減処理は,UV展開に不適切なメッシュを生成してしまうようです.そのため,Decimation Masterでメッシュをある程度削減した後にZRemesherという機能を使います.ZRemesherを使用すると,UV展開に適した綺麗なポリゴンに変換することができます.

リメッシュ周りの資料です.

テクスチャの生成

メッシュデータにUV座標をつけることができれば,テクスチャデータを生成することは難しくありません.重心座標(Barycentric Coordinates)を計算することで,UV平面の三角形上の点と空間の三角形上の点を対応付けることができます.

愚直な実装ですが,テクスチャを生成するコードを置いておきます.シェーダを使ってレンダリングすればよりクオリティの高いテクスチャを生成できるので,次の課題です.
3d-printing-tools/GenTex at master · soma-arc/3d-printing-tools · GitHub
生成されたテクスチャとマッピングされたオブジェクトは以下のようになります.
f:id:soma_arc:20171223184905p:plain
UV展開の過程でメッシュを削りすぎてしまいましたが,うまくマッピングできました.すぐに3Dプリントサービスに出したいところですが,このままですと,かなり料金がかかります.この状態で見積もりをとった時は十万円を超えてしまいました.かかる料金を減らすため,もうひと手間必要です.

中空化

何らかの3Dプリントサービスに出す場合は,モデルの中身をくり抜いて中空構造にする,肉抜きを行うと,かかる料金を減らすことができます.
【3Dプリンタ】肉抜きをして制作コストを下げよう! | 初心者魂 今更聞けない使い方
BlenderZBrushでも肉抜きを行うことはできますが,meshmixerというソフトウェアを使えば,ほとんど自動で肉抜きを行う事ができます.meshmixerはautodeskが提供するフリーソフトです.

meshmixerを起動し,メッシュを読み込ませたら,編集->中空を選択することで自動的に内側がくり抜かれます.
f:id:soma_arc:20171223173025p:plain
同時に,素材抜き用の穴も生成されます.プリント素材によって素材抜き用の穴の大きさが異なるので注意が必要です.例えば,DMMで石膏素材をプリントする場合,10mm以上の穴が必要になります.

肉抜きしてエクスポートした.objファイルのメッシュグループはバラバラになってしまうようです.
f:id:soma_arc:20171223173950p:plain
利用するサービスによってはひとつにまとめておく必要があるかもしれません.Blenderでは各グループを選択してCtrl + Jで結合することができます.

最終的にDMMで見積もりを取った結果がこちらです.
f:id:soma_arc:20171223175402j:plain
石膏フルカラーで6.7cm x 7.7cm x 5cmで約一万四千円,フルカラープラスチックなら約二万五千円です.流石にこのクオリティでこの値段はしんどいので,メッシュ削減,UV展開の最適化でクオリティを上げ,肉抜きを工夫して値段を減らそうと考えています.

おわりに

ボリュームデータから3Dプリントデータを作成するためのツール群を簡単にまとめました.ボリュームデータさえ用意出来てしまえば,既存のツールの組み合わせで3Dプリントまで持っていくことが可能ですが,根気が必要です.なるべく少ないツール,手間でプリント用データ生成を行えるスキームを確立したいところです.レンダラでレンダリングしたフラクタルの好きな部分を切り取って手軽に3Dプリント用データを生成できるようにする予定です.

かなりの手間がかかる3Dプリントですが,いくつかの場所でデモをした際には,それなりに良い反応をもらえました.やはり,手で触ることのできる立体があることは,アイデアを伝えるために非常に有用であることがわかりました.何か立体化できるようなコンテンツがある方は挑戦してみてはいかがでしょうか.