Comenceu a utilitzar WebGL: dibuixeu un quadrat

Autora: Laura McKinney
Data De La Creació: 9 Abril 2021
Data D’Actualització: 10 Ser Possible 2024
Anonim
Comenceu a utilitzar WebGL: dibuixeu un quadrat - Creatiu
Comenceu a utilitzar WebGL: dibuixeu un quadrat - Creatiu

Content

  • Coneixements necessaris: Coneixement intermedi d’HTML / JavaScript
  • Requereix: Últims Chrome o Firefox 4/5 que admeten WebGL
  • Hora del projecte: 2-3 hores
  • Fitxer de suport

La primera trobada amb WebGL pot ser intimidant. L'API no té res de les biblioteques simples orientades a objectes que podríeu haver utilitzat. WebGL es basa en OpenGL, que és una biblioteca tipus C de tipus bastant antic. Inclou una llarga llista de funcions que s’utilitzen per configurar diferents estats i passar dades a la GPU. Tot això es descriu a l'especificació oficial. Aquest document no està pensat per a principiants, pensant que serà molt útil un cop comenceu a cercar el camí cap a l’API. Però no us temeu: amb un bon enfocament, tot això es pot domar i aviat començareu a sentir-vos còmodes.

Una idea equivocada habitual sobre WebGL és que es tracta d’un tipus de motor o API 3D. Tot i que WebGL té de fet moltes funcions que us ajudaran a desenvolupar aplicacions 3D, en si mateix no és 3D. És molt millor pensar en WebGL com en una API de dibuix que us doni accés a gràfics accelerats per maquinari.


01. Dibuixar un quadrat

En aquest tutorial ens centrarem en entendre com funciona WebGL dibuixant una forma 2D senzilla. Però el primer és el primer. Abans d’escriure qualsevol codi, hem de crear un document HTML per contenir-lo.

html>
cap>
script id = "vertex" type = "x-shader"> / script>
script id = "fragment" type = "x-shader"> / script>
script type = "text / javascript">
funció init () {
}
/ script>
/ cap>
body onload = "init ()">
canvas id = "mycanvas" width = "800" height = "500"> / canvas>
/ cos>
/ html>

A part dels registres HTML habituals, el document té algunes coses específiques de WebGL. Primer de tot, definim dues etiquetes de script que en lloc de JavaScript allotjaran el codi shader. Els Shaders són una característica central de WebGL i hi tornarem a parlar més endavant.

L’altre element que necessitarem és el llenç. Tot el WebGL es dibuixa en un element de llenç.

Finalment definim una funció anomenada init que s'invocarà tan bon punt es carregui el document. Aquí és on emetrem les ordres necessàries per dibuixar qualsevol cosa a la pantalla. Comencem a afegir algun codi dins d'aquesta funció.


02. El context i la finestra gràfica de WebGL

A la funció init hem d’obtenir el context WebGL de l’element canvas.

canvas = document.getElementById ("mycanvas");
gl = canvas.getContext ("experimental-webgl");

Obtenim una referència a l’element canvas definit al document HTML i, a continuació, obtenim el context WebGL. L'objecte retornat ens permetrà accedir a l'API WebGL. Podeu anomenar-lo com vulgueu, però "gl" sembla una bona convenció.

Tingueu en compte que el context 3D s'anomena "experimental-webgl". Aquesta és una solució temporal fins que els fabricants de navegadors decideixin que és estable. Aleshores el nom canviarà a només "webgl".

Un cop tenim el context, és hora de definir la finestra gràfica i establir-hi un color per defecte. La finestra gràfica defineix l'àrea on voleu dibuixar el contingut de WebGL: en el nostre cas es tractarà del llenç sencer. A continuació, definim un color per defecte per a la finestra gràfica i cridem a la funció neta per configurar la finestra gràfica a aquest color. Continueu afegint les línies següents:


