WebGL
WebGL
Børre Stenseth
Basis >En firkant

Et minimalt eksempel

Hva
capture

I denne modulen skal vi se på et enkelt eksempel. Vi skal rett og slett tegne ut en rød firkant på grå bakgrunn i et canvas-element.

Vi ser først på en løsning i tradisjonell OpenGL. Dette er programmert i Java med biblioteket JOGL [1] som binding til OpenGL.

Deretter ser vi hvordan vi kan oppnå det samme med OpenGL ES. Løsningen er modifisert fra Mozilla Development Network [2] .

Tradisjonell OpenGL

Nedenfor finner du essensen i et Java-program som bruker OpenGL til å lage figuren som er vist øverst på siden. Dette er klippet fra en løsning som lager tegningen i et eget vindu og det finnes altså ikke noen kopling til noe canvas-element.

public void init(GLAutoDrawable drawable) {
    GL gl = drawable.getGL();
    System.err.println("INIT GL IS: " + gl.getClass().getName());
    gl.setSwapInterval(1);
    gl.glClearColor(0.8f, 0.8f, 0.8f, 1.0f);
    gl.glShadeModel(GL.GL_SMOOTH); 
}
public void reshape(GLAutoDrawable drawable,int x, int y, int width, int height) 
{
    GL gl = drawable.getGL();
    GLU glu = new GLU();
    if (height <= 0) {height = 1;}
    final float h = (float) width / (float) height;
    gl.glViewport(0, 0, width, height);
    gl.glMatrixMode(GL.GL_PROJECTION);
    gl.glLoadIdentity();
    glu.gluPerspective(45.0f, h, 1.0, 20.0);
    gl.glMatrixMode(GL.GL_MODELVIEW);
    gl.glLoadIdentity();
}
public void display(GLAutoDrawable drawable) {
    GL gl = drawable.getGL();
    gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
    gl.glLoadIdentity();
    gl.glTranslatef(-0.0f, 0.0f, -6.0f);
    gl.glBegin(GL.GL_QUADS);
        gl.glColor3f(1.0f, 0.0f, 0.0f); 
        gl.glVertex3f(-1.0f, 1.0f, 0.0f); 
        gl.glVertex3f(1.0f, 1.0f, 0.0f);
        gl.glVertex3f(1.0f, -1.0f, 0.0f);
        gl.glVertex3f(-1.0f, -1.0f, 0.0f); 
    gl.glEnd();
    gl.glFlush();
}

OpenGL ES

Her må vi altså fordele logikken på flere kodesegmenter:

  • Shading language kode for hvert fragment (~ pixel)
  • Shading language kode for hvert hjørne, vertex
  • JavaScript kode for selve organiseringen av tegningen

og vi må ha et canvas-element.

Shading language

Både fragment-shader og vertex-shader er plassert som kildekode på selve websiden, i hver sin script-tag med mimetyper henholdsvis:

  • type="x-shader/x-fragment"
  • type="x-shader/x-vertex"

Fragment shader

Fragment shaderen er svært enkel: Den produserer et rødt, ikke gjennomsiktig, fragment uansett. gl_FragColor er en predfinert variabel.

void main(void) {
   gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}

Vertex shader

De to variablene: uMVMatrix og uPMatrix blir satt fra Javascriptkoden. aVertexPosition representerer det aktuelle punktet, slik det er ordnet i en buffer fra Javascriptet. Det denne shaderen gjør er å ta det aktuelle punktet og multiplisere den med de to matrisene som kontrollerer transformasjoner i selve modellen (uMVMatrix) og perspektivet (uPMatrix). Resultatet av denne multiplikasjonen er punktet angitt i rommet, sett fra betrakteren. I tradisjonell OpenGL-programmering heter disse to matrisene henholdsvis GL_MODELVIEW og GL_PROJECTION. gl_Position er en predfinert variabel.

attribute vec3 aVertexPosition; // attribute deprecated use: in (when implemented)
// ModeView matrix
uniform mat4 uMVMatrix;
// Perspective matrix
uniform mat4 uPMatrix;
 
void main(void) {
    // transformed position
    gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);
}
      

Javascript

Websiden bruker noen Javascriptbiblioteker for å håndtere matriser og vektorer, Sylvester [5] og et enkelt tillegg til Sylvester som brukes av Mozillas WebGL sider [2] .

Ellers er alle nødvendige biblioteker implementert som en integrert del av nettleseren, altså ingen plug-ins.

Javascriptet som handterer vår tegning er inkludert som egen fil. De viktigste delene av denne koden er kommentert funksjon for funksjon nedenfor. Hele fila ser slik ut:

_squarescript.js

Det kan være lurt å kikke på OpenGL ES 2.0 Reference Pages [6] for å få en forklaring av de enkelte metodene.

Følgende globale variable er definert.

var canvas;                    // the canvas we use
var gl;                        // the gl-context we find in canvas
var squareVerticesBuffer;      // the vertices of our square
var mvMatrix;                  // the modelview matrix
var perspectiveMatrix;         // the perspective matrix
var shaderProgram;             // the shaderprogram we build and compile
var vertexPositionAttribute;
var viewAspect=1.0;

Funkjsonen start() kalles typisk enten ved body onload, eller ved et script i bunnen (etter canvas) i selve websiden. I dette eksempelet er det denne funksjone som drar hele jobben.

function start() {
  canvas = document.getElementById("glcanvas");
  initWebGL(canvas); 
  
  if (gl) {
    gl.clearColor(0.8, 0.8, 0.8, 1.0); 
    gl.clearDepth(1.0);       
    gl.enable(gl.DEPTH_TEST);
    gl.depthFunc(gl.LEQUAL); 
    
    initShaders();
    
    initBuffers();
    onWindowResize();
    drawScene();
    // pick up resize
    window.addEventListener( 'resize', onWindowResize, false );    
  }
}

Funkjsonen initWebGL() forsøker å sette opp WebGL i canvas-elementet. Merk at rekken av konstanter som forsøkes anvendt i metoden getContext() skal standardiseres til "webgl" etterhvert som denne teknologien modnes hos nettleserne.

_initWebGL

I funksjonen initBuffers() setter vi opp de punktene som beskriver modellen vår og som etterhvert skal sendes til vertex-shaderen.

_initBuffers

Funksjonen drawScene() skiller seg fra det vi kjenner fra tradisjonell OpenGL på den måten at vi ikke lenger "tegner" hjørne for hjørne. I stedet sender vi en punktliste til shaderen, sammen med de to matrisene (modelview og perspective). Deretter starter vi tegningen med gl.drawArrays

_drawScene

de to funksjonene initShaders() og getShader() laster inn shaderne, kompilerer dem og etablerer shaderprogrammet.

_initShaders

_getShader

Dette er resultatet lagt i en iframe:

Du kan også inspisere resultatet og kildekoden på en enklere side:
simple.html https://borres.hiof.no/wep/webgl/basis/firkant/simple.html

Referanser
  1. JOGL, Javabinding for OpenGL jogl.dev.java.net/ 14-04-2009
  1. WebGL Mozilla Developer Network developer.mozilla.org/en/WebGL 14-05-2011
  1. OpenGL Software Development Kit Khronos Group www.opengl.org/sdk/docs/man/ 14-05-2011
  1. OpenGL Shading Language (GLSL) Reference Pages Opengl.org www.opengl.org/sdk/docs/manglsl/ 14-05-2011
  1. Sylvester sylvester.jcoglan.com/ 14-05-2011
  1. OpenGL ES Software Development Kit Khronos Group www.khronos.org/opengles/sdk/docs/man/ 14-05-2011
Basis >En firkant