Three.js texture resolution messed up if loaded on small window

I’m using three.js and I have an image as a texture on a 3d-plane that I want to use as a fullscreen image (there are reasons to this). I have therefore coded rules for how to crop the image when resizing (affecting css margins of the canvas). It works fine if the image loads close to the original image size and I then resize it. But if the window loads with dimensions much smaller, resolution gets messed up. Let me show you:

PS: picture dimensions are: 4256, 2832

When I load the page with close to the image dimensions (it’s not about ratio because smaller picture still looks trash). And the picture below is how it looks when I resize it and make it smaller (it looks good):

BUT! When I load the page with the small window it looks trash (upper right in the coming link). The second picture, below, is how it looks when I then resize the window and makes it bigger and closer to original picture dimensions:

https://i.imgur.com/nw0JzeW.jpg

So, apparently there’s something wrong. Here’s some of the relevant code that may help in search of a solution: https://gist.github.com/scummtomte/a83cc219b9ab4ae637c25ed0b6ba8d85

Thank you!

Textures need to be a power of 2 - so 4096 x 4096 or 2048 x 2048 are valid texture sizes, but 4256 x 4256 is not.

Yes, that’s correct and it is planned to be changed. But’s its not related/solving the issue I posted. Thanks anyway, though!

Is 4096 the maximum (perhaps just for WebGLRenderer or perhaps just on iOS)?

The maximum texture size varies depending on your device’s graphics card. Go to https://webglreport.com/ on the device you’re wondering about, and look for Textures: Max Texture Size. For example, my desktop’s max is 16384, my laptop’s max is 8192 and my phone’s is 4096.

You could also get this info via WebGLRenderer.capabilities.maxTextureSize

1 Like

Well, 4256 x 4256 or 2832 x 2832 are of course a valid resolutions for textures. It’s just not possible with WebGL 1 to generate mipmaps with NPOT textures. However, this is not true for WebGL 2. So the distinction between POT and NPOT is not important anymore.

1 Like

Thanks, marquizzo. That’s a directly useful answer.

I see those stats also cover cube maps and combined texture image units. I’m projecting onto a sphere, not a cube, but I wonder if there’s any way to tile two image textures next to each other to get a combined 8192x4096 texture despite the hardware’s base 4096 limit. All I find in in google is how to layer two textures on top of each other.

Easiest solution: If you’re projecting onto a sphere, you could build two sphere halves by setting the phiLength argument in the constructor to Math.PI, and change the phiStart on the second half. Then just use a different 4096x4096 texture on each hemisphere.

See here for an example with phiStart and phiLength for more details: https://threejs.org/docs/#api/en/geometries/SphereGeometry

That was my backup solution. Seems easy enough. Thanks!

Apple devices will never support WebGL2, so, unfortunately, we are still stuck with this limitation for a while yet.

Aside from that, is this something that we get automatically when we use WebGL2 with the WebGLRenderer? Or will it have to be implemented in three.js first?

Resizing of NPOT textures is not necessary since R101 anymore (see #15574). You automatically benefit from this feature by just using a WebGL 2 rendering context.

1 Like

Nice! :grin:

Now, if only Apple was to support WebGL2…

Users can also set Texture.minFilter to LinearFilter or set Texture.generateMipmaps to false in order to avoid a texture resize. However, best texture quality is achieved with mipmapping.

Did Apple release a statement declaring they would never support WebGL 2? Or are they just silently not doing it?

I remember this one:

3 Likes

Oh, amazing :grin:
I had previously heard that the official response from Apple was that they were never going to support WebGL2.