Jdi na navigaci předmětu

OpenSCAD

Program OpenSCAD slouží k modelování 3D modelů nejen pro 3D tiskárny. Je to program umožňující CSG modelování deklarativním zápisem – kódem.

openscad
Obrázek 1. Program OpenSCAD

Vyčerpávající manuál v angličtině použijte jako referenci.

CSG modelování

CSG modelování (Constructive Solid Geometry) je vektorové modelování grafických prvků, v našem případě 3D modelů. Základní primitiva (koule, kužel/válec, kvádr…) se skládají do CSG stromu pomocí hran transformací (posun, škálování, rotace…) a uzlů booleovských operací (rozdíl, průnik, sloučení).

Na obrázku vidíte ilustraci CSG stromu. Zde jsou pro zjednodušení primitivy již otočené.

csg tree
Obrázek 2. CSG strom. © Zottie, GNU FDL

OpenSCAD umožňuje takové stromy zapsat pomocí kódu a vyrenderovat z nich výsledný 3D model ve formě triangulární meshe (o té se budeme učit později).

Uživatelské rozhraní

Okno programu se skládá ze tří částí:

Editor
(vlevo) V něm píšete zdrojový kód modelu.
Náhled
(vpravo) 3D plátno, kde uvidíte náhled modelu.
Konzole
(vpravo dole) V konzoli je vidět chybový a ladící výstup.

Po napsání kódu do editoru je třeba model „zkompilovat“. Existuje rychlý (ne vždy přesný) náhled pomocí OpenGL (Design → Zobrazit, F5) a plnohodnotný render do 3D modelu pro export (počítá se bohužel na procesoru, Design → Vyrenderovat, F6). V nabídce Design lze zapnout i Automaticky načítat a zobrazovat, po uložení se pak provede náhled automaticky.

V nabídce Zobrazit najdete spousto možností pro zobrazení náhledu, doporučujeme zapnout osy a pravítko.

Pro pohyb modelem později použijete myš (vyzkoušejte různá tlačítka).

Abyste něco viděli, potřebujete ale zdrojový kód. Můžete si vybrat z pestré nabídky Soubor → Příklady.

Syntax

Syntaxe je hned na první pohled velmi podobná C/C++/Javě – obsahuje středníky, chlupaté závorky, komentáře se píší stejně. Kromě jiného můžete psát čísla (buď celá, nebo s plovoucí desetinnou čárkou (zápis pomocí tečky nebo vědecky)) – 1, 0, -5, 5.3, 9.99998, 185e-5; vektory/souřadnice v hranatých závorkách – [1, 2, 3]; řetězce ve "dvojitých uvozovkách", boolean true/false.

Můžete používat proměnné (které se nedeklarují, ale chovají se nestandardně, k tomu se dostaneme dále), matematické výrazy a funkce, konstantu PI

Varování:

Nenechte se syntaxí zmást, nejedná se o programovací, ale deskriptivní jazyk! To znamená, že jednotlivé příkazy a výrazy se nedějí postupně odshora dolů, ale spolu najednou popisují výsledek – CSG strom.

Primitiva

cube(size, center);
kvádr (size=[1, 2, 3]) nebo krychle (size=5)
sphere(r);
koule (lze použít r – poloměr nebo d – průměr)
cylinder(…​);
(komolý) kužel (h, r1, r2, center) nebo válec (h, r, center)
polyhedron(…​);
mnohostěn, nízkoúrovňová primitiva popisující přímo triangulární mesh
Ukázka 1. Ukázka použití dvou primitiv. V tomto případě se provede implicitní sloučení
cube(150, center=true); 1
sphere(100); 2
  1. vycentrovaná krychle o hraně délky 150 (všimněte si, že argumenty se dají předávat pozičně i pomocí jména)
  2. koule o poloměru 100
ex1
Obrázek 3. Ukázka použití dvou primitiv

Transformace

Když už umíte vytvářet primitivní geometrická tělesa, je dobré naučit se s nimi provádět jednotlivé transformace.

