Obsah
1. Zápis přepisovacích gramatik v souborech .ls
2. Příkazy želví grafiky implementované v Lparseru1
2.1 Příkazy ovlivňující orientaci želvy
2.2 Speciální příkazy ovlivňující orientaci želvy
2.3 Příkazy pro posun želvy s případným kreslením
2.4 Práce se zásobníkem a „listy“
2.5 Ovlivnění stavových proměnných želvy
2.6 Další příkazy
3. Nastavení axiomu pro jednodušší tvorbu 2D modelů
4. Vytvoření gramatik jednoduchých 2D modelů
5. Tvorba „větví“
6. Tvorba „listů“
7. Fraktální struktury vytvořené v ploše
8. Obsah dalšího pokračování tohoto seriálu
1. Zápis přepisovacích gramatik v souborech .ls
V předchozí části tohoto seriálu jsme si zevrubně popsali program L-System Parser/Mutator (zkráceně pojmenovaný pouze jako Lparser), včetně zdůraznění největších rozdílů mezi jeho první a druhou verzí. V dnešní části si na praktických příkladech přepisovacích gramatik ukážeme použití Lparseru verze 1 při tvorbě plošných (2D) modelů. Volba první verze není v žádném případě náhodná – pro tuto verzi totiž existuje zdrojový kód, takže je možné Lparser přeložit a spustit na prakticky jakékoli 32 či 64bitové platformě vybavené překladačem programovacího jazyka ANSI C. Pro připomenutí dodám, že zdrojový kód Lparseru1, příklady gramatik z původní DOSovské verze a další materiál je možné získat na adrese http://home.wanadoo.nl/laurens.lapre/lparser.html.
Lparser verze 1 předpokládá, že přepisovací gramatiky modelů jsou uloženy v textových souborech s koncovkou „.ls“. V těchto souborech se kromě vlastních přepisovacích pravidel nachází také zápis axiomu (řetězce, který se v jednotlivých iteracích přepisuje), specifikace maximálního počtu iterací, implicitní úhel, o který se otáčí želva při provádění některých příkazů a počáteční tloušťka „větví“, které želva při svém pohybu kreslí. V souborech „.ls“ se mohou nacházet i poznámky, které začínají znakem „#“ a končí znakem či dvojicí znaků značících konec řádku (z tohoto důvodu by neměl být problém s přenosem „.ls“ souborů mezi Microsoftími operačními systémy a jejich unixovými protějšky). Poznámky se mohou vyskytovat kdekoli, tj. i za číselnými údaji popsanými v dalším odstavci.
Na prvních třech významných řádcích (tj. řádcích, které neobsahují pouze bílé znaky a/nebo poznámku) se nachází tři důležité číselné údaje. Prvním údajem je maximální počet prováděných iterací (hloubka rekurze), druhým údajem implicitní úhel otáčení želvy a konečně údajem třetím počáteční tloušťka větví. Větve odpovídají úsečkám, které jsme kreslili v případě plošných modelů. Na čtvrtém významovém řádku je zapsán axiom (přepisovaný řetězec) a na řádcích ležících za ním již jednotlivá přepisovací pravidla, která mají tvar symbol=řetězec. Celý soubor by měl být ukončen řádkem, který obsahuje jediný znak „@“. Tento znak zápis celého objektu ukončuje. Výše uvedené informace se vztahují k první verzi Lparseru, verze druhá přidává do souboru klíčová slova (axiom, rule, thickness) a z tohoto důvodu nepoužívá ukončující znak.
Následuje příklad zápisu 3D modelu pomocí přepisovacích gramatik. V původní DOSové verzi je L-systém tohoto 3D modelu uložen v souboru bop01.ls
# --- L-System Parser/Mutator --- Lj Lapre ----------------------------------
5 # recursion depth
18 # angle
50 # thickness as % of length
p
p=i++[p+o]--->>[--l]i[++l]--[po]+++po
i=Fs[>>&&l][>>^^l]Fs
s=sFs
l=[c{++f--ff--f++|++f--ff--f}]
o=[&!ce>w>>>>w>>>>w>>>>w>>>>w]
e=FF
w=[c^!F][cc&&&&{---f+++f|---f+++f}]
@
Pomocí výše uvedeného souboru je možné vygenerovat zajímavě vypadající trojrozměrný model:
Obrázek 1: Trojrozměrný model specifikovaný v souboru „bop01.ls“ vytvořený pomocí blobů (metaballs)
Obrázek 2: Trojrozměrný model specifikovaný v souboru „bop01.ls“ vytvořený pomocí trojúhelníků
2. Příkazy želví grafiky implementované v Lparseru1
Lparser používá v přepisovacích gramatikách pouze jednopísmenné příkazy ovládající želvu či měnící její stav (tloušťku kreslené stopy, barvu stopy aj.). Omezení na pouze jedno písmeno má svůj praktický význam, neboť se tím celé zpracování urychlí, což je patrné zejména u modelů používajících složitá přepisovací pravidla. V tabulkách uvedených v následujících podkapitolách jsou vypsány všechny symboly, které Lparser rozpoznává, ostatní zde neuvedené symboly je možné použít pro pojmenování pravidel. Přesný význam jednotlivých symbolů bude popsán v dalších kapitolách a některé z nich až v navazující části tohoto seriálu.
2.1 Příkazy ovlivňující orientaci želvy
Želva se může v prostoru otáčet okolo trojice vektorů, které tvoří její souřadný systém. Tyto vektory jsou zobrazené na třetím obrázku. Pomocí dále uvedených příkazů je možné otáčení želvy okolo zadané osy spustit. Úhel α, který je v tabulce zmíněn, je zadán přímo v souboru „.ls“ jako jeden z globálních parametrů.
Obrázek 3: Trojice vektorů tvořících souřadný systém želvy
Symbol | Příkaz | Úhel |
---|---|---|
+ | turn left | RU(α) |
+(x) | turn left | RU(x) |
- | turn right | RU(-α) |
-(x) | turn right | RU(-x) |
& | pitch down | RL(α) |
&(x) | pitch down | RL(x) |
^ | pitch up | RL(-α) |
^(x) | pitch up | RL(-x) |
< | roll left | RH(α) |
<(x) | roll left | RH(x) |
> | roll right | RH(-α) |
>(x) | roll right | RH(-x) |
2.2 Speciální příkazy ovlivňující orientaci želvy
Následující příkazy také ovlivňují orientaci želvy. Některé slouží k jejímu otočení o 180° (π), pokaždé však okolo jiného vektoru. Další příkazy slouží k narovnání želvy do vodorovné polohy, otočení o náhodný úhel nebo pro takzvanou korekci gravitace, tj. změnu otočení želvy směrem dolů nezávisle na tom, kde se želva nachází a jakou má orientaci.
Symbol | Příkaz |
---|---|
| | turn around (o π = 180°) |
% | roll around (o π = 180°) |
$ | roll until horizontal |
~ | turn/pitch/roll in a random direction |
~(x) | turn/pitch/roll in a random direction (max. x) |
t | correction for gravity with 0.2 |
t(x) | correction for gravity with x |
2.3 Příkazy pro posun želvy s případným kreslením
Příkazy z této kategorie slouží k přesunu želvy ve směru její orientace, přesněji řečeno ve směru vektoru Forward (F). Želva přitom může během posunu vykreslovat dva typy entit: „větve“ a/nebo „listy“ (buď současně nebo každý zvlášť). Některé příkazy želvu přesunou bez nakreslení větve, jiné naopak vykreslení provádí. Poněkud speciální je v této skupině příkaz „.“, při jehož interpretaci se želva neposune, pouze se zapíše její pozice do seznamu vrcholů (vertexů). Detaily vykreslování „větví“ a „listů“ budou vysvětleny v následujících kapitolách.
Symbol | Příkaz |
---|---|
F | move forward and draw full length |
F(x) | move x forward and draw |
Z | move forward and draw half length |
Z(x) | move x forward and draw |
f | move forward with full length, record vertex |
f(x) | move x forward, record vertex |
z | move forward with half length, record vertex |
z(x) | move x forward, record vertex |
g | move forward with full length |
g(x) | move x forward |
. | don't move, record vertex |
2.4 Práce se zásobníkem a „listy“
V tabulce uvedené v této podkapitole jsou vypsány dvě skupiny příkazů. První skupina příkazů slouží pro ukládání stavu želvy na zásobník (stack) a následné zpětné načítání stavu želvy ze zásobníku. Tyto příkazy mají obdobný význam jako v případě dříve popisovaných 2D L-systémů, ovšem s tím rozdílem, že stavový vektor želvy je v případě 3D L-systémů delší, tj. obsahuje větší počet stavových proměnných. Druhá skupina příkazů slouží k zahájení a ukončení záznamu vrcholů (vertexů), ze kterých se posléze vytváří „listy“, tj. plošné entity.
Symbol | Příkaz |
---|---|
[ | push current state |
] | pop current state |
{ | start polygon shape |
} | end polygon shape |
2.5 Ovlivnění stavových proměnných želvy
Příkazy uvedené v této podkapitole slouží k ovlivnění obsahu interních proměnných, které společně tvoří stavový vektor želvy. Ten je, jak jsme si již řekli v předchozích částech tohoto seriálu, tvořen skupinou proměnných plně popisujících želvu nacházející se v prostoru. Mezi stavové proměnné patří například proměnná popisující tloušťku „větví“ vytvářených při pohybu želvy, úhel, o který se želva natáčí okolo svého souřadného systému tvořeného vektory Forward (F), Up (U) a Left (L) a také o délku kroku želvy, která přímo ovlivňuje délku vytvářených větví (viz příkazy z předchozích podkapitol).
Symbol | Příkaz |
---|---|
" | increment length with 1.1 |
' | decrement length with 0.9 |
"(x) | multiply length with x |
'(x) | multiply length with x |
; | increment angle with 1.1 |
: | decrement angle with 0.9 |
:(x) | multiply angle with x |
;(x) | multiply angle with x |
? | increment thickness with 1.4 |
! | decrement thickness with 0.7 |
?(x) | multiply thickness with x |
!(x) | multiply thickness with x |
2.6 Další příkazy
Do poslední skupiny příkazů jsou zařazeny příkazy používané pro změnu barvy vykreslovaných větví a listů – tyto barvy jsou použity například při vykreslování modelů pomocí programu POV-Ray nebo při exportu vytvořeného modelu do souborů typu VRML. Dále je v této skupině uveden příkaz, který znovunastaví stavové proměnné želvy na hodnoty specifikované ve vstupním souboru „.ls“ (reset). Poslední příkaz z této skupiny již známe: jedná se o zavináč (@), který ukončuje definici celého objektu. Po výskytu tohoto znaku se generování objektu pomocí želví grafiky zastaví.
Symbol | Příkaz |
---|---|
c | increment color index |
c(x) | set color index to x |
* | reset color, thickness, length and angle |
@ | end of object |
3. Nastavení axiomu pro jednodušší tvorbu 2D modelů
Vzhledem k tomu, že se v dnešní části seriálu zabýváme pouze tvorbou 2D, tj. plošných modelů, ukážeme si, jakým způsobem se nastaví axiom (přepisovací řetězec) tak, aby se želva pohybovala v ploše x-y. Lparser při inicializaci nastaví želvu do takové pozice, aby byla umístěna v počátku [0, 0, 0], vektor Forward směřoval ve směru růstu osy z a vektor Left ve směru osy y (vektor Up není problém dopočítat pomocí vektorového součinu s využitím zbývajících dvou vektorů). Pomocí příkazů &(90) a +(90) můžeme želvu natočit do roviny x-y tak, jak jsme zvyklí z 2D L-systémů. Proto také každý axiom, který si dnes ukážeme, bude začínat následujícím řetězcem:
&(90)+(90)
4. Vytvoření gramatik jednoduchých 2D modelů
S pomocí želví grafiky je možné v Lparseru vytvářet dva typy objektů. Podle tvaru a funkce budeme v dalším textu tyto objekty nazývat „větve“ a „listy“. Mezi větvemi a listy existuje jeden podstatný rozdíl: větve jsou tvořeny relativně úzkými a dlouhými objekty (podle způsobu konstrukce modelu například válcem či čtveřicí úzkých obdélníků) a želva tyto objekty generuje při svém pohybu v prostoru. Počáteční bod větve leží v místě počátku pohybu želvy, koncový bod pak v místě, kde želva svůj pohyb ukončí.
Listy jsou naproti tomu tvořeny plošnými polygony, jejichž vrcholy určuje želva pokládáním „značek“ při svém pohybu. Položení značky je nutné specifikovat pomocí speciálního příkazu, který buď kombinuje tvorbu značky s pohybem želvy, nebo značku nastaví na aktuální poloze želvy. Počet vrcholů polygonů není omezen, většinou se však při exportu modelu polygon rozpadá na trojúhelníky, u nichž je ve všech případech zaručeno, že tvoří rovinný útvar. V páté kapitole si na jednoduchých L-systémech ukážeme tvorbu modelů sestavených z větví, v kapitole šesté do vytvářených modelů přidáme i listy.
5. Tvorba „větví“
V předchozí kapitole jsme si řekli, že struktury typu „větve“ jsou generovány přímo při pohybu želvy. Podobně jako u 2D L-systémů, i zde je možné použít příkaz F, který želvu instruuje k posunu ve směru jejího vektoru Forward spolu s vytvořením větve vedoucí od počátečního do koncového bodu cesty želvy. Vše si ukážeme na jednoduchém demonstračním příkladu, který vykreslí čtverec pomocí čtyř příkazů F (posun dopředu) a třech příkazů + (otočení želvy okolo vektoru Up). Úhel otočení je nastavený na 90°, počet iterací na 1. V tomto případě však počet iterací nehraje vůbec žádnou roli, protože se v přepisovacích pravidlech nevyskytuje rekurze:
# demonstracni L-system cislo 1
# Vykresleni ctverce pouze pomoci vetvi
1 # hloubka rekurze
90 # implicitni uhel natoceni zelvy
10 # tloustka vetvi
&(90)+(90)X # axiom (natoceni zelvy a leva strana pravidla)
X=F+F+F+F # jedine prepisovaci pravidlo
@ # konec specifikace objektu
Obrázek 4: Čtverec vytvořený prvním demonstračním L-systémem
6. Tvorba „listů“
Na rozdíl od „větví“ nejsou „listy“ vytvářeny přímo při pohybu želvy, tj. nekopírují dráhu jejího pohybu, ale jejich tvorba nastává až v následujícím kroku zpracování 2D či 3D modelu. Želva při svém pohybu může do prostoru pomocí několika příkazů klást značky, které určují polohy jednotlivých vrcholů (vertexů) tvořících krajní body polygonů, ze kterých se listy skládají. Lparser automaticky z těchto značek požadované plošky vytvoří a popř. i provede rozpad plošek do jednotlivých trojúhelníků (takzvaná teselace). Začátek a konec plošky je v přepisovacích pravidlech reprezentován příkazy „{“ a „}“, místo příkazů „F“ jsou použity příkazy „f“, které želvu posunují bez kreslení větví, ovšem se zaznamenáním vrcholu listu. Vše si opět můžeme ukázat na příkladu, který vykreslí čtverec, tentokrát však složený ze čtvercového listu
# demonstracni L-system cislo 2
# Vykresleni ctverce pouze pomoci listu
1 # hloubka rekurze
90 # implicitni uhel natoceni zelvy
10 # tloustka vetvi (nema vyznam)
&(90)+(90)X # axiom (natoceni zelvy a leva strana pravidla)
X={f+f+f+f} # jedine prepisovaci pravidlo
@ # konec specifikace objektu
Obrázek 5: Čtverec vytvořený druhým demonstračním L-systémem
Kombinace větví a listů je ukázána na třetím demonstračním příkladu. Všimněte si použití složených závorek (tvorba listů) a příkazů „F“ (kreslení větví) spolu s příkazem „.“ (záznam vertexu).
# demonstracni L-system cislo 3
# Vykresleni ctverce pouze pomoci vetvi i listu
1 # hloubka rekurze
90 # implicitni uhel natoceni zelvy
10 # tloustka vetvi
&(90)+(90)X # axiom
X={F.+F.+F.+F.} # jedine prepisovaci pravidlo
@ # konec specifikace objektu
Obrázek 6: Čtverec vytvořený třetím demonstračním L-systémem
7. Fraktální struktury vytvořené v ploše
Na tvorbě fraktálních struktur Lparserem není nic záhadného. Podobně jako u klasických 2D L-systémů, i zde se využije rekurze v přepisovacích gramatikách, kdy se na pravé straně nějakého přepisovacího pravidla objeví levá strana jiného či stejného pravidla. Ukážeme si použití rekurze na klasickém příkladu: křivce Helge von Kocha.
# demonstracni L-system cislo 4
# Vykresleni krivky Helge von Kocha
4 # hloubka rekurze
60 # implicitni uhel natoceni zelvy
20 # tloustka vetvi
&(90)+(90)F--F--F# axiom
F=F+F--F+F # jedine prepisovaci pravidlo
@ # konec specifikace objektu
Obrázek 7: Křivka Helge von Kocha
Další příklad slouží k vykreslení Sierpinského křivky:
# demonstracni L-system cislo 5
# Vykresleni Sierpinskeho krivky
5 # hloubka rekurze
60 # implicitni uhel natoceni zelvy
30 # tloustka vetvi
&(90)+(90)YF # axiom
X=YF+XF+Y
Y=XF-YF-X
@ # konec specifikace objektu
Obrázek 8: Sierpinského křivka
S využitím zásobníku je možné vytvářet mnohem složitější objekty, například následující kruhovou mozaiku:
# demonstracni L-system cislo 6
# Vykresleni kruhove mozaiky
3 # hloubka rekurze
15 # uhel natoceni zelvy
20 # tloustka vetvi
&(90)+(90)X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X
X=[F+F+F+F[---X-Y]+++++F++++++++F-F-F-F]
Y=[F+F+F+F[---Y]+++++F++++++++F-F-F-F]
@ # konec specifikace objektu
Obrázek 9: Obrázek kruhové mozaiky
8. Obsah dalšího pokračování tohoto seriálu
V následujícím pokračování seriálu o fraktálech se již budeme věnovat té nejdůležitější funkcionalitě Lparseru. Ukážeme si tvorbu trojrozměrných modelů, od těch nejjednodušších (obdoba binárního stromu) až po velmi složité modely obsahující stovky tisíc polygonů. Také si řekneme, jakým způsobem je možné vytvářené modely při jejich generování nechat „zmutovat“.