You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
thebookofshaders/06/README-pl.md

19 KiB

Paul Klee - Color Chart (1931)

Kolory

Nie mieliśmy zbytnio okazji porozmawiać o typach wektorowych w GLSL. Zanim przejdziemy dalej, ważne jest żebyśmy dowiedzieli się o nich więcej, a temat kolorów może być w tym bardzo pomocny.

Jeżeli paradgymat programowania obiektowego jest ci bliski, to prawdopodobnie zauważyłeś, że proces wyciągania danych z wektorów wygląda podobnie przy C-podobnych struct'ach.

vec3 red = vec3(1.0,0.0,0.0);
red.x = 1.0;
red.y = 0.0;
red.z = 0.0;

Definiowanie kolor za pomocą notacji x, y i z jest trochę mylące, prawda? Właśnie dlatego istnieją inne sposoby dostępu do tej samej informacji, ale za pomocą różncyh nazw. Wartości .x, .y i .z mogą być również uzyskane za pomocą .r, .g i .b, jak i .s, .t i .p (.s, .t i .p są zwykle używane przy współrzędnych tekstur, które zobaczymy w następnych rozdziałach). Możesz również uzyskać dane wektora za pomocą indeksów [0], [1] i [2].

Następujący kod przedstawia wszystkkie sposoby uzysakania tych samych danych:

vec4 vector;
vector[0] = vector.r = vector.x = vector.s;
vector[1] = vector.g = vector.y = vector.t;
vector[2] = vector.b = vector.z = vector.p;
vector[3] = vector.a = vector.w = vector.q;

Ta mnogość metod uzyskiwania tych samych danych jest tylko po to, aby ułatwić pisanie zrozumiałego kodu. Ta elastyczność wbudowana w język shadingowy stanowi też okazję, żebyś zaczął myśleć o współrzędnych koloru i przestrzeni jako zamiennych.

Inną świetną własnością typów wektorowych w GLSL jest to, że współrzędne mogą być mieszane w dowolnej kolejności, co ułatwia castowanie i mieszanie wartości. Właśność ta nazywana jest swizzle'owaniem.

vec3 yellow, magenta, green;

// Tworzenie żółtego
yellow.rg = vec2(1.0);  // Przypisanie 1. do kanału czerwonego i zielonego
yellow[2] = 0.0;        // Przypisanie 0. do kanału niebieskiego

// Tworzenie magenty
magenta = yellow.rbg;   // Przypisanie wektora z przestawionym kanałem zielonym i niebieskim

// Tworzenie zielonego
green.rgb = yellow.bgb; // Przypisanie kanału niebieskiego do kanału czerwonego i niebieskiego

Mieszanie koloru

Teraz, gdy już wiesz jak definiuje się kolory, pora na połączenie tego z naszą wcześniejszą wiedzą. W GLSL istnieje bardzo przydatna funkcja mix(), która pozwala mieszać dwie wartości wobec określonego stosunku wyrażonego w procentach. Potrafisz zgadnąć jaki jest zakres procentów? Oczywiście, że 0.0 i 1.0! Czas na wykorzystanie naszego shadingowego karate!

Sprawdź linijkę 18 poniższego kodu i zoabcz jak używamy wartości bezwględnej z sinusa od czasu, aby mieszać colorA i colorB.

Pokaż na co cie stać:

  • Stwórz ekspresywną tranzycje między kolorami. Pomyśl o konkretnej emocji. Jaki kolor najlepiej ją reprezentuje? Jak wygląda? Jak zanika? Pomyśl o innej emocji i pasującym do niej kolorze. Zmień colorA i colorB w kodzie powyżej, aby pasowały do tych emocji. Następnie zanimuj tę tranzycję za pomocą funkcji kształtujących. Robert Penner stworzył serię popularnych funkcji kształtujących, z zasotoswaniami w animacji komputerowej, zwanych easing functions, skorzystaj z tego przykładu jako inspiracji, ale najlepsze rezultaty osiągniesz tworząc własne tranzycje.

Zabawa z gradientem

Funkcja mix() ma więcej do zaoferowania. Zamiast pojedynczego floata, możemy podać zmienną tego samego typu, co dwa pierwsze argumenty; w naszym wypadku jest to vec3. W ten sposób zdobywamy kontrolę nad stosunkiem mieszania każdego indywidualnego kanału koloru, r, g i b.

Spójrz na poniższy przykład. Tak jak w przykładach z poprzedniego rozdziału, podłączamy tranzycję do znormalizowanej współrzędnej x i wizualizujemy za pomocą linii. Aktualnie, wszystkie kanały leżą na tej samej linii.

Odkomentuj linjkę 25 i zobacz, co się stanie. Następnie odkomentuj linijki 26 i 27. Pamiętaj, że linie wizualizują stosunek mieszania każdego z kanałów wektorów colorA i colorB.

Prawdopodobnie rozpoznajesz trzy funkcje kształtującego, które używamy w linijkach 25 i 27. Baw się nimi! Czas pokazać swoje umiejętności z poprzednich rozdziałów, tworząc interesujące gradienty. Spróbuj następujących ćwiczeń:

