Tutorial We Bgl

download Tutorial We Bgl

of 26

Transcript of Tutorial We Bgl

  • 7/25/2019 Tutorial We Bgl

    1/26

    Wprowadzenie do WebGL

    Monika Falarz, Grzegorz Jako, Patryk Kiepas

    9 listopad 2012

    Streszczenie

    Dokument prezentuje podstawy i wprowadza w proces tworzeniagrafiki przestrzennej przy uyciu biblioteki WebGL i jzyka JavaScript,renderowanej przez wiodce przegldarki WWW. W trakcie procesunauki bdziemy tworzy wsplnie szkielet aplikacji WebGL.

    1 Wstp

    Celem niniejszego dokumentu jest zapoznanie czytelnika z now tech-nologi WebGL w stopniu umoliwajcym pisanie prostych scen przestrzen-nych. Zakadamy, e czytelnik posiada podstawow znajomo popularnychjzykw JavaScript i HTML5 oraz posiada ogln wiedz programistyczn

    (zmienne, ptle, instrukcje warunkowe itp.), matematyczn (macierze, wek-tory i operacje na nich) i szcztkow znajomo poj pochodzcych z grafikikomputerowej (renderowanie, potok grafiki, translacja, rotacja, skalowania,bufor gbi, bufor wierzchokw, shader, test przycicia itp.).

    WebGL to nic innego jak API jzyka JavaScript, ktre umoliwa namtworzenie interaktywnej grafiki 3D bezporednio w przegldarce. Jest tostandard webowy tworzony przez grup Khronos odpowiedzialn za stworze-nie i kolejne specyfikacje OpenGL. API bazuje bezporednio na mobilnejwersji OpenGL ES 2.0 przez co, grafika utworzona przy pomocy WebGL mo-e by uruchamiania nie tylko na pececie, ale i na urzdzeniach mobilnych i

    telewizorach.

    W trakcie nauki zaczniemy wprowadza coraz to kolejne elementy wa-snego szkieletu aplikacji WebGL. W zaoeniu, ma on by prosty i umoliwijak najwygodniejsze przeskoczenie caego procesu inicjalizacji. W wyniku te-go w pniejszych czciach wprowadzania, bdziemy mogli w caoci skupisi na tworzeniu i modyfikacji tworzonej przez nas trjwymiarowej sceny.

    1

  • 7/25/2019 Tutorial We Bgl

    2/26

    Nasz nauk rozpoczniemy od przygotowania naszej przegldarki do

    obsugi technologi WebGL. Nastpnie przejdziemy przez proces integra-cji WebGL z HTML5, co umoliwi nam osadzanie kreowanych programwwprost w kodzie naszej strony WWW. Kolejnym krokiem, bdzie prbaprzygotowania przez nas pustej sceny, a nastpnie narysowania na niej pro-stego obiektu dwuwymiarowego. Gdy to nam si uda, sprbujemy swychsi w trzecim wymiarze. Rozpoczniemy od prostych bry, by przej do ichtransformacji (obroty, translacje etc.), bufora gbi i obiektw na siebie za-chodzcych, nakadania tekstur, owietlenia, shaderw, obsugi klawiatury imyszki oraz wielu innych.

    2 Uruchomienie WebGL2.1 Wstp

    Nie kada przegldarka jest w stanie uruchomi aplikacje WebGL zdwch przyczny. Pierwsza to technologiczna bariera, gdy przegldarka poprostu go nie obsuguje. Druga to kwestia bezpieczestwa. Ot WebGL mapar bdw przez co osoby postronne jak i zoliwe oprogramowanie jestw stanie zawiesi nam przegldark i nawet cay komputer. Z tego powoduWebGL jest domylnie wyczony.

    2.2 Wybr przegldarki

    Przegldarki obsugujce WebGLa to m.in.:

    a) Firefox (wersja 4.0 i wiksza)

    b) Opera (wersja 12.00 i wysza)

    c) Chrome (wersja 9.0 i wysza)

    d) Safari (wersja 5.1 i wysza na MacOS)

    Wsparcie dla adnej z przegldarek nie jest mocne i moe ulec zmianiew zalenoci od wersji. Kompatybilno poszczeglnych przegldarek naley

    sprawdza na stronie producenta.

    2.3 Wczenie WebGL w przegldarce

    Z powodu wspomnianej kwestii sabego bezpieczestwa WebGL do-mylnie jest zazwyczaj wyczony. Wczenie go w wikszoci przegldarkachwyglda podobnie. W pasku adresu wpisujemy podany adres, wyszukujemyatrybut i ustawiamy odpowiedni warto:

    i) Firefox - adres=about:config, atrybut=webgl.force-enabled , war-to=true

    2

  • 7/25/2019 Tutorial We Bgl

    3/26

    ii) Opera - adres=opera:config, atrybut=Enable WebGL, warto=1

    iii) Chrome - adres=chrome://flags, atrybut=Disable WebGL, warto=Disable

    To czy udao nam si wczy mona sprawdzi wchodzc na strone:http://aleksandarrodic.com/p/jellyfish/ i zobaczy czy aplikacja siuruchamia.

    Warto te wspomnie o wymaganym sprzcie. Potrzebna jest kartaz Shaderami w wersji conjamniej 2.0. Najlepiej od NVidia, ATI. Wyst-puj problemy z kartami wbudowanymi producentw Intel, SiS. Niekiedybdziemy musieli siowo wymusi uruchomienie WebGL, gdy nasza karta

    jest nie do koca zgodna ze specyfikacj. Mona to zrobi poprzez ustawie-nie odpowiednich atrybutw bd te rezygnujc ze wsparcia sprztowego iuruchomi renderowanie programowe (ang. software rendering, na CPU).

    3 Integracja z HTML5

    3.1 Po stronie HTML5

    Caa magia zwizana z WebGL w przegldarce dzieje si na kompo-nenciecanvaspochodzcym z nowego HTML5. Integracja jest prosta. Two-rzymy podstawowy szablon strony HTML5, obiekt canvasokrelajc przy

    tym jego identyfikator i wymiary oraz okrelamy, ktra funkcja JavaScriptma zosta wywoana podczas adowania strony. Uywamy do tego celu eventonload:

    Integracja WebGL z HTML5

    3.2 Po stronie WebGL

    Nastpnie w kodzie start.jsodwoujemy si do elementu canvaszapomoc obiektowego modelu dokumentu DOM i funkcji getElementByIdi

    3

  • 7/25/2019 Tutorial We Bgl

    4/26

    ju moemy renderowa grafik w przegldarce:

    function start() {

    var canvas = document.getElementById("empty_canvas");

    (...)

    }

    4 Pusta scena

    4.1 Inicjalizacja

    W tej czci postaramy stworzy nasz pierwsz pust scen. Zaczy-namy od stworzenia globalnej zmiennej gl przechowujcej cay kontekstWebGL oraz od wywoania funkcji inicjalizujcej sam WebGL init() wnaszej gwnej funkcji start():

    var gl;

    function start() {

    var canvas = document.getElementById("empty_canvas");

    init();

    (...)

    }

    Nastpnie wypeniamy funkcj init() nastpujcym kodem inicjali-zujcym globaln zmien gl, ktra jest wypeniana odpowiednimi danymipochodzcymi z ptna canvas. Midzy innymi kontekstem WebGL, udo-stpniajcym zestaw funkcji do rysowania:

    function init(canvas) {

    gl = canvas.getContext("webgl") ||

    canvas.getContext("experimental-webgl");

    gl.viewportWidht = canvas.width;

    gl.viewportHeight = canvas.height;

    if(!gl) {alert("Nie mozna zainicjalizowac!");

    }

    }

    4.2 Rysowanie

    Teraz moemy si zajc rysowaniem naszej pustej sceny dopisujc dostart()odpowiednie instrukcje. Zaczynamy od wyczyszczenia ptna i usta-wieniu mu koloru czarnego. Nastpnie wczamy test bufora gbi, ktry

    4

  • 7/25/2019 Tutorial We Bgl

    5/26

    odpowiada za warstwowe rysowanie obiektw, tak aby odpowiednio si za-

    saniay. Na koniec ustawiamy wielko obszaru rysowania pobierajc danez ptna i wywoujemy funkcje rysujc draw():

    function start() {

    (...)

    gl.clearColor(0.0, 0.0, 0.0, 1.0);

    gl.enable(gl.DEPTH_TEST);

    gl.viewport(0, 0, gl.viewportWidth, gl.viewportHeight);

    draw();

    }

    Nasza funkcja rysujca bdzie bardzo prosta skoro niczego nie rysuje.Jedyne co robi to czyci bufor ekranu i bufor gbi co jest wymagane przyzwykym renderowaniu sceny. Nie moemy przecie pozwoli, by dane za-pisywane do bufora ekranu i gbi nakaday si na siebie. Zawsze tworzcnow klatk musimy zapisywa dane do pustch buforw:

    function draw() {

    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

    }

    Przykadowy kod rdowy znajduje si w folderze 1. Pusta scena.Po uruchomieniu powinnimy otrzyma czarny pusty widok.

    5 Szkielet fruitGL (cz.1)

    5.1 Wstp

    Tworzony przez nas szkielet fruitGL ma by nieskomplikowany. Maumoliwi nam jak najszybsze przejcie do tworzenia grafiki, pozostawia-jc w niepami takie operacje jak inicjalizacja ekranu, buforw, shaderw,operacje na macierzach i wektorach czy przeksztacenia w przestrzeni.

    5.2 Kod

    Wszystkie funkcje szkieletu s umieszczone we wsplnej przestrzeninazw fruitGL. Technicznie kod zawarty w szkielecie nie rni si od te-go uytego wczeniej przy okazji tworzenia pustej sceny. Jest tylko inaczejzorganizowany:

    var fruitGL = {

    gl : null,

    5

  • 7/25/2019 Tutorial We Bgl

    6/26

    initialize : function(canvasName) {

    var canvas = document.getElementById(canvasName);

    fruitGL.gl = canvas.getContext("webgl") ||

    canvas.getContext("experimental-webgl");

    fruitGL.gl.viewportWidht = canvas.width;

    fruitGL.gl.viewportHeight = canvas.height;

    if(!fruitGL.gl) {

    alert("Nie mozna zainicjalizowac!");

    }

    fruitGL.gl.clearColor(0.0, 0.0, 0.0, 1.0);fruitGL.gl.enable(fruitGL.gl.DEPTH_TEST);

    fruitGL.gl.viewport(0, 0, fruitGL.gl.viewportWidth,

    fruitGL.gl.viewportHeight);

    },

    beginDraw : function() {

    fruitGL.gl.clear(fruitGL.gl.COLOR_BUFFER_BIT |

    fruitGL.gl.DEPTH_BUFFER_BIT);

    },

    endDraw : function() {}

    }

    5.3 Wykorzystanie fruitGL

    Wykorzystanie szkieletu fruitGL jest bardzo proste. Najpierw do-czamy plik z kodem fruitGL.js do kodu naszej strony (przed docze-niem kodu start.js), a nastpnie wywoujemy funkcje szkieletu w funkcjistart(). Nasz kod strony w html:

    (...)

    (...)

    6

  • 7/25/2019 Tutorial We Bgl

    7/26

    UyciefruitGLw kodzie naszej aplikacji start.js:

    function start() {

    fruitGL.initialize("empty_canvas");

    fruitGL.beginDraw();

    draw();

    fruitGL.endDraw();

    }

    function draw() {

    // tu rysujemy!

    }

    Szkielet fruitGL oraz przykady jego wykorzystania znajduj si wkatalogu "Kody rdowe\fruitGL".

    6 Pierwszy obiekt (trjkt)

    Wywietlajc grafik w WebGL nie moemy korzysta ze standardowe-go potoku karty graficznej (tzw. fixed-pipeline). Musimy utworzy bardziejwspczesny potok wymagajcy od nas zdefiniowania jednostek cieniuj-cych, ktre w rzeczywistoci s prostymi funkcjami wykonywanymi na rzecz

    kadego wierzchoka bd te pixela sceny.

    6.1 Vertex Shader

    Pomijajc nieistotne etapy, przekazane na kart graficzn wierzchokitrafiaj wpierw do jednostki vertex shader odpowiedzialnej za ich transfor-macj. Jednostka ta ustawia im m.in. odpowiedni pozycj z uwzgldnieniemmacierzy widoku, projekcji i wiata.

    attribute vec3 position;

    void main(void){

    gl_Position = vec4(position, 1.0);

    }

    Zaczynamy od deklaracji wektora 3-elementowegoposition, ktremubdziemy przypisywa z programu pozycj naszych wierzchokw. Pozycjata jest przepisywana bez zmian do odpowiedniego miejsca gl_Position, zktrego nastpny etap potoku bdzie j pobiera. Dziki temu zabiegowi,pozycje wierzchokw bd oznaczay ich rzeczywiste pooenie na ekraniew zakresie 0.0-1.0 dla kadej ze wsprzdnych.

    7

  • 7/25/2019 Tutorial We Bgl

    8/26

    6.2 Pixel Shader

    Zwrcone wierzchoki trafiaj do pixel shadera odpowiedzialnego zamodyfikacj pojedyczych pixeli. Jest to jedna z ostatnich faz renderingu,ktra wykorzystuje ju uoon w przestrzeni scene i skupia si tylko nawidocznych fragmentach modeli.

    precision mediump float;

    void main(void){

    gl_FragColor = vec4(0.5, 0.2, 1.0, 1.0);

    }

    Wpierw ustawiamy redni precyzj typu zmiennopozycjnego, a na-stpnie przypisujemy kademu modyfikowanemu pixelu kolor RGB(0.5, 0.2,1.0). Tym razem, nie przekazujemy niczego z programu. Odpowiedni pixeljest wydobywany z przesanych od vertex shadera, wstpnie przetworzonychwierzchokw.

    6.3 adowanie shaderw

    Definiujemy shadery w acuchach znakw shaderPSi shaderVS. Na-stpnie tworzymy pusty shader o odpowiednim typie i przypisujemy mu kodshaderw oraz kompilujemy:

    var shaderPS = "precision mediump float; void main(void)

    { gl_FragColor = vec4(0.5, 0.2, 1.0, 1.0);}";

    var shaderVS = "attribute vec3 position; void main(void)

    { gl_Position = vec4(position, 1.0); }";

    var pixelShader = gl.createShader(gl.FRAGMENT_SHADER);

    gl.shaderSource(pixelShader, shaderPS);

    gl.compileShader(pixelShader);

    var vertexShader = gl.createShader(gl.VERTEX_SHADER);

    gl.shaderSource(vertexShader, shaderVS);gl.compileShader(vertexShader);

    Same wypenione shadery nie na wiele nam si zdadz. Musimy utwo-rzy podprogram reprezentujcy potok, ktremu przypisujemy utworzonejednostki cieniujce i go linkujemy. Nastpnie ustawiamy go jako domyl-ny sposb na tworznie grafiki oraz wskazujemy atrybut positionjako tenw vertex shaderze, pod ktry bdziemy przesya pozycje wierzchokw zprogramu:

    8

  • 7/25/2019 Tutorial We Bgl

    9/26

    shaderProgram = gl.createProgram();

    gl.attachShader(shaderProgram, vertexShader);

    gl.attachShader(shaderProgram, pixelShader);

    gl.linkProgram(shaderProgram);

    gl.useProgram(shaderProgram);

    shaderProgram.position = gl.getAttribLocation(shaderProgram,

    "position");

    gl.enableVertexAttribArray(shaderProgram.position);

    6.4 Bufor wierzchokw

    Tworzone przez nas figury i bryy skadaj si z wierzchokw. Umiesz-czamy je w tzw. buforach, czyli szybkich, wydzielonych obszarach pamicina karcie graficznej, ktrych uycie znaczco redukuje czas odczytu. Zaczy-namy od wywoania funkcji tworzcej bufor, a nastpnie ustawiamy go nabufor domylny, czyli ten na ktrym aktualnie dziaamy:

    triangleBuffer = gl.createBuffer();

    gl.bindBuffer(gl.ARRAY_BUFFER, triangleBuffer);

    Nie pozostaje nam nic innego jak zdefiniowa trzy wierzchoki dla na-szego trjkta pamitaj, e przy uywaniu wsprzdnych ekranowych po-ruszamy si po zakresie 0.0-1.0. Nastpnie funkcj bufferData()adujemywierzchoki do bufora ustawiajc przy tym jego rozmiar:

    var vertices = [

    0.0, 0.7, 0.0,

    -0.7, -0.7, 0.0,

    0.7, -0.7, 0.0

    ];

    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices),

    gl.STATIC_DRAW);

    triangleBuffer.itemSize = 3;

    triangleBuffer.numItems = 3;

    6.5 Wywietlenie

    Majc zdefiniowany potok graficzny i wczytane wierzchoki trjkta, moe-my przej do wywietlania sceny. Uzupeniamy funkcj draw()o nastpu-jce instrukcje:

    function draw() {

    gl.bindBuffer(gl.ARRAY_BUFFER, triangleBuffer);

    9

  • 7/25/2019 Tutorial We Bgl

    10/26

    gl.vertexAttribPointer(shaderProgram.position,

    triangleBuffer.itemSize,gl.FLOAT, false, 0, 0);

    gl.drawArrays(gl.TRIANGLES, 0,

    triangleBuffer.numItems);

    }

    Wpierw ustawiamy bufor z wierzchokami trjkta jako domylny i nanim pracujemy. Pniej definiujemy rozmieszczenie wierzchokw w buforzepoczynajc od miejsca gdzie dane z niego bd trafia do vertex shadera,poprzez liczb wsprzdnych (wymiar), a po typ je przechowujcy (do-kadno).

    Rysunek 1: Pierwsza grafika (trjkt)

    Cay proces wywietlania koczymy funkcj drawArrays(), ktra wy-wietla na ekranie aktywny bufor. W naszym przypadku rysujemy trzywierzchoki (triangleBuffer.numItems) tworzce trjkt (gl.TRIANGLES).Powyszy rysunek przedstawia nasze dotychczasowe dokonanie.

    7 Trzeci wymiar

    Rysowanie w dwch wymiarach wstpnie przetransformowanych wierz-chokw jest proste. Trzeci wymiar oznacza konieczno wymnoenia wszyst-kich wierzchokw przez odpowiednie macierze (projekcji, widoku, wiata),ktre ustawi ich pozycje z uwzgldnieniem odpowiedniej perspektyw. Wy-nikiem tego jest zudzenie trzeciego wymiaru sceny.

    Nie dokonamy tego jednak przy uyciu samego WebGL, gdy nie za-wiera on wbudowanych operacji matematycznych na wektorach i macier-zach. Uyjemy do tego gotowej biblioteki glMatrix v0.9.5dostpnej podadresem http://code.google.com/p/glmatrix.

    10

  • 7/25/2019 Tutorial We Bgl

    11/26

    7.1 Macierze

    Zaczniemy od utworzenia macierzy projekcji (stworzenie iluzji trzecie-go wymiaru na paskim ekranie) i macierzy wiata (rozmieszczenie obiektwna scenie). Wpierw doczamy bibliotek glMatrixdo strony przed naszymskryptemstart.js, tworzymy globalne zmienne dla naszych macierzy i mo-dyfikujemy vertex shader tak by z nich korzysta:

    var worldMat = mat4.create();

    var projectionMat = mat4.create();

    Modyfikacja vertex shadera:

    attribute vec3 position;

    uniform mat4 uWorldMat;

    uniform mat4 uProjectionMat;

    void main(void) {

    gl_Position = uProjectionMat * uWorldMat *

    vec4(aVertexPosition, 1.0);

    }

    Kolejny krok to stworzenie poczenia pomidzy naszymi macierzami

    w programie i vertex shaderze:

    shaderProgram.worldMatUniform =

    gl.getUniformLocation(shaderProgram, "uWorldMat");

    shaderProgram.projectionMatUniform =

    gl.getUniformLocation(shaderProgram, "uProjectionMat");

    Przy wypenianiu macierzy projekcji i wiata bdziemy korzysta zfunkcji bibliotecznych glMatrix. Dziki funkcji perspective() utworzo-na macierz projekcji sprawi, e pozbdziemy si widoku ortogonalnego narzecz perspektywy przestrzennej o horyzontalnym polu widzenia 45 stopni

    i zgodnym ze stosunkiem dugoci do szerokoci ekranu widokiem. Macierzwiata tworzymy wpierw jako macierz jednostkow (neutralna dla mnoe-nie,identity()), by nastpnie dokonywa za jej pomoc translacji obiektwsceny o wektor [0.5, 0.5, -4.0]i rotacje wzgledem osi Z o 90 stopni:

    mat4.perspective(45, gl.viewportWidth / gl.viewportHeight,

    0.1, 100.0, projectionMat);

    mat4.identity(worldMat);

    mat4.translate(worldMat, [0.5, 0.5, -4.0]);

    mat4.rotateZ(worldMat, degToRad(90));

    11

  • 7/25/2019 Tutorial We Bgl

    12/26

    Ostatni rzecz jest zaaplikowanie tak utworzonych macierzy do na-

    szego vertex shadera, tak aby mg z nich swobodnie korzysta. Dokonujemytego tu przed wywoaniem funkcji rysujcej:

    (...)

    gl.uniformMatrix4fv(shaderProgram.worldMatUniform,

    false, worldMat);

    gl.uniformMatrix4fv(shaderProgram.projectionMatUniform,

    false, projectionMat);

    gl.drawArrays(gl.TRIANGLES, 0, triangleBuffer.numItems);

    7.2 Efekt kocowy

    Rysunek 2: Trjkt w trzecim wymiarze po transformacjach

    Przykad znajduje si w katalogu"Kody rdowe\3. Trzeci wymiar".Uylimy w nim pomocniczej funkcji degToRad(), ktra odpowiada za za-miane kta wyraonego w stopniach na radiany. Jest to wymagane przezwszystkie funkcje przyjmujce kt rotacji:

    function degToRad(degrees) {

    return degrees * Math.PI / 180;

    }

    8 Troch kolorkw

    Dokonamy lekkiej modyfikacji poprzedniego trjkta dodajc do wierz-chokw dodatkow informacj w postaci koloru. Przykad z tego rozdziauznajduje si w folderze "Kody rdowe\4. Troch kolorkw".

    12

  • 7/25/2019 Tutorial We Bgl

    13/26

    8.1 Jednostki cieniujce

    Poniewa wszystkie dane sceny w potoku odbiera najpierw vertex sha-der, take i do niego musimy przesa kolor wierzchoka. Rwnie i pixelshader wymaga modyfikacji, tak aby mg korzysta z nowej informacji okolorze:

    attribute vec3 position;

    attribute vec4 color;

    varying vec4 vColor;

    uniform mat4 uWorldMat;

    uniform mat4 uProjectionMat;

    void main(void) {

    gl_Position = uProjectionMat * uWorldMat *

    vec4(aVertexPosition, 1.0);

    vColor = color;

    }

    Uywamy zmiennejvColorz modyfikatoremvaryingdziki czemu jejwarto jest przekazywana pomidzy wywoaniami jednostek cieniujcych:

    precision mediump float;

    varying vec4 vColor;

    void main(void){

    gl_FragColor = vColor;

    }

    Ostatni krok zwizany z ustawianiem shaderw to wskazanie i po-czenie nowych atrybutw z programem:

    shaderProgram.color = gl.getAttribLocation(shaderProgram,

    "color");

    gl.enableVertexAttribArray(shaderProgram.color);

    8.2 Bufor kolorw

    Informacje o kolorach wierzchokw przechowujemy tak jak i pozycjepo prostu w buforze. Tworzymy zmienn dla bufora a nastpnie wypeniamygo:

    var triangleColorBuffer;

    (...)

    triangleColorBuffer = gl.createBuffer();

    13

  • 7/25/2019 Tutorial We Bgl

    14/26

    gl.bindBuffer(gl.ARRAY_BUFFER, triangleColorBuffer);

    var colors = [1.0, 0.0, 0.0, 1.0,

    0.0, 1.0, 0.0, 1.0,

    0.0, 0.0, 1.0, 1.0

    ];

    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors),

    gl.STATIC_DRAW);

    triangleColorBuffer.itemSize = 4;

    triangleColorBuffer.numItems = 3;

    8.3 Wywietlenie

    Jedyne co musimy zrobi by wywietli tak pokolorowany trjkt toprzesa bufor kolorw do vertex shadera zaraz obok bufora pozycji. Wszyst-ko to dokonujemy w funkcji draw(), tu przed funkcj rysowania:

    gl.bindBuffer(gl.ARRAY_BUFFER, triangleVertexColorBuffer);

    gl.vertexAttribPointer(shaderProgram.vertexColorAttribute,

    triangleVertexColorBuffer.itemSize,

    gl.FLOAT, false, 0, 0);

    (...)

    gl.drawArrays(gl.TRIANGLES, 0, triangleBuffer.numItems);

    Rysunek 3: Efekt kocowy: trjkt kolorowych

    9 Animacja

    9.1 Podstawy

    Poniewa animacja opiera si na cigym tworzeniu sceny na nowo zuwzgldnieniem pewnych zmian, potrzebujemy mechanizmu, ktry nam toumoliwi. Z pomoc przychodzi nam biblioteka od Google webgl-utils ifunkcja requestAnimFrame()cyklicznie wywoujca podan funkcj.

    14

  • 7/25/2019 Tutorial We Bgl

    15/26

    cigamy bibliotek z http://code.google.com/p/webglsamples/

    source/browse/book/extension/webgl-utils.js oraz doczamy j donaszej strony tak jak przy okazji glMatrix. Nastpnie tworzymy funkcjtick() odpowiedzaln za cykliczne wywoania animacji:

    function tick() {

    requestAnimFrame(tick);

    beginDraw();

    draw();

    endDraw();

    animate();

    }

    Wywoujemy j w funkcji start()zamiast funkcji draw(), ktra jesturuchamiana teraz wraz z tick(). Nastpnie tworzymy globaln zmiennangleledzc aktualn rotacje naszego trjkta oraz lastTime do prze-chowywania czasu. Wypeniamy funkcjanimate()odpowiedzialn za samanimacje obiektw i ich pynn form w zalenoci od liczby klatek wywie-tlanego obrazu:

    function animate() {

    var timeNow = new Date().getTime();

    if (lastTime != 0) {

    var elapsed = timeNow - lastTime;

    angle += (90 * elapsed) / 1000.0;

    }

    lastTime = timeNow;

    }

    9.2 Stos macierzy

    Uyjemy prostego stosu dla macierzy wiata, aby zachowywa jej po-cztkowy stan i oddzieli od wszelkich modyfikacji wynikych z transformacjina pojedyczym obiekcie. Definiujemy pust zmienn tablicow dla stosu.Nastpnie tworzym dwie funkcje obsugujce stos, ktre zdejmuj z (pop())

    oraz wkadaj na niego macierz (push()):

    var stackMat = [];

    function push() {

    var copy = mat4.create();

    mat4.set(worldMat, copy);

    stackMat.push(copy);

    }

    15

  • 7/25/2019 Tutorial We Bgl

    16/26

    function pop() {

    if (stackMat.length == 0) {throw ParamConst.INVALID_POP_MATRIX_CALL;

    }

    worldMat = stackMat.pop();

    }

    9.3 Wywietlenie

    Pozostao jeszcze zmodyfikowa funkcje rysujc tak aby po ustawie-niu macierzy wiata odoy j na stos, dokona transformacji obiektw,wyrenderowa na ekranie oraz zdj pocztkow warto macierzy dla no-

    wej klatki:function draw() {

    (...)

    mat4.translate(worldMat, [0.0, 0.0, -2.0]);

    push();

    mat4.rotate(worldMat, degToRad(angle), [0, 1, 1]);

    (...)

    gl.drawArrays(gl.TRIANGLES, 0, triangleBuffer.numItems);

    pop();

    }

    Rysunek 4: Efekt kocowy: trjkt animowany

    10 Szecian

    Stworzym cakowicie trjwymiarow bry: szecian. Uyjemy do te-go tzw. indeksowanego bufora wierzchokw. Poniewa niektre wierzchokis wsplne dla wielu trjktw/cian dlatego te moemy pozycj takiegowierzchoka przechowywa tylko raz, a dobiera si do niego poprzez usta-lony indeks. Moliwo tak daje nam wanie indeksowany bufor.

    16

  • 7/25/2019 Tutorial We Bgl

    17/26

    10.1 Bufory danych

    Pozbywamy si cakiem wszystkich zmiennych zwizanych z trjk-tem. Tworzymy nowe bufory wierzchokw, kolorw i indeksw dla naszegoszecianu:

    var cubeVertexBuffer;

    var cubeColorBuffer;

    var cubeIndexBuffer;

    Zaczynamy od wypenienia bufora wierzchokw skadajcego si z 24elementw jako standardowyARRAY_BUFFER, analogicznie jak w poprzednichprzykadach. Nastpnie bierzemy si za rwnie standardowy bufor kolorw.

    Do jego utworzenia uywamy tylko 6 kolorw i ptli, ktra dla kadej ze cianpowiela 4-krotnie dany kolor. Bliej przyjrzymy si tylko nowemu buforowiindeksw, w ktrym za pomoc indeksw do wierzchokw i grupowaniu ichpo trzy wyznaczamy trjkty do renderowania:

    cubeIndexBuffer = gl.createBuffer();

    gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, cubeIndexBuffer);

    var cubeIndices = [

    0, 1, 2, 0, 2, 3, // Przednia

    4, 5, 6, 4, 6, 7, // Tylnia

    8, 9, 10, 8, 10, 11, // Grna

    12, 13, 14, 12, 14, 15, // Dolna16, 17, 18, 16, 18, 19, // Prawa

    20, 21, 22, 20, 22, 23 // Lewa

    ]

    gl.bufferData(gl.ELEMENT_ARRAY_BUFFER,

    new Uint16Array(cubeIndices),

    gl.STATIC_DRAW);

    cubeIndexBuffer.itemSize = 1;

    cubeIndexBuffer.numItems = 36;

    10.2 Wywietlenie

    Rysowanie wszystkiego nie powinno by problematyczne. Zaczynamyod zbindowania wszystkich trzech buforw, a nastpnie wywietlenia danychpochodzcych z bufora indeksw:

    function draw() {

    (...)

    mat4.translate(worldMat, [0.0, 0.0, -7.0]);

    (...)

    gl.bindBuffer(gl.ARRAY_BUFFER, cubePositionBuffer);

    gl.vertexAttribPointer(shaderProgram.position,

    17

  • 7/25/2019 Tutorial We Bgl

    18/26

    cubePositionBuffer.itemSize,

    gl.FLOAT, false, 0, 0);gl.bindBuffer(gl.ARRAY_BUFFER, cubeColorBuffer);

    gl.vertexAttribPointer(shaderProgram.color,

    cubeColorBuffer.itemSize,

    gl.FLOAT, false, 0, 0);

    gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, cubeIndexBuffer);

    gl.drawElements(gl.TRIANGLES, cubeIndexBuffer.numItems,

    gl.UNSIGNED_SHORT, 0);

    (...)

    }

    Rysunek 5: Efekt kocowy: szecian

    11 Teksturowanie

    11.1 Przygotowanie tekstury

    Na kad z tworzonych powierzchni moemy naoy dowoln tek-stur naladujc pewien materia. Tekstura to nic innego jak plik gra-ficzny obrazujcy np. drewno, metal. Przykad ten znajduje si w folde-rze"Kody rdowe\7. Teksturowanie", a uyta do naoenia na szeciantekstura towood.jpg. Zaczynam od zadeklarowania zmiennej na nasz tek-sture i stworzenia funkcji inicjalizujcej wywoywanej po inicjalizacji bufo-rw w funkcji start():

    var texture;

    (...)

    function initializeTexture() {

    texture = gl.createTexture();

    texture.image = new Image();

    texture.image.crossOrigin = "anonymous";

    18

  • 7/25/2019 Tutorial We Bgl

    19/26

    texture.image.onload = function() {

    setTexture(texture);}

    texture.image.src = "wood.jpg";

    }

    Nastpnie tworzymy funkcje setTexture() odpowiedzialn za usta-wienie odpowiednich parametrw tekstury (sposb skadowania tekstury,jej rodzaj, uyty system kolorw i techniki jej filtrowania):

    function setTexture(tex) {

    gl.bindTexture(gl.TEXTURE_2D, tex);

    gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA,

    gl.UNSIGNED_BYTE, tex.image);

    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER,

    gl.NEAREST);

    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER,

    gl.NEAREST);

    gl.bindTexture(gl.TEXTURE_2D, null);

    }

    11.2 Przygotowanie wsprzdnych

    Jednak tekstura nie moe wspistnie z powierzchni bez pewnegokleju. Tym klejem s dwuwymiarowe (u, v) wsprzdne tekstury okre-lajce pooenie wierzchoka powierzchni na teksturze. Umoliwia to rozsze-rzanie, zwanie i w oglnoci dopasowanie danej tekstury do powierzchni.Zakres dla tych wsprzdnych to 0.0-1.0.

    I tak wierzchoek o wsprzdnych u: 0.0, v: 0.0bdzie tam gdzielewy grny rg tekstury, a wic t jej czci zostanie przykryty. Z koleiwierzchoek ze wsprzednymiu: 1.0,v: 1.0to nic innego jak prawy dolnyrg. Pomidzy wierzchokami tekstura jest odpowiednio dopasowana. Kodwyglda nastpujco:

    var cubeTextureBuffer;

    (...)

    cubeTextureBuffer = gl.createBuffer();

    gl.bindBuffer(gl.ARRAY_BUFFER, cubeTextureBuffer);

    var coords = [

    // Przednia

    0.0, 0.0,

    1.0, 0.0,

    1.0, 1.0,

    19

  • 7/25/2019 Tutorial We Bgl

    20/26

    0.0, 1.0,

    (...)];

    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(coords),

    gl.STATIC_DRAW);

    cubeTextureBuffer.itemSize = 2;

    cubeTextureBuffer.numItems = 24;

    11.3 Modyfikacja shaderw

    Wszystko czego do tej pory dokonalimy w kontekcie tekstur na nic sizda jeli nie zmodyfikujemy jednostek cieniujcych. Wsprzdne tekstury s

    w tej kwestii na rwni z kolorem wierzchoka (ktry zostanie przez teksturzastpiony) i s przekazywane do potoku graficznego poczynajc od vertexshadera. Wymagana dlatego jest jego modyfikacja:

    attribute vec3 position;

    attribute vec2 coord;

    varying vec2 vCoord;

    uniform mat4 uWorldMat;

    uniform mat4 uProjectionMat;

    void main(void)

    {

    gl_Position = uProjectionMat * uWorldMat *

    vec4(position, 1.0);

    vCoord = coord;

    }

    Wsprzdne tekstur zazwyczaj nie s wykorzystywane w vertex sha-derze, a tylko przekazywane dalej do pixel shadera. To w nim dla kadegofragmentu powierzchni pobierany jest odpowiedni pixel tekstury przy po-mocy tzw. obiektu prbkujcego (ang. sampler), by nastpnie zosta nowymkolorem danego wycinka powierzchni:

    precision mediump float;varying vec2 vCoord;

    uniform sampler2D uSampler;

    void main(void)

    {

    gl_FragColor = texture2D(uSampler,

    vec2(vCoord.s, vCoord.t));

    }

    20

  • 7/25/2019 Tutorial We Bgl

    21/26

    11.4 Wywietlenie

    Przed rozpoczciem wywietlania musimy powiza dane programu zdanymi shaderw:

    shaderProgram.coord =

    gl.getAttribLocation(shaderProgram, "coord");

    gl.enableVertexAttribArray(shaderProgram.coord);

    (...)

    shaderProgram.samplerUniform =

    gl.getUniformLocation(shaderProgram, "uSampler");

    Wywietlanie zaczynamy od przekazania przekazania danych z progra-

    mu do vertex shadera, by nastpnie aktywowa nakadan tekstur i dokonakocowego renderingu:

    function draw() {

    (...)

    gl.bindBuffer(gl.ARRAY_BUFFER, cubeTextureBuffer);

    gl.vertexAttribPointer(shaderProgram.coord,

    cubeTextureBuffer.itemSize,

    gl.FLOAT, false, 0, 0);

    (...)

    gl.activeTexture(gl.TEXTURE0);

    gl.bindTexture(gl.TEXTURE_2D, texture);

    gl.uniform1i(shaderProgram.samplerUniform, 0);

    gl.drawElements(gl.TRIANGLES, cubeIndexBuffer.numItems,

    gl.UNSIGNED_SHORT, 0);

    (...)

    }

    Rysunek 6: Efekt kocowy: szecian oteksturowany

    21

  • 7/25/2019 Tutorial We Bgl

    22/26

    12 Obsuga klawiatury

    12.1 Wprowadzenie

    Obsuga klawiatury jest niezwykle atwa i opera si o zdarzenia prze-gldarki/obiektowego dokumentu wyzwalane podczas wcinicia bd pusz-czenia klawisza. Aktualna informacja o stanie klawisza (wcinity / puszczo-ny) jest przechowywana w tablicy currentKeys, ktrej stan jest zmienianyprzy pomocy funkcjikeyDownHandle()orazkeyUpHandle()wywoywanychwraz z wywoaniem wspomnianych wczeniej zdarze. Wszystko to opako-wujemy w funkcje inicjalizujc klawiatur:

    var currentKeys = {};

    function initializeKeyboard() {

    document.onkeydown = keyDownHandle;

    document.onkeyup = keyUpHandle;

    }

    function keyDownHandle(event) {

    currentKeys[event.keyCode] = true;

    }

    function keyUpHandle(event) {

    currentKeys[event.keyCode] = false;}

    12.2 Obsuga klawiszy

    Pozostao nam tylko obsuy odpowiedni klawisze. Zaczynamy odzdefiniowania zmiennej zoom przechowujcej aktualne oddalenie szecianiuod ekranu oraz od funkcji wykonujcej na tej zmiennej modyfikacje w zale-noci od wcinitego klawisza:

    function handleKeys() {

    if (currentKeys[38]) { // Strzaka w gr

    zoom -= 0.05;

    }

    if (currentKeys[40]) { // Strzaka w d

    zoom += 0.05;

    }

    }

    I tak strzaka w gr oddali szecian, a strzaka w d przybliy godo nas. Funkcj t wywoujemy funkcji tick()tu przed rysowaniem, tak

    22

  • 7/25/2019 Tutorial We Bgl

    23/26

    aby aktualna scena moga pozosta aktualne w stosunku do ustawionego

    przyblienia:function tick() {

    (...)

    handleKeys();

    beginDraw();

    draw();

    (...)

    }

    Na koniec musimy zaaplikowa zmienn zoom do operacji translacji

    szecianu. Dokonujemy tego w funkcji draw():draw() {

    (...)

    mat4.translate(worldMat, [0.0, 0.0, -7.0+zoom]);

    (...)

    }

    Rysunek 7: Efekt kocowy: szecian przybliony

    13 PrzeroczystoPrzeroczysto jest atwa do osignicia. Naley wyczy bufor gbi

    (wkocu nie interesuje nas obiekt najbardziej na wierzchu ale rwnie itan za, gdy z racji przeroczystoci pierwszego obiektu bdzie widoczny).Nastpnie wczy funkcje mieszania (ang. blending) i odpowiednio ustawi:

    function initialize(canvasName) {

    (...)

    gl.disable(gl.DEPTH_TEST);

    gl.enable(gl.BLEND);

    23

  • 7/25/2019 Tutorial We Bgl

    24/26

    gl.blendFunc(gl.SRC_ALPHA, gl.ONE);

    (...)}

    Kolejny krok to modyfikacja pixel shadera tak aby wynikowy kanaalpha (przeroczystoci) dla fragmentu tekstury by przemnoony przez od-powiedni wspczynnik przewitywania (u nas 0.5 - pprzeroczysto):

    precision mediump float;

    varying vec2 vCoord;

    uniform float uAlpha;

    uniform sampler2D uSampler;

    void main(void)

    {

    vec4 textureColor = texture2D(uSampler,

    vec2(vCoord.s, vCoord.t));

    gl_FragColor = vec4(textureColor.rgb,

    textureColor.a * uAlpha);

    }

    Nastpnie musimy obsuy nowy parametr w shaderze. W inicjalizacjishaderw pobieramy dla niego uniform, a w funkcji rysujcej ustawiamy na

    stae warto 0.5:shaderProgram.alphaUniform = gl.getUniformLocation(shaderProgram, "uAlpha");

    Oraz:

    gl.uniform1f(shaderProgram.alphaUniform, 0.5);

    Rysunek 8: Efekt kocowy: szecian przeroczysty

    24

  • 7/25/2019 Tutorial We Bgl

    25/26

    Spis treci

    1 Wstp 1

    2 Uruchomienie WebGL 22.1 Wstp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22.2 Wybr przegldarki . . . . . . . . . . . . . . . . . . . . . . . 22.3 Wczenie WebGL w przegldarce . . . . . . . . . . . . . . . 2

    3 Integracja z HTML5 33.1 Po stronie HTML5 . . . . . . . . . . . . . . . . . . . . . . . . 33.2 Po stronie WebGL . . . . . . . . . . . . . . . . . . . . . . . . 3

    4 Pusta scena 44.1 Inicjalizacja . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44.2 Rysowanie . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4

    5 Szkielet fruitGL (cz.1) 55.1 Wstp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55.2 Kod . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55.3 Wykorzystanie fruitGL . . . . . . . . . . . . . . . . . . . . . . 6

    6 Pierwszy obiekt (trjkt) 7

    6.1 Vertex Shader . . . . . . . . . . . . . . . . . . . . . . . . . . . 7

    6.2 Pixel Shader . . . . . . . . . . . . . . . . . . . . . . . . . . . 86.3 adowanie shaderw . . . . . . . . . . . . . . . . . . . . . . . 86.4 Bufor wierzchokw . . . . . . . . . . . . . . . . . . . . . . . . 96.5 Wywietlenie . . . . . . . . . . . . . . . . . . . . . . . . . . . 9

    7 Trzeci wymiar 107.1 Macierze . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117.2 Efekt kocowy . . . . . . . . . . . . . . . . . . . . . . . . . . 12

    8 Troch kolorkw 128.1 Jednostki cieniujce . . . . . . . . . . . . . . . . . . . . . . . 138.2 Bufor kolorw . . . . . . . . . . . . . . . . . . . . . . . . . . . 138.3 Wywietlenie . . . . . . . . . . . . . . . . . . . . . . . . . . . 14

    9 Animacja 149.1 Podstawy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 149.2 Stos macierzy . . . . . . . . . . . . . . . . . . . . . . . . . . . 159.3 Wywietlenie . . . . . . . . . . . . . . . . . . . . . . . . . . . 16

    25

  • 7/25/2019 Tutorial We Bgl

    26/26

    10 Szecian 16

    10.1 Bufory danych . . . . . . . . . . . . . . . . . . . . . . . . . . 1710.2 Wywietlenie . . . . . . . . . . . . . . . . . . . . . . . . . . . 17

    11 Teksturowanie 1811.1 Przygotowanie tekstury . . . . . . . . . . . . . . . . . . . . . 1811.2 Przygotowanie wsprzdnych . . . . . . . . . . . . . . . . . . 1911.3 Modyfikacja shaderw . . . . . . . . . . . . . . . . . . . . . . 2011.4 Wywietlenie . . . . . . . . . . . . . . . . . . . . . . . . . . . 21

    12 Obsuga klawiatury 22

    12.1 Wprowadzenie . . . . . . . . . . . . . . . . . . . . . . . . . . 22

    12.2 Obsuga klawiszy . . . . . . . . . . . . . . . . . . . . . . . . . 2213 Przeroczysto 23

    26