pic
Pomimo iż technologia WebGL jest stosunkowo młoda, już dostępna jest bogata baza frameworków. W zasadzie jest ich tak dużo, że na początku trudno któryś wybrać. W ostatnim czasie miałem okazję spróbować kilku z nich i podzielę się z  wami moimi spostrzeżeniami. Ostrzegam, że pewne cechy bibliotek, o których piszę mogą się zmienić w czasie (np. uwagi dot. niepełnych dokumentacji). Dodatkowo oceniałem ich możliwości pod kątem swoich potrzeb, ktoś inny może mieć inne wrażenia. SceneJS Dynamicznie rozwijany Framework z API sceny opartym na formacie JSON. Projekt zapoczątkowany przez Lindsay Key, aktualnie rozwijany przez kilka osób. Framewo...
pic
Artykuł poświęcony jest eksportowaniu modeli (stworzonych w programie blender) do formatu JSON i ładowaniu ich w WebGL. Zrobimy również mały porządek z shaderami, które wrzucimy do osobnych plików, co daje lepszą czytelność i pozwala chociażby na kolorowanie składni, jeśli mamy edytor, który rozpoznaje GLSL. Lekcja ta jest modyfikacją poprzedniej lekcji. Efekt końcowy na rysunku poniżej lub na żywo tutaj. JSON (JavaScript Object Notation) jest czytelnym i intuicyjnym formatem, który ma swoje korzenie w JavaScript (więcej możecie doczytać na wikipedii). JavaScript posiada wbudowany obiekt globalny JSON, który potrafi parsować ten format. Poniżej mamy zaw...
pic
Ukończyliśmy właśnie prace nad grą "Vehicle Soccer". Jest to trójwymiarowa zręcznościówka polegająca na umiejętnym manewrowaniu jednym z pojazdów w celu łapania, uderzania oraz omijania różnych piłek na arenach. Grać można samemu przechodząc i odblokowując kolejne rundy (tryb single) lub w 2 osoby na jednej klawiaturze starając się zdobyć więcej punktów od przeciwnika (tryb multi). Gra została wystawiona do konkursu Mozilla Labs - Game ON więc możecie trzymać kciuki i jeśli wam się spodoba - oddać swój głos :-) Lista wszystkich gier zgłoszonych do konkursu znajduje się w galerii gier konkursu Game On. Aby zagrać wystarczy kliknąć w scr...
pic
źródło: Mozilla Konkurs skierowany jest do niezależnych twórców gier. Aby wziąć w nim udział trzeba stworzyć grę przeglądarkową wykorzystującą wyłącznie otwarte standardy webowe. Mile widziane są nowo powstające technologie takie jak WebGL, czy HTML5. Zasada jest jedna: gra musi być kompatybilna z przegladarką Firefox w najnowszej (testowej jeszcze) wersji 4.0. Gdy gra będzie gotowa, trzeba zarejestrować się na oficjalnej stronie wydarzenia: gaming.mozillalabs.com i podać nazwę, krótki opis oraz link do dzieła umieszczonego w sieci. Podczas oceniania gier brane będą pod uwagę następujące walory: Poprawność techniczna (engine, kod), wykorz...
pic
Dzisiaj dodamy trochę światła do naszej sceny. Lekcja ta bazuje na kodzie jednej z poprzednich: Porządek w kodzie i omówię jedynie różnice. Efekt końcowy dzisiejszej lekcji zobaczyć możecie na rysunku poniżej, lub na żywo tutaj. Możecie również pobrać kod dzisiejszej lekcji. Osoby zaznajomione z OpenGL mogą być trochę zawiedzone faktem, że WebGL (który bazuje na OpenGL ES) nie posiada automatycznego wsparcia dla światła (czytaj funkcji ustawiających pozycję, kolor itp. parametrów światła). Wszelkie obliczenia związane z oświetleniem musimy zrobic sami w shaderach. Przytoczona tu metoda jest tzw. "opartą na wierzchołkach". Znaczy to tyle, że...
lip

30

efekt_końcowy

Dzisiaj dodamy trochę światła do naszej sceny. Lekcja ta bazuje na kodzie jednej z poprzednich:
Porządek w kodzie i omówię jedynie różnice. Efekt końcowy dzisiejszej lekcji zobaczyć możecie na rysunku poniżej, lub na żywo tutaj. Możecie również pobrać kod dzisiejszej lekcji.

Osoby zaznajomione z OpenGL mogą być trochę zawiedzone faktem, że WebGL (który bazuje na OpenGL ES) nie posiada automatycznego wsparcia dla światła (czytaj funkcji ustawiających pozycję, kolor itp. parametrów światła). Wszelkie obliczenia związane z oświetleniem musimy zrobic sami w shaderach. Przytoczona tu metoda jest tzw. „opartą na wierzchołkach”. Znaczy to tyle, że światło obliczane jest tylko dla wierzchołków, a kolor każdego innego punktu w polygonie jest automatycznie uśredniany. Dlatego np. oświetlenie na kuli posiadającej mało wierzchołków będzie wyglądać dosyć sztucznie. Oświetlenie oparte na fragmentach przybliżymy w jednej z następnych lekcji.

