In this posting I will again be using WebGL. However as opposed to just drawing a triangle and doing a gradient fill, which you can see here. Gradient Triangle.
The code listed below will use WebGL to draw a cube and make it rotate.
WebGL Rotating a Cube
The cube has solid face colors, each color different so you can easily see the rotation of the cube faces. In the var boxVertices, you can see that we are drawing two triangles for each cube face.
In the second part of the tuple the RGB values are specified, and they are listed as a range of luminance from 0.0 to 1.0. It is a little different than how colors are represented in most other programs. You normally see the RGB values shown as a value from 0 to 255, i.e. 2^8. It is just one of the fun things about working with WebGL.
The example uses a JavaScript library available from glMatrix.net The library will handle the matrix math that are required to rotate the cube.
Link to a working example. Rotating a Cube
The code should work on most modern browsers including iPhones. The speed the cube is being rotated can be adjusted by changing the value of 6 in the line below. Change 6 to a lower value to rotate the cube faster or higher value to rotate slower.
1 |
angle = performance.now() / 1000 / 6 * 2 * Math.PI; |
Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 |
//js draw a cube via webGL //vertex shader var vertexShaderText = [ 'precision mediump float;' ,'' ,'attribute vec3 vertPosition;' ,'attribute vec3 vertColor;' ,'varying vec3 fragColor;' ,'uniform mat4 mWorld;' ,'uniform mat4 mView;' ,'uniform mat4 mProj;' ,'' ,'void main()' ,'{' ,' fragColor = vertColor;' ,' gl_Position = mProj * mView * mWorld * vec4(vertPosition, 1.0);' ,'}' ].join('\n'); //fragment shader var fragmentShaderText = [ 'precision mediump float;' ,'' ,'varying vec3 fragColor;' ,'void main()' ,'{' ,' gl_FragColor = vec4(fragColor ,1.0);' ,'}' ].join('\n'); var InitDemo = function() { console.log("this is working"); var canvas = document.getElementById('blank_surface'); var gl = canvas.getContext("webgl"); if (!gl) { console.log("using experimental webgl"); gl = canvas.getContext("experimental-webgl"); } if(!gl) { alert("Your Browser doesn't have webGL support"); } //adjust the width / height of canvas //canvas.width = window.innerWidth; //canvas.width = window.innerHeight; //reset the viewport since adjusted the canvas size //gl.viewport(0, 0, window.innerWidth, window.innerHeight); //setting color in format of RGB Alpha gl.clearColor(0.75,0.85,0.8,1.0); //argument of what buffer to render too gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); //enable the depth tester gl.enable(gl.DEPTH_TEST); //enable back culling gl.enable(gl.CULL_FACE); gl.frontFace(gl.CCW); gl.cullFace(gl.BACK); // open the shaders var vertexShader = gl.createShader(gl.VERTEX_SHADER); var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER); //set shader source gl.shaderSource(vertexShader, vertexShaderText); gl.shaderSource(fragmentShader, fragmentShaderText); //compile the shaders gl.compileShader(vertexShader); //to check if compiled correctly if(!gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS)) { console.error("ERROR in compile: vertex shader" ,gl.getShaderInfoLog(vertexShader)); return; } gl.compileShader(fragmentShader); if(!gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS)) { console.error("ERROR in compile: fragment shader" ,gl.getShaderInfoLog(fragmentShader)); return; } //create an opengl program var program = gl.createProgram(); gl.attachShader(program, vertexShader); gl.attachShader(program, fragmentShader); //link gl program gl.linkProgram(program); //check for errors while linking if(!gl.getProgramParameter(program, gl.LINK_STATUS)) { console.error("ERROR linking program" , gl.getProgramInfoLog(program)); return; } //validate the program -- only in debug, not production code gl.validateProgram(program); if(!gl.getProgramParameter(program, gl.VALIDATE_STATUS)) { console.error("ERROR validating program" ,gl.getProgramInfoLog(program)); return; } // create buffer // x coord, y coord, z coord, RGB var boxVertices = [ //top -1.0 ,1.0 ,-1.0 ,0.5 ,0.5 ,0.5 ,-1.0 ,1.0 ,1.0 ,0.5 ,0.5 ,0.5 ,1.0 ,1.0 ,1.0 ,0.5 ,0.5 ,0.5 ,1.0 ,1.0 ,-1.0 ,0.5 ,0.5 ,0.5 //left ,-1.0 ,1.0 ,1.0 ,0.75 ,0.25 ,0.5 ,-1.0 ,-1.0 ,1.0 ,0.75 ,0.25 ,0.5 ,-1.0 ,-1.0 ,-1.0 ,0.75 ,0.25 ,0.5 ,-1.0 ,1.0 ,-1.0 ,0.75 ,0.25 ,0.5 //right ,1.0 ,1.0 ,1.0 ,0.25 ,0.25 ,0.75 ,1.0 ,-1.0 ,1.0 ,0.25 ,0.25 ,0.75 ,1.0 ,-1.0 ,-1.0 ,0.25 ,0.25 ,0.75 ,1.0 ,1.0 ,-1.0 ,0.25 ,0.25 ,0.75 //front ,1.0 ,1.0 ,1.0 ,1.0 ,0.0 ,0.15 ,1.0 ,-1.0 ,1.0 ,1.0 ,0.0 ,0.15 ,-1.0 ,-1.0 ,1.0 ,1.0 ,0.0 ,0.15 ,-1.0 ,1.0 ,1.0 ,1.0 ,0.0 ,0.15 //back ,1.0 ,1.0 ,-1.0 ,0.0 ,1.0 ,0.15 ,1.0 ,-1.0 ,-1.0 ,0.0 ,1.0 ,0.15 ,-1.0 ,-1.0 ,-1.0 ,0.0 ,1.0 ,0.15 ,-1.0 ,1.0 ,-1.0 ,0.0 ,1.0 ,0.15 //bottom ,-1.0 ,-1.0 ,-1.0 ,0.5 ,0.5 ,1.0 ,-1.0 ,-1.0 ,1.0 ,0.5 ,0.5 ,1.0 ,1.0 ,-1.0 ,1.0 ,0.5 ,0.5 ,1.0 ,1.0 ,-1.0 ,-1.0 ,0.5 ,0.5 ,1.0 ]; var boxIndices = [ //top 0,1,2 ,0,2,3 //left ,5,4,6 ,6,4,7 //right ,8,9,10 ,8,10,11 //front ,13,12,14 ,15,14,12 //back ,16,17,18 ,16,18,19 //bottom ,21,20,22 ,22,20,23 ]; var boxVertexBufferObject = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, boxVertexBufferObject); //cast array to float 32 gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(boxVertices), gl.STATIC_DRAW); var boxIndexBufferObject = gl.createBuffer(); gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, boxIndexBufferObject); gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(boxIndices), gl.STATIC_DRAW); var positionAttribLocation = gl.getAttribLocation(program, 'vertPosition'); var colorAttribLocation = gl.getAttribLocation(program, 'vertColor'); //layout of the attribute gl.vertexAttribPointer( positionAttribLocation //attribute location ,3 //number of elements per attribute ,gl.FLOAT //32 bit float ,gl.FALSE // ,6 * Float32Array.BYTES_PER_ELEMENT //size of an individual vertex ,0 //offset from the beginning of a single vertex to this attribute ); gl.vertexAttribPointer( colorAttribLocation //attribute location ,3 //number of elements per attribute ,gl.FLOAT //32 bit float ,gl.FALSE // ,6 * Float32Array.BYTES_PER_ELEMENT //size of an individual vertex ,3 * Float32Array.BYTES_PER_ELEMENT //offset from the beginning of a single vertex to this attribute ); gl.enableVertexAttribArray(positionAttribLocation); gl.enableVertexAttribArray(colorAttribLocation); //activate the main program for openGL gl.useProgram(program); var matWorldUniformLocation = gl.getUniformLocation(program, 'mWorld'); var matViewUniformLocation = gl.getUniformLocation(program, 'mView'); var matProjUniformLocation = gl.getUniformLocation(program, 'mProj'); //create the matrix values var worldMatrix = new Float32Array(16); var viewMatrix = new Float32Array(16); var projMatrix = new Float32Array(16); mat4.identity(worldMatrix); mat4.lookAt(viewMatrix,[0,0,-8],[0,0,0,],[0,1,0]); mat4.identity(projMatrix); mat4.perspective(projMatrix,glMatrix.toRadian(45), canvas.width / canvas.height, 0.1, 1000.0); //send matrix over to graphics card gl.uniformMatrix4fv(matWorldUniformLocation, gl.FALSE, worldMatrix); gl.uniformMatrix4fv(matViewUniformLocation, gl.FALSE, viewMatrix); gl.uniformMatrix4fv(matProjUniformLocation, gl.FALSE, projMatrix); //lateral rotation var xRotationMatrix = new Float32Array(16); var yRotationMatrix = new Float32Array(16); //main render loop //rotate primative var angle = 0; var identityMatrix = new Float32Array(16); mat4.identity(identityMatrix); var loop = function() { //one rotation per every 6 seconds angle = performance.now() / 1000 / 6 * 2 * Math.PI; mat4.rotate(yRotationMatrix, identityMatrix, angle, [0,1,0]); mat4.rotate(xRotationMatrix, identityMatrix, angle/4, [1,0,0]); //multiple both rotations mat4.mul(worldMatrix, yRotationMatrix, xRotationMatrix); gl.uniformMatrix4fv(matWorldUniformLocation, gl.FALSE, worldMatrix); //clear the screen gl.clearColor(0.75,0.85,0.8,1.0); //argument of what buffer to render too gl.clear(gl.DEPTH_BUFFER_BIT | gl.COLOR_BUFFER_BIT); gl.drawElements(gl.TRIANGLES, boxIndices.length, gl.UNSIGNED_SHORT, 0); //only called when it has focus requestAnimationFrame(loop); }; requestAnimationFrame(loop); }; |
Leave a Reply