scale()
škáluje objekt o zadanou konstantu nebo vektor tří hodnot
resize()
škáluje objekt na zadanou velikost
rotate()
objekt otáčí o úhel zadaný ve stupních, použije se jako rotate([deg,deg,deg]) nebo rotate(deg,[1,1,0])
translate([x, y, z])
relativní posun objektu
mirror([x, y, z])
překlopí (zrcadlí) objekt podle počátkem procházející roviny se zadaným normálovým vektorem, např. [1, 0, 0] zrcadlí podle roviny YZ; zrcadlený objekt se neduplikuje
multmatrix([[…​]])
transformační matice velikosti 4×4, nízkoúrovňové
color(…​)
obarví objekt zadanou barvou, funguje jen v náhledu

Transformace se aplikují zápisem před objekt, který chcete transformovat: transformace() objekt();. Dají se také řetězit, jsou aplikované postupně od „nejbližší“ po nejvzdálenější. Dají se aplikovat i na více objektů současně, zabalením objektů do chlupatých závorek a předsazením před ně.

Ukázka 2. Transformace aplikovaná na více objektů současně
transformace() {
  objekt1();
  objekt2();
}
Důležité:

Veškeré operace (snad kromě barvy) se dějí kolem počátku souřadnic. Např. pokud objekt leží někde mimo počátek a vy jej otočíte, jeho poloha se změní.

Ukázka 3. Na pořadí operací záleží
color("green") rotate([0,0,60]) translate([30,0,0]) cube(5); 1
color("red") translate([30,0,0]) rotate([0,0,60]) cube(5); 2
  1. Kostka se nejprve posune, poté otočí kolem počátku a nakonec obarví
  2. Kostka se nejprve otočí kolem počátku, poté posune a nakonec obarví
ex2
Obrázek 4. Na pořadí operací záleží

Booleovské operace

Základem CSG modelování jsou tři boolovské operace:

union() – sloučení
z více objektů udělá jeden (pokud by měl mít výsledný CSG strom více kořenů, provede se na nich implicitně)
difference() – rozdíl
od prvního objektu odečte všechny další
intersection() – průnik
zůstane pouze společná část všech objektů
Ukázka 4. Sloučení (to by se zde provedlo implicitně, ale jinde přijde vhod)
union() {
  cube(150, center=true);
  sphere(100);
}
ex1
Obrázek 5. Sloučení
Ukázka 5. Rozdíl
difference() {
  cube(150, center=true);
  sphere(100);
}
ex3
Obrázek 6. Rozdíl
Ukázka 6. Průnik
intersection() {
  cube(150, center=true);
  sphere(100);
}
ex4
Obrázek 7. Průnik

Všechny tyto operace nemají žádné argumenty, ale zpracují libovolný počet objektů. Takovým objektům se říká children dané operace. Česky to znamená děti, ale my tento pojem raději překládat nebudeme.

Použití proměnných

Není nutné všude používat hodnoty přímo, v OpenSCADu se dají používat i proměnné.

Ukázka 7. Použití proměnné
awesome = 42;
cylinder(h=awesome, r=awesome/2);

Mějte ale na paměti fakt, že všechno se děje zároveň. Proměnou proto nelze předefinovat, respektive lze, ale chová se to jinak, než jste zvyklí.

Ukázka 8. Proměnnou lze předefinovat, ale neuvěříte, co se stane
awesome = 42;
echo(awesome); 1
awesome = 4242; 2
echo(awesome);
  1. funkce echo vypisuje ladící informace do konzole
  2. přenastavení, co se stane?

Výsledkem je dvakrát vypsané ECHO: 4242 🤯 Důvodem je to, že nezáleží, kdy proměnnou nastavíte, její hodnota platí v celém scopu. Pokud proměnnou nastavíte v jednom scopu dvakrát, platí později uvedená hodnota, to berte ale jen jako implementační detail a nikdy to nedělejte.

Varování:

Ze stejného důvodu nemůžete použít a = a + 1; a syntaxe pro a += 1; ani neexistuje (jedná se o syntaktickou chybu).

