「不」と「可」と「解」に見える不可解な立体を作った話
やったこと
見る面によって「不」だったり「可」だったり「解」にみえる立体を作った.
花譜のライブを見た感動から生まれた、「不」と「可」と「解」に見える不可解な立体#花譜 #花譜不可解 pic.twitter.com/T1qGH0rtrQ
— びー (@kbkbirogy) 2019年8月25日
背景,目的
- 花譜の1st ライブ「不可解」が滅茶苦茶よかった衝撃のまま *1,何か不可解な物を作りたくなって,気が付いたら新しい3Dプリンターまで買っていた.
- せっかくなので,不と可と解の文字をいい感じにつかって不可解なものを作りたい. → 「不」と「可」と「解」を各面から成立するような立体を作ったら,最終的に不可解な形状ができるのでは?
実現のための方針
- 各方向からみたときだけ文字が成立する立体形状を作りたい.
- XY平面に「不」,XZ平面に「可」,YZ平面に「解」を描いて,それぞれ軸方向に押し出して交差する点を残せばそれっぽい形ができそう.
- 「不」と「可」と「解」をところてんみたいにした三次元行列準備して,3つのANDを取る.
- XY平面に「不」,XZ平面に「可」,YZ平面に「解」を描いて,それぞれ軸方向に押し出して交差する点を残せばそれっぽい形ができそう.
- 作ったデータを確認&出力するために,可視化&stl化したい.
詳細
「不」と「可」と「解」の準備
まず,それぞれの文字を表す「0,1」の二次元行列を準備する. すごいプログラマーなら,画像処理とかでもりもりやっちゃうんだろうけれど, 100年くらいかかりそうだったので,12×12くらいのドット文字を書いた.→
立体形状をつくる
さっき作ったドット文字を見ながら,ポチポチ二次元行列を作る*4. こんなかんじで,確認していく
# 不 fu=np.array([ [0,0,0,0,0,0,0,0,0,0,0,0.], [0,1,1,1,1,1,1,1,1,1,1,1.], [0,0,0,0,0,0,1,0,0,0,0,0.], [0,0,0,0,0,1,1,1,0,0,0,0.], [0,0,0,0,1,1,1,1,1,0,0,0.], [0,0,0,1,1,0,1,0,1,1,0,0.], [0,0,0,1,0,0,1,0,0,1,0,0.], [0,0,0,0,0,0,1,0,0,0,0,0.], [0,0,0,0,0,0,1,0,0,0,0,0.], [0,0,0,0,0,0,1,0,0,0,0,0.], [0,0,0,0,0,0,0,0,0,0,0,0.], [0,0,0,0,0,0,0,0,0,0,0,0.] ]) plt.figure() plt.pcolor(fu)
次は,ところてん的な三次元行列をつくる.賢く作る方法はありそうだが,ググるフレーズが分からなかったので,筋肉で解決した.
# ところてん
tmp=fu
fu2=np.dstack([tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp,tmp,tmp,tmp])
これをボクセルプロットすると,いい感じにところてんになっていることが確認できる. ついでに,行列を回転させておいて,行列同士でANDをする準備をする.
# ボクセルプロット fig = plt.figure() ax3 = fig.gca(projection='3d') ax3.set_aspect('equal') ax3.voxels(np.rot90(fu2, k=1, axes=(2, 1)), edgecolor="k"); fu2_rot=np.rot90(fu2, k=1, axes=(2, 1))
「不」と「可」だけでANDをするとこんな感じで,上から見ると「可」と横から見ると「不」にみえるような形ができてることが確認できる.
— びー (@kbkbirogy) 2019年8月25日
fukakai=np.logical_and(fu2_rot,ka2) fig = plt.figure() ax4 = fig.gca(projection='3d') ax4.set_aspect('equal') ax4.voxels(fukakai, edgecolor="k");
全部重ねた結果がこれ.斜めから見るといい感じに,謎の不可解オブジェクトになってていい感じ*5. 次に,できた点ををcsvを吐き出すことを考える. しかし今の三次元行列は0,1表記なので,これを各点の座標を示す(x,y,z)表記の二次元行列にしたい. 何らかの便利な関数がnumpyにありそうな気がしたが,forでごり押して,座標と点の有無を表す二次元行列に変換した. その後,点が有る座標だけ残して,csvに吐き出した.
out=np.zeros((12*12*12, 4)) cnt=0 for i in range(fukakai.shape[0]) : for j in range(fukakai.shape[1]) : for k in range(fukakai.shape[2]) : out[cnt,3]=fukakai[i,j,k] out[cnt,0]=i out[cnt,1]=j out[cnt,2]=k cnt=cnt+1 po=out[out[:,3]>0,:] np.savetxt('outpo.csv',po,delimiter=",")
openscadでのプロット
openscadは,こんな感じに座標を入れてあげれば,cubeを与えた座標に生成してくれる*6. あとは,cubeの大きさを少し大きくしたら,Renderして,stl形式で吐き出せば,準備完了.
for(i= [ [1.00E+00,1.00E+00,3.00E+00], [8.00E+00,8.00E+00,5.00E+00], // ~~~~~~~~ //中略 // ~~~~~~~~ [9.00E+00,8.00E+00,5.00E+00]] ) { translate(i) cube(1.2, 1.2, 1.2,center = true); }
3Dプリンターでの出力
stlまで作ったので,これを3Dプリンターで出力する*7.
買いたてほやほやのFlashforgeのAdventurer 3を使った.
開けたらすぐ動く.感涙した.完全に未来.
FlashPrintで適当にスケールを調整し,スライスしてPLAで出力.
ノズルとベッドが温まるのが異常に早くて笑ってしまった.
綺麗な上に早いので,もっと早く買うべきだった感ある.
まとめと感想とデータ配布
ところどころ,気合や修正が入ったが,一応不可解な立体物ができた.
いつかもっと楽にでできるようになるといいなって感じ.
* 画像の二値化
* 各面の向きの組み合わせ.
* 浮島(どこにもつながっていないボクセル)の解消
* そもそもプログラミングよく分からない.
などなどを解決する必要がありそう.
個人的には,Pythonのnumpyを初めてまともに(?)さわったので,この調子でなれていきたい.
奇遇なことに,花譜1stアルバム「観測α」「観測β」がBOOTHで販売中らしいので,stlを落とすついでに買えちゃいますね? https://booth.pm/topics/kamitsubaki_recordbooth.pm
*1:そのうち感想的なものを書きたい
*2:めっちゃプログラムっぽいCADOpenSCAD - The Programmers Solid 3D CAD Modeller
*3:二度手間感があるので,もっと綺麗な手順がありそう
*4:二度手間感があるので,もっと綺麗な手順が(略
*5:実作業の時は,ANDした結果を見ながら各面で成立するようにするにドット文字と向きを微調整した."いい感じ"に
*6:空中に浮いている点があったので手動で消した.実は3Dプリント後に物理的にもげばよいので,ここで消さなくてもよい
*7:Vtuberのバーチャルなデータしかないファングッズを実世界に出力するのめっちゃエモーショナルじゃないですか????