Proceduralne podejście do generowania tekstur



Podobne dokumenty
Proceduralne podejście do generowania tekstur

Programowanie gier 3D w HTML5. Andrzej P.Urbański Politechnika Poznańska

Rys.2.1. Drzewo modelu DOM [1]

WIZUALIZACJA INFORMACJI TEKSTOWEJ WSTĘP DO HTML 5 CANVAS

1 Temat: Vertex Shader

INSTRUKCJA UŻYTKOWNIKA. Spis treści. I. Wprowadzenie II. Tworzenie nowej karty pracy a. Obiekty b. Nauka pisania...

która metoda jest najlepsza

Aplikacja projektu Program wycinki drzew i krzewów dla RZGW we Wrocławiu

Smarty PHP. Leksykon kieszonkowy

KRYPTOGRAFIA I OCHRONA DANYCH PROJEKT

znajdowały się różne instrukcje) to tak naprawdę definicja funkcji main.

Wskaźniki a tablice Wskaźniki i tablice są ze sobą w języku C++ ściśle związane. Aby się o tym przekonać wykonajmy cwiczenie.

Gry Komputerowe Laboratorium 4. Teksturowanie Kolizje obiektów z otoczeniem. mgr inż. Michał Chwesiuk 1/29. Szczecin, r

Programowanie Procesorów Graficznych

Po zakończeniu rozważań na temat World Wide Web, poznaniu zasad organizacji witryn WWW, przeczytaniu kilkudziesięciu stron i poznaniu wielu nowych

1. Prymitywy graficzne

JAVAScript w dokumentach HTML (1)

Dodawanie grafiki i obiektów

Modele danych walidacja widoki zorientowane na model

GLKit. Wykład 10. Programowanie aplikacji mobilnych na urządzenia Apple (IOS i ObjectiveC) #import "Fraction.h" #import <stdio.h>

Expo Composer Garncarska Szczecin tel.: info@doittechnology.pl. Dokumentacja użytkownika

Programowanie obiektowe

E-geoportal Podręcznik użytkownika.

Ćwiczenie 6. Transformacje skali szarości obrazów

Instrukcja obsługi systemu zarządzania treścią dwajeden.pl

Technologie i usługi internetowe cz. 2

OpenGL : Oświetlenie. mgr inż. Michał Chwesiuk mgr inż. Tomasz Sergej inż. Patryk Piotrowski. Szczecin, r 1/23

XQTav - reprezentacja diagramów przepływu prac w formacie SCUFL przy pomocy XQuery

REFERAT PRACY DYPLOMOWEJ

Programowanie obiektowe

Pierwsze kroki z easy Soft CoDeSys Eaton Corporation. All rights reserved.

Tworzenie szablonów użytkownika

Programowanie w języku Python. Grażyna Koba

Rys. 1. Główne okno programu QT Creator. Na rysunku 2 oznaczone zostały cztery przyciski, odpowiadają kolejno następującym funkcjom:

Przewodnik użytkownika (instrukcja) AutoMagicTest

POMOC / INSTRUKCJA OBSŁUGI

Portal zarządzania Version 7.5

Wizualne systemy programowania. Wykład 11 Grafika. dr Artur Bartoszewski -Wizualne systemy programowania, sem. III- WYKŁAD

Zasady programowania Dokumentacja

Systemy wirtualnej rzeczywistości. Komponenty i serwisy

Laboratorium 1 - Programowanie proceduralne i obiektowe

Programowanie obiektowe

PLAN WYNIKOWY PROGRAMOWANIE APLIKACJI INTERNETOWYCH. KL IV TI 6 godziny tygodniowo (6x15 tygodni =90 godzin ),

Cw.12 JAVAScript w dokumentach HTML

Przewodnik po soczewkach

Podstawy programowania. Wykład Funkcje. Krzysztof Banaś Podstawy programowania 1

INSTRUKCJA OBSŁUGI ⓫ Dodatki

Tworzenie Stron Internetowych. odcinek 9

Zacznij Tu! Poznaj Microsoft Visual Basic. Michael Halvorson. Przekład: Joanna Zatorska

Dokumentacja systemu NTP rekrut. Autor: Sławomir Miller

PLAN WYNIKOWY PROGRAMOWANIE APLIKACJI INTERNETOWYCH. KL III TI 4 godziny tygodniowo (4x30 tygodni =120 godzin ),

lekcja 8a Gry komputerowe MasterMind

Programowanie w Javie 1 Wykład i Ćwiczenia 3 Programowanie obiektowe w Javie cd. Płock, 16 października 2013 r.

Niezwykłe tablice Poznane typy danych pozwalają przechowywać pojedyncze liczby. Dzięki tablicom zgromadzimy wiele wartości w jednym miejscu.

Microsoft Small Basic

Podstawy Programowania Obiektowego

Zad. 4: Rotacje 2D. 1 Cel ćwiczenia. 2 Program zajęć. 3 Opis zadania programowego

1 Wskaźniki i zmienne dynamiczne, instrukcja przed zajęciami

Karta przedmiotu. Podstawy programowania procesorów graficznych. realizowanego w ramach projektu PO WER

Jak posługiwać się edytorem treści

Wprowadzenie do programowania w języku Visual Basic. Podstawowe instrukcje języka

Pętle. Dodał Administrator niedziela, 14 marzec :27

Animacje z zastosowaniem suwaka i przycisku

Politechnika Gdańska Wydział Elektrotechniki i Automatyki Katedra Inżynierii Systemów Sterowania KOMPUTEROWE SYSTEMY STEROWANIA (KSS)

Algorytm. a programowanie -

0. OpenGL ma układ współrzędnych taki, że oś y jest skierowana (względem monitora) a) w dół b) w górę c) w lewo d) w prawo e) w kierunku do

Serwery aplikacji. dr Radosław Matusik. radmat

Programowanie Obiektowe GUI

PRZEWODNIK PO ETRADER ROZDZIAŁ XII. ALERTY SPIS TREŚCI

WYKONANIE APLIKACJI OKIENKOWEJ OBLICZAJĄCEJ SUMĘ DWÓCH LICZB W ŚRODOWISKU PROGRAMISTYCZNYM. NetBeans. Wykonał: Jacek Ventzke informatyka sem.

Zastosowania Robotów Mobilnych

Politechnika Poznańska Wydział Budowy Maszyn i Zarządzania

Wskaźnik może wskazywać na jakąś zmienną, strukturę, tablicę a nawet funkcję. Oto podstawowe operatory niezbędne do operowania wskaźnikami:

Lab 9 Podstawy Programowania

Zacznijmy więc pracę z repozytorium. Pierwsza konieczna rzecz do rozpoczęcia pracy z repozytorium, to zalogowanie się w serwisie:

Laboratorium 7 Blog: dodawanie i edycja wpisów

Podstawy JavaScript ćwiczenia

PHP: bloki kodu, tablice, obiekty i formularze

- Narzędzie Windows Forms. - Przykładowe aplikacje. Wyższa Metody Szkoła programowania Techniczno Ekonomiczna 1 w Świdnicy

Podstawy technologii WWW