Pomůže o proměnných uvažovat jako o konstantách pro daný scope. Zatím známe jen jeden (globální) scope, ale to se brzy změní.

Cykly

Two or more, use a for.

Forrestova máma

Syntaxe foru je kapku odlišná od C a vypadá asi takto:

Ukázka 9. Syntax cyklu for
for (var = [...]) { 1
    ... 2
}
  1. hlavička cyklu, do proměnné přiřadíme vektor
  2. v těle cyklu proměnná var nabývá hodnot z použitého vektoru

Zastavme se na chvíli u zápisu vektorů, které jde zapsat několika způsoby:

výčtem
var = [-1, 1] – hodnoty -1 a 1
intervalem
var = [0 : 5] – celá čísla od 0 do 5, obě meze jsou použity
intervalem se skokem
var = [0 : 0.2 : 5] – hodnoty od 0 do 5 (včetně), použije se krok 0,2

Toho často využijeme v zápisu cyklu for.

Ukázka 10. Cyklus s intervalem
for (i = [0:10:100]) echo(i); // => ECHO 10, 20, 30...
Ukázka 11. intersection_for je speciální varianta foru, která neprovádí sjednocení, ale průnik
intersection_for(n = [1 : 6]) {
  rotate([0,0,n*60]) translate([5,0,0]) sphere(12);
}
ex6
Obrázek 8. intersection_for

Cykly lze samozřejmě do sebe vnořovat, existuje k tomu i zkratka.

Ukázka 12. Vnořené cykly
for (xpos=[0:3]) {
  for (ypos=[2,4,6]) { 1
    ...
  }
}

for (xpos=[0:3], ypos=[2,4,6]) { 2
  ...
}

 

  1. Vnořený cyklus
  2. Zkratka (syntactic sugar) pro vnořený cyklus

Vzhledem k tomu, jak cyklus for v OpenSCADu funguje, zde vypichujeme několik informací, na které pozorný čtenář jistě již přišel sám:

  • Každá „iterace“ cyklu má vlastní scope, jakékoliv nastavení proměnných v další iteraci (a také po skončení cyklu) pozbývá platnosti.
  • Z předchozího bodu plyne, že v cyklu se nedá nic iterativně počítat, je možné pouze použít matematické výrazy s řídící proměnnou.
  • Cyklus while nedává v OpenSCADu smysl a tedy neexistuje.

Podmínky

OpenSCAD obsahuje dva druhy podmínek: if a ternární operátor.

if, else if, else

Syntaxe podmínky if není překvapující (chlupaté závorky jsou volitelné):

Ukázka 13. Syntax podmínky if
if (...) { 1
  ... 2
} else if (...) { 3
  ... 4
} else { 5
  ... 6
}
  1. pravdivostní výraz (např. a > b, 0, true, len(vec) != 42)
  2. vlastní scope!
  3. volitelná větev s jinou podmínkou
  4. vlastní scope!
  5. volitelná větev, když žádná podmínka neplatí
  6. vlastní scope!

Jednotlivé větve podmínky mají vlastní scope. To znamená, že není následující kód může mít pro někoho překvapující výsledek:

Ukázka 14. Na tohle se studenti vždy nachytají, ptali bychom se na to u zkoušky, kdybychom nějakou měli
num = 42;

if (num > 0) {
  sign = 1;
} else if (num < 0) {
  sign = -1;
} else {
  sign = 0;
}

echo(sign); // WARNING: Ignoring unknown variable 'sign'.

Tuto vlastnost OpenSCADu lze obejít jedině ternárním operátorem.

Ternární operátor

Ternární operátor, je jediný způsob, jak podmíněně nastavit nějakou hodnotu s dlouhodobou platností.

Ukázka 15. Ternární operátor
num = 42;

// var =   test ? TrueValue : FalseValue;

sign = num > 0 ? 1 : (num < 0 ? -1 : 0); 1
echo(sign); // ECHO: 1
  1. Zde noříme operátory do sebe

Funkce

Podobně jako ternární operátor se zapisují funkce. Funkce nevytváří části CSG stromu, pouze počítají nějakou hodnotu ze svého vstupu. Jsou to jednovýrazové zkratky.