William Turner - The Fighting Temeraire (1838)

  • Skomponuj gradient przypominający zachód słońca Williama Turnera.

  • Zanimuj tranzycje między wschodem i zachodem za pomocą u_time.

  • Czy potrafisz stworzyć tęczę korzystając z tego, czego nauczyliśmy się dotychaczas?

  • Użyj step(), by stworzyć kolorową flagę.

HSB

Nie da się mówić o kolorze bez poruszenia tematu przestrzeni barw. Jak prawdopodobnie wiesz, istnieją też inne sposoby reprezentacji koloru poza RGB (z kanałem czerwonym, zielonym i niebieskim).

HSB oznacza Hue (pol. "barwa"), Saturation (pol. "nasycenie") i Brightness (pol. "jasność) i jest o wiele bardziej intuicyjną reprezentacją koloru niż RGB. Czasem zamiast Brightness używa sie Value, stąd zamiast HSB można spotkać się też z HSV. Przyjrzyj się funkcjom rgb2hsv() i hsv2rgb() w następującym kodzie:

Mapując pozycję na osi x do barwy i pozycję na osi y do jasności, otrzymujemy spektrum widzialnych kolorów. O wiele bardziej intuicyjnie wybiera się kolor HSB niż RGB.

HSB we współrzędnych biegunowych

Oryginalnie, HSB miało być reprezentowane z pomocą współrzędnych biegunowych (opartych na kącie i promieniu), a nie kartezjańskich (opartych na x i y). By zpamować naszą funkcję HSB do współrzędnych biegunowych, musimy otrzymać kąt i dystans wektora od centrum kanwy do współrzędnej piksela. W tym celu użyjemy funkcje length() i atan(y,x) (który jest odpowiednikami atan2(y,x) w GLSL).

Uwaga: Jest weięcej funkcji geometrycznych poza length jak: distance(), dot(), cross, normalize(), faceforward(), reflect() i refract(). Ponadto, GLSL ma specjalne funkcje do porównywania wektorów: lessThan(), lessThanEqual(), greaterThan(), greaterThanEqual(), equal() i notEqual().

Gdy już zdobędziemy kąt i promień, musimy znormalizować ich wartości do zakresu od 0.0 do 1.0. W linijce 27, atan(y,x) zwróci kąt w radianach między -PI a PI (-3.14 a 3.14), więc musimy podzielić tę liczbę przez TWO_PI (zdefiniowane na górze kodu), uzyskując wartości między -0.5 i 0.5, które, przez proste dodawanie, mapujemy dalej do zakresu od 0.0 do 1.0. Promień ma długość 0.5 (ponieważ liczymy odległość od środka TODO kanwy), więc musimy podwoić ten zakres (mnożąc przez 2), by uzyskać 1.0.

Jak widzisz, sedno leży w transformowaniu i mapowaniu zakresów do 0.0 i 1.0.

Spróuj poniższych ćwiczeń:

  • Zmodyfikuj przykład ze współrzędnymi biegunowymi, aby uzyskać kręcące się (jak w ikonce czekania myszki) koło barw.

  • Użyj funkcji kształtującej razem z funkcją konwersji z HSB do RGB, aby rozszerzyć jedną barwę i zwężyć inną.

William Home Lizars - Red, blue and yellow spectra, with the solar spectrum (1834)

  • Jeśli przyjrzysz się uważnie kołom barw używanym w narzędziach do wybierania koloru (ang "color picker") (spójrz na obrazek poniżej), zobaczysz, że używają innego sepktrum koloru, zgodnego z przestrzenią barw RYB. Przykładowo, kolorem przeciwnym do czerwonego powienien być zielony, ale w naszym przykładzie jest cyjan. Czy potrafiłbyś zrekonstruować poniższy obrazek? [Wskazówka: to dobry moment, by użyć funkcji kształtujących]

Uwaga o funkcjach i ich argumentach

Zanim przeskoczysz do następnego rozdziału, zatrzymajmy się na chwilę. Wróć do funkcji hsb2rgb z poprzedniego interaktywnego przykładu. Zauważysz in przed typem argumentu. Jest to kwalifikator (ang. "qualifier") i akurat ten oznacza, że zmienna jest tylko do odczytu. W przyszłości zobaczymy, że jest również możliwe, by poprzedzić argumenty kwalifikatorami out i inout. out określa, że argument jest tylko do zapisu, natomiast inout działa podobnie jak przekazywanie argumentu przez referencje, co umożliwia modyfikowanie go.

int newFunction(in vec4 aVec4,      // read-only
                out vec3 aVec3,     // write-only
                inout int aInt);    // read-write

Może w to nie uwierzysz, ale mamy wszystkie składniki potrzbne do tworzenia fajnych rysunków. W następnym rozdziale nauczymy się jak połączyć wszystkie poznane tricki, by stworzyć geometryczne formy przez blendowanie przestrzeni. Dobrze słyszysz... blendowanie przestrzeni.

You may not believe it but now we have all the elements to make cool drawings. In the next chapter we will learn how to combine all our tricks to make geometric forms by blending the space. Yep... blending the space.