Ulotka. Zmiany w wersji

2. Tablice. Tablice jednowymiarowe - wektory. Algorytmy i Struktury Danych

Dariusz Brzeziński. Politechnika Poznańska, Instytut Informatyki

Tworzenie stron internetowych z wykorzystaniem HTM5, JavaScript, CSS3 i jquery. Łukasz Bartczuk

Instrukcja obsługi narzędzia API

Delphi podstawy programowania. Środowisko Delphi

16) Wprowadzenie do raportowania Rave

INSTRUKCJA obsługi certyfikatów

Bartłomiej Filipek

Ustawienia personalne

Podstawy programowania, Poniedziałek , 8-10 Projekt, część 1

1. Dockbar, CMS + wyszukiwarka aplikacji Dodawanie portletów Widok zawartości stron... 3

Wprowadzenie do programowania aplikacji mobilnych

Ćwiczenie: JavaScript Cookies (3x45 minut)

Robert Barański, AGH, KMIW MathScript and Formula Nodes v1.0

6. Pętle while. Przykłady

Instrukcja do ćwiczenia P4 Analiza semantyczna i generowanie kodu Język: Ada

Korzystanie z aplikacji P-touch Transfer Manager

Transkrypt:

Proceduralne podejście do generowania tekstur Paweł Sabat Praca zamieszczona na http://noni.hswro.org Wersja bez obrazków na końcu Praca inżynierska Promotor: dr Przemysław Kobylański Wydział Podstawowych Problemów Techniki Politechnika Wrocławska Wrocław 2014

1 Wstęp Celem projektu inżynierskiego było zaimplementowanie przykładowych technik tekstur proceduralnych przy użyciu jednej z najnowszych technologii internetowych - WebGL 1.0. Obowiązkowym elementem pracy jest implementacja wybranych technik, oraz zaprezentowanie ich. Ważnym elementem jest też możliwość modyfikowania parametrów i oglądania wyników w czasie rzeczywistym. Znaczna część technik i informacji o nich jest zaczerpnięta z książki Texturing & Modeling. A procedural approach [1]. Kod bazowej funkcji - noise - został zaczerpnięty ze strony https://github.com/ashima/webglnoise [NOISE]. Pełny spis pozycji które wykorzystywano przy pisaniu pracy znajduje się w dziale Literatura. Praca składa się z następujących rozdziałów 1. Wstęp - opis celu projektu inżynierskiego 2. Wyjaśnienie pojęć - wprowadzanie i wyjaśnienie niezbędnych pojęć 3. Wstęp do tekstur proceduralnych - wyjaśnienie czym są tekstury proceduralne, gdzie się je używa i z jakich powodów 4. Użyte technologie - ogólny opis użytych technologii, oraz podrozdział przybliżający temat WebGL 1.0 5. Wymagania, uruchamianie programu, różnice między przeglądarkami 6. Szkielet programu - ogólny opis kodu bazowego, współdzielonego przez wszystkie strony 7. Noise - opis niezbędnej funkcji będącej podstawą wszystkich zaimplementowanych efektów 8. Zaimplementowane techniki - wyjaśnienie i opis 9. Ograniczenia technologii 10. Podsumowanie Literatura 2 Wyjaśnienie pojęć model Komputerowa reprezentacja obiektu. 1

tekstura Obraz nakładany na model w celu nadania mu bardziej realnego wyglądu przy jedoczesnym niskim nakładzie obliczeniowym. tekstura proceduralna Tekstura wygenerowana przez komputer, a nie stworzona przez człowieka. Jako tekstury proceduralne nie są zaliczane też procedury malowane w programach graficznych. API Application Programming Interface - zestaw interfejsów do wykonywania określnego zadania. OpenGL API do renderowania grafiki 3D. OpenGl ES API do renderowania grafiki 3D na urządzeniach mobilnych. Okrojone w stosunku do OpenGL. WebGL API do renderowania grafiki 3D dostępne z poziomu przeglądarki internetowej za pomocą javascript. Shader Program uruchamiany na karcie graficznej służący do przetwarzania grafiki 3D i generowania obrazu. GLSL Język programowania w którym pisane są shadery. Vertex Punkt w przestrzeni i powiązane z nim atrybuty np. jego pozycja czy kolor. Vertex shader Shader, który odpowiada za przetwarzanie vertexów np. zmienianie ich pozycji przez przesunięcie czy obrót. Fragment Dane, które mogą posłużyć do wygenerowania pixela. Fragment shader Shader, który odpowiada za przetworzenie fragmentów, w szczególności obliczenie koloru możliwego pixela. 2

Pixel Najmniejszy wyświetlany fragment obrazu. Zlepek słów od ang. picture element. Noise Funkcja, która w wersji idealnej powinna spełniać następujące kryteria: dla tego samego argumentu da to samo wyjście jej wartość jest w przedziale -1 do 1 ma ograniczoną częstotliwość z dołu i z góry, z czego maksymalna częstotliwość to ok. 1 nie posiada oczywistych regularności ani krótkiego okresu jest stacjonarna, czyli jej statystyczne właściwości nie zmieniają się po translacji jest izotropiczna, czyli jej statystyczne właściwości nie zmieniają się przy rotacji 3 Wstęp do tekstur proceduralnych 3.1 Czym są? Tekstury proceduralne to tekstury wygenerowane przez komputer. Za tekstury proceduralne uważa się np. wartości funkcji przekształcone do postaci możliwej do użycia jako kolor pixela, ale już np. nie będzie teksturą proceduralną obraz malowany w photoshop ie mimo że całkowicie zostaje stworzony przez oprogramowanie. Jest kwestią dyskusyjną, czy obraz stworzony przez np. ręczne nakładanie na siebie tekstur proceduralnych w celu uzyskania pożądanego efektu jest też teksturą proceduralną. 3.2 Jakie są zalety i wady tekstur proceduralnych? Tekstury proceduralne mają następujące zalety: są bardzo małe w porównaniu z obrazami zapisanymi w plikach potrafią generować bardzo skomplikowane wzory można łatwo kontrolować ich poziom szczegółów przy powiększaniu- /zmniejszaniu Tekstury proceduralne mają następujące wady: ciężko jest stworzyć teksturę z pożądanym efektem 3