function name ( parameters ) = expression;

Funkcemi se v tomto kurzu moc nezabýváme, ale zvídaví studenti je mohou samozřejmě používat. Více o funkcích v manuálu.

Moduly

Ekvivalentem k funkci pro CSG strom je modul. Modul se více podobá funkcím, jak je známe z programovacích jazyků, s tím rozdílem, že nevrací žádnou hodnotu, ale uzel (či hranu) CSG stromu.

Laicky řečeno: modul něco „nakreslí“ tam, kde se použije.

Stejně jako funkce, přijímá modul parametry, které mohou nabývat výchozích hodnot. Navíc může přijímat (zpracovávat) children().

Moduly (a funkce) mohou existovat v samostatných souborech (knihovnách), ve vlastním souboru s modelem můžete použít use nebo include:

use <lib.scad>;
dá k dispozici moduly a funkce ze souboru lib.scad
include <lib.scad>;
na místo vloží celý soubor lib.scad (případné objekty se rovnou vykreslí)
Ukázka 16. Příklad vlastního modulu (válec s kulatými konci)
module rounded_cylinder(h=20, r=5, center=false) {
  baseh = h-2*r;
  translate([0, 0, center ? -baseh/2 : r]) {
    cylinder(h=baseh, r=r);
    sphere(r);
    translate([0, 0, baseh]) sphere(r);
  }
}

// pro zobrazení musíte modul zavolat
rounded_cylinder(center=true);
ex7
Obrázek 9. Válec s kulatými konci

children()

Kromě modulů, které vytvářejí tvary jen na základě vstupních parametrů (argumentů), jdou vytvářet i moduly, které přijímají children().

Používá se to na modifikování nebo zakomponování libovolného objektu.

children()
reprezentuje všechny předané objekty
children(n)
reprezentuje n-tý předaný objekt
children([n1, …​, nx])
reprezentuje n-první až n-x-tý předaný objekt
$children
magická (s dolarem) konstanta s počtem předaných objektů
children([1 : 2 : $children])
každý druhý předaný objekt
Ukázka 17. Příklad modulu, který provede s children() nějakou operaci
module elongate() {
  scale([10 , 1, 1])
    children();
}

elongate() {
  sphere(30);
  cube(45, center=true);
  cylinder(r=10, h=50);
}
ex8
Obrázek 10. Příklad použití modulu elongate()

Debugging

Pro debugging modelů je dobbré naučit si několik modifikátorů:

%
F5 vykreslí uzel poloprůhledně, F6 vůbec
#
F5 vykreslí uzel poloprůhledně a červeně, F6 normálně
!
F5 i F6 zobrazí pouze tento uzel
*
F5 i F6 tento uzel bude ignorovat
Ukázka 18. Modifikátor #
difference() {
  sphere(45);
  #cube(65, center=true);
}
ex9
Obrázek 11. Modifikátor #

Pomocníčci

Varování:

Zde zhruba končí obsah druhého cvičení a pokračuje obsah třetího.

Speciálními operacemi v OpenSCADu jsou minkowski() a hull(). Pomocí nich můžete vyvářet složité tvary, které by se jinak vytvářely velice obtížně.

Minkowského suma

Minkowského suma je množinová operace, kdy všechny body z jedné množiny sečtete se všemi body z druhé množiny. Nejlépe to vystihuje následující obrázek:

minkowski
Obrázek 12. Minkowského suma © Tosha (Public Domain)

Můžete si to představit tak, že jeden z objektů uchopíte za počátek souřadný a objíždíte s ním po povrchu druhého objektu, zanechávajíc za sebou stopu. Jedná se o operaci komutativní a asociativní, je tedy jedno, kterým objektem jezdíte po kterém. V praxi se tato operace používá většinou s koulí pro zaoblení, ale pozor, zaoblený objekt se zvětší.

Ukázka 19. Operace minkowski()
minkowski() {
  cube(300);
  sphere(30);
}
ex5
Obrázek 13. Vlevo operandy, vpravo výsledek operace minkowski()
Varování:

