three.js: Couldn't create Texture from resized DOM Image
Describe the bug
If the DOM image is resized with CSS, like: width: 10%, and you try to create texture with THREE.Texture(DOM_ELEMENT) class, that will result in:
GL ERROR :GL_INVALID_VALUE : glTexSubImage2D: bad dimensions.
The behaviour appears since v135. It is not present in v134.
To Reproduce
Steps to reproduce the behavior:
- Create a DOM image in HTML
- Resize it with CSS: img{width: 10%}
- Create a texture from image with THREE.Texture(DomElement) class
- Use texture on any material
- You will get: GL ERROR :GL_INVALID_VALUE : glTexSubImage2D: bad dimensions. in latest Chrome.
Code
let material = new THREE.MeshBasicMaterial();
let img = document.querySelector('img')
let texture = new THREE.Texture(img)
texture.needsUpdate = true;
material.map = texture;
mesh = new THREE.Mesh( geometry, material );
scene.add( mesh );
Live example
- ~jsfiddle-latest-release (forgot to set display:block here, hence new demo)~
- bug
Expected behavior
To see sphere with kitten texture.
Screenshots
This is the expected result of demo.

Platform:
- Device: Desktop
- OS: MacOs
- Browser: Chrome
- Three.js version: r136
About this issue
- Original URL
- State: closed
- Created 2 years ago
- Comments: 25 (3 by maintainers)
Commits related to this issue
- fix #23164: use image original size for gl.texStorage2D — committed to MickeyMiao7/three.js by MickeyMiao7 2 years ago
Yeah, so, instead of
I used this workaround:
also in one case this:
But of course, would be perfect to fix issue, to not do this. Or is it best practice now to clone everything from DOM before converting it to texture? 🤔
could asking other developers on discord be a way to make up a decision? For me as one of three.js dev-users it is obvious that i expect three.js to disregard any CSS, when i convert DOM element to WebGL Texture. And my hypothesis is its like that for 99% people. Because those are two different mental models/concepts/coordinate-systems, and i dont want them to interfere.
What are the possible drawbacks of using naturalWidth here?
I have exactly this issue when trying to load images from the DOM as textures in r157 (same scenario as @akella’s using THREE.Texture). I am surprised that under the bonnet Three is thrown due to some CSS applied to the image - as @mrdoob suggested I agree that image.naturalWidth and image.naturalHeight should be used instead the current mechanism - it would be amazing to see a fix for this.
The current implementation is inconsistent because it doesn’t work around the inconsistent property behaviour in the spec:
The
widthandheightproperties of bothHTMLCanvasElementandImageBitmapreflect the logical pixels of their intrinsic ImageData container. Changing the display properties of a canvas via CSS does not affect its intrinsicwidthandheightproperties.The correct equivalents for HTMLImageElement are
naturalWidthandnaturalHeightbecause, likewidthandheightforHTMLCanvasElementandImageBitmap, these properties reflect the logical pixels of the intrinsic imageData and are not affected by changes in display logic.I guess the question is whether or not Three.js should correct for this inconsistency by internally mapping
widthtonaturalWidthandheighttonaturalHeightwhenimage instanceof HTMLImageElement, instead of usingimage.widthandimage.heightregardless of the constructor.Hmm…
image.naturalWidth || image.width? 😅It sure makes things a bit more complicated…
It seems like using
image.naturalWidthis what we want? https://stackoverflow.com/questions/28167137/whats-the-difference-between-width-naturalwidth-and-clientwidthThis approach appears to work regardless of the CSS.
https://jsfiddle.net/wh9g0dqn/
@Mugen87 Any idea what is going on?
i will just add my 2c: the current change from v135 is actually breaking a lot of code. Common use case: Converting DOM Images into WebGL layer to animate them. With this case you have images in HTML with design applied to them, and you convert them to textures, and now it doesnt work if you have any sizing CSS applied to them. Which will always be because web is responsive now. So this makes texture creation from DOM element kind of useless in most cases, does it?
What would be the alternative way? To copy all the IMG into hidden DIV and strip all CSS from them before converting to Texture? Or to collect SRC’s and load images second time with TextureLoader? =(