Difference between revisions of "WebGL and OpenGL Differences"

From WebGL Public Wiki
Jump to navigation Jump to search
(Make these proper wiki sections)
Line 57: Line 57:
  
 
If your application allows, you can also resize your source images offline.
 
If your application allows, you can also resize your source images offline.
 +
 +
==Other restrictions on textures in shaders==
 +
 +
There are more requirements on textures, and textures not meeting them will also be evaluated as RGBA color (0, 0, 0, 1). The NPOT texture requirements discussed [[#Non-Power of Two Texture Support|above]] are just one part of that. For a complete description of these requirements, see section 3.8.2 "Shader execution" in the [http://www.khronos.org/registry/gles/specs/2.0/es_full_spec_2.0.24.pdf OpenGL ES 2.0 specification]. In particular:
 +
* there are requirements on mipmaps to be considered "complete", if your texture's MIN_FILTER is one that requires a mipmap;
 +
* with cube maps, all 6 faces must be square textures, and have identical size, format, and type.
 +
Notice that this section 3.8.2 refers to various notions of "completeness" that are defined in section 3.7.10.
  
 
==Vertex Attribute 0==
 
==Vertex Attribute 0==

Revision as of 16:28, 27 August 2010

WebGL is based on the OpenGL ES 2.0 specification, and retains the semantics of OpenGL ES in order to maximize portability to mobile devices. There are some significant differences in behavior of similar APIs between OpenGL ES 2.0 and the OpenGL API on desktop systems. Many OpenGL programmers are familiar with the semantics on the desktop, and may not know about these differences in behavior. We highlight them here for clarity.

Non-Power of Two Texture Support

While OpenGL 2.0 and later for the desktop offer full support for non-power-of-two (NPOT) textures, OpenGL ES 2.0 and WebGL have only limited NPOT support. The restrictions are defined in Sections 3.8.2, "Shader Execution", and 3.7.11, "Mipmap Generation", of the OpenGL ES 2.0 specification, and are summarized here:

  • generateMipmap(target) generates an INVALID_OPERATION error if the level 0 image of the texture currently bound to target has an NPOT width or height.
  • Sampling an NPOT texture in a shader will produce the RGBA color (0, 0, 0, 1) if:
    • The minification filter is set to anything but NEAREST or LINEAR: in other words, if it uses one of the mipmapped filters.
    • The repeat mode is set to anything but CLAMP_TO_EDGE; repeating NPOT textures are not supported.

If your application doesn't require the REPEAT wrap mode, and can tolerate the lack of mipmaps, then you can simply configure the WebGLTexture object appropriately at creation time:

var texture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, texture);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
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);

However, if your application requires the REPEAT wrap mode for correctness, you can easily resize the image to the next largest power of two dimensions using DOM APIs. Here is an example of how to do this. image is an HTML image object that has been fully loaded; its onload handler has already been called.

function createTextureFromImage(image) {
    var texture = gl.createTexture();
    gl.bindTexture(gl.TEXTURE_2D, texture);
    if (!isPowerOfTwo(image.width) || !isPowerOfTwo(image.height)) {
        // Scale up the texture to the next highest power of two dimensions.
        var canvas = document.createElement("canvas");
        canvas.width = nextHighestPowerOfTwo(image.width);
        canvas.height = nextHighestPowerOfTwo(image.height);
        var ctx = canvas.getContext("2d");
        ctx.drawImage(image,
                      0, 0, image.width, image.height,
                      0, 0, canvas.width, canvas.height);
        image = canvas;
    }
    gl.texImage2D(gl.TEXTURE_2D, 0, image);
    gl.generateMipmap(gl.TEXTURE_2D);
    gl.bindTexture(gl.TEXTURE_2D, null);
    return texture;
}

function isPowerOfTwo(x) {
    return (x & (x - 1)) == 0;
}

function nextHighestPowerOfTwo(x) {
    --x;
    for (var i = 1; i < 32; i <<= 1) {
        x = x | x >> i;
    }
    return x + 1;
}

If your application allows, you can also resize your source images offline.

Other restrictions on textures in shaders

There are more requirements on textures, and textures not meeting them will also be evaluated as RGBA color (0, 0, 0, 1). The NPOT texture requirements discussed above are just one part of that. For a complete description of these requirements, see section 3.8.2 "Shader execution" in the OpenGL ES 2.0 specification. In particular:

  • there are requirements on mipmaps to be considered "complete", if your texture's MIN_FILTER is one that requires a mipmap;
  • with cube maps, all 6 faces must be square textures, and have identical size, format, and type.

Notice that this section 3.8.2 refers to various notions of "completeness" that are defined in section 3.7.10.

Vertex Attribute 0

On desktop GL, vertex attribute 0 has special semantics. First, it must be enabled as an array, or no geometry will be drawn. Second, it does not have persistent state, so calling glGetVertexAttribfv(0, GL_CURRENT_VERTEX_ATTRIB, ...) generates an OpenGL error.

On OpenGL ES 2.0, vertex attribute 0 has no special semantics.

WebGL follows the OpenGL ES 2.0 convention; all vertex attributes behave identically. This requires implementations on desktop GL to perform a certain amount of emulation, but this was considered to be a small price to pay for consistent behavior.

texture2DLod

GLSL texture functions that end in "Lod" (eg texture2DLod) are only permitted in the vertex shader.