Vypočtení minkowského sumy může trvat velmi dlouho.

Konvexní obal

Konvexní obal (convex hull) objektů je takový nejmenší konvexní objekt, který pojme všechny objekty v něm. Opět se jedná o komutativní a asociativní množinovou operaci.

Ukázka 20. Operace hull()
hull() {
  cube(100);
  sphere(30);
}
ex5a
Obrázek 14. Vlevo operandy, vpravo výsledek operace hull()
Varování:

Vypočtení konvexního obalu může trvat celkem dlouho.

Dvourozměrný subsystém

Zatím jsme vytvářeli jen trojrozměrné objekty. V OpenSCADu se dá ale využít dvourozměrný subsystém, ve kterém se pracuje jen na jedné rovině.

V 2D subsystému je možné vyvářet 2D primitiva: circle(), square() a polygon().

Pomocí linear_extrude() nebo rotate_extrude() jde z 2D objektu vytvořit 3D objekt. Naopak projection() slouží k projekci 3D objektů do 2D.

Když pracujete ve 2D subsystému, lze použít vše, co již znáte, jen API některých operací se náležitě změní (např. translate() bere vektor 2 hodnot, rotate() bere jen jeden úhel…).

Ukázka 21. Dvourozměrný subsystém
hull() {
  rotate(45) square([25, 15]);
  translate([12, 7]) circle(7);
}
ex11a
Obrázek 15. Dvourozměrný subsystém

Operace hull() a minkowski() jsou ve 2D subsystému relativně rychlé. Pokud to jde, je tedy lepší provádět je v něm.

2D primitiva

square()
alternativa ke cube()
circle()
alternativa ke sphere()
polygon()
alternativa k polyhedron()

offset()

K zaoblení dvourozměrných tvarů lze použít offset(). Ten má několik způsobů použití:

offset out
Obrázek 16. Použití kladného offsetu v závislosti na použitých argumentech a jejich hodnotách © Torsten Paul (CC BY-SA)
offset in
Obrázek 17. Použití záporného offsetu v závislosti na použitých argumentech a jejich hodnotách © Torsten Paul (CC BY-SA)

linear_extrude()

Operace linear_extrude() vytáhne 2D tvar do prostoru a vytvoří tedy 3D tvar. Lze nastavit několik parametrů:

height
výška vytažení
center
false vytahuje jen nahoru, true na oba směry (každý o polovinu výšky)
twist
o kolik stupňů se 2D tvar při vytažení otočí
slices
počet kroků u twist
scale
kolikrát se 2D tvar při vytažení zvětší
convexity
hodnota ovlivňující náhled; kuchař radí: „nevíš-li, dej tam 10“
Ukázka 22. Použití linear_extrude()
linear_extrude(height=20, twist=180, slices=100, center=true) {
  square(5);
  square(5, center=true);
}
ex11
Obrázek 18. Použití linear_extrude()

rotate_extrude()

Další možností, jak převést 2D tvar na 3D tvar, je rotovat ho. K tomu slouží rotate_extrude(), které rotuje 2D tvar do prostoru.

Rotace probíhá kolem osy Y, ale objekt se „vzpřímí“ kolem osy Z (dodnes nevíme proč).

Ukázka 23. Použití rotate_extrude()
rotate_extrude()
  polygon(points=[[0,0],[20,10],[10,20],[10,30],[30,40],[0,50]]);
ex10
Obrázek 19. Použití rotate_extrude()

projection()

Projekce (projection()) promítne 3D objekt na rovinu XY. Parametr cut umožní použít jen průnik s rovinou XY. Výsledkem projekce je vždy 2D tvar; ten pak můžete využít opět k vytvoření 3D tvaru.

Ukázka 24. Parabola pomocí projection()
projection(cut=true)
  translate([0, 0, -15])
    rotate([45, 0, 0])
      cylinder(r1=0, r2=500, h=500);
ex13
Obrázek 20. Parabola pomocí projection()

import()

