OpenSCAD CheatSheet

February 21, 2022

想學習 OpenSCAD,〈OpenSCAD User Manual〉算是個蠻完整的說明,官網的〈Tutorial〉也很努力地收集了不少教學,不過老實說,大部份的時間裏,我都是查詢〈OpenSCAD CheatSheet〉,知道想使用的模組、轉換等如何使用,然後就動手做了…XD

OpenSCAD CheatSheet)

在〈Hello, OpenSCAD〉看過基本的 OpenSCAD 程式樣貌,像是變數、for 語法、cubetext 模組、translaterotate 轉換等,這邊就以 OpenSCAD CheatSheet 中的說明來進行。

不可變動的變數

首先你看到的是變數,其說明是列在〈OpenSCAD CheatSheet〉的 Syntax 區域:

my_text = "Hello, OpenSCAD!";
step_angle = 30;
radius = 30;
height = 5;

乍看沒什麼,就像是個動態定型語言,不需要宣告變數型態,不過,在〈Variable〉 中有這麼一句話:

OpenSCAD is a Functional programming language, as such variables are bound to expressions and keep a single value during their entire lifetime due to the requirements of referential transparency.

不過,說是 Functional programming 語言,其實還是有些不同,OpenSCAD 中對同一變數多次設值,並不會產生錯誤,只是同一範圍中,只會有一個值,而同一範圍中,無論你在哪些地方取值,取得的一定是最後一次設定的值。例如:

x = 1;
echo(x); // 顯示 2
x = 2;
echo(x); // 顯示 2

你可以在 OpenSCAD 的環境右下角控制台看到兩次的 “ECHO: 2”。至於這個行為在〈Variables are set at compile-time, not run-time〉有解釋為什麼,總之,別管這個行為,就照著 Functional programming 的基本概念,變數只能指定值一次,之後當變數值不可變動(Immutable)就是了。

或者應該說,OpenSCAD 的變數,概念上可以看成是數學上的變數,指定 x = 1,那麼 x 就是 1,1 就是 x,不會有 x = x + 1 這種行為,畢竟數學上就不成立。

for 迴圈

你看到的 for 迴圈,是列在 〈OpenSCAD CheatSheet〉 的 Other 區域,在〈For Loop〉的說明中有些範例,看了就明白了。

在〈Hello, OpenSCAD〉看到的是最基本的 for(variable = [start : end]) 形式,[start : end] 會產生 startend 的範圍,在 for 的括號中指定給 variable,表示將範圍內的數字指定給 variable,預設遞增值 1,若想指定遞增值,可以使用 [start:step:end] 形式,step 用來指定遞增值,因此…

for (a =[3:5]) {
    echo(a);
}

會在控制台看到 3、4、5 的顯示;for 的括號中,也可以指定 list 或字串,例如:

for (a =[1, 2, 3]) {
    echo(a);     // 逐一顯示 1 2 3
}

for (c = "abc") {
    echo(c);      // 逐一顯示  a b c 
}

不過,別以為下面的程式會顯示 1 到 6:

sum = 0;
for (a =[0:5]) {
    sum = sum + 1;
    echo(sum);
}

實際上的結果最後會顯示六個 1,該怎麼說?官方說明是說,同一範圍中,一個變數只會有一個值,也就是說,for 外是一個範圍,因此,對 for 外頭來說,sum 的值一定是剛開始設定的 0,至於 for 中每次都複製 forsum 的值 0,然後加 1 後指定給一個新變數 sum

好吧!我也覺得以上這說明有點難懂,從 Functional programming 的角度來想比較簡單,因為 Functional programming 不會有 sum = sum + 1,因為數學上不成立,不要試圖做這種運算!

目前可以先知道的是,在 OpenSCAD 中,for 是用於有副作用(side effect)的操作,像是輸出資訊至控制台,或者呼叫模組(module)繪製模型,至於沒有副作用的運算,可以透過函式(function),如何透過 modulefunction 來自訂模組及函數,之後的文件還會再介紹。

內建 3D 模組

