mpetroff / pannellum

Pannellum is a lightweight, free, and open source panorama viewer for the web.
https://pannellum.org/
MIT License
4.22k stars 717 forks source link

"Error: The image is too big; ..." what should one aim for, for good mobile support? #472

Closed DanielBiegler closed 7 years ago

DanielBiegler commented 7 years ago

Greetings @mpetroff and others,

I've recently encountered said error on my mobile phone while viewing a panorama. Image in question was over 5000px wide and my device appearently only supports up to 4096px.

I was wondering what size is most commonly supported mobile wise? 1024px, 2048px, .. ? Whats a good, general value to choose?

Second question is about a fallback options. I checked the documentation first and only found for multires this:

fallbackPath (string)

This is a format string for the location of the fallback tiles for the CSS 3D transform-based renderer if the WebGL renderer is not supported, relative to multiRes.basePath, which is relative to basePath. The only format parameter is %s, for the cube face. For each face, .extension is appended.

My image in question was an equirectangular though, are there fallback options that I'm unaware of?

If there are none, would this be something that you would like to have in pannellum?

Something along the lines of:

Try the biggest image, if that doesnt work, try a smaller image, if that doesnt work, try ... etc.

Best regards, Daniel.

mpetroff commented 7 years ago

4096px is the safe limit and is supported my 99.9% of devices: http://webglstats.com/webgl/parameter/MAX_TEXTURE_SIZE

That fallback is for lack of WebGL support; it uses CSS 3D transforms instead. The CSS 3D transform fallback renderer is also used for cube maps. It's not possible for equirectangular, though.

I've thought about resizing the image in the browser to fit by drawing it to a canvas, but the browsers all seem to use bilinear interpolation, which is pretty bad. Trying a series of images one after the other is very inefficient, since each has to be downloaded. The better approach would be to specify the size of each image in the configuration and then just use the largest supported image.

DanielBiegler commented 7 years ago

Ah interesting! Thank you very much for your quick response.

You're right, I didnt think about the download speed.

What would a good API for that look like? Something like this?:

{
  "panorama":{
    "img_big":{
      "url":"/img_big.jpg",
      "width":5123,
      "height":3123
    },
    "img_medium":{
      "url":"/img_med.jpg",
      "width":3912,
      "height":1400
    },
    "img_small":{
      "url":"/img_small.png",
      "width":1024,
      "height":800
    }
  }
}

Then one could potentially reuse the image fields if needed and it's clear on syntax but I guess this adds a bit much complexity for such a little feature. How about something simpler like:

{
  "panorama": {
    "8192": "/img_big.jpg",
    "4096": "/img_med.jpg",
    "2048": "/img_small.png"
  }
}

This would be way easier to implement and to write too. One could check for the MAX_TEXTURE_SIZE and instantly pick the right image. Is there a better way?

What are your thoughts on this?

Best regards, Daniel.

mpetroff commented 7 years ago

I think the second syntax is better, since it's simpler.

However, I'm not sure there's a clean way to add this, due to the way Pannellum is structured. All of the WebGL functionality is in libpannellum.js, while the configuration processing and image loading is in pannellum.js. This would requiring adding a separate WebGL context for checking the texture size to pannellum.js. I'm not strongly against this, but I think its use is somewhat limited.

As far as limitations of WebGL texture size go, there's only a need for at most two sizes. Since 99.9% of WebGL devices support 4096px textures, there's no need for a 2048px size, and since a 8192px panorama is already a 33.5 megapixel image, anything larger should not be loaded as a single image anyway, so there's no need for a 16384px image. This leaves 4096px and 8192px. While there is definitely utility to this, I think it might be best left to the user, as this gives more flexibility allowing for other data points outside of the maximum supported texture size to be used, e.g. smaller images could be loaded on mobile devices to save on data usage.

If you want to play around with this, here's code for checking the maximum supported texture size:

var canvas = document.createElement('canvas');
var gl = canvas.getContext('experimental-webgl');
var maxSize = gl.getParameter(gl.MAX_TEXTURE_SIZE);
var extension = gl.getExtension('WEBGL_lose_context');
if (extension)
    extension.loseContext();
DanielBiegler commented 7 years ago

Thanks for your input.

I've thought about having an option for my users to be able to choose different resolutions. 2048 on mobile so It loads quicker, 4096 as a default and for superusers optional 8192 on desktops.

Now that I think about it, how the viewer could be destroyed and again initialized via the settings buttons, this really seems prettier than having Pannellum deal with this.

I guess if 4096 was only being supported on like 50% of devices this issue could have made sense but 99.9% is definitely good enough.

I appreciate your feedback, thanks.