ciężkie lub niemożliwe jest kontrolowanie pojawiających się szczegółów wymagają sporej wiedzy nt. programowania, grafiki, obycia i dużej wyobraźni 3.3 Jak się tworzy tekstury proceduralne Tekstury proceduralne tworzy się przez napisanie odpowiedniego kodu, który wygeneruje obraz. Ponieważ wyniki takiego programu często są zaskakujące i nieprzewidziane, tworzenie tekstur proceduralnych to w dużym stopniu wprowadzanie możliwych modyfikacji do już istniejącego kodu i sprawdzanie wyników już w postaci wygenerowanego obrazu. Jest to więc bardziej sztuka niż nauka ścisła, w której można zawsze z góry przewidzieć jaki obraz się wygeneruje. 4 Użyte technologie Praca wykorzystuje technologie: HTML5 JavaScript WebGL 1.0, GLSL ES 1 HTML5 oraz JavaScript to trzon wszystkich współczesnych aplikacji webowych. Służą one do prezentowania treści (HTML5) oraz do tworzenia bardziej interaktywnych i dynamicznych stron (JavaScript). Ponieważ technologie te są powszechnie znane, pomija się ich dokładniejszy opis. 4.1 WebGL 1.0, GLSL ES 1 WebGL 1.0 to opublikowane po raz pierwszy w 2011 roku [WEBGL100] API do renderowania grafiki 3D zaprojektowane do użycia w sieci. WebGL 1.0 jest oparte na OpenGL ES 2.0, stąd posiada bardzo podobne możliwości, z tą różnicą że WebGL jest przeznaczone do użycia z elementem HTML5 Canvas [WEBGL10]. Dostęp do API WebGL jest uzyskiwane przez kontekst pobrany z elementu canvas [WEBGL10, HTML5]. 1 var canvas = document. getelementbyid ( some canvas id ) 2 var context = canvas. getcontext ( webgl ) Po pobraniu kontekstu można zacząć programować pod WebGL. WebGL jest jedynie narzędziem pośredniczącym. Odpowiada ono za ustawienie rzeczy pod renderowanie grafiki 3D (stworzenie buforów, dostarczenie danych) oraz za wywołanie funkcji, w wyniku której zostanie wyświetlony 4

obraz. Kod wywołujący funkcje WebGL to JavaScript, zatem jest wykonywany po stronie procesora. Z drugiej strony są shadery. Są to małe programy, dla WebGL 1.0 pisane w języku OpenGL ES Shading Language 1 (w skrócie GLSL ES 1) i odpalane na karcie graficznej. To one odpowiadają za przetworzenie dostarczonych danych i ich renderowanie. Aby zrozumieć, jak te technologie współdziałają ze sobą, należy zapoznać się z przepływ danych w WebGL. Został on przejrzyście przestawiony i wyjaśniony w książce [2]. W uproszczeniu wygląda następująco: bufory danych vertex shader fragment shader ekran Bufory danych to pamięć na karcie graficznej, do której wgrano informacje potrzebne do wyświetlenia obiektu. Są to np.: położenie verteksów w przestrzeni kolor każdego verteksa normalna do verteksa ilość odbijanego światła Niezbędnym jest jedynie położenie verteksów w przestrzeni, ponieważ bez tego nie mamy kształtu do wyświetlenia. Wszystkie pozostałe paramtery są całkowicie opcjonalne. Za tworzenie buforów i wgrywanie do nich danych odpowiada WebGL. Vertex shader odpowiada za przekształcenia położenia verteksów w przestrzeni. Pozwala on np. na obrót obiektów na scenie poprzez zaaplikowanie odpowiedniej transformacji na każdym verteksie tworzącym dany obiekt. W tej pracy inżynierskiej vertex shader używa się jedynie do transformacji wyświetlanego obszaru do przedziału [0, 1] 2. Fragment shader odpowiada za ustalenie jakiego koloru ma być wyświetlany piksel. Jego zadaniem jest nakładanie tekstur na obiekty, aplikowanie efektów specjalnych czy światła na scenie. Ponieważ fragment shader odpowiada za kolor, kod w nim zawarty odpowiada za wszystkie efekty generowane w ramach tej pracy inżynierskiej i stanowi najważniejszą jej część. Verteks shader oraz fragment shader razem tworzą tzw. program, który stanowi całość i może zostać użyty przy kolejnym wywołaniu funkcji rysującej. Program będzie dalej nazywany jako webgl program, żeby nie powodować dezorientacji. Całość akcji niezbędnych do wyświetlenia obrazu na ekranie przy użyciu WebGL 1.0 w uproszczeniu przestawia się następująco: 1. stwórz webgl program 2. stwórz vertex shader 5

3. załaduj źródła do vertex shadera 4. skompiluj vertex shader 5. dodaj vertex shader do webgl programu 6. stwórz fragment shader 7. załaduj źródła do framgent shadera 8. skompiluj fragment shader 9. dodaj fragment shader do webgl programu 10. zlinkuj webgl program 11. ustaw webgl program jako aktualnie używany 12. utwórz bufor na atrybuty verteksów 13. wgraj dane do bufora 14. podepnij bufor pod odpowiedni atrybut fragment shadera 15. wywołaj funkcję rysującą prymitywy Z powodu tak wielu niezbędnych akcji do narysowania nawet najprostszego kształtu na ekranie, WebGL posiada początkowo bardzo stromą krzywą uczenia się. Nie jest możliwe rozbicie tych etapów na mniejsze, łatwiej przyswajalne i niezależne części, ponieważ wszystkie one są niezbędne. Osoba chcąca zrozumieć działanie całego procesu powinna zajrzeć do pozycji [2], oraz uzupełniająco do [WEBGL10] oraz [GLES20]. 5 Wymagania, uruchamianie programu, różnice między przeglądarkami Całość pracy została napisana w postaci stron internetowych. Nie jest więc wymagana instalacja. Wystarczy uruchomić odpowiednią stronę. Wymagane za to są: przeglądarka internetowa obsługująca HTML5, javascript, WebGL 1.0 włączona obsługa WebGL w przeglądarce dostępna akceleracja 3D w systemie 6

Program był uruchamiany na Firefox 27, Chrome 33, Internet Explorer 11 pod Windows 7. Na wszystkich przeglądarkach działa, jednak z powodu różnic między przeglądarkami strony wykazują trochę odmienne zachowanie. Firefox oraz IE nie obsługują pola color w formularzach HTML5, stąd pole to jest w nich wyświetlane jedynie jako tekst z wartością koloru w postaci #RRGGBB, tak jak w CSS. Wartości te można ręcznie modyfikować. W Chrome pole to jest wyświetlane w postaci przycisku wyświetlającego aktualnie wybrany kolor, który po kliknięciu pozwala wybrać inny kolor z palety kolorów. Firefox nie przesyła na bieżąco powiadomień do strony nt. modyfikacji pola typu range w trakcie przesuwania. Stąd obraz jest odświeżany dopiero po puszczeniu suwaka. W Chrome oraz IE powiadomienia o zmianie wartości są przesyłane na bieżąco, dzięki czemu można w trakcie obserwować zmiany jakie to powoduje w generowanym obrazie. IE pyta za każdym razem czy pozwalać stronie na włączenie zablokowanych skryptów. Żeby strona działała, niezbędna jest zgoda użytkownika. Program nie był testowany w przeglądarce Opera. WebGL jest tam domyślnie wyłączony i trzeba go najpierw aktywować. 6 Opis szkieletu programu Wszystkie strony składają się z wcześniej utworzonego kodu szkieletowego, który następnie był powielany i dostosowywany na potrzeby danego efektu. Różnice między poszczególnymi efektami to przede wszystkim kod fragment shadera oraz kontrolki pozwalające na wygodną zmianę przekazywanych parametrów. Poniżej przedstawiam główne elementy szkieletu. Dokładne opisy użytych tutaj funkcji znajdują się w specyfikacjach [HTML5, WEBGL10, GLES20, GLES20GLSL]. Ogromnie przydatną pozycją, bez której ciężko byłoby napisać cokolwiek jest książka [2]. Implementacja szkieletu wykorzystuje bibliotekę ze strony [MATRIX] do operacji na macierzach. Opis teoretyczny przekształceń przestrzeni na macierzach, ich znaczenie i wyprowadzenie znajduje się w znakomitej pozycji [3]. Zakładam, że w zmiennej gl znajduje się kontekst elementu canvas. 1 var canvas = document. getelementbyid ( some canvas id ) 2 var g l = canvas. getcontext ( webgl ) 6.1 Tworzenie shadera 1 f u n c t i o n getshader ( gl, tagid, shadertype ) 2 { 3 var shadernode = document. getelementbyid ( t a g I d ) ; 4 var shadersrc = shadernode. innerhtml ; 7

