はじめに
OpenSCADはFusion360,SketchUp,FreeCADなどの3DCADとは異なり,プログラムから3Dモデルを作成するソフトウェアです.そのためパラメトリックなモデリングが可能です.
OpenSCADについては次のリンクが参考になります.
OpenSCADではOpenSCAD独自のプログラミング言語(OpenSCAD Language)を使ってモデリングを行います.しかし,実際に使ってみるとわかるのですが,この言語はあまり使いやすいとはいえません.
もしこれがPythonとかでできたら最高なのに...と思って調べたら,SolidPythonというライブラリを見つけました.PythonプログラムからOpenSCADプログラムを生成することで,Pythonでのモデリングを可能にしているようです.
この記事ではOpenSCAD,Python,SolidPythonでそこそこ快適に3Dモデリングするための方法について,調べたり試したことをまとめます.最終的には次の画像のような感じでモデリングしています.
OpenSCADのインストール
ここでダウンロードできます.
https://www.openscad.org/downloads.html
SolidPythonのインストール
仮想環境を作ってSolidPythonをインストールします.Numpyもあるとモデリングのときに便利なので一緒にインストールします.
※Python3.8.2,Windows
$ python -m venv venv
$ venv\Scripts\activate
$ pip install solidpython numpy
※今現在,普通にNumpyをインストールするとNumpy 1.19.4がインストールされるのですが,WindowsではNumpy 1.19.4が使えないという問題があります.これを回避するためにNumpy 1.19.3を指定しています.詳しくはこの記事を見てください.
→ 現在この問題は発生しません.普通にNumpyをインストールできます.(2021/05/07)
※私はPython3.8で問題なくSolidPythonをインストールできましたが,Python3.9以降ではインストールできないようです.(2021/05/23)
Pythonで3Dモデリング!
次のようなPythonファイルを作成します.
from solid import *
from solid.utils import *
c = cube(10)
scad_render_to_file(c, "output.scad")
これを実行すると,output.scad
というファイルが生成されます..scad
はOpenSCADプログラムのファイル形式です.
output.scad
をOpenSCADで開くと,右側に1辺10mmの立方体が表示されます.
表示されなければF5キーを押すか,画像の赤く囲ったプレビューボタンを押してみてください.
今見ているのはプレビューで,3Dモデルをエクスポートするためにはレンダリングという処理が必要になります.画像の青く囲ったボタンを押すとレンダリングが始まります.
右下のコンソールに
Rendering finished.
と出てくればレンダリング終了です.
青く囲ったボタンの右にある「STL」と書かれているボタンを押すと,3DモデルをSTLファイルとして保存できます.レンダリングしてからでないと3Dモデルを出力できないので注意です.
これでPythonを使って3Dモデリングできました!
一応プログラムの内容について軽く説明します.
from solid import *
from solid.utils import *
ここでSolidPythonをインポートしています.import *
を使うことで,OpenSCADと近い感覚でプログラムが書けます.
c = cube(10)
ここでは10mmの立方体を作ってc
に代入しています.当たり前な感じがしますが,OpenSCAD言語では変数に対して3Dモデルを代入することができなかったのでこれは大きな変化です.3Dモデルをオブジェクトとして扱えることで,より直感的にプログラムが書けるようになります.
scad_render_to_file(c, "output.scad")
最後に作成した3DモデルをOpenSCADプログラムに変換します.
ここで注意が必要なのは,SolidPythonはあくまでも「Pythonが行ったモデリングの操作をOpenSCADプログラムに変換しているだけ」ということです.
Pythonプログラムがそれほど複雑に見えなくても,それをOpenSCADプログラムに変換したときにとんでもないサイズになってしまうことがあります.プレビューに時間がかかったり,3DモデルをSTLで出力しようとしてもレンダリングが永遠に終わらなかったり,OpenSCADが落ちたりします.
もっと快適に
一応PythonでOpenSCADを使ってモデリングできるようになりましたが,上で説明した方法だと毎回OpenSCADプログラムを生成してOpenSCADで開いてプレビューする必要があってめんどくさいです.OpenSCADの設定をいじってそこそこ快適にします.
「Design」の中の「Automatic Reload and Preview」をチェックします.これでOpenSCADプログラムに変更が加えられたときに自動でプレビューしてくれます.
次に「View」を見ます.
一番下の4つのオプションにチェックを入れることでエディターやコンソールなどを非表示にできます.OpenSCADはプレビュー用に使いたいのでEditorは非表示にします.Customizerもここでは使わない(たぶん使えない)ので非表示です.それ以外は好みです.
これでOpenSCADでプレビューだけを見れるようにできました.VSCodeとならべるとこんな感じになります.
例えばOpenSCADでoutput.scad
を開いた状態で,Pythonを実行してoutput.scad
に変更を加えると,右のOpenSCADのプレビューに表示されます.
毎回scad_render_to_file
でoutput.scad
に書き込むように注意しないといけませんが,Pythonを実行してすぐにプレビューが見れるのでそこそこ快適です.
さらに次のようなテンプレを作ってmake_model
関数内でモデリングするようにしました.
from solid import *
from solid.utils import *
def make_model():
c = cube(5)
return c
if __name__ == "__main__":
scad_render_to_file(make_model(), "output.scad")
Jupyter Notebook でモデリング
紹介するだけに留めますが,ViewSCADというPythonライブラリがあります.これを使うとJupyter Notebook内でプレビューできるようになります.
SolidPython入門
OpenSCAD言語のif
やfor
などの基本的な制御はPythonを使って置き換えられますが,モデリングに関する操作はOpenSCADから引き継がれています.なのでOpenSCADの機能の多くは同じような使い方でPythonでも使えます.
ここではとりあえずこれだけ知っていればなんとかなる(?)ところだけ説明します.詳しくはOpenSCAD User Manualを見てください.
3D Primitives
3D Primitivesとは,例えばキューブ(cube)や球(sphere),円筒(cylinder)などの基本的な3Dモデルのことを指します.引数を与えることである程度自由に形を決めることができます.これらを次に説明するTransformやBoolean Combinationと組み合わせて使って好きな形を作っていきます.
Transform
Transformを使うと,3Dモデルの位置や形状,色などを変えることができます.
中でも頻繁に使うのはtranslate
,rotate
です.言葉で説明するよりも例を見たほうがわかりやすいです.
from solid import *
from solid.utils import *
def make_model():
# 1mmの立方体
c1 = cube(1)
# c1をx方向に3mm移動
c1_t = translate([3, 0, 0])(c1)
# c1をz軸で45°回転
c1_r = rotate([0, 0, 45])(c1)
# c1,c1_t,c1_rをまとめて返す
return c1+c1_t+c1_r
if __name__ == "__main__":
scad_render_to_file(make_model(), "output.scad", include_orig_code=False)
translate
とrotate
のどちらの場合も,最初のカッコ内で移動や回転を指定して,次のカッコ内にそれを適用するオブジェクトを指定しています.
return
の行のc1 + c1_t + c1_r
という式では,3つの3Dオブジェクトc1
,c1_t
,c1_r
を結合して1つの3Dオブジェクトにまとめています.これはscad_render_to_file
関数が1つの3Dオブジェクトしか受け取らないためです.
結合と言っても,結合する3Dオブジェクトが必ずしも重なってる必要はありません.上の例のように空間的に離れていても,結合することで1つの3Dオブジェクトとして扱うことができます.
ちなみにscad_render_to_file
の引数のinclude_orig_code
は,生成されるOpenSCADプログラムのコメントとして「元のPythonプログラム」を含めるかどうかを指定できます.ただPythonプログラムに日本語のコメントがあると,SolidPythonで日本語を処理しようとしてエラーが出るのでinclude_orig_code=False
としています.
Boolean Combination
Boolean Combinationでは,3Dオブジェクト同士で足し算や引き算ができます.User Manualにある次の画像がわかりやすいです.
演算にはunion
(和),difference
(差),intersection
(共通部分)の3つがありますが,SolidPythonではこれらの演算をPythonの演算子+
,-
,*
でできるようになっています.
https://github.com/SolidCode/SolidPython#basic-operators
from solid import *
from solid.utils import *
def make_model():
c = cube(4, center=True)
cy = cylinder(1.5, 6, segments=30, center=True)
return c - (cy + rotate([90, 0, 0])(cy) + rotate([0, 90, 0])(cy))
if __name__ == "__main__":
scad_render_to_file(make_model(), "output.scad", include_orig_code=False)
center
という引数をTrue
にすると,原点が中心になるようにして3Dオブジェクト作成できます.またsegments
という引数で曲線部分の滑らかさを指定できます.
+
演算子で3Dオブジェクトを結合できることを利用すると,sum([obj1, obj2, ...])
というふうにして3Dオブジェクトを結合できて面白いです.
2D Primitives
Fusion360やSolidWorksなどの3DCADを使ったことがあれば,平面に図形を書いてからそれを押し出すことで3Dオブジェクトを作るということに馴染みがあると思います.
OpenSCADでも2D Primitivesを使うことで平面図形を作成することができます.
square
,circle
,polygon
の3つがあり,その中でも一番使うのがpolygon
だと思います.polygon
は引数に2次元の点のリストを与えると,順番につないで2Dオブジェクトを作ってくれます.次の例ではpolygon
で六角形を作っています.
from solid import *
from solid.utils import *
import numpy as np
def make_model():
hexagon_points = np.array([[1, 0],
[0.5, -0.866],
[-0.5, -0.866],
[-1, 0],
[-0.5, 0.866],
[0.5, 0.866]])
hexagon_points *= 10
hexagon = polygon(hexagon_points)
return hexagon
if __name__ == "__main__":
scad_render_to_file(make_model(), "output.scad", include_orig_code=False)
プレビューをよく見ると,六角形に厚みがあって2Dオブジェクトのはずなのに3Dオブジェクトのように見えます.これは「2Dオブジェクトをプレビュー表示する場合,xy平面にある厚さ1mmの3Dオブジェクトとして表示する」というOpenSCADの仕様のためです.
レンダリングしてみると2Dオブジェクトであることがはっきりとわかります.上のメニューの「File > Export」からSVGなどの2D形式で出力することができます.
Extrude
2Dオブジェクトができたら,それを押し出し(Extrude)て3Dオブジェクトにします.
linear_extrude
を使った例です.(あまり押し出していませんが)
from solid import *
from solid.utils import *
import numpy as np
def make_model():
hexagon_points = [[1, 0],
[0.5, -0.866],
[-0.5, -0.866],
[-1, 0],
[-0.5, 0.866],
[0.5, 0.866]]
hexagon = polygon(hexagon_points)
hex_col = sum([translate([0, 2*i])(hexagon) for i in range(5)])
hex_tile = sum([translate([1.73*i, 1*(i%2)])(hex_col) for i in range(5)])
hex_outline = square([7, 7]) - hex_tile
return color("yellow")(linear_extrude(0.1)(hex_outline))
if __name__=="__main__":
o = make_model()
scad_render_to_file(o, "output.scad")
おわりに
お手軽にそこそこ快適にPythonとOpenSCADで3Dモデリングできるようになりました.Pythonの豊富なライブラリと組み合わせれば面白いものがたくさん作れそうで楽しみです.