在〈Hello, OpenSCAD〉一開始看到的 cube 模組,列在〈OpenSCAD CheatSheet〉的 3D 區域,顧名思義,就是建立 3D 物件用的模組,在〈cube〉說明中,可以看到一些範例,cube 可用來繪製立方體。

最主要的是可以記得兩點:一是當使用陣列指定時,三個數值分別是座標 xyz,大部份的情況下,總是要指定三個值,畢竟建立正立方體的機會沒那麼多;第二點是可以指定 center = true,這會讓模型以原點來置中,大部份的 3D 模組,多半可以有這個參數。

你也可以看到,cube 可以有 cube(size = [x,y,z], center = true) 這樣的指定方式,這很方便,因為可以不用管參數順序,只要記得參數名稱,也就是說,cube(center = true, size = [x,y,z]) 也是可以的。

內建 2D 模組

建立文字時使用了 text 模組,這是歸類在〈OpenSCAD CheatSheet〉的 2D 區域,你可以在〈OpenSCAD User Manual/Text〉看到,可以設定的參數還蠻多的,就初學而言,可以先認識 textsizefont 這三個參數。

text 參數沒有問題,就是你要指定的文字,不好打出來的特殊字元,也可以使用 Unicode 碼指定,例如:

text("\u20AC 10 \u263A");

這會顯示歐元符號、10 與一個笑臉:

OpenSCAD CheatSheet

size 參數預設是 10,單位是 mm,至於 font字型名稱,如果要建立中文,原始碼 .scad 檔案要是 UTF-8 編碼,而 font 指定中文字型,例如,來個「標楷體」的「春」字:

text("春", font = "標楷體");

這會建立以下的文字:

OpenSCAD CheatSheet

你也可以加粗或者是斜體,方式就如文件中說明的例子之一 font="Liberation Sans:style=Bold Italic",在字型名稱號加上冒號,使用 style 指定 BoldItalic 等。

擠出(extrude)

上頭說 text 列於 2D 模組,也就是說,即使看起來有厚度,也只是看起來而已,它並不是建立 3D 模型,只是 2D 平面上的一張圖而已,要讓 2D 變 3D,你得進行擠出的動作。

在〈Hello, OpenSCAD〉看到的是 linear_extrude,它歸類於〈OpenSCAD CheatSheet〉的 Other 之中,作用是線性擠出,將 2D 圖案像擠牙膏似地,令其成為 3D 物件:

linear_extrude(10)
    text("春", font = "標楷體");

linear_extrude(10) 之後不用分號,這類輔助某個模組的操作,後頭都是接上某個完成操作的模組。這會建立以下的 3D 模型:

OpenSCAD CheatSheet

轉換(transformation)

在〈Hello, OpenSCAD〉看到的 translaterotate,很簡單,前者以陣列指定 X、Y、Z 座標對模型作平移,後者以陣列指定繞 X、Y、Z 的轉動角度,對模型做旋轉,舉例來說:

translate([-5, -5, -5])
linear_extrude(10) 
	text("春", font = "標楷體"); 

會讓方才建立的「春」整個以原點置中,結果就是…

OpenSCAD CheatSheet

如果接下來再繞 X 軸轉動 90 度…

rotate([90, 0, 0])
translate([-5, -5, -5])
linear_extrude(10) 
	text("春", font = "標楷體");

就會產生以下的結果:

OpenSCAD CheatSheet

要留意的是,在轉換操作部份,OpenSCAD 採用後乘(post-post-multiplication)的概念,以上例來說,想要依序進行擠出、平移與旋轉,程式碼撰寫時,是由下往上疊加 linear_extrudetranslaterotate

許多 2D/3D 繪圖方案都是採用後乘,像是 OpenGL/WebGLp5.js 等,後續談到 OpenSCAD 的矩陣運算,以及 multmatrix 模組之使用時,記得也是採用後乘。

你可以看到,rotatetranslatelinear_extrude 連續對一個模組進行操作,中間不用逗號,而我喜歡如上的縮排方式,這會比 rotate([90, 0, 0]) translate([-5, -5, -5]) linear_extrude(10) text("春", font = "標楷體"); 容易閱讀。

分享到 LinkedIn 分享到 Facebook 分享到 Twitter