5 6 var shader = g l. createshader ( shadertype ) ; 7 g l. shadersource ( shader, shadersrc ) ; 8 g l. compileshader ( shader ) ; 9 10 i f ( g l. getshaderparameter ( shader, g l. COMPILE STATUS )!= true ) 11 { 12 a l e r t ( tagid + shader compilation f a i l e d \n\n + g l. getshaderinfolog ( shader ) ) ; 13 r eturn n u l l ; 14 } 15 16 return shader ; 17 } Powyższa funkcja odpowiada za: utworzenie shadera wyciągnięcia źródeł z elementu strony o przekazanym id wstawienie źródeł do shadera skompilowanie shadera ewentualną obsługę błędów podczas kompilacji Pierwsze dwie linijki w ciele funkcji odpowiadają za uzyskanie kodu źródłowego dla shadera. Następnie tworzony jest shader, do którego wstawiane są źródła shadera, po czym następuje kompilacja. Jeśli wystąpiły błędy są one wyświetlane za pomocą powiadomienia alert i zwracany jest null. Jeśli wszystko przebiegło pomyślnie, funkcja zwraca skompilowany shader. Aby przekazać źródła shadera do funkcji gl.shadersource, trzeba je mieć w zmiennej typu string. Niektórzy autorzy stron używających WebGL piszą shader bezpośrednio jako string, jednak jest to wysoce niewygodne. Innym rozwiązaniem, używanym np. na stronie http://learningwebgl.com/ jest wstawienie kodu shadera do tagu 1 <s c r i p t type = xxx id = s c r i p t i d >... </ s c r i p t > gdzie xxx to typ skryptu, który przeglądarka nie rozpoznaje. Domyślnym zachowaniem przeglądarki jest zignorowanie takiego elementu, a dzięki przypisanemu id jest możliwe odwołanie się do tego elementu w dalszych skryptach. 1 var scriptelement = document. getelementbyid ( s c r i p t i d ) ; 8

Aby wyciągnąć tekst shadera z elementu, który już został znaleziony można posłużyć się jedną z dwóch metod: użyć API HTML DOM (Document Object Model) użyć atrybutu innerhtml Użycie HTML DOM polega na pobraniu wszystkich węzłów zawartych w uzyskanym elemencie i sklejeniu zawartości węzłów tekstowych. Jest to jednak niepotrzebne, ponieważ istnieje drugi sposób. Atrybut innerhtml zawiera tekstową reprezentację elementów zawartych w ciele elementu, na którym ten atrybut jest sprawdzany. Stąd można łatwo i wygodnie uzyskać treść shadera ze skryptu. 1 var source = scriptelement. innerhtml ; W pracy tej użyto sposobu drugiego. 6.2 Tworzenie i używanie webgl programu 1 // c r e a t e program 2 var program = g l. createprogram ( ) ; 3 // add shaders to program 4 g l. attachshader ( program, vertexshader ) ; 5 g l. attachshader ( program, fragmentshader ) ; 6 // l i n k program 7 g l. linkprogram ( program ) ; 8 i f ( g l. getprogramparameter ( program, g l. LINK STATUS )!= true ) 9 { 10 a l e r t ( Program l i n k i n g f a i l e d + g l. getprograminfolog ( program ) ) ; 11 r eturn ; 12 } 13 // s e t to use program 14 g l. useprogram ( program ) ; W pierwszej linijce tworzony jest webgl program. Następnie dodawane są do niego wcześniej utworzone shadery za pomocą funkcji getshader(), po czym następuje linkowanie. Ponieważ vertex shader i fragment shader ściśle ze sobą współpracują, muszą one być ze sobą zgodne: zmienne przez które parametry są przekazywane z jednego do drugiego (zmienne typu varying) muszą mieć takie same nazwy i typy w obu 9

zmienne uniform przez które przekazywane są parametry globalne dla shaderów muszą mieć zgodne nazwy jeśli są użyte w obu Dodatkowo na shadery są narzucone pewne ograniczenia, takie jak maksymalna ilość zmiennych typu uniform. Wszystkie te rzeczy są sprawdzane podczas linkowania. Jeśli w trakcie linkowania nastąpiły błędy, są one wyświetlane. W przeciwnym razie webgl program jest ustawiany jako aktualnie używany. Od tej pory wszystkie wyświetlane kształty będą przez niego przetwarzane. 6.3 Przekazywanie danych do webgl programu Dane do webgl programu są przekazywane przez dwa typy zmiennych: uniform attrib 6.3.1 uniform Zmienne typu uniform można traktować jak zmienne globalne w ramach programu. Wartość tych zmiennych jest przypisana przed uruchomieniem funkcji wyświetlającej, zatem podczas pracy shadera, wartość zmiennych uniform jest stała. W zmiennych tych zapisuje się np. macierz transformacji dla verteksów. Wszystkie parametry dostępne do modyfikacji na stronach implementujących techniki proceduralne są przekazywane przez zmienne typu uniform, np. kolory. 1 uniform vec3 c o l o r a t 0 ; 2 uniform vec3 c o l o r a t 1 ; Ustawianie wartości typu uniform odbywa się przez wywołanie funkcji WebGL. Zmienna typu uniform przyjmuje dokładnie jedną wartość, która w trakcie działania shadera się nie zmienia. Bufor na dane jest więc niepotrzebny. 1 program vars. s c a l e = g l. getuniformlocation ( program, c o l o r a t 0 ) 2 g l. uniform3f ( program vars. c o l o r a t 0, 1. 0, 1. 0, 0. 0 ) W pierwszej linijce pobierana jest lokalizacja zmiennej uniform o nazwie color at 0. Lokalizacja ta służy jako id dla zmiennej w programie. Następnie do zmiennej tej (pod jej lokalizację) jest wstawiana wartość (1.0, 1.0, 0.0), co odpowiada kolorowi żółtemu. Pozostałe parametry dostępne do modyfikacji na stronie (scale, threshold,... ) też są zmiennymi typu uniform, tak samo jak color at 0, są więc przekazywane do shadera w analogiczny sposób. 10

