Tutorial 07 Texture Mapping
This tutorial introduces the mechanism of texture mapping in WebGL pipeline. We are going to map textures to the table scene (see last Tutorial). In addition to texture mapping, this tutorial also introduces the techniques for developing more robust application: handling of lost context. Use Firefox browser if Google Chrome does not load the texture images.
Please note how we define the cube this time. We treat the cube as 6 independent square surfaces, i.e., we use 24 pairs vertex coordinates. This is to ensure the number of vertices matches those of texture (and normals, future tutorial session), which makes texture mapping easier without drastically change other part of the program.
1. Texture mapping
Copyright By PowCoder代写 加微信 powcoder
To use texture, the texture coordinates must be assigned to the vertices of each object using appropriate buffers. This is done by modify the corresponding setup buffer functions. Notice that, because textures are used, colours no longer needed and they are removed from the buffers and the shaders. Textures are setup and loaded through three functions: setupTextures(), loadImageForTexture(), andtextureFinishedLoading().
2. Store properties in a global variable
In previous tutorials, we have added new properties to the different WebGL resource objects that are created from the WebGL API. For example, the itemSize and numberOfItems are added to the created WebGLBuffer object, as shown in the following code segment:
floorVertexPositionBuffer = gl.createBuffer(); …
floorVertexPositionBuffer.itemSize = 3; floorVertexPositionBuffer.numberOfItems = 4;
While this might be a convenient way to organize the code, it is not a way to have robust code if the context of the W ebGL program is lost (see below). When the context is lost, the method gl.createBuffer() returns null and an exception will be thrown when you try to add the properties itemSize and numberOfItems to the floorVertexPositionBuffer that is null. For the same reason, we should avoid adding properties to any other WebGL objects, such as texture objects, shader objects, program objects, and so on.
A better way to handle such WebGL object-related properties is to store them in a global object that is not created by WebGL. In following code snippet, a JavaScript object called pwgl (or whatever name you like) is used to store the items.
// globals
var pwgl = {}; // declare a global JavaScript object.
pwgl.floorVertexPositionBuffer=gl.createBuffer(); …
pwgl.FLOOR_VERTEX_POS_BUF_ITEM_SIZE = 3; pwgl.FLOOR_VERTEX_POS_BUF_NUM_ITEMS = 4;
Pay attention to the use of object pwgl through out the program to see what have been stored in it.
3. Handling lost context
We have learnt that to run a WebGL application, a WebGL context has to be created for the application. The context provides an environment for, and access to, the WebGL API. However, this context could be lost. There are several reasons why a WebGL application could lose its context. For example, when a call to drawing functions takes too long to execute and the system becomes unresponsive or hangs. Once the context is lost, any access to WebGL resources becomes unavailable and the application will stop running.
When a WebGL application has lost its context, the default behaviour is that the device will not try to restore the context and the user must reload the application manually in the browser. When lost context happens, the operating systems and device drivers will find that the GPU becomes unresponsive. To recover, the GPU will be reset and an event webglcontextlost is sent to the WebGL application where it will trigger the event handling (lost context) procedure provided by the programmer.
The lost context handling mechanism in this tutorial will rely on the detection of this event. On detecting the webglcontextlost event, the program will prevent the default behaviour (not restoring the lost context) from working and try to restore the lost context. Once the context is restored, another event webglcontextrestored will be sent to the application. On receiving this event, a procedure that re-initialises the shaders and buffers will be launched.
See http://www.khronos.org/webgl/wiki/HandlingContextLost for more details.
Detection of webglcontextlost and webglcontextrestored events is done by
registering event listeners to canvas object:
canvas.addEventListener(‘webglcontextlost’, handleContextLost, false);
canvas.addEventListener(‘webglcontextrestored’, handleContextRestored, false);
where the first argument are the events that the event listeners are registered for. The second argument are the listeners, handleContextLost and handleContextRestored, which are two functions. The third argument is a Boolean that specifies whether the event handler should capture events during what is called the capturing phase of the event propagation. In this case, we don¡¯t need to capture any events during the capturing phase, so false is set.
When the listener for the webglcontextlost event is called, the program first stops the default action (i.e., the lost context will not be restored). This is done by calling preventDefault() on the detection of the event. Meanwhile, the rendering loop is stopped. So far we have worked with examples where the drawing method is called once. When working with animations, the drawing method must be called every frame in a loop. This loop is created by calling
pwgl.requestId = requestAnimFrame(draw,canvas);
which returns an ID (a value other than zero) for the callback. The method cancelRequestAnimFrame() stops the callback by its ID.
The second listener handleContextRestored, when called, will restore the lost context, but all resources that you have allocated/created through WebGL, e.g., textures, buffers, shaders and shader program, will not be recovered. These resources have to be re-initialised. Also, we need to re-start the
rendering loop (from where it was lost) when the context is restored and the needed resources are re- initialised.
function handleContextRestored(event) {
setupShaders();
setupBuffers();
setupTextures();
gl.clearColor(0.0, 0.0, 0.0, 1.0); pwgl.requestId = requestAnimFrame(draw,canvas);;
To test if a WebGL application can handle the events correctly, we can simulate the context lost event by creating a test environment. The simulation environment is created by calling the function in library webgl-debug.js :
canvas = WebGLDebugUtils.makeLostContextSimulatingCanvas(
The method makeLostContextSimulatingCanvas() creates a wrapper around the original canvas. The wrapper simulates the webglcontextlost and webglcontextrestored events. This tutorial makes use this simulated environment. On successful running of the program, you will see a change in background colour when you press a mouse button, which indicates the re- initialisation of the application.
Context lost is checked when compile and link the shaders.
gl.compileShader(shader);
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS) &&
!gl.isContextLost()) {
gl.linkProgram(shaderProgram);
if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS) &&
!gl.isContextLost()) {
Exercise: Copy the library and texture files from Moodle. Start from the program provided. The program is unfinished. It draws a black background colour on the canvas. When you click, you should see changes in the background colour. Once the program works correctly, complete it by adding the missing statements in the shaders, floor texture coordinates, and texture set up functions.
Note: If your program works but fails to load the textures, in Firefox URL type about:config and navigate to security.fileuri.strict_origin_policy and turn its value to false. Reload the application.