3D WebGL demonstration tutorial. Today we continue HTML5 canvas examples. And today we will try to begin learning WebGL. In my demonstration I will show you how to initialize WebGL and draw simple 3D object. Also we will animate this object too.
Here are our demo and downloadable package:
[sociallocker]
[/sociallocker]
Ok, download the example files and lets start coding !
Step 1. HTML
Here are html source code of our demo. As you can see – just empty page.
index.html
04 | <link href="css/main.css" rel="stylesheet" type="text/css" /> |
05 | <script type="text/javascript" src="js/glMatrix-0.9.5.min.js"></script> |
06 | <script type="text/javascript" src="js/webgl-utils.js"></script> |
07 | <script type="text/javascript" src="js/script.js"></script> |
08 | <title>WebGL demonstration | Script Tutorials</title> |
10 | <body onload="initWebGl();"> |
13 | <canvas id="panel" width="500" height="333"></canvas> |
14 | <div style="clear:both;"></div> |
Step 2. CSS
Here are used CSS styles.
css/main.css
03 | font-family:Verdana, Helvetica, Arial, sans-serif; |
11 | border:1px #000 solid; |
15 | -moz-border-radius: 3px; |
16 | -webkit-border-radius:3px |
Step 3. JS
js/webgl-utils.js and js/glMatrix-0.9.5.min.js
These files we will use in project for working with WebGL. Both files will in our package.
js/script.js
003 | function initGL(canvas) { |
005 | gl = canvas.getContext('experimental-webgl'); |
006 | gl.viewportWidth = canvas.width; |
007 | gl.viewportHeight = canvas.height; |
010 | alert('Can`t initialise WebGL, not supported'); |
013 | function getShader(gl, type) { |
016 | if (type == 'x-fragment') { |
017 | str = "#ifdef GL_ES\n"+ |
018 | "precision highp float;\n"+ |
020 | "varying vec4 vColor;\n"+ |
021 | "void main(void) {\n"+ |
022 | " gl_FragColor = vColor;\n"+ |
024 | shader = gl.createShader(gl.FRAGMENT_SHADER); |
025 | } else if (type == 'x-vertex') { |
026 | str = "attribute vec3 aVertexPosition;\n"+ |
027 | "attribute vec4 aVertexColor;\n"+ |
028 | "uniform mat4 uMVMatrix;\n"+ |
029 | "uniform mat4 uPMatrix;\n"+ |
030 | "varying vec4 vColor;\n"+ |
031 | "void main(void) {\n"+ |
032 | " gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);\n"+ |
033 | " vColor = aVertexColor;\n"+ |
035 | shader = gl.createShader(gl.VERTEX_SHADER); |
039 | gl.shaderSource(shader, str); |
040 | gl.compileShader(shader); |
041 | if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) { |
042 | alert(gl.getShaderInfoLog(shader)); |
047 | function initShaders() { |
048 | var fragmentShader = getShader(gl, 'x-fragment'); |
049 | var vertexShader = getShader(gl, 'x-vertex'); |
050 | shaderProgram = gl.createProgram(); |
051 | gl.attachShader(shaderProgram, vertexShader); |
052 | gl.attachShader(shaderProgram, fragmentShader); |
053 | gl.linkProgram(shaderProgram); |
054 | if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) { |
055 | alert('Can`t initialise shaders'); |
057 | gl.useProgram(shaderProgram); |
058 | shaderProgram.vertexPositionAttribute = gl.getAttribLocation(shaderProgram, 'aVertexPosition'); |
059 | gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute); |
060 | shaderProgram.vertexColorAttribute = gl.getAttribLocation(shaderProgram, 'aVertexColor'); |
061 | gl.enableVertexAttribArray(shaderProgram.vertexColorAttribute); |
062 | shaderProgram.pMatrixUniform = gl.getUniformLocation(shaderProgram, 'uPMatrix'); |
063 | shaderProgram.mvMatrixUniform = gl.getUniformLocation(shaderProgram, 'uMVMatrix'); |
065 | var mvMatrix = mat4.create(); |
066 | var mvMatrixStack = []; |
067 | var pMatrix = mat4.create(); |
068 | function mvPushMatrix() { |
069 | var copy = mat4.create(); |
070 | mat4.set(mvMatrix, copy); |
071 | mvMatrixStack.push(copy); |
073 | function mvPopMatrix() { |
074 | if (mvMatrixStack.length == 0) { |
075 | throw 'Invalid popMatrix!'; |
077 | mvMatrix = mvMatrixStack.pop(); |
079 | function setMatrixUniforms() { |
080 | gl.uniformMatrix4fv(shaderProgram.pMatrixUniform, false, pMatrix); |
081 | gl.uniformMatrix4fv(shaderProgram.mvMatrixUniform, false, mvMatrix); |
083 | function degToRad(degrees) { |
084 | return degrees * Math.PI / 180; |
086 | var objVertexPositionBuffer; |
087 | var objVertexColorBuffer; |
088 | function initObjBuffers() { |
089 | objVertexPositionBuffer = gl.createBuffer(); |
090 | gl.bindBuffer(gl.ARRAY_BUFFER, objVertexPositionBuffer); |
101 | gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW); |
102 | objVertexPositionBuffer.itemSize = 3; |
103 | objVertexPositionBuffer.numItems = 8; |
104 | objVertexColorBuffer = gl.createBuffer(); |
105 | gl.bindBuffer(gl.ARRAY_BUFFER, objVertexColorBuffer); |
116 | gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.STATIC_DRAW); |
117 | objVertexColorBuffer.itemSize = 4; |
118 | objVertexColorBuffer.numItems = 8; |
121 | function drawScene() { |
122 | gl.viewport(0, 0, gl.viewportWidth, gl.viewportHeight); |
123 | gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); |
124 | mat4.perspective(45, gl.viewportWidth / gl.viewportHeight, 0.1, 100.0, pMatrix); |
125 | mat4.identity(mvMatrix); |
126 | mat4.translate(mvMatrix, [0.0, 0.0, -10.0]); |
128 | mat4.rotate(mvMatrix, degToRad(iObjDeg), [1, 1, 1]); |
129 | gl.bindBuffer(gl.ARRAY_BUFFER, objVertexPositionBuffer); |
130 | gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, objVertexPositionBuffer.itemSize, gl.FLOAT, false, 0, 0); |
131 | gl.bindBuffer(gl.ARRAY_BUFFER, objVertexColorBuffer); |
132 | gl.vertexAttribPointer(shaderProgram.vertexColorAttribute, objVertexColorBuffer.itemSize, gl.FLOAT, false, 0, 0); |
134 | gl.drawArrays(gl.TRIANGLE_STRIP, 0, objVertexPositionBuffer.numItems); |
137 | function drawFrame() { |
138 | requestAnimFrame(drawFrame); |
142 | function initWebGl() { |
143 | var canvas = document.getElementById('panel'); |
147 | gl.clearColor(1.0, 0.5, 0.3, 1.0); |
148 | gl.enable(gl.DEPTH_TEST); |
Pretty big code, isn’t it? but anyway – here are all necessary to draw our demo. Since page loaded – we performing few initializations (initGL, initShaders, initObjBuffers functions), then we defining color for our scene (via gl.clearColor), and after – drawing our scene (drawFrame function). In this function we using ‘requestAnimFrame’ to define function which will calling periodically when WebGL will need to draw next frame.
Conclusion
Not bad, isn`t it? Possible today we made first step to next generation. And possible that in coming future we will start a series of articles related with game development with HTML5. Welcome back!