Create a WebGL texture from a photo

Use any photo to create a WebGL texture for the Warp example.

Loading the photo

WebGL uses photos to create textures that make shapes more realistic or useful. While you can use any size photo in the Warp example, WebGL needs the image in a set size to work. To scale the image you choose, the example uses a three step process to create a WebGL texture.

The following code and steps describe how the Warp example uses 2D canvas commands to scale an image before loading it as a texture.

This code gets the image, scales it, and puts it on a 2D canvas.

// load a the user's image.
this.loadImageX = function (dataURL) {
    var image = new Image();
    
    image.onload = function () {
        renderer.loadImage2(image);
    }

    image.src = dataURL;
}

// This function does the heavy lifting of creating the texture from the image.
this.loadImage2 = function (image) {
    // Convert the image to a square image via the temporary 2d canvas. 
    var canvas = document.getElementById("2dcanvas");
    var ctx = canvas.getContext("2d");
    var canvHeight = document.getElementById("2dcanvas").height;

    var x = 0;
    var y = 0;
    var xx = canvHeight;
    var yy = canvHeight;

    ctx.clearRect(0, 0, canvHeight, canvHeight);
    // If image isn't square, adjust width, height, and origin so it's centered.
       if (image.width < image.height) {
        // Change origin and dimensions if the image isn't square.
        // Change x, xx
        xx = image.width / image.height * canvHeight;
        x = (canvHeight - xx) / 2;
    }
    if (image.width > image.height) {
        // Change y, yy 
      yy = image.height / image.width * canvHeight;
      y = (canvHeight - yy) / 2;
    }

// Put the image on the canvas, scaled using xx & yy.
    ctx.drawImage(image, 0, 0, image.width, image.height, x, y, xx, yy);
  1. Create an Image object and an event to call the loadImage2 function when the photo has finished loading.
  2. When the image finishes loading, it calls loadImage2.
  3. LoadImage2 gets the 2D canvas from the HTML code using document.getElementById.
  4. Using the canvas, the function then gets the 2D context from the canvas element using getContext("2d").
  5. Get the canvas height and create four variables; origin x, origin y, height, and width that are used to place the image on the canvas. Since the canvas is square, the height is used for both height and width.
  6. Clear the canvas using clearRect.
  7. Get the largest dimension of the image. If the image isn't square, calculate a scaled height or width, and an offset into the canvas for the shorter side.
  8. Put the image onto the canvas using drawImage. The drawImage method puts the image onto the canvas at a specific origin and automatically scales it based on the origin, height, and width specified for the canvas.

LoadImage2 creates a texture object and loads the image from the canvas using the following steps:

// Create a texture object that will contain the image.
var texture = gl.createTexture();

// Bind the texture the target (TEXTURE_2D) of the active texture unit.
gl.bindTexture(gl.TEXTURE_2D, texture);

// Flip the image's Y axis to match the WebGL texture coordinate space.
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
    
// Set the parameters so we can render any size image.        
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); 
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);

  // Upload the resized canvas image into the texture.
//    Note: a canvas is used here but can be replaced by an image object. 
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, canvas);
  1. Get the WebGL context (gl) and create a new WebGLTexture object using createTexture. CreateTexture accepts the WebGLTexture object, and the type of texture to use (either TEXTURE_2D or TEXTURE_CUBE_MAP). The Warp example uses TEXTURE_2D.
  2. Bind the texture to make it the active texture using bindTexture. Making this texture active causes subsequent texture operations to use this texture.
  3. Change the texture's coordinate system to match the WebGL texture coordinate system with pixelStorei. Using the flag UNPACK_FLIP_Y_WEBGL changes the Y axis from zero in the upper left corner to zero in the lower left corner. See note below.
  4. Use the texParameteri with TEXTURE_WRAP_S and TEXTURE_WRAP_T to specify how WebGL should handle wrapping an image. These constants tell WebGL how to fill areas to the side or top and bottom when filling an area larger than the image. The CLAMP_TO_EDGE parameter tells WebGL to tile the image. For example, if you sample the image at coordinate 1.5, it's the same as sampling at .5.
  5. Also use texParameteri with the TEXTURE_MIN_FILTER and TEXTURE_MAX_FILTER constants to specify how colors are calculated. Using the LINEAR flag tells WebGL to use the closest four pixels to calculate the color of new pixels as the texture expands past the initial size.
  6. The image is loaded into the texture using texImage2D with the target texture type (TEXTURE_2D), level (always 0), the internal format and image format (both RGBA), the texture data type (UNSIGNED_BYTE), and finally the image (in this case the 2D canvas).
  7. Clear the canvas with clearRect.

Note  

Textures use a system called the s/t coordinate system with an origin of 0,0 in the lower left corner, the s access going horizontally, and the t axis going vertically. Think of it as going to the side and going to the top...you'll see this later. Using s/t naming differentiates it from the x/y/z coordinate system that WebGL otherwise uses. When copying an image to a texture, you can set texImage2D to flip the image when transferred to the GPU using pixelStorei. To switch the photo from a coordinate system where the upper left corner is the 0,0 origin, to the s/t system where the 0,0 origin is in the lower-left corner call pixelStorei with the flag UNPACK_FLIP_Y_WEBGL. This can be important when using several textures at a time.

 

In UI Support, you get an overview of the of the example, getting a file, mouse movement, and file saving.

Use GLSL to write WebGL shaders

UI support

WebGL demos, references, and resources