Et minimalt eksempel
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.5f, 0.5f, 0.5f, 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 [3] 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 [4] 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;
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.5, 0.5, 0.5, 1.0); gl.clearDepth(1.0); gl.enable(gl.DEPTH_TEST); gl.depthFunc(gl.LEQUAL); initShaders(); initBuffers(); drawScene(); } }
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.
I funksjonen initBuffers() setter vi opp de punktene som beskriver modellen vår og som etterhvert skal sendes til vertex-shaderen.
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
de to funksjonene initShaders() og getShader() laster inn shaderne, kompilerer dem og etablerer shaderprogrammet.
Dette er resultatet:
Du kan også inspisere resultatet og kildekoden på en enklere side:
index.html
http://www.it.hiof.no/~borres/dw/wgl/square/index.html