6.3.2 attrib Zmienne typu attrib są parametrami wejściowymi dla shadera, które mogą być różne dla każdego verteksa. Wartość zmiennych attrib jest ustalana na stałe lub pobierana z ustalonego wcześniej bufora. W zmiennych tych przechowuje się wszelkie atrybuty unikalne dla verteksów np. ich pozycja czy kolor. Zmienne typu attrib mogą być przekazywane tylko do verteks shadera. Stąd, żeby fragment shader dostał parametr unikalny dla każdego verteksa, verteks shader musi go przekazać fragment shaderowi. Ustawianie wartości typu attrib zostanie omówione na przykładzie poniższego kodu. 1 // v a l u e s f o r apos w i l l be taken from array 2 var vsposindex = g l. g e t A t t r i b L o c a t i o n ( program, apos ) ; 3 i f ( vsposindex == 1 ) 4 { 5 a l e r t ( I n v a l i d a t t r i b u t e name in g e t A t t r i b L o c a t i o n ( ) ) ; 6 return ; 7 } 8 g l. enablevertexattribarray ( vsposindex ) ; 9 10 // s e t some p o i n t s 11 var v e r t i c e s = [ 12 0. 0, 1. 0, 0. 5, 13 0. 0, 0. 0, 0. 5, 14 1. 0, 1. 0, 0. 5, 15 1. 0, 0. 0, 0. 5 16 ] ; 17 18 // c r e a t e b u f f e r f o r v e r t i c e s 19 v e r t B u f f e r = g l. c r e a t e B u f f e r ( ) ; 20 g l. bindbuffer ( g l.array BUFFER, v e r t B u f f e r ) ; 21 // put v e r t i c e s i n t o b u f f e r 22 g l. bufferdata ( g l.array BUFFER, new Float32Array ( v e r t i c e s ), g l.static DRAW ) ; 23 24 // say that v a l u e s f o r vertexshader. pos should be taken from v e r t B u f f e r 25 g l. v e r t e x A t t r i b P o i n t e r ( vsposindex, 3, g l.float, f a l s e, 0, 0 ) ; Najpierw trzeba pobrać lokalizację atrybutu w programie. Lokalizacja ta służy jako id dla zmiennej w programie. W tym celu przekazuje się program 11

oraz nazwę zmiennej do funkcji getattriblocation(), która zwraca żądaną lokalizację. Następnie ustawiane jest, że zmienna apos (jej lokalizacja jest w vsposindex) ma mieć wartości pobierane z bufora, a nie ustalone na jedną wartość. Dalej tworzona jest tablica pozycji kolejnych verteksów oraz bufor na nie, po czym bufor ten zostaje ustawiony jako aktualny ARRAY BUFFER. W tym momencie wszystko co zostaje wykonane na ARRAY BUFFER będzie dotyczyło vertbuffer. Należy zaznaczyć, że bufor ten znajduje się w pamięci karty graficznej, a nie w pamięci RAM. Ponieważ funkcja bufferdata() przyjmuje jedynie tzw. typed arrays, trzeba skonwertować tablicę vertices na tablicę typed array odpowiedniego typu. Zajmuje się tym funkcja Float32Array(). Szczegóły dotyczące typed arrays są w odpowiedniej specyfikacji [TYPEDARRAY]. Po konwersji na tablicę typed array dane z vertices są wstawiane do bufora aktualnie przypisanego do ARRAY BUFFER, czyli do wcześniej utworzonego vertbuffer. Na koniec bufor ten zostaje powiązany z atrybutem apos, którego kolejne wartości będą brane z właśnie przypisanego bufora. 6.4 Rysowanie wprowadzonych danych Gdy wszystko zostanie już ustalone należy wywołać jedną z dwóch funkcji rysujących: drawarrays() bądź drawelements(). Obie z tych funkcji rysują prymitywy takie jak: punkty linie trójkąty drawarrays() bierze jednak kolejne verteksy z bufora, natomiast drawelements() bierze verteksy z bufora wedle indeksów przechowywanych w innym buforze. Pozwala to zaoszczędzić pamięć, jeśli duża liczba verteksów w wyświetlanym kształcie się powtarza. Ponieważ jednak w tej pracy wykorzystuje się jedynie dwa trójkąty do wyświetlania obrazu, używana jest funkcja drawarrays(). 1 // f i n a l l y show what we ve done 2 g l. drawarrays ( g l. TRIANGLE STRIP, 0, v e r t i c e s. l e n g t h /3) ; Powyższa funkcja powoduje wyświetlenie trójkątów zbudowanych z 4 verteksów (w vertices jest 12 punktów), bez żadnego offsetu. Trójkąty są bufowane za pomocą trybu TRIANGLE STRIP, który bierze dwa pierwsze verteksy, po czym dla każdego kolejnego tworzy trójkąt zbudowany z aktualnego verteksa i dwóch poprzednich. 12

6.5 Interfejs użytkownika Interfejs użytkownika został stworzony na bazie HTML5. Na każdej ze stron zawiera on canvas na którym wyświetlany jest generowany obraz, oraz odpowiednie kontrolki podpięte pod zmienne uniform shaderów. Obraz jest odświeżany przy każdej zmianie dowolnego parametru, dzięki czemu można od razu oglądać wyniki dokonanych zmian. Zakresy kontrolek zostały dobrane eksperymentalnie, tak żeby najlepiej było widać tworzące się ciekawe zachowania generowanego obrazu. Stąd w pewnych teksturach ten sam parametr może mieć większy zakres, bądź inną granulację. W zależności od tekstury dodano też do stron dodatkowe paramtery kontrolujące nowe funkcje, tak żeby udostępnić użytkownikowi nie tylko podstawowy zakres modyfikacji parametrów, ale też dać mu nowe możliwości kontroli. 7 Noise Bazą prawie wszystkich stworzonych efektów jest funkcja noise. Bazuje ona na rozmieszczeniu watości losowych na n-wymiarowej kracie, których suma przemnożona przez współczynniki jest zwracana jako wartość. Współczynniki te zależą od punktu w którym chcemy obliczyć wartość funkcji i zawsze są równe zero oprócz komórek kratki w bezpośrednim otoczeniu punktu. Szczegółowe omówienie implementacji znajduje się w książce [1]. Implementacja funkcji noise wykorzystana w tej pracy została pobrana ze strony [NOISE]. Implementacja ta jest powszechnie używana nie tylko w swojej oryginalnej postaci, ale też przepisywana do innych języków. Z powodu ograniczeń technologii implementacja ta jest wklejona bezpośrednio w kod źródłowy każdej strony, a nie zaimportowana osobno z pliku. 8 Zaimplementowane techniki Techniki tekstur proceduralnych zostały zaimplementowane i osadzone w stronach internetowych, we wcześniej opisany sposób. Nazwy poniższych podrozdziałów odpowiadają nazwom poszczególnych stron zawierających implementację odpowiedniej techniki. Opisy kolejnych stron nie zawierają rzeczy opisane na stronach wcześniejszych. Stąd jeśli czytelnik ma wątpliwości, należy przeczytać opis wcześniejszych technik. Obrazy prezentujące poszczególne techniki dla różnych parametrów zostały zamieszczone na końcu pracy inżynierskiej. 13