Pro použití již existujících 2D nebo 3D tvarů můžete použít import(), pomocí něhož lze do CSG stromu vložit STL a DXF soubory. Argumentem je cesta k souboru (relativní či absolutní).

Při importování 2D tvarů (DXF) si dejte především pozor na výslednou velikost, je vhodné použít resize().

Ukázka 25. Použití 2D tvaru ze souboru
rotate_extrude()
  resize([20, 0], auto=[false, true])
    import("bottle.dxf");
ex12
Obrázek 21. Použití 2D tvaru ze souboru

Importované soubory lze využít k jakýmkoliv dalším operacím. Cizí STL soubory se ne vždy povedou vyrenderovat, je třeba je nejprve opravit, k tomu se dostaneme ve cvičení o opravě meshe.

Ukázka 26. Použití 3D tvaru ze souboru
difference() {
  import("kangaroo.stl"); // http://www.thingiverse.com/thing:33273 CC BY-NC-SA
  translate([0, -10, 80])
    cube(30, center=true);
}
ex14
Obrázek 22. Použití 3D tvaru ze souboru

surface()

Alternativním způsobem využité externích souborů je surface(), který slouží k převodu obrázků do výškové mapy.

surface
Obrázek 23. surface(file="smiley.png", center=true); © Torsten Paul (CC BY-SA)

Rozlišení

Jistě jste si všimli, že kulaté věci jsou v OpenSCADu hranaté. Čím menší jsou, tím je to více poznat.

ex16a
Obrázek 24. Koule velikosti 1

Pomocí speciálních proměnných $fn, $fa a $fs lze rozlišení měnit, viz manuál. V praxi se nejčastěji nastavuje proměnná $fn, která nastaví absolutní počet hran na kruh (minimálně 3). Tvary jsou vytvořené tak, že zadaná velikost je velikost opsané kružnice. Proměnou $fn lze využít například k vytvoření n-úhelníku.

Tyto speciální proměnné se mohou nastavit globálně, ve scopu nebo argumentem libovolné operaci, primitivu či modulu. Při vytváření modulů není třeba tyto proměnné uvádět v předpisu.

fn
Obrázek 25. for (fn=[1:10]) translate([fn*2.1,0,0]) circle($fn=fn);

Simple – 2-Manifold

Pro správný export STL souboru je potřeba, aby byl model Simple – 2-Manifold. To mj. znamená, že stěny modelu se nemohou všelijak protínat. Skoro všechny možné problémy řeší výsledný implicitní union(). Nějaké problémy ale přece jen můžou vzniknout, například při nesprávném použití polyhedronu.

Jedním z problémů, který může nastat jednoduše, je společná hrana dvou objektů. Pokud si představíte dvě kostky (např. z obrázku níže), v reálném světě nemohou mít společnou hranu. Buďto jde „projít“ z jedné kostky do druhé, nebo „jde projít“ mezi nimi; jinými slovy buďto to jsou dvě kostky nebo jedna dvoukostka.

ex15
Obrázek 26. Dvě kostky nemohou sdílet hranu
Ukázka 27. Takhle to nejde
cube(20);
translate([20, 20, 0]) cube(20);
Ukázka 28. Jde to takhle
e=0.0001;
cube(20);
translate([20-e, 20-e, 0]) cube(20);
Ukázka 29. Nebo takhle
e=0.0001;
cube(20);
translate([20+e, 20+e, 0]) cube(20);

Knihovna MCAD

Pomocí modulů lze pro OpenSCAD vytvářet různé knihovny. Některé již existují, jednou z nich je knihovna MCAD, která bývá často distribuovaná společně s OpenSCADem.

Knihovna MCAD obsahuje spoustu elementárních i pokročilých věcí:

  • nové tvary,
  • vhodné věci pro RepRap:
    • motorky,
    • řemeničky…

Pro použití knihovny MCAD je potřeba použít include, ne use.

Ukázka 30. Použití knihovny MCAD
include <MCAD/stepper.scad>
motor(Nema17);
ex16
Obrázek 27. Je libo motor NEMA 17?

Pokročilá práce s proměnnými

Příklady ze cvičení