gl.viewport (0, 0, canvas.width, canvas.height);
gl.clearColor (0, 0,5, 0, 1);
gl.clear (gl.COLOR_BUFFER_BIT);

Tingueu en compte que els colors de WebGL no es defineixen mitjançant la notació hexadecimal, sinó generalment com a quatre nombres, cadascun en l'interval [0-1] que defineixen els valors dels canals vermell, verd, blau i alfa per separat. Si obriu el fitxer al navegador, hauríeu de veure l'àrea del llenç pintada de verd fosc.

Si no veieu el color verd fosc al llenç i esteu segur que el codi és correcte, consulteu aquest enllaç. És possible que algunes targetes gràfiques antigues no funcionin amb WebGL, fins i tot si teniu un navegador que el suporti.

03. Ombres: ombra de vèrtex

En aquest moment, deixem la funció init per un temps i ens centrem en els shaders. Els shaders són fonamentals per a WebGL: defineixen com es dibuixa qualsevol cosa a la pantalla. Un programa de ombres es compon de dues parts: un vèrtex i un ombrejat de fragments. L’ombrador de vèrtex processa punts de la geometria de la forma que representem, mentre que l’ombrador de fragments processa cada píxel que omple aquesta forma.

Per al nostre exemple, crearem uns shaders realment bàsics. Comencem pel vèrtex. Dins de l'etiqueta de script amb l'identificador "vèrtex" afegiu les línies següents:

atribut vec2 aVertexPosition;

void main () {
gl_Position = vec4 (aVertexPosition, 0,0, 1,0);
}

Tots els ombres tenen una funció anomenada principal que s’executarà durant la representació. Les variables declarades a la capçalera són paràmetres d'aquesta funció; poden ser atributs o uniformes. Veurem una variable uniforme més endavant; ara examinem l'atribut de més a prop.

Un atribut és una matriu de dades que es processaran: es cridarà a la funció principal del sombreador per a cada element d’aquesta matriu. Normalment, un atribut conté dades relacionades amb les posicions dels vèrtexs, els seus colors o les coordenades de textura. Tot i això, no es limita només a això: és un conjunt de números i el sombreador els pot interpretar de la manera que vulgueu. Més endavant, passarem les dades de l’atribut de JavaScript al shader.

El que passa aquí és que prenem el valor de l'atribut i l'assignem a una variable especial anomenada gl_Position. Aquesta és la forma en què els shaders retornen valors; no hi ha cap paraula clau "return", però haurà d'assignar un valor a aquesta variable especial.

Tingueu en compte que decidim utilitzar un vector de dos components com a tipus del nostre atribut, cosa que té sentit, perquè dibuixarem una forma mitjançant coordenades 2D. Tanmateix, gl_Position espera un vector de quatre components. El que farem és codificar els dos valors restants, ja que sempre seran els mateixos.

Si us pregunteu què representen aquests dos valors: el tercer, que establim a 0, és la "profunditat" del vèrtex. Pot tenir qualsevol valor, però si és> 1 o -1, aquest vèrtex no es dibuixarà. Es dibuixarà qualsevol cosa entremig i es dibuixaran objectes amb una profunditat menor. Penseu que és similar a l’índex z de CSS. La profunditat és crucial per representar escenes en 3D.

El quart número és l’anomenada coordenada homogènia que s’utilitza en la projecció en perspectiva. Està fora de l’abast d’aquest tutorial per parlar-ne, però en casos simples com aquest hauria de tenir el valor d’1.

04. Ombres: ombra de fragments

Ara definim el sombreador de fragments. Afegiu les línies següents a l'etiqueta de script amb l'identificador "fragment"

#ifdef GL_ES
flotador highp de precisió;
#endif

uniforme vec4 uColor;

void main () {
gl_FragColor = uColor;
}

