|
| 1 | +<html> |
| 2 | + |
| 3 | +<head> |
| 4 | +<title>Programming 3D Applications in HTML5 and WebGL — Example 2-3</title> |
| 5 | +<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1"> |
| 6 | +<script src="../libs/jquery-1.9.1/jquery-1.9.1.js"></script> |
| 7 | +<script src="../libs/gl-matrix/gl-matrix.js"></script> |
| 8 | +<script src="../libs/requestAnimationFrame/RequestAnimationFrame.js"></script> |
| 9 | +<script type="text/javascript"> |
| 10 | + |
| 11 | + |
| 12 | + function initWebGL(canvas) { |
| 13 | + |
| 14 | + var gl = null; |
| 15 | + var msg = "Your browser does not support WebGL, " + |
| 16 | + "or it is not enabled by default."; |
| 17 | + try |
| 18 | + { |
| 19 | + gl = canvas.getContext("experimental-webgl"); |
| 20 | + } |
| 21 | + catch (e) |
| 22 | + { |
| 23 | + msg = "Error creating WebGL Context!: " + e.toString(); |
| 24 | + } |
| 25 | + |
| 26 | + if (!gl) |
| 27 | + { |
| 28 | + alert(msg); |
| 29 | + throw new Error(msg); |
| 30 | + } |
| 31 | + |
| 32 | + return gl; |
| 33 | + } |
| 34 | + |
| 35 | + function initViewport(gl, canvas) |
| 36 | + { |
| 37 | + gl.viewport(0, 0, canvas.width, canvas.height); |
| 38 | + } |
| 39 | + |
| 40 | + var projectionMatrix, modelViewMatrix; |
| 41 | + var rotationAxis; |
| 42 | + |
| 43 | + function initMatrices(canvas) |
| 44 | + { |
| 45 | + // Create a model view matrix with object at 0, 0, -8 |
| 46 | + modelViewMatrix = mat4.create(); |
| 47 | + mat4.translate(modelViewMatrix, modelViewMatrix, [0, 0, -8]); |
| 48 | + |
| 49 | + // Create a project matrix with 45 degree field of view |
| 50 | + projectionMatrix = mat4.create(); |
| 51 | + mat4.perspective(projectionMatrix, Math.PI / 4, canvas.width / canvas.height, 1, 10000); |
| 52 | + |
| 53 | + rotationAxis = vec3.create(); |
| 54 | + vec3.normalize(rotationAxis, [1, 1, 1]); |
| 55 | + } |
| 56 | + |
| 57 | + // Create the vertex, color and index data for a multi-colored cube |
| 58 | + function createCube(gl) { |
| 59 | + |
| 60 | + // Vertex Data |
| 61 | + var vertexBuffer; |
| 62 | + vertexBuffer = gl.createBuffer(); |
| 63 | + gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer); |
| 64 | + var verts = [ |
| 65 | + // Front face |
| 66 | + -1.0, -1.0, 1.0, |
| 67 | + 1.0, -1.0, 1.0, |
| 68 | + 1.0, 1.0, 1.0, |
| 69 | + -1.0, 1.0, 1.0, |
| 70 | + |
| 71 | + // Back face |
| 72 | + -1.0, -1.0, -1.0, |
| 73 | + -1.0, 1.0, -1.0, |
| 74 | + 1.0, 1.0, -1.0, |
| 75 | + 1.0, -1.0, -1.0, |
| 76 | + |
| 77 | + // Top face |
| 78 | + -1.0, 1.0, -1.0, |
| 79 | + -1.0, 1.0, 1.0, |
| 80 | + 1.0, 1.0, 1.0, |
| 81 | + 1.0, 1.0, -1.0, |
| 82 | + |
| 83 | + // Bottom face |
| 84 | + -1.0, -1.0, -1.0, |
| 85 | + 1.0, -1.0, -1.0, |
| 86 | + 1.0, -1.0, 1.0, |
| 87 | + -1.0, -1.0, 1.0, |
| 88 | + |
| 89 | + // Right face |
| 90 | + 1.0, -1.0, -1.0, |
| 91 | + 1.0, 1.0, -1.0, |
| 92 | + 1.0, 1.0, 1.0, |
| 93 | + 1.0, -1.0, 1.0, |
| 94 | + |
| 95 | + // Left face |
| 96 | + -1.0, -1.0, -1.0, |
| 97 | + -1.0, -1.0, 1.0, |
| 98 | + -1.0, 1.0, 1.0, |
| 99 | + -1.0, 1.0, -1.0 |
| 100 | + ]; |
| 101 | + gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(verts), gl.STATIC_DRAW); |
| 102 | + |
| 103 | + var texCoordBuffer = gl.createBuffer(); |
| 104 | + gl.bindBuffer(gl.ARRAY_BUFFER, texCoordBuffer); |
| 105 | + var textureCoords = [ |
| 106 | + // Front face |
| 107 | + 0.0, 0.0, |
| 108 | + 1.0, 0.0, |
| 109 | + 1.0, 1.0, |
| 110 | + 0.0, 1.0, |
| 111 | + |
| 112 | + // Back face |
| 113 | + 1.0, 0.0, |
| 114 | + 1.0, 1.0, |
| 115 | + 0.0, 1.0, |
| 116 | + 0.0, 0.0, |
| 117 | + |
| 118 | + // Top face |
| 119 | + 0.0, 1.0, |
| 120 | + 0.0, 0.0, |
| 121 | + 1.0, 0.0, |
| 122 | + 1.0, 1.0, |
| 123 | + |
| 124 | + // Bottom face |
| 125 | + 1.0, 1.0, |
| 126 | + 0.0, 1.0, |
| 127 | + 0.0, 0.0, |
| 128 | + 1.0, 0.0, |
| 129 | + |
| 130 | + // Right face |
| 131 | + 1.0, 0.0, |
| 132 | + 1.0, 1.0, |
| 133 | + 0.0, 1.0, |
| 134 | + 0.0, 0.0, |
| 135 | + |
| 136 | + // Left face |
| 137 | + 0.0, 0.0, |
| 138 | + 1.0, 0.0, |
| 139 | + 1.0, 1.0, |
| 140 | + 0.0, 1.0, |
| 141 | + ]; |
| 142 | + gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(textureCoords), gl.STATIC_DRAW); |
| 143 | + |
| 144 | + // Index data (defines the triangles to be drawn) |
| 145 | + var cubeIndexBuffer = gl.createBuffer(); |
| 146 | + gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, cubeIndexBuffer); |
| 147 | + var cubeIndices = [ |
| 148 | + 0, 1, 2, 0, 2, 3, // Front face |
| 149 | + 4, 5, 6, 4, 6, 7, // Back face |
| 150 | + 8, 9, 10, 8, 10, 11, // Top face |
| 151 | + 12, 13, 14, 12, 14, 15, // Bottom face |
| 152 | + 16, 17, 18, 16, 18, 19, // Right face |
| 153 | + 20, 21, 22, 20, 22, 23 // Left face |
| 154 | + ]; |
| 155 | + gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(cubeIndices), gl.STATIC_DRAW); |
| 156 | + |
| 157 | + var cube = {buffer:vertexBuffer, texCoordBuffer:texCoordBuffer, indices:cubeIndexBuffer, |
| 158 | + vertSize:3, nVerts:24, texCoordSize:2, nTexCoords: 24, nIndices:36, |
| 159 | + primtype:gl.TRIANGLES}; |
| 160 | + |
| 161 | + return cube; |
| 162 | + } |
| 163 | + |
| 164 | + function createShader(gl, str, type) { |
| 165 | + var shader; |
| 166 | + if (type == "fragment") { |
| 167 | + shader = gl.createShader(gl.FRAGMENT_SHADER); |
| 168 | + } else if (type == "vertex") { |
| 169 | + shader = gl.createShader(gl.VERTEX_SHADER); |
| 170 | + } else { |
| 171 | + return null; |
| 172 | + } |
| 173 | + |
| 174 | + gl.shaderSource(shader, str); |
| 175 | + gl.compileShader(shader); |
| 176 | + |
| 177 | + if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) { |
| 178 | + alert(gl.getShaderInfoLog(shader)); |
| 179 | + return null; |
| 180 | + } |
| 181 | + |
| 182 | + return shader; |
| 183 | + } |
| 184 | + |
| 185 | + var vertexShaderSource = |
| 186 | + |
| 187 | + " attribute vec3 vertexPos;\n" + |
| 188 | + " attribute vec2 texCoord;\n" + |
| 189 | + " uniform mat4 modelViewMatrix;\n" + |
| 190 | + " uniform mat4 projectionMatrix;\n" + |
| 191 | + " varying vec2 vTexCoord;\n" + |
| 192 | + " void main(void) {\n" + |
| 193 | + " // Return the transformed and projected vertex value\n" + |
| 194 | + " gl_Position = projectionMatrix * modelViewMatrix * \n" + |
| 195 | + " vec4(vertexPos, 1.0);\n" + |
| 196 | + " // Output the texture coordinate in vTexCoord\n" + |
| 197 | + " vTexCoord = texCoord;\n" + |
| 198 | + " }\n"; |
| 199 | + |
| 200 | + var fragmentShaderSource = |
| 201 | + " precision mediump float;\n" + |
| 202 | + " varying vec2 vTexCoord;\n" + |
| 203 | + " uniform sampler2D uSampler;\n" + |
| 204 | + " void main(void) {\n" + |
| 205 | + " // Return the pixel color: always output white\n" + |
| 206 | + " gl_FragColor = texture2D(uSampler, vec2(vTexCoord.s, vTexCoord.t));\n" + |
| 207 | + "}\n"; |
| 208 | + |
| 209 | + |
| 210 | + var shaderProgram, shaderVertexPositionAttribute, shaderVertexColorAttribute, |
| 211 | + shaderProjectionMatrixUniform, shaderModelViewMatrixUniform, shaderSamplerUniform; |
| 212 | + |
| 213 | + function initShader(gl) { |
| 214 | + |
| 215 | + // load and compile the fragment and vertex shader |
| 216 | + //var fragmentShader = getShader(gl, "fragmentShader"); |
| 217 | + //var vertexShader = getShader(gl, "vertexShader"); |
| 218 | + var fragmentShader = createShader(gl, fragmentShaderSource, "fragment"); |
| 219 | + var vertexShader = createShader(gl, vertexShaderSource, "vertex"); |
| 220 | + |
| 221 | + // link them together into a new program |
| 222 | + shaderProgram = gl.createProgram(); |
| 223 | + gl.attachShader(shaderProgram, vertexShader); |
| 224 | + gl.attachShader(shaderProgram, fragmentShader); |
| 225 | + gl.linkProgram(shaderProgram); |
| 226 | + |
| 227 | + // get pointers to the shader params |
| 228 | + shaderVertexPositionAttribute = gl.getAttribLocation(shaderProgram, "vertexPos"); |
| 229 | + gl.enableVertexAttribArray(shaderVertexPositionAttribute); |
| 230 | + |
| 231 | + shaderTexCoordAttribute = gl.getAttribLocation(shaderProgram, "texCoord"); |
| 232 | + gl.enableVertexAttribArray(shaderTexCoordAttribute); |
| 233 | + |
| 234 | + shaderProjectionMatrixUniform = gl.getUniformLocation(shaderProgram, "projectionMatrix"); |
| 235 | + shaderModelViewMatrixUniform = gl.getUniformLocation(shaderProgram, "modelViewMatrix"); |
| 236 | + shaderSamplerUniform = gl.getUniformLocation(shaderProgram, "uSampler"); |
| 237 | + |
| 238 | + if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) { |
| 239 | + alert("Could not initialise shaders"); |
| 240 | + } |
| 241 | + } |
| 242 | + |
| 243 | + var okToRun = false; |
| 244 | + |
| 245 | + function handleTextureLoaded(gl, texture) { |
| 246 | + gl.bindTexture(gl.TEXTURE_2D, texture); |
| 247 | + gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true); |
| 248 | + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, texture.image); |
| 249 | + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); |
| 250 | + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); |
| 251 | + gl.bindTexture(gl.TEXTURE_2D, null); |
| 252 | + okToRun = true; |
| 253 | + } |
| 254 | + |
| 255 | + var webGLTexture; |
| 256 | + |
| 257 | + function initTexture(gl) { |
| 258 | + webGLTexture = gl.createTexture(); |
| 259 | + webGLTexture.image = new Image(); |
| 260 | + webGLTexture.image.onload = function () { |
| 261 | + handleTextureLoaded(gl, webGLTexture) |
| 262 | + } |
| 263 | + |
| 264 | + webGLTexture.image.src = "../images/webgl-logo-256.jpg"; |
| 265 | + } |
| 266 | + |
| 267 | + |
| 268 | + function draw(gl, obj) { |
| 269 | + |
| 270 | + // LAB: clear the background (with RED) |
| 271 | + gl.clearColor(1.0, 0.0, 0.0, 1.0); |
| 272 | + gl.enable(gl.DEPTH_TEST); |
| 273 | + gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); |
| 274 | + |
| 275 | + // set the shader to use |
| 276 | + gl.useProgram(shaderProgram); |
| 277 | + |
| 278 | + // connect up the shader parameters: vertex position, texture coordinate, |
| 279 | + // projection/model matrices and texture |
| 280 | + // set up the buffers |
| 281 | + gl.bindBuffer(gl.ARRAY_BUFFER, obj.buffer); |
| 282 | + gl.vertexAttribPointer(shaderVertexPositionAttribute, obj.vertSize, gl.FLOAT, false, 0, 0); |
| 283 | + gl.bindBuffer(gl.ARRAY_BUFFER, obj.texCoordBuffer); |
| 284 | + gl.vertexAttribPointer(shaderTexCoordAttribute, obj.texCoordSize, gl.FLOAT, false, 0, 0); |
| 285 | + gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, obj.indices); |
| 286 | + |
| 287 | + gl.uniformMatrix4fv(shaderProjectionMatrixUniform, false, projectionMatrix); |
| 288 | + gl.uniformMatrix4fv(shaderModelViewMatrixUniform, false, modelViewMatrix); |
| 289 | + |
| 290 | + gl.activeTexture(gl.TEXTURE0); |
| 291 | + gl.bindTexture(gl.TEXTURE_2D, webGLTexture); |
| 292 | + gl.uniform1i(shaderSamplerUniform, 0); |
| 293 | + |
| 294 | + // draw the object |
| 295 | + gl.drawElements(obj.primtype, obj.nIndices, gl.UNSIGNED_SHORT, 0); |
| 296 | + } |
| 297 | + |
| 298 | + var duration = 5000; // ms |
| 299 | + var currentTime = Date.now(); |
| 300 | + function animate() { |
| 301 | + var now = Date.now(); |
| 302 | + var deltat = now - currentTime; |
| 303 | + currentTime = now; |
| 304 | + var fract = deltat / duration; |
| 305 | + var angle = Math.PI * 2 * fract; |
| 306 | + mat4.rotate(modelViewMatrix, modelViewMatrix, angle, rotationAxis); |
| 307 | + } |
| 308 | + |
| 309 | + function run(gl, cube) { |
| 310 | + requestAnimationFrame(function() { run(gl, cube); }); |
| 311 | + if (okToRun) |
| 312 | + { |
| 313 | + draw(gl, cube); |
| 314 | + animate(); |
| 315 | + } |
| 316 | + } |
| 317 | + |
| 318 | + $(document).ready( |
| 319 | + function() { |
| 320 | + var canvas = document.getElementById("webglcanvas"); |
| 321 | + var gl = initWebGL(canvas); |
| 322 | + initViewport(gl, canvas); |
| 323 | + initMatrices(canvas); |
| 324 | + var cube = createCube(gl); |
| 325 | + initShader(gl); |
| 326 | + initTexture(gl); |
| 327 | + run(gl, cube); |
| 328 | + } |
| 329 | + ); |
| 330 | + |
| 331 | +</script> |
| 332 | + |
| 333 | + |
| 334 | +</head> |
| 335 | + |
| 336 | + |
| 337 | +<body> |
| 338 | + |
| 339 | + <canvas id="webglcanvas" style="border: none;" width="500" height="500"></canvas> |
| 340 | + |
| 341 | +</body> |
| 342 | + |
| 343 | +</html> |
| 344 | + |
0 commit comments