55
47

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

PythonとOpenSCADで快適な3Dモデリング生活

Last updated at Posted at 2020-12-02

はじめに

image.png

OpenSCADはFusion360,SketchUp,FreeCADなどの3DCADとは異なり,プログラムから3Dモデルを作成するソフトウェアです.そのためパラメトリックなモデリングが可能です.

OpenSCADについては次のリンクが参考になります.

OpenSCADではOpenSCAD独自のプログラミング言語(OpenSCAD Language)を使ってモデリングを行います.しかし,実際に使ってみるとわかるのですが,この言語はあまり使いやすいとはいえません.

もしこれがPythonとかでできたら最高なのに...と思って調べたら,SolidPythonというライブラリを見つけました.PythonプログラムからOpenSCADプログラムを生成することで,Pythonでのモデリングを可能にしているようです.

この記事ではOpenSCAD,Python,SolidPythonでそこそこ快適に3Dモデリングするための方法について,調べたり試したことをまとめます.最終的には次の画像のような感じでモデリングしています.
image.png

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キーを押すか,画像の赤く囲ったプレビューボタンを押してみてください.
無題.png

今見ているのはプレビューで,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プログラムに変更が加えられたときに自動でプレビューしてくれます.
image.png

次に「View」を見ます.
image.png
一番下の4つのオプションにチェックを入れることでエディターやコンソールなどを非表示にできます.OpenSCADはプレビュー用に使いたいのでEditorは非表示にします.Customizerもここでは使わない(たぶん使えない)ので非表示です.それ以外は好みです.

これでOpenSCADでプレビューだけを見れるようにできました.VSCodeとならべるとこんな感じになります.
image.png
例えばOpenSCADでoutput.scadを開いた状態で,Pythonを実行してoutput.scadに変更を加えると,右のOpenSCADのプレビューに表示されます.

毎回scad_render_to_fileoutput.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内でプレビューできるようになります.
image.png

SolidPython入門

OpenSCAD言語のifforなどの基本的な制御はPythonを使って置き換えられますが,モデリングに関する操作はOpenSCADから引き継がれています.なのでOpenSCADの機能の多くは同じような使い方でPythonでも使えます.

ここではとりあえずこれだけ知っていればなんとかなる(?)ところだけ説明します.詳しくはOpenSCAD User Manualを見てください.

3D Primitives

3D Primitivesとは,例えばキューブ(cube)や球(sphere),円筒(cylinder)などの基本的な3Dモデルのことを指します.引数を与えることである程度自由に形を決めることができます.これらを次に説明するTransformやBoolean Combinationと組み合わせて使って好きな形を作っていきます.

Transform

Transformを使うと,3Dモデルの位置や形状,色などを変えることができます.

中でも頻繁に使うのはtranslaterotateです.言葉で説明するよりも例を見たほうがわかりやすいです.

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)

実行結果:
image.png

translaterotateのどちらの場合も,最初のカッコ内で移動や回転を指定して,次のカッコ内にそれを適用するオブジェクトを指定しています.

returnの行のc1 + c1_t + c1_rという式では,3つの3Dオブジェクトc1c1_tc1_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にある次の画像がわかりやすいです.
image.png

演算には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)

image.png

centerという引数をTrueにすると,原点が中心になるようにして3Dオブジェクト作成できます.またsegmentsという引数で曲線部分の滑らかさを指定できます.

+演算子で3Dオブジェクトを結合できることを利用すると,sum([obj1, obj2, ...])というふうにして3Dオブジェクトを結合できて面白いです.

2D Primitives

Fusion360やSolidWorksなどの3DCADを使ったことがあれば,平面に図形を書いてからそれを押し出すことで3Dオブジェクトを作るということに馴染みがあると思います.

OpenSCADでも2D Primitivesを使うことで平面図形を作成することができます.

squarecirclepolygonの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)

image.png

プレビューをよく見ると,六角形に厚みがあって2Dオブジェクトのはずなのに3Dオブジェクトのように見えます.これは「2Dオブジェクトをプレビュー表示する場合,xy平面にある厚さ1mmの3Dオブジェクトとして表示する」というOpenSCADの仕様のためです.

レンダリングしてみると2Dオブジェクトであることがはっきりとわかります.上のメニューの「File > Export」からSVGなどの2D形式で出力することができます.
image.png

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")

image.png

おわりに

お手軽にそこそこ快適にPythonとOpenSCADで3Dモデリングできるようになりました.Pythonの豊富なライブラリと組み合わせれば面白いものがたくさん作れそうで楽しみです.

55
47
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
55
47

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?