Igual que amb l'ombra de vèrtex, l'ombra de fragments és essencialment una funció i cal anomenar-la "principal". Les tres primeres línies són el codi de la placa de la caldera: defineix la precisió utilitzada amb valors de coma flotant i només cal que hi sigui.

A continuació, definim una variable uniforme uColor. A diferència dels atributs, les variables uniformes són constants. Quan s'executa el sombreador per a cada vèrtex i píxel de la pantalla, el valor uniforme seguirà sent el mateix a cada trucada. L’utilitzem per definir el color de la forma que dibuixarem. Passarem un valor per a aquest color des de JavaScript.

Tingueu en compte que el color també és un vector de quatre components: un per a cada canal de color: vermell, verd i blau i un per al canal alfa. A diferència de CSS, els valors de cada canal no es troben entre 0-255, sinó més aviat entre 0-1.

El sombreador de fragments és molt senzill: només pren el valor del color i l’assigna a una variable especial anomenada gl_FragColor. Aquest ombrejat només aplicarà el mateix color a cada píxel dibuixat a la pantalla.

05. Compilació i enllaç de shaders

Els nostres shaders estan al seu lloc, així que tornem a JavaScript i continuem amb la funció init. Just després de la trucada a gl.clear (), afegiu les línies següents:

var v = document.getElementById ("vèrtex"). firstChild.nodeValue;
var f = document.getElementById ("fragment"). firstChild.nodeValue;

var vs = gl.createShader (gl.VERTEX_SHADER);
gl.shaderSource (vs, v);
gl.compileShader (vs);

var fs = gl.createShader (gl.FRAGMENT_SHADER);
gl.shaderSource (fs, f);
gl.compileShader (fs);

programa = gl.createProgram ();
gl.attachShader (programa, vs);
gl.attachShader (programa, fs);
gl.linkProgram (programa);

Hi ha una cosa que cal saber sobre els shaders. No s'executen al navegador com fa el codi JavaScript. Primer heu de compilar el sombreador, i això és el que fa el codi anterior. Les dues primeres línies només fan servir el model DOM per agafar la font del sombreador com una cadena. Un cop tenim la font, creem a dos objectes de sombra, passem la font i els compilem.

En aquesta etapa tenim dos shaders separats i els hem de reunir en alguna cosa que s'anomena "programa" a WebGL. Això es fa enllaçant-los, cosa que es fa a la darrera secció del codi.

06. Depuració de shaders

La depuració dels shaders pot ser complicada. Si hi ha un error en un codi shader, fallarà silenciosament i no hi ha manera de registrar-ne els valors. Per tant, sempre és bo comprovar si el procés de compilació i enllaç ha anat bé. Després d'enllaçar el programa, afegiu les línies següents:

if (! gl.getShaderParameter (vs, gl.COMPILE_STATUS))
console.log (gl.getShaderInfoLog (vs));

if (! gl.getShaderParameter (fs, gl.COMPILE_STATUS))
console.log (gl.getShaderInfoLog (fs));

if (! gl.getProgramParameter (programa, gl.LINK_STATUS))
console.log (gl.getProgramInfoLog (programa));

Ara, si hi ha un problema durant la compilació o l’enllaç, rebreu un bon missatge a la consola.

Amb els nostres shaders al seu lloc i compilats, podem passar a definir les coordenades de la nostra forma.

07. Sistema de coordenades nadiu

El sistema de coordenades natives de WebGL té aquest aspecte:

El píxel superior esquerre és a -1, -1 i la part inferior a 1,1, independentment de la mida i les proporcions del llenç. Cal tenir cura de les proporcions vosaltres mateixos.

A WebGL hi ha tres tipus de primitives de dibuix: punts, línies i triangles. Les línies i els punts són força útils, però el triangle és, amb diferència, el més popular: tots els objectes sòlids en 3D estan formats per triangles. Volem dibuixar un quadrat i un quadrat pot estar format per dos triangles.