8.1 01 noise Strona przedstawia jak wygląda noise bez żadnych dodatkowych przekształceń. Ponieważ antydziedzina funkcji noise jest wartością z przedziału [ 1.0, 1.0], musi ona zostać przekształcona na przedział [0.0, 1.0] żeby mogła być wyświetlona. Przekształceniem zastosowanym jest tutaj bezpośrednie odwzorowanie odcinka [ 1.0, 1.0] na odcinek [0.0, 1.0]. 1 f l o a t n o i s e = ( c n o i s e ( vpos. xy ) + 1. 0 ) / 2. 0 ; Dodatkowo użyty jest parametr scale pozwalający na przeskalowanie wektora wejściowego dla noise, dzięki czemu można kontrolować stopień powiększenia funkcji w generowanym obrazie. 1 f l o a t n o i s e = ( c n o i s e ( vpos. xy s c a l e ) + 1. 0 ) / 2. 0 ; Wartość wynikowa funkcji noise jest poddana przekształceniu przez funkcję wykładniczą. W ramach ekperymentowania uznano, że funkcja wykładnicza najlepiej nadaje się do przekształcania wartości wyjściowej. Ma ona te zalety, że jest ciągła, monotonicznie rosnąca w przedziale [0.0, 1.0], a wartości z odcinka [0.0, 1.0] poddane przekształceniu nigdy poza niego nie wychodzą. Dodatkowo efekty jakie powstają przez takie przekształcenie są w wielu przypadkach interesujące. Na stronie wartość pow factor jest nazywana threshold z powodu efektu jaki zdaje się ona mieć na generowany obraz. 1 f l o a t f a c t o r = pow( noise, pow factor ) ; Ostatnim elementem jest możliwość wybrania koloru dla wartości 0.0 oraz 1.0. Kolor, który jest wyświetlany jest interpolowany między wybranymi kolorami zgodnie z wartością powyższej zmiennej factor. 1 gl F r a g C o l o r = mix ( c o l o r 0, c o l o r 1, f a c t o r ) ; 8.2 01a noise abs Strona ta jest identyczna z 01 noise poza jednym przekształceniem. W 01 noise wartość funkcji noise jest przekształcona przez przesunięcie i przeskalowanie, tak żeby wartości były w przedziale [0.0, 1.0]. Natomiast w 01a noise abs użyto wartości bezwzględnej do przekształcenia wartości funkcji noise. 1 f l o a t n o i s e = abs ( c n o i s e ( vpos. xy s c a l e ) ) ; Ciekawe jest, że tak drobna zmiana ma znaczący wpływ na generowany obraz. Zamiast rozmytych, nieokreślonych kształtów wyraźnie widać linie oddzielające fragmenty. 14

