webgl-fundamentals icon indicating copy to clipboard operation
webgl-fundamentals copied to clipboard

Loading images to textures is trickier than described!

Open trusktr opened this issue 6 years ago • 7 comments

Apparently, loading a texture from an arbitrary image isn't that easy.

For example, I've followed the tutorial, but when I try to load a texture from a jpeg image like

        const image = new Image
        const isPowerOf2 = value => (value & (value - 1)) == 0
        image.addEventListener('load', () => {
            // Now that the image has loaded copy it to the texture.
            console.log('texture target????', gl.TEXTURE_2D)
            gl.bindTexture(gl.TEXTURE_2D, this.texture)
            gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, image)

            // Mip maps can only be generated on images whose width and height are a power of 2.
            if (isPowerOf2(image.width) && isPowerOf2(image.height)) {
                console.log('is power of two.')
                gl.generateMipmap(gl.TEXTURE_2D)
                // TODO make filters configurable?
                gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR)
                gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_LINEAR)
            }
            else {
                console.log('is NOT power of two.')
                gl.texParameteri(gl.TETXURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE) // INVALID_ENUM: texParameter: invalid texture target
                gl.texParameteri(gl.TETXURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE) // INVALID_ENUM: texParameter: invalid texture target
                // TODO make filters configurable?
                gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR)
                gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR)
            }
        })
        image.src = imageUrl

where imageUrl is a data URL for a jpeg in my case, then I get this error in console:

scene.js:223 WebGL: INVALID_ENUM: texParameter: invalid texture target

This is happening when I try to do like in your tutorial for dealing with non-power-of-two images, on the lines above marked with INVALID_ENUM.

Unfortunately, googling around for that error has like no results!

So I am trying to figure out what is wrong, but it isn't as easy as most things web are.

Maybe we can update the tutorial with examples for specific types of popular image formats.

trusktr avatar Jul 07 '17 03:07 trusktr

TEXTURE not TETXURE

greggman avatar Jul 07 '17 03:07 greggman

Aha!!!!! Haha. Wow. Alright, here we go: https://github.com/greggman/webgl-fundamentals/pull/84

trusktr avatar Jul 07 '17 03:07 trusktr

sorry about the typo

the clue was in the error message

scene.js:223 WebGL: INVALID_ENUM: texParameter: invalid texture target

the texture target is the first parameter and INVALID_ENUM in particular means that one of the gl.XXX parameters is just flat out wrong for that particular function . If it was ok sometimes but just not for the situation then it would be INVALID_VALUE or INVALID_OPERATION

greggman avatar Jul 07 '17 03:07 greggman

Ah cool, thanks for that tip. 😊

trusktr avatar Jul 07 '17 04:07 trusktr

On my desktop, everything works fine, but when I open the same app on mobile, I see the blue texture as expected before the image is loaded, but the image fails to become a texture and I see in the console:

WebGL: INVALID_VALUE: texImage2D: width or height out of range

Any idea why this might happen on Android Chrome, but not on Desktop Chrome?

trusktr avatar Jul 07 '17 22:07 trusktr

How big is the image? WebGL has a size limit

maxSize = gl.getParameter(gl.MAX_TEXTURE_SIZE);

Looks like for most phones the max size is 4096

http://webglstats.com/webgl/parameter/MAX_TEXTURE_SIZE?platforms=0000007c0012800500

Also note that size is the max dimension, you still have to take into consideration memory. For example if the max is 4096 then a 4096x4096 RGBA 8bit texture with mips would take almost 90meg of GPU accessible ram and given you had to load the image and decompress it before it can be copied to the GPU that means you need at least double the memory to load it.

greggman avatar Jul 08 '17 11:07 greggman

Hmmm, I think it may be an SVG that is 5500 by 5500. Probably.i need to make sure the other canvas is sized to the quad that I'm putting the texture on.

trusktr avatar Jul 09 '17 03:07 trusktr