Árnyalás, env mapping Szécsi László 3D Grafikus Rendszerek 3. labor
Egyszerű árnyaló FS legyen egy fényirány-vektor normálvektor és fényirány közötti szög koszinusza az irradiancia textúrából olvasott színt szorozzuk ezzel
Várt eredmény
Feladat pontfényforrás uniform pozíció, teljesítmény diffúz + Phong-Blinn BRDF uniform kd, ks, gamma per-pixel lighting worldnormal normalizálása, viewdir, lightdir számítása keringő fényforrás pozíció változtatása minden frameben
Environment mapping doboztextúra betöltése új FS ami kiszámolja az ideális visszaverődési irányt és kiolvassa a textúrát
TextureCube.js - betöltés const TextureCube = function(gl, mediafileurls) { gl.pendingresources[mediafileurls[0]] = ++gl.pendingresources[mediafileurls[0]] 1; this.mediafileurls = mediafileurls; this.gltexture = gl.createtexture(); this.loadedcount = 0; this.images = []; var thetexture = this; for(let i=0; i<6; i++){ this.images[i] = new Image(); this.images[i].onload = function() { thetexture.loaded(gl); } this.images[i].src = mediafileurls[i]; } };
TextureCube.js erőforrás létrehozása TextureCube.prototype.loaded = function(gl){ this.loadedcount++; if(this.loadedcount < 6) return; gl.bindtexture(gl.texture_cube_map, this.gltexture); for(var i=0; i<6; i++){ gl.teximage2d(gl.texture_cube_map_positive_x+i, 0, gl.rgba, gl.rgba, gl.unsigned_byte, this.images[i]); } gl.texparameteri(gl.texture_cube_map, gl.texture_mag_filter, gl.linear); gl.texparameteri(gl.texture_cube_map, gl.texture_min_filter, gl.linear_mipmap_linear); gl.generatemipmap(gl.texture_cube_map); gl.bindtexture(gl.texture_cube_map, null); if( --gl.pendingresources[this.mediafileurls[0]] === 0 ) { delete gl.pendingresources[this.mediafileurls[0]]; } };
Tükröző objektum létrehozása fragment shader // kell egy sampler uniform uniform samplercube envmaptexture; // kiolvasni a tükörirányban texturecube( envmaptexture, reflect(-viewdir, normal)) gyártsuk le a TextureCube-ot, kössük be a fenti FS-t használó Material-ba, a GameObject használja ezt az anyagot this.skycubetexture = new TextureCube(gl, [ "media/posx512.jpg", "media/negx512.jpg", "media/posy512.jpg", "media/negy512.jpg", "media/posz512.jpg", "media/negz512.jpg",] ); this.slowpokematerial0. envmaptexture.set ( this.skycubetexture);
Várt eredmény higany pokemon visszaveri a környezetét de maga a környezet nem látszik
RayDir mátrix számítása PerspectiveCamera.prototype.updateRayDirMatrix = function(){ // önállóan megoldandó feladat // már nem ér rá annyira // az env mapping háttérhez kell most };
Sugárirány kiszámítása NDC-ből (EVP) -1 -et nevezzük raydirmatrix-nak
Környezet megjelenítése háttérként teljes képernyős téglalapot kell rajzolni (hurrá!) új VS: kiszámolja a sugárirányt át kell adni a képernyőkoordinátából-világkoordinátamínusz-szempozíció-számító mátrixot (a.k.a. raydirmatrix) a kamera ezt kiszámolja nem transzformál (mert full viewport quad) z=0.99999, minden mőgé FS megkapja a VS-től varying-ben a sugárirányt ezzel címzi a textúrát visszaadja a kapott színt
Ne felejtsük el a GameObject adja át a raydirmatrix-ot az új shadereket vegyük be az index.html-be gyártsuk le szükséges shader, program, material objektumokat ugyanazt a doboztextúrát kössük be a háttér anyagába, mint amit a tükröző objektuméba legyen quadgeometry legyen egy mesh a quadgeometry és a fenti material használatával legyen egy gameobject a mesh-sel
Várt eredmény tükröző objektum és háttér
Házi feladat procedurális normal mapping zajfüggvény: random (de fix) irányok mentén koszinuszok összege normálvektor perturbációja zajfüggvény gradiensével env mappinggel kombinálva (háttér is kell)
Egyszerű zaj float snoise(vec3 r) { vec3 s = vec3(7502, 22777, 4767); float f = 0.0; for(int i=0; i<16; i++) { f += sin( dot(s - vec3(32768, 32768, 32768), r) / 65536.0); s = mod(s, 32768.0) * 2.0 + floor(s / 32768.0); } return f / 32.0 + 0.5; }
Egyszerű zaj gradiense vec3 snoisegrad(vec3 r) { vec3 s = vec3(7502, 22777, 4767); vec3 f = vec3(0.0, 0.0, 0.0); for(int i=0; i<16; i++) { f += cos( dot(s, r - vec3(32768, 32768, 32768)) / 65536.0) * s; s = mod(s, 32768.0) * 2.0 + floor(s / 32768.0); } return f / 65536.0; }