Lekcja druga - efekt końcowy

Na poczatek przybliżmy trochę teorii…

W „normalnym” świecie istnieje tylko jeden typ światła – fotony z różnych miejsc (ze Słońca, nieba, odbite od ściany itd) padają na dane miejsce i odbijają część światła zależnie od materiału (czy to szkło, drewno, skóra) i kąta nachylenia.
Niestety źródeł światła jest praktycznie nieskończenie wiele i chociażby z tego powodu taki sposób nie może być użyty (dla ciekawskich polecam temat: radiosity lub ogólnie „global illumination”).

Uproszczenie, które stosuje się najczęściej w grafice polega na podzieleniu światła na 3 składowe:

  • Światło otaczające (ambient), padające ze wszystkich stron równomiernie
  • Światło rozproszone (diffuse), padające z pewnego kierunku, jednak jasność punktu nie zależy od pozycji patrzącego
  • Światło odbite (specular), refleksy świetlne (w tej lekcji jeszcze nie rozpatrujemy tej składowej)

Patrz również obrazek na tej stronie: http://en.wikipedia.org/wiki/Phong_shading
W tej lekcji również uprościmy sprawę pozycji światła – otóż założymy tu, że pada ono na każdy wierzchołek z tego samego kierunku, a nie pozycji (uprości nam to trochę obliczenia w vertex shaderze, gdyż nie będziemy musieli martwić się o obliczenie kierunku padania światła, który jest różny dla różnych wierzchołków).

Przejdźmy może do kodu… Najpierw dodajmy przycisk przełączania światła:

<button onclick="switchLight();">switch light</button>

oraz funkcje obslugującą to przelączanie:

// wskazuje czy swiatlo jest wlaczone
var lightIsEnabled = true;
// wlacza / wylacza swiatlo
function switchLight(){
  lightIsEnabled = !lightIsEnabled;
}

Definicja modelu (tablica wierzchołków, indeksów, koordynatów tekstur) tym razem jest dużo bardziej złożona (eksportowanie modeli z programów graficznych pojawi się w innej lekcji) i zawiera dodatkowo tablicę wektorów normalnych dla wszystkich wierzchołków (możesz podejrzeć ją w pliku objects/Sphere_geometry.js). Wektor normalny jest to wektor prostopadły do powierzchni, do której należy dany wierzchołek. Im kąt między wektorem normalnym a kierunkiem światła jest mniejszy tym ten wierzchołek będzie bardziej oświetlony (przez składową rozproszoną (diffuse)). Po więcej szczegółów, doczytaj np tu: wektor normalny oraz tu: Prawo Lamberta.

A więc musimy poszerzyć zbiór naszych zmiennych o niezbędne bufory oraz wskaźniki na zmienne w shaderach. Najpierw w funkcji Model_init postępujemy analogicznie jak w przypadku dotychczasowych buforów:

//create vertex normal buffer
if (tabNormal)
{
  this.Normals = gl.createBuffer();
  gl.bindBuffer(gl.ARRAY_BUFFER, this.Normals);
  gl.bufferData(gl.ARRAY_BUFFER, new WebGLFloatArray(tabNormal), gl.STATIC_DRAW);
  this.Normals.itemSize = 3;
  this.Normals.numItems = tabNormal.length / 3;
}
	

i wywołamy ją z dłuższą listą parametrów:

Sphere.init("textures/earth.jpg", 0, 0, SphereData.vertices, SphereData.texCoords, null, SphereData.normals);
	

a w funkcji Model_draw przekazujemy do shaderów niezbędne dane:

gl.bindBuffer(gl.ARRAY_BUFFER, this.Normals);
gl.vertexAttribPointer(shaderProgram.vertexNormalAttribute, this.Normals.itemSize, gl.FLOAT, false, 0, 0);
// tu wlaczamy / wylaczamy swiatlo po nacisnieciu przycisku
gl.uniform1i(shaderProgram.useLightingUniform, lightIsEnabled);
if (lightIsEnabled) {
  // tu przekazujemy swiatlo otaczajace - pokombinuj z wartosciami - z reguly te wartosci powinny byc nieduze
  gl.uniform3f(shaderProgram.ambientColorUniform, 0.2, 0.2, 0.2);

  // tu na sztywno ustawilismy kierunek (NIE POZYCJE!) padania światła
  var lightingDirection = Vector.create([5, 5, 10]);
  // normalizujemy ten wektor - czyli skracamy lub wydluzamy wektor (bez zmiany jego kierunku, tab aby jego dlugosc byla rowna 1
  var adjustedLD = lightingDirection.toUnitVector();
  var flatLD = new WebGLFloatArray(adjustedLD.flatten());
  // i przekazujemy go do shadera
  gl.uniform3fv(shaderProgram.lightingDirectionUniform, flatLD);

  // a tu przekazujemy kolor swiatla diffuse (składowe RGB z zakresu od 0 do 1)
  gl.uniform3f(shaderProgram.directionalColorUniform, 0.9, 0.9, 0.7);
}
	

Musimy również dodać do funkcji setMatrixUniforms następujący kod:

var normalMatrix = mvMatrix.inverse().transpose();
gl.uniformMatrix4fv(shaderProgram.nMatrixUniform, false, new WebGLFloatArray(normalMatrix.flatten()));
	

Żeby dogłębnie wyjaśnić powyższe działania, chociażby dlaczego potrzebujemy dodatkowej macierzy dla wektorów normalnych, należałoby wprowadzić trochę niskopoziomowej algebry. Ja tylko zarysuję, że „zwykła” macierz Model-View przetransformowałaby (po translacji [0, -1, 0]) wektor normalny [0, 1, 0] do [0, 0, 0] co byłoby nonsensem, ponieważ wektory normalne nie poddają się translacji.

Odnośnie szczegołów „wyciągania” macierzy dla wektorów normalnych z macierzy MV można doczytać np tu: gl_NormalMatrix.

I wreszczcie najważniejsza i najbardziej interesująca część, czyli kod shaderów:

<script id="shader-vs" type="x-shader/x-vertex">
  attribute vec3 aVertexPosition;
  attribute vec3 aVertexNormal;
  attribute vec2 aTextureCoord;
  uniform mat4 uMVMatrix;
  uniform mat4 uPMatrix;
  uniform mat4 uNMatrix;
  uniform vec3 uAmbientColor;
  uniform bool uUseLighting;
  varying vec2 vTextureCoord;
  varying vec3 vLightWeighting;

  uniform vec3 uLightingDirection;
  uniform vec3 uDirectionalColor;

  void main(void) {
    gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);
    vTextureCoord = aTextureCoord;
    if (!uUseLighting) {
      vLightWeighting = vec3(1.0, 1.0, 1.0);
    } else {
      vec4 transformedNormal = uNMatrix * vec4(aVertexNormal, 1.0);
      float directionalLightWeighting = max(dot(transformedNormal.xyz, uLightingDirection), 0.0);
      vLightWeighting = uAmbientColor + uDirectionalColor * directionalLightWeighting;
    }
  }
</script>
	

Oprócz długiej listy zmiennych jedyną nowością jest blok if. W przypadku wyłączenia światła ustawiamy wagę (współczynnik) światła na maksymalną wartość, czego skutkiem będzie w pełni oświetlona scena bez zacienionych miejsc, co wygląda sztucznie.

Ciekawiej jest, gdy mamy włączone oświetlenie. Jeśli wczytałeś się w link o Prawie Lamberta, to pewnie już wiesz, że jasność danego wierzchołka zależy od cosinusa kąta padania światła i wektora normalnego (dla 0 kąta jest maksymalna, dla 90′ i większych jest zerowy). Jak powszechnie wiadomo w grafice 3d, cosinus można łatwo i wydajnie wyrazić za pomocą iloczynu skalarnego (ang. dot product), który na szczęście jest wbudowaną funkcją w shaderach GLSL. Funkcję max uzywamy, żeby wykluczyć minusowe wartości.

Ostateczna wartość współczynnika oświetlenia wierzchołka (vLightWeighting) jest równa sumie składowej ambient (zawsze jest stała i niezależna od cech wierzchołka) oraz iloczynu koloru światła diffuse i wartości wynikającej z Prawa Lamberta.

Shader fragmentów jest nadal nieskomplikowany i różni się jedynie tym, że dany fragment jest rozjaśniany / przyciemniany przez zmienną varying vLightWeighting:

<script id="shader-fs" type="x-shader/x-fragment">
  varying vec2 vTextureCoord;
  varying vec3 vLightWeighting;
  uniform sampler2D uSampler;

  void main(void) {
    vec4 textureColor = texture2D(uSampler, vec2(vTextureCoord.s, vTextureCoord.t));
    gl_FragColor = vec4(textureColor.rgb * vLightWeighting, textureColor.a);
  }
</script>
	

I to wszystko. Możemy uruchomić nasz pierwszy program wyposażony w proste oświetlenie. Na kolejnej lekcji pokażę Wam, jak stworzyć oświetlenie oparte na fragmentach. Dodamy również światło odbite – specular.

autor: Gliniak

2 Comments

  1. [...] For Polish-speaking readers, here’s what looks like another good tutorial from 3dgames.pl, this time on ambient and directional lighting. [...]

  2. [...] nazwę, krótki opis oraz link do dzieła umieszczonego w sieci. Podczas oceniania gi… Oświetlenie globalne oraz światło kierunkowe w WebGL Dzisiaj dodamy trochę światła do naszej sceny. Lekcja ta bazuje na kodzie jednej z poprzednich: [...]

Comment

Copyright © 2012 3dgames - Kolejny blog oparty na WordPressie.
Website powered by WordPress and Emescale wordpress theme designed by TopTut.com & TopWPThemes.com.
Visit WebHostingFan.com for the latest news on web hosting and cms review.