El que hem de fer ara és crear una matriu, que a WebGL s’anomena búfer, amb les coordenades dels dos triangles. Aquí teniu el codi:

var aspect = canvas.width / canvas.height;

var vertices = new Float32Array ([
-0,5, 0,5 * aspecte, 0,5, 0,5 * aspecte, 0,5, -0,5 * aspecte, // Triangle 1
-0,5, 0,5 * aspecte, 0,5, -0,5 * aspecte, -0,5, -0,5 * aspecte // Triangle 2
]);

vbuffer = gl.createBuffer ();
gl.bindBuffer (gl.ARRAY_BUFFER, vbuffer);
gl.bufferData (gl.ARRAY_BUFFER, vèrtexs, gl.STATIC_DRAW);

itemSize = 2;
numItems = vertices.length / itemSize;

En primer lloc, per tal de fer que el quadrat tingui les proporcions adequades sobre un llenç de qualsevol mida, calculem la relació d’aspecte. A continuació, creem una matriu mecanografiada amb 12 coordenades: sis punts en dimensions 2D que formen dos triangles. Multiplicem els valors Y de cada vèrtex per la relació d'aspecte. Tingueu en compte que aquests dos triangles "s'enganxaran" a un costat per crear el quadrat, però realment no estan connectats en absolut.

A continuació, passem a les funcions WebGL per crear una memòria intermèdia i connectar la matriu de vèrtex a aquesta memòria intermèdia. La manera de fer-ho és lligar la memòria intermèdia: convertint-la en la memòria intermèdia "actual" de WebGL. Quan està lligat, qualsevol trucada a una funció funcionarà en aquest buffer i això és el que passa quan invocem bufferData.

Així succeeixen moltes coses a WebGL: definiu un valor a una propietat o definiu algun objecte com a "actual" i, fins que no el configureu a una altra cosa o a nul, aquest valor s'utilitzarà en totes les trucades a l'API . En aquest sentit, a WebGL tot és global, així que organitzeu el vostre codi.

Finalment, assignem la mida d’un sol vèrtex a una variable i la quantitat de vèrtexs de la matriu a una altra, per a un ús posterior.

08. Establir uniformes i atributs

Quasi hem acabat, però encara hem de passar totes les dades de JavaScript als shaders abans de poder dibuixar res. Si ho recordeu, el vèrtex shader té un atribut del tipus vec2 anomenat aVertexAttribute i el fragment shader té una variable uniforme del tipus vec4 anomenada uColor. Com que els dos shaders s'han compilat en un sol programa, fem servir una referència a aquest programa per assignar-los valors significatius.

Continuem dins de la funció init:

gl.useProgram (programa);

program.uColor = gl.getUniformLocation (programa, "uColor");
gl.uniform4fv (program.uColor, [0,0, 0,3, 0,0, 1,0]);

program.aVertexPosition = gl.getAttribLocation (programa, "aVertexPosition");
gl.enableVertexAttribArray (program.aVertexPosition);
gl.vertexAttribPointer (program.aVertexPosition, itemSize, gl.FLOAT, false, 0, 0);

La primera línia indica a WebGL que utilitzi el programa actual per a qualsevol trucada posterior.

Mitjançant la funció getUniformLocation podem obtenir una referència a la ubicació de la variable uniforme al nostre ombrejat de fragments. Tingueu en compte que si la variable uniforme es trobés a l'ombra del vèrtex, el codi seria exactament el mateix. Un cop el tinguem, el conservem en una variable dinàmica de l’objecte del programa (també podríem mantenir-lo en una variable global o local, però d’aquesta manera es fa que aquest codi sigui una mica més organitzat).

A continuació, assignem un valor a l'uniforme uColor. En aquest cas, ha de ser una matriu de quatre números, que defineixin els canals vermell, verd, blau i alfa respectivament.