8.3 02 fractalsum Kod fractalsum został oparty na kodzie (książka [1], s.85): 1 f l o a t 2 f r a c t a l s u m ( point Q) 3 { 4 f l o a t value = 0 ; 5 f o r ( f = MINFREQ; f < MAXFREQ; f = 2) 6 value += s n o i s e (Q f ) / f ; 7 return value ; 8 } który przedstawia ideę nakładania kolejnych wartości funkcji na siebie, jednak za każdym razem w innej skali i z innego punktu. Jest to ciekawe narzędzie, które można wykorzystywać w wielu różnych miejscach. Kod 02 fractalsum został oparty bezpośrednio na tym kodzie, a interesujący fragment wygląda następująco: 1 f l o a t f r a c t a l s u m ( vec2 point ) 2 { 3 f l o a t value = 0. 0 ; 4 f l o a t f r e q = 1. 0 ; 5 6 value += c n o i s e ( point ) ; // c n o i s e ( point 1. 0 ) / 1. 0 ; 7 value += c n o i s e ( point 2. 0 ) / 2. 0 ; 8 value += c n o i s e ( point 4. 0 ) / 4. 0 ; 9 value += c n o i s e ( point 8. 0 ) / 8. 0 ; 10 11 return clamp ( value, 1.0, 1. 0 ) ; 12 } 13 14 void main ( void ) 15 { 16 vec4 c o l o r 0 = vec4 ( c o l o r a t 0, 1. 0 ) ; 17 vec4 c o l o r 1 = vec4 ( c o l o r a t 1, 1. 0 ) ; 18 19 f l o a t value = ( f r a c t a l s u m ( vpos. xy s c a l e ) + 1. 0 ) / 2. 0 ; 20 f l o a t f a c t o r = pow( value, pow factor ) ; 21 g l F r a g C o l o r = mix ( c o l o r 0, c o l o r 1, f a c t o r ) ; 22 } Pętla w funkcji fractalsum została ręcznie rozwinięta, z powodu ograniczeń narzuconych na pętle w GLSL ES 1.0. Szczegóły ograniczeń są w 15

[GLES20GLSL] Appendix A, sekcja 4 Control Flow. Dodatkowo użyto funkcji clamp na obliczonej wartości, żeby funkcja fractalsum zwracała wartość z przedziału [ 1.0, 1.0], w celu wygodniejszego jej użycia. Funkcja main pobiera wartość fractalsum dla aktualnego punktu i przeskalowuje ją do przedziału [0.0, 1.0]. Na podstawie tej wartości obliczany kolor, którego wartość jest między wybranymi przez użytkownika kolorami. 8.4 02a factalsum levels Pomysł ten został oparty na książce [1, s.88], która w podobny sposób uzyskuje efekt zwany marble (marmur). Pomysł polega na podzieleniu odcinka [0.0, 1.0] na przedziały. Każda granica między przedziałami ma nadany kolor. Wartość wynikowego koloru jest mieszaniną dwóch sąsiadujących ze sobą kolorów z wybranego punktu. Pozycję punktu na rzeczonym odcinku [0.0, 1.0] uzyskuje się używając wartości zwróconej przez fractalsum. Funkcja marble color zwraca kolor w zależności od parametru, który przyjmuje się że jest w znormalizowanym zakresie [0.0, 1.0]. Dzieli ona ten zakres na cztery części, których granice są w punktach: 0.0 0.4 0.8 1.0 Kolory dla tych punktów to odpowiednio: Color 0 Color 1 Color 2 Color 3 Implementacja wygląda następująco: 1 vec3 m a r b l e c o l o r ( f l o a t f a c t o r ) 2 { 3 i f ( f a c t o r < 0. 4 ) 4 { 5 r eturn mix ( c o l o r 0, c o l o r 1, f a c t o r / 0. 4 ) ; 6 } 7 e l s e i f ( f a c t o r < 0. 8 ) 8 { 16

9 return mix ( c o l o r 1, c o l o r 2, ( f a c t o r 0. 4 ) / 0. 4 ) ; 10 } 11 e l s e 12 { 13 r eturn mix ( c o l o r 2, c o l o r 3, ( f a c t o r 0. 8 ) / 0. 2 ) ; 14 } 15 16 } 17 18 void main ( void ) 19 { 20 f l o a t value = clamp ( 21 f r a c t a l s u m ( vec2 ( vpos. x s c a l e x, vpos. y s c a l e y ). xy s c a l e ), 22 1.0, 1. 0 ) ; 23 value = ( value + 1. 0 ) / 2. 0 ; 24 f l o a t f a c t o r = pow( value, pow factor ) ; 25 g l F r a g C o l o r = vec4 ( m a r b l e c o l o r ( f a c t o r ), 1. 0 ) ; 26 } 8.5 02b fractalsum levels jump Efekt ten to modyfikacja 02a fractalsum levels polegająca na ostrej zmianie jednego koloru w drugi, bez żadnej interpolacji między nimi. Powoduje to powstanie ciekawych granic między obszarami. Przy odpowiednim doborze kolorów i przeskalowań można uzyskać efekt przypominający korę drzewa. Z drugiej strony uzyskuje się bardzo ciekawy efekt przejścia przypominający wypalanie się papieru, jeśli dwa środkowe kolory zostaną ustawione na czerwony i żółty, natomiast dwa skrajne na zupełnie inne kolory. Przy płynnej zmianie parametru threshold wyraźnie widać efekt przejścia między skrajnymi kolorami. 1 vec3 m a r b l e c o l o r ( f l o a t f a c t o r ) 2 { 3 i f ( f a c t o r < 0. 5 ) 4 { 5 r eturn mix ( c o l o r 0, c o l o r 1, f a c t o r 2. 0 ) ; 6 } 7 e l s e 8 { 17

9 return mix ( c o l o r 2, c o l o r 3, ( f a c t o r 0. 5 ) 2. 0 ) ; 10 } 11 12 } 13 14 void main ( void ) 15 { 16 f l o a t value = clamp ( 17 f r a c t a l s u m ( vec2 ( vpos. x s c a l e x, vpos. y s c a l e y ). xy s c a l e ), 18 1.0, 1. 0 ) ; 19 value = ( value + 1. 0 ) / 2. 0 ; 20 f l o a t f a c t o r = pow( value, pow factor ) ; 21 g l F r a g C o l o r = vec4 ( m a r b l e c o l o r ( f a c t o r ), 1. 0 ) ; 22 } 8.6 02c fractalsum 9 levels 2 colors Kod tej strony rozwija pomysł poprzedniej, żeby tworzyć ostre przejście między kolorami. Tym razem jednak ilość kolorów została zredukowana tylko do dwóch, jednak ilość poziomów na jakie jest dzielony odcinek [0.0, 1.0] został zwiększony do 9. W ramach każdego pododcinka następuje interpolacja między kolorami, jednak początek następnego pododcinka zaczyna się od razu od pierwszego koloru bez łagodnego przejścia. Powoduje to powstanie poziomów, niczym na mapie terenu, bądź na korze niektórych drzew. 1 vec3 m a r b l e c o l o r ( f l o a t f a c t o r ) 2 { 3 i f ( f a c t o r < 0. 1 1 ) 4 { 5 return mix ( c o l o r 0, c o l o r 1, f a c t o r / 0. 1 1 ) ; 6 } 7 e l s e i f ( f a c t o r < 0. 2 2 ) 8 { 9 return mix ( c o l o r 0, c o l o r 1, ( f a c t o r 0. 1 1 ) / 0.11 ) ; 10 } 11 e l s e i f ( f a c t o r < 0. 3 3 ) 12 { 13 r eturn mix ( c o l o r 0, c o l o r 1, ( f a c t o r 0. 2 2 ) / 0.11 ) ; 14 } 18

15 e l s e i f ( f a c t o r < 0. 4 4 ) 16 { 17 r eturn mix ( c o l o r 0, c o l o r 1, ( f a c t o r 0. 3 3 ) / 0.11 ) ; 18 } 19 e l s e i f ( f a c t o r < 0. 5 5 ) 20 { 21 r eturn mix ( c o l o r 0, c o l o r 1, ( f a c t o r 0. 4 4 ) / 0.11 ) ; 22 } 23 e l s e i f ( f a c t o r < 0. 6 6 ) 24 { 25 r eturn mix ( c o l o r 0, c o l o r 1, ( f a c t o r 0. 5 5 ) / 0.11 ) ; 26 } 27 e l s e i f ( f a c t o r < 0. 7 7 ) 28 { 29 r eturn mix ( c o l o r 0, c o l o r 1, ( f a c t o r 0. 6 6 ) / 0.11 ) ; 30 } 31 e l s e i f ( f a c t o r < 0. 8 8 ) 32 { 33 r eturn mix ( c o l o r 0, c o l o r 1, ( f a c t o r 0. 7 7 ) / 0.11 ) ; 34 } 35 e l s e 36 { 37 r eturn mix ( c o l o r 0, c o l o r 1, ( f a c t o r 0. 8 8 ) / 0.12 ) ; 38 } 39 40 } Funkcja main jest identyczna jak w przypadku 02a fractalsum levels. 8.7 03 turbulence Kod turbulence został oparty na kodzie (książka [1], s.86): 1 f l o a t 2 t u r b u l e n c e ( point Q) 3 { 4 f l o a t value = 0 ; 5 f o r ( f = MINFREQ; f < MAXFREQ; f = 2) 6 value += abs ( s n o i s e (Q f ) ) / f ; 19

7 return value ; 8 } który do złudzenia przypomina kod fractalsum. Jedyną różnicą jest użycie funkcji abs() na wartości funkcji snoise(). Przez ten zabieg wartości są znacznie przesunięte w stronę zera, co też wyraźnie widać jeśli porówna się obrazy generowane przez turbulence i fractalsum. Turbulence ma znacznie mniejszą różnorodność w odcieniach barw jakie widać. Kod zaimplementowanej funkcji wygląda następująco: 1 f l o a t t u r b u l e n c e ( vec2 point ) 2 { 3 f l o a t value = 0. 0 ; 4 f l o a t f r e q = 1. 0 ; 5 6 value += abs ( c n o i s e ( point ) ) ; // c n o i s e ( point 1. 0 ) / 1. 0 ; 7 value += abs ( c n o i s e ( point 2. 0 ) ) / 2. 0 ; 8 value += abs ( c n o i s e ( point 4. 0 ) ) / 4. 0 ; 9 value += abs ( c n o i s e ( point 8. 0 ) ) / 8. 0 ; 10 11 return clamp ( value, 1.0, 1. 0 ) ; 12 } 13 14 void main ( void ) 15 { 16 vec4 c o l o r 0 = vec4 ( c o l o r a t 0, 1. 0 ) ; 17 vec4 c o l o r 1 = vec4 ( c o l o r a t 1, 1. 0 ) ; 18 19 f l o a t value = ( t u r b u l e n c e ( vpos. xy s c a l e ) + 1. 0 ) / 2. 0 ; 20 f l o a t f a c t o r = pow( value, pow factor ) ; 21 g l F r a g C o l o r = mix ( c o l o r 0, c o l o r 1, f a c t o r ) ; 22 } Zgodnie z oczekiwaniami kod 02 fractalsum i 03 turbulence różnią się jedynie użyciem funkcji abs() na wartościach zwracanych przez cnoise. 8.8 04 lattice Lattice (ang. krata) to efekt sprawdzenia, co wyjdzie jeśli użyje się funkcji okresowej np. sinus na współrzędnych obrazu. Okazuje się, że jeśli do sinusa podana zostanie wartość x każdego fragmentu, to otrzyma się pasy jako obraz. Dodano więc sin(y) dla każdego fragmentu, a wartość w danym punkcie jest determinowana przez mniejszą wartość z tych dwóch funkcji. 20

1 void main ( void ) 2 { 3 vec4 c o l o r 0 = vec4 ( c o l o r a t 0, 1. 0 ) ; 4 vec4 c o l o r 1 = vec4 ( c o l o r a t 1, 1. 0 ) ; 5 6 f l o a t v a l u e x = ( s i n ( vpos. x s c a l e ) + 1. 0 ) / 2. 0 ; 7 f l o a t v a l u e y = ( s i n ( vpos. y s c a l e ) + 1. 0 ) / 2. 0 ; 8 f l o a t value = min ( value x, v alue y ) ; 9 g l F r a g C o l o r = mix ( c o l o r 0, c o l o r 1, pow( value, pow factor ) ) ; 10 } 8.9 04a lattice and noise Program sprawdza jaki wyjdzie obraz, jeśli połączy się lattice oraz noise. Dla pozycji x jest liczony sinus do którego jest dodawana wartość noise, a wynik jest przycinany do przedziału [ 1.0, 1.0] i przeskalowany do [0.0, 1.0]. Tak samo dla pozycji y. Wartością wynikową jest mniejsza z tych dwóch wartości. Najciekawszy efekt uzyskuje się przy dużych wartościach lattice scale. Obraz przypomina wtedy, jakby był drukowany. 1 void main ( void ) 2 { 3 vec4 c o l o r 0 = vec4 ( c o l o r a t 0, 1. 0 ) ; 4 vec4 c o l o r 1 = vec4 ( c o l o r a t 1, 1. 0 ) ; 5 6 f l o a t v a l u e x = 7 ( 8 clamp ( 1.0, 1. 0, s i n ( vpos. x 10.0 l a t t i c e s c a l e ) + noise2d ( vpos. xy s c a l e ) 3. 0 ) 9 + 1. 0 10 ) 11 / 2. 0 ; 12 f l o a t v a l u e y = 13 ( 14 clamp ( 1.0, 1. 0, s i n ( vpos. y 10.0 l a t t i c e s c a l e ) + noise2d ( vpos. xy s c a l e ) 3. 0 ) 15 + 1. 0 16 ) 17 / 2. 0 ; 18 21

19 f l o a t value = min ( value x, v alue y ) ; 20 g l F r a g C o l o r = mix ( c o l o r 0, c o l o r 1, pow( value, pow factor ) ) ; 21 } 8.10 04b sin and noise To ciekawe połączenie używa wartości funkcji noise jako parametru dla funkcji sinus, co w efekcie daje mocno zniekształcone okręgi. Przeskalowanie parametru dla sinusa powoduje zagęszczenie pojawiających się okręgów, natomiast threshold kontroluje ich grubość. 1 void main ( void ) 2 { 3 vec4 c o l o r 0 = vec4 ( c o l o r a t 0, 1. 0 ) ; 4 vec4 c o l o r 1 = vec4 ( c o l o r a t 1, 1. 0 ) ; 5 6 f l o a t value = ( s i n ( noise2d ( vpos. xy s c a l e ) s i n s c a l e ) + 1. 0 ) / 2. 0 ; 7 f l o a t f a c t o r = pow( value, pow factor ) ; 8 g l F r a g C o l o r = mix ( c o l o r 0, c o l o r 1, f a c t o r ) ; 9 } 9 Ograniczenia technologii Wersja GLSL użyta w WebGL 1.0 nie pozwala na tworzenie pętli, której nie da się rozwinąć do postaci nieiteracyjnej w trakcie kompilacji shader a. Narzuca to ograniczenia w możliwych modyfikacjach i może stanowić przeszkodę do osiągania ciekawych efektów inaczej niedostępnych. W pracy zrezygnowano z tego powodu z implementacji komórek voronoi jako elementu bazowego do tworzenia kolejnych technik proceduralnych, ponieważ implementacja funkcji wyznaczającej odległość do drugiego najbliższego punktu przy dynamicznym generowaniu punktów jest mocno utrudniona. Klasyczny diagram voronoi jest możliwy do zaimplementowania w WebGL dzięki sztuczce z buforem głębokości [VORONOI]. WebGL 1.0 nie udostępnia rozszerzenia Transform Feedback, które pozwala na przechowywanie danych już przetworzonych przez shader. Pozwalało by to nie tylko na przeprowadzanie wcześniejszych obliczeń w celu optymalizacji, ale też używanie karty graficznej do obliczeń na bieżąco, co w przypadku bardziej skomplikowanych technik proceduralnych może mieć kluczowe znaczenie. 22

10 Podsumowanie Techniki proceduralne są bardzo ciekawym narzędziem w rękach wprawionego artysty. Przy stosunkowo małym nakładzie pracy możliwe jest tworzenie ciekawych efektów, których aplikacje ogranicza jedynie wyobraźnia osoby tworzącej. Techniki proceduralne pozwalają też w zupełnie innym świetle spojrzeć na powszechnie znane funkcje. Zamiast myśleć o sinusie jako o funkcji mającej coś wspólnego z kątami, możemy jej używać jako narzędzia do generowania pasów czy krat w teksturach proceduralnych. Funkcja wykładnicza natomiast okazuje się być bardzo dobrym przekształceniem tworzącym złudzenie parametru określającego wartość progową. Literatura [1] David S. Ebert, F. Kenton Musgrave, Darwyn Peachey and Ken Perlin, Texturing & modeling. A procedural approach. Third edition. 2003. [2] Aaftab Munshi, Dan Ginsburg, Dave Shreiner, OpenglES 2.0 Programming Guide. 2008. [3] Peter Shirley, Michael Ashikhmin and Steve Marschner, Fundamentals of Computer Graphics. 2009. [HTML5] HTML5 A vocabulary and associated APIs for HTML and XHTML. W3C Candidate Recommendation 04 February 2014 http://www.w3.org/tr/html5/ [WEBGL10] WebGL 1.0 Specification Version 1.0.2. 01 March 2013 https://www.khronos.org/registry/webgl/specs/1.0/ [WEBGL100] WebGL 1.0 Specification Version 1.0. 10 February 2011 https://www.khronos.org/registry/webgl/specs/1.0.0/ [GLES20] OpenGL R ES Common Profile Specification Version 2.0.25, A. Munshi, J. Leech, November 2010. http://www.khronos.org/registry/gles/specs/2.0/es full spec 2.0.25.pdf [GLES20GLSL] The OpenGL R ES Shading Language Version 1.00, R. Simpson, May 2009. http://www.khronos.org/registry/gles/specs/2.0/glsl ES Specification 1.0.17.pdf [TYPEDARRAY] Typed Array Specification Version 1.0, 08 February 2011 https://www.khronos.org/registry/typedarray/specs/1.0/ [NOISE] https://github.com/ashima/webgl-noise 23

[VORONOI] http://blog.alexbeutel.com/332/interactive-voronoidiagrams-with-webgl/ [MATRIX] http://glmatrix.net/ 24