Atramentová krivka
Nadviažeme voľne na tutoriál Lomená čiara a vyrobíme si nekonečnú farebnú krivku. Ale namiesto ostrých zlomov bude mať plynulý priebeh. A doplníme jednoduchý efekt na rozmazávanie obrazovky:

Základný program
Začneme so štandardným skečom so setup()
a draw()
, nič špeciálne.
Lomenú čiaru predtým sme vyrábali so segmentou na seba nadviazaných. Každý segment bola jedna krátka úsečka. Tu budeme na seba nadväzovať krátke krivky.
Príkazy beginShape()
a endShape()
beginShape()
a endShape()
Aby sme mohli kresliť krivku, už nám nebude stačiť obyčajný príkaz line()
ale naučíme sa univerzálnejší postup, ktorý vie nakresliť aj tvary z viacerými vrcholmi alebo zaoblené krivky.
Vyskúšajte tento skeč:
void setup()
{
size(400,400);
}
void draw()
{
beginShape();
vertex(100,100);
vertex(300,200);
vertex(50,350);
endShape();
}
Vykreslí to trojuholník. Skúste za tretí príkaz vertex()
pridať ďalší príkaz vertex()
s nejakými svojimi súradnicami. Vykreslí sa štvoruholník. Skúste pridať ďalší vertex. Vykreslí sa päťuholník.
Takto vieme, okrem iného, vykresliť ľubovoľný n-uholník. Každý jeho vrchol má svoj príkaz vertex()
.
Bézierova krivka
Cez príkazy beginShape()
a endShape()
vieme kresliť aj zaoblenú krivku, takzvanú Bézierovu. Tá pozostáva zo 4 bodov. V prvom bode začína, druhý a tretí bod určujú jej zaoblenie, vo štvrtom bode končí:

Vyrobíme si v skeči súradnice pre 4 body abcd a len tak na skúšku priraďme im nejaké súradnice:
float ax,ay, bx,by, cx,cy, dx,dy;
void setup()
{
size(400,400);
ax = 50;
ay = 200;
bx = 100;
by = 100;
cx = 250;
cy = 50;
dx = 350;
dy = 300;
}
Takto potom vykreslíme medzi týmito 4 bodmi krivku:
void draw()
{
beginShape();
vertex(ax,ay);
bezierVertex(bx, by, cx, cy, dx, dy);
endShape();
}
Prvý vertex()
určuje, odkiaľ krivka začína (bod a). A súradnice ďalších 3 bodov sú potom v nasledujúcom príkaze bezierVertex()
. Program sa dá čitať tak, že začni v bode ax
,ay
a potom urob krivku cez body bx
, by
, cx
, cy
až do bodu dx
, dy
.
Náhodné súradnice
Ak by sme dali krivke úplne náhodné súradnice, tak bude dosť veľká divoká. Vyskúšajte v setup()
namiesto konkrétnych čísel priradiť x-ovým súradniciam random(width)
a y-ovým súradniciam random(height)
.

My chceme, aby naša veľká krivka bola vyskladaná s malých segmentov. Takže upravíme súradnice tak, aby bod B bol v blízkom okolí bodu A, bod C v blízkom okolí bodu B a bod D v blízkom okolí bodu C. V akom blízkom? Na to si vyrobíme premennú v
(ako vzdialenosť):
float ax,ay, bx,by, cx,cy, dx,dy;
float v = 30;
Generovanie náhodnej pozície v okolí inej pozície sme už robili pri Lomenej čiare, tu je to podobné. Začneme v strede obrazovky a ďalšie súradnice generujeme v okolí tých predošlých:
void setup()
{
size(400,400);
ax = width/2;
ay = height/2;
bx = random(ax - v, ax + v);
by = random(ay - v, ay + v);
cx = random(bx - v, bx + v);
cy = random(by - v, by + v);
dx = random(cx - v, cx + v);
dy = random(cy - v, cy + v);
}
Nová krivka je už krátka a dobre sa nám tak budú skladať segmenty:

Nadväzovanie
Ak budeme chcieť kresliť ďalšie a ďalšie segmenty, tak budeme potrebovať, aby nový segment začínal tam, kde skončil predošlý. Takže po vykreslení si ax
,ay
nastavíme na dx
,dy
a ostatné súradnice vygenerujeme znova náhodne:
void draw()
{
beginShape();
vertex(ax,ay);
bezierVertex(bx, by, cx, cy, dx, dy);
endShape();
ax = dx;
ay = dy;
bx = random(ax - v, ax + v);
by = random(ay - v, ay + v);
cx = random(bx - v, bx + v);
cy = random(by - v, by + v);
dx = random(cx - v, cx + v);
dy = random(cy - v, cy + v);
}

Hladké nadväzovanie
Jednotlivé segmenty na seba náhodne nadväzujú, ale sú dosť kostrbaté. To preto, že na seba nenadväzujú hladko. Nový začiatok A je síce umiestnený tam, kde bol starý konec C, ale inak je krivka inak zaoblená. Takto to vyzerá zväčšené. Šípka označuje nadpojenie nového segmentu na starý.

Aby bolo napojenie hladké, musíme prispôsobiť nie len nový začiatok A starému koncu D, ale aj nové zaoblenie B starému koncu. Konkrétne takto:
void draw()
{
beginShape();
vertex(ax,ay);
bezierVertex(bx, by, cx, cy, dx, dy);
endShape();
ax = dx;
ay = dy;
bx = ax + dx - cx;
by = ay + dy - cy;
cx = random(bx - v, bx + v);
cy = random(by - v, by + v);
dx = random(cx - v, cx + v);
dy = random(cy - v, cy + v);
}
Nová krivka je už o poznanie hladšia:

Kozmetická úprava kódu:
Ak si všimnete, tak náhodné pozície C a D generujeme dvakrát úplne rovnako. Raz na konci v setup()
a druhý raz na konci v draw()
. Je to zbytočné a postačí, keď ich budeme generovať iba raz, a to na začiatku draw()
:
float ax,ay, bx,by, cx,cy, dx,dy;
float v = 30;
void setup()
{
size(400,400);
noFill();
ax = width/2;
ay = height/2;
bx = random(ax - v, ax + v);
by = random(ay - v, ay + v);
}
void draw()
{
cx = random(bx - v, bx + v);
cy = random(by - v, by + v);
dx = random(cx - v, cx + v);
dy = random(cy - v, cy + v);
beginShape();
vertex(ax,ay);
bezierVertex(bx, by, cx, cy, dx, dy);
endShape();
ax = dx;
ay = dy;
bx = ax + dx - cx;
by = ay + dy - cy;
}
Zaloopovanie krivky
Keď nám vylezie krivka von z okna, chceme ju vrátiť naspäť na opačnom okraji obrazovky. Pri lomenej čiare, stačilo prehodiť na opačný koniec obrazovky jeden bod. Tu máme ale krivku, tak budeme prehadzovať na opačný koniec dva body: A aj B.
Vyrobíme si na to podprogram zaloopuj()
, aby sme nemali už moc komplikovaný draw()
:
void zaloopuj()
{
if (ax > width)
{
ax = ax - width;
bx = bx - width;
}
if (ax < 0)
{
ax = ax + width;
bx = bx + width;
}
if (ay > height)
{
ay = ay - height;
by = by - height;
}
if (ay < 0)
{
ay = ay + height;
by = by + height;
}
}
A podprogram potom zavoláme na konci draw()
:
void draw()
{
cx = random(bx - v, bx + v);
cy = random(by - v, by + v);
dx = random(cx - v, cx + v);
dy = random(cy - v, cy + v);
beginShape();
vertex(ax,ay);
bezierVertex(bx, by, cx, cy, dx, dy);
endShape();
ax = dx;
ay = dy;
bx = ax + dx - cx;
by = ay + dy - cy;
zaloopuj();
}
Farba
Geometriu máme vyriešenú, poďme dekorovať. Nastavme farebný režim na HSB a pozadie na čierne:
void setup()
{
size(400,400);
noFill();
colorMode(HSB);
background(0);
ax = width/2;
ay = height/2;
bx = random(ax - v, ax + v);
by = random(ay - v, ay + v);
}
A v draw()
budeme pred každým vykreslením postupne posúvať farebný tón. V minulosti by sme si vyrobili časovú premennú t
a zvyšovali ju na konci draw()
o nejakú hodnotu. Ale ukážeme si iný spôsob.
Processing nám v systémovej premennej frameCount
hovorí, koľký krát sa práve vykresľuje draw()
. Koľký snímok v poradí sa práve vykresľuje. Preto frameCount
. Na začiatku je v tejto premennej uložená hodnota 1
a po každom draw()
sa automaticky zvyšuje o 1.
Použijeme ju teda na nastavenie farby pred vykreslením segmentu krivky:
stroke(frameCount, 255, 255);
beginShape();
vertex(ax,ay);
bezierVertex(bx, by, cx, cy, dx, dy);
endShape();

Akurát, že po istom čase je už krivka len červená, lebo nám frameCount
vyliezol nad hodnotu 255
. Tak ho po dosiahnutí 256
zrazíme naspäť na nulu pomocou %
:
stroke(frameCount % 256, 255, 255);
Hrúbka čiary
Zaujímavý efekt ako pri písaní štetcom docielime, ak budeme náhodne meniť hrúbku čiary pre každý segment:
stroke(frameCount % 256, 255, 255);
strokeWeight(random(2,10));
beginShape();
vertex(ax,ay);
bezierVertex(bx, by, cx, cy, dx, dy);
endShape();

Obrazový efekt cez image()
image()
Na záver ešte dorobíme vizuálny efekt, kedy sa vykreslený obraz postupne zväčšuje a tým aj rozostruje. Toto vyrobíme tak, že na konci každého draw()
si uložíme do premennej celý obsah obrazovky a na začiatku ďalšieho draw()
ho vykreslíme trochu zväčšený a trochu posunutý.
Vyrobíme si na to premennú špeciálneho typu PImage
, do ktorej sa dá uložiť obrázok.
float ax,ay, bx,by, cx,cy, dx,dy;
float v = 30;
PImage img;
Na konci draw()
si do premennej img
uložíme obsah obrazovky jednoduchým príkazom get()
:
void draw()
{
cx = random(bx - v, bx + v);
cy = random(by - v, by + v);
dx = random(cx - v, cx + v);
dy = random(cy - v, cy + v);
stroke(frameCount % 256, 255, 255);
strokeWeight(random(2,10));
beginShape();
vertex(ax,ay);
bezierVertex(bx, by, cx, cy, dx, dy);
endShape();
ax = dx;
ay = dy;
bx = ax + dx - cx;
by = ay + dy - cy;
zaloopuj();
img = get();
}
Na začiatku draw()
vykreslíme obrázok uložený v premennej img
príkazom image()
. Akurát, v úplne prvom draw()
ešte nie je v img
nič uložené, tak počítač by sa hneval. Aby sa to nedialo, tak si to ošetríme podmienkou, že img
sa vykresľuje iba, ak už som v neskoršom frame ako v prvom. Využijeme na to frameCount
, ktorý si pamätá, v ktorom frame teraz sme.
void draw()
{
if (frameCount > 1)
{
image(img, 0, 0);
}
cx = random(bx - v, bx + v);
cy = random(by - v, by + v);
dx = random(cx - v, cx + v);
dy = random(cy - v, cy + v);
stroke(frameCount % 256, 255, 255);
strokeWeight(random(2,10));
beginShape();
vertex(ax,ay);
bezierVertex(bx, by, cx, cy, dx, dy);
endShape();
ax = dx;
ay = dy;
bx = ax + dx - cx;
by = ay + dy - cy;
zaloopuj();
img = get();
}
Príkaz image()
má niekoľko parametrov. Prvý je obrázok, ktorý sa má vykresliť. Druhý a tretí parameter sú súradnice, odkiaľ sa má obrázok začať vykresľovať. Dali sme tam zatiaľ 0
,0
a preto sa nič nedeje. Obrázok na konci zosnímame z obrazovky a na začiatku ho vykreslíme do ľavého horného rohu obrazovky. Presne na to isté miesto, odkiaľ sme ho zobrali. Preto sa nič viditeľné nedeje.
Skúste upraviť volanie príkazu image()
takto:
image(img, 1, 1);
Obrázok bude ubiehať doprava dole:

Ak chceme, aby sa postupne zväčšoval, tak urobíme dve veci:
Začneme ho vykresľovať nie od 1,1 ale od -1,-1, takže bude začínať trochu mimo obrazovky vľavo hore
A vykreslíme ho väčší o 2 pixely než je obrazovka, takže bude končiť trochu mimo obrazovky vpravo dole.
Na nastavenie veľkosti vykresľovaného obrázka slúži tretí a štvrtý parameter v image()
:
image(img, -1, -1, width+2, height+2);
Toto je už efekt zväčšovania a s tým aj spojené rozostrenie, lebo obrázok je pixelový a pri jeho zväčšovaní dochádza k strate kvality:

Hotový skeč
Tu si môžete stiahnuť finálny skeč:
Last updated