Ponieważ shadery wykonywane są piksel po pikselu, więc niezależnie od tego, jak często powtarzasz (duplikujesz) dany kształt, liczba obliczeń pozostaje stała. Oznacza to, że fragment shadery nadają się szczególnie do wzorów kafelkowych.
W tym rozdziale zamierzamy zastosować to, czego nauczyliśmy się do tej pory, dodając powtarzalność. Podobnie jak w poprzednich rozdziałach, nasza strategia będzie opierała się na mnożeniu współrzędnych przestrzeni (z przedziału 0.0 a 1.0), dzięki czemu kształty, które narysujemy pomiędzy wartościami 0.0 a 1.0, będą się powtarzać, tworząc siatkę.
Siatka (ang. "grid") zapewnia ramy, w których może działać ludzka intuicja i inwencja, i które może obalić. W chaosie natury wzory zapewniają kontrast i obietnicę porządku. Od wczesnych wzorów na ceramice do geometrycznych mozaik w rzymskich łaźniach, ludzie od dawna używali siatek, by wzbogacić swoje życie o dekoracje. " 10 PRINT, Mit Press, (2013)
Najpierw przypomnijmy sobie funkcję fract()
. Zwraca ona część ułamkową liczby, dzięki czemu fract()
to w istocie funkcja modulo jeden (mod(x,1.0)
). Innymi słowy, fract()
zwraca liczbę po przecinku. Nasza zmienna znormalizowanego układu współrzędnych (st
) już znajduje sie w zakresie od 0.0 do 1.0, więc nie ma sensu robić czegoś takiego jak:
void main(){
vec2 st = gl_FragCoord.xy/u_resolution;
vec3 color = vec3(0.0);
st = fract(st);
color = vec3(st,0.0);
gl_FragColor = vec4(color,1.0);
}
Ale jeśli przeskalujemy znormalizowany układ współrzędnych w górę - powiedzmy o trzy - otrzymamy trzy sekwencje interpolacji liniowych między 0-1: pierwszą między 0-1, drugą dla punktów między 1-2 i trzecią dla punktów między 2-3.
Teraz nadszedł czas, aby narysować coś w każdej podprzestrzeni, odkomentowując linię 27. (Ponieważ mnożymy x i y po równo, współczynnik proporcji przestrzeni nie zmienia się i kształty będą zgodne z oczekiwaniami).
Spróbuj wykonać niektóre z poniższych ćwiczeń, aby uzyskać głębsze zrozumienie:
-
Pomnóż przestrzeń przez różne liczby. Spróbuj z wartościami zmiennoprzecinkowymi, a także z różnymi wartościami dla x i y.
-
Zrób funkcję z tej kafelkowej sztuczki, abyś mógł ją ponownie wykorzystać.
-
Podziel przestrzeń na 3 wiersze i 3 kolumny. Znajdź sposób identyfikowania, w której kolumnie i rzędzie znajduje się wątek (piksel). Użyj tego, aby zmienić kształt, który jest wyświetlany. Spróbuj stworzyć mecz Kółko i krzyżyk
Ponieważ każdy kafelek jest pomniejszą wersją znormalizowanego układu współrzędnych, którego już używaliśmy, więc możemy zastosować do niego przekształcenie macierzowe w celu translacji, obrotu lub skalowania przestrzeni wewnątrz.
-
Pomyśl o ciekawych sposobach animacji tego wzoru. Rozważ animowanie koloru, kształtu i ruchu. Wykonaj trzy różne animacje.
-
Odtwórz bardziej skomplikowane wzory poprzez skomponowanie różnych kształtów.
- Połącz różne warstwy wzorów, aby skomponować własny szkocki tartan.
Powiedzmy, że chcemy odtworzyć mur z cegły. Patrząc na ścianę, można zauważyć przesunięcie pół cegły na osi x w co drugim rzędzie. Jak możemy to zrobić?
Jako pierwszy krok musimy wiedzieć, czy rząd naszego wątku (piksela) jest liczbą parzystą czy nieparzystą, co pomoże określić, czy musimy przesunąć x w tym rzędzie. W tym celu użyjemy mod()
z 2.0
, a następnie zobaczymy, czy wynik jest mniejszy niż 1.0
czy nie. Spójrz na poniższy kod i odkomentuj dwie ostatnie linie.
Jak widać możemy użyć operatora warunkowego do sprawdzenia czy mod()
z 2.0
jest mniejszy od 1.0
(druga linia) lub podobnie możemy użyć funkcji step()
, która wykonuje tę samą operację, ale szybciej. Dlaczego? Chociaż trudno jest wiedzieć jak każda karta graficzna optymalizuje i kompiluje kod, to można bezpiecznie założyć, że funkcje wbudowane są szybsze od tych niewbudowanych. Zawsze, gdy możesz użyć wbudowanej funkcji, użyj jej!
Korzystając z powyższej metody wykrywania liczb nieparzystych, możemy przesunąć nieparzyste rzędy, aby upodobnić naszą kawnę do ceglanej ściany. W linii 14 poniższego kodu identyfikujemy parzystość rzędów i nadajemy im przesunięcie na x
. Zauważ, że dla parzystych rzędów, wynikiem obliczeń w step()
jest 0.0
, co, mnożąc przez 0.5
, daje przesunięcie 0.0
. Natomiast w nieparzystych rzędach mnożymy 1.0
przez 0.5
, co powoduje przesunięcie osi x
układu współrzędnych o 0.5
.
Teraz spróbuj odkomentować linię 32 - rozciąga ona proporcje układu współrzędnych, aby odtworzyć wymiary "nowoczesnej cegły". Odkomentowując linię 40 możesz zobaczyć jak wygląda układ współrzędnych zmapowany na kolor czerwony i zielony.
-
Zanimuj ten przykład, zwiększając przesunięcie w zależności od czasu.
-
Zrób kolejną animację, w której parzyste wiersze przesuwają się w lewo, a nieparzyste w prawo.
-
Czy możesz powtórzyć ten efekt, ale z kolumnami?
-
Spróbuj połączyć przesunięcie na osi
x
iy
, aby uzyskać coś takiego:
Teraz, gdy dowiedzieliśmy się, jak określić, czy nasza komórka znajduje się w parzystym czy nieparzystym wierszu lub kolumnie, możliwe jest ponowne wykorzystanie pojedynczego elementu projektu w zależności od jego pozycji. Rozważmy przypadek kafelków Truchet'a, gdzie pojedynczy kafelek może być przedstawiony na cztery różne sposoby:
Zmieniając wzór na kafelkach, można zbudować nieskończony zestaw skomplikowanych wzorów.
Zwróć uwagę na funkcję rotateTilePattern()
, która dzieli przestrzeń na cztery komórki i każdej z nich przypisuje kąt obrotu.
-
Zakomentowywuj, odkomentowywuj i powielaj linie od 69 do 72, aby komponować nowe wzory.
-
Zmień czarno-biały trójkąt na inny element, taki jak: półkola, obrócone kwadraty lub linie.
-
Zakoduj inne wzory, w których elementy są obracane w zależności od ich położenia.
-
Zrób wzór, który zmienia inne właściwości w zależności od położenia elementów.
-
Pomyśl o czymś innym, co niekoniecznie jest wzorem, gdzie możesz zastosować zasady z tego działu. (Na przykład: heksagramy I Ching)
Tworzenie wzorców proceduralnych to ćwiczenie umysłowe polegające na znajdowaniu minimalnych elementów wielokrotnego użytku. Praktyka ta jest stara; my jako gatunek od dawna używamy siatek i wzorów do dekorowania tkanin, podłóg i obramowań obiektów: od meandrowych wzorów w starożytnej Grecji, po chińskie wzory kratowe, przyjemność z powtórzeń i wariacji przykuwa naszą uwagę i pobudza wyobraźnię. Poświęć trochę czasu, aby spojrzeć na dekoracyjne wzory i zobacz długą historię tego, jak artyści i projektanci poruszają się po cienkiej krawędzi między przewidywalnością porządku a niespodzianką zmienności i chaosu. Od arabskich wzorów geometrycznych do wspaniałych afrykańskich wzorów tkanin, istnieje cały wszechświat wzorów, z których można się uczyć.
Tym rozdziałem kończymy część poświęconą Rysowaniu Algorytmicznemu. W kolejnych rozdziałach dowiemy się, jak wprowadzić trochę entropii do naszych shaderów, tworząc generatywny design.