Després d’establir la variable uniforme, passem a l’atribut. Requereix uns quants passos addicionals. Obtenim la ubicació de l’atribut a la sombra d’una manera similar a la de l’uniforme, tot i que fem servir una funció diferent per a això.

A continuació, hem d’habilitar explícitament l’atribut i assignar-li un punter. En cas que us pregunteu com WebGL sap que volem utilitzar el buffer declarat anteriorment, recordeu el caràcter global de les funcions WebGL. Vam trucar a bindBuffer unes quantes línies abans, de manera que encara és l’actual.

Les aplicacions del món real poques vegades són tan senzilles com aquest exemple i haureu de tenir molta cura per saber quin búfer o programa estan actualment vinculats i en ús. A més, una regla general per a l’optimització del codi és minimitzar la quantitat de memòria intermèdia d’enllaç i desenllaç o de commutar entre programes de sombra.

A la trucada de funció vertexAttribPointer especifiquem la mida de l’element de les dades a l’atribut. És com dir: cada atribut es compon de dos números posteriors a la matriu. WebGL els extreurà automàticament i els empaquetarà en una variable de tipus vec2 que entra al sombreador.

09. Dibuix

Aquí teniu la línia final i més important:

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

El primer argument de la funció drawArrays especifica el mode de dibuix. Volem dibuixar un quadrat sòlid, de manera que fem servir gl.TRIANGLES. També podeu provar gl.LINES i gl.POINTS.

Aquesta funció utilitzarà la memòria intermèdia actualment lligada i cridarà el programa de sombreador actual per a cada atribut tantes vegades com especifiquem a l'últim argument. És per això que abans hem calculat el valor numItems. Si la memòria intermèdia no té prou elements, es produirà un error, de manera que cal tenir més cura per assegurar-se que les dades no estiguin malmeses.

Si tot anava bé, hauríeu de veure un quadrat de qualsevol color que passés a la variable uniforme. La font completa de l'exemple es pot trobar a la demostració a la part superior d'aquest tutorial.

10. Conclusió

Pot ser que no sembli gaire, de manera que hem creat un quadrat ... De fet, és un exemple bastant senzill, però si entenem els conceptes bàsics, podreu avançar bastant ràpid en l’aprenentatge i comprensió de la resta.

Per començar, és bo conèixer el sistema de coordenades nadiu. Tot i que més endavant no ho tractareu directament, sinó a través de diverses transformacions de matriu, és molt útil saber on acaba tot.

Els atributs i els uniformes també són molt importants: són la manera de comunicar-se entre JavaScript i els shaders que s’executen a la GPU, així que coneixeu-los i utilitzeu-los.

Això és tot per ara. Espero que us hagi agradat el tutorial i WebGL.

Bartek treballa com a tecnòleg creatiu a Tool of North America. Escriu un blog centrat en 3D interactiu en temps real, anomenat Everyday3D i és autor de J3D, un motor de codi obert WebGL. El podeu seguir a Twitter: @bartekd.

Missatges Nous
Es defineixen 3 tendències que afectaran l’economia creativa
Més Lluny

Es defineixen 3 tendències que afectaran l’economia creativa

Adobe ha publicat el eu primer conjunt de conclu ion d’una nova èrie d’inve tigacion obre l’economia creativa.Com vam informar al març, Adobe i Behance van llançar recentment el eu prim...
Per què el futur web estarà liderat per dissenyadors visuals
Més Lluny

Per què el futur web estarà liderat per dissenyadors visuals

Internet é va t i ha recorregut un llarg camí en un temp relativament curt. De vegade é difícil recordar per què hem fet le co e de la manera que ho hem fet. El any d’antecede...
10 joves desenvolupadors web brillants per veure el 2013
Més Lluny

10 joves desenvolupadors web brillants per veure el 2013

E tem con tantment orpre o pel nou talent que entra al món de la web a una edat primerenca i aque t 10 jove de envolupador en cierne ón nomé algun del punt fort que donen a la indú...