Jump to content

2x graphics bigger than expected on Retina display


mwatt
 Share

Recommended Posts

Hello all,

 

I'm trying to situationally swap in graphics files based upon device pixel ratio and to some extent, screen size.  My understanding is that a standard retina display will require graphics that are twice as large as the graphics that a non-retina display of the same screen size would require.  My understanding appears to be wrong, because when I load in double sized graphics on a retina display, the scene extends beyond the visible screen.  Perhaps I should add that I specifying a game size of 640 x 690 and comparing a browser with body sized to 320 x 480, to an iPhone 4. 

 

Let me give an example.  Suppose I have a graphic of a circle.  In the browser, I am loading a circle with a diameter of 240.  In the iPhone 4, I am loading a circle with a diameter of 480.  I expect these to be the same relative size on the screen, but they are not.  What am I misunderstanding?

Link to comment
Share on other sites

I think you are assuming a pixel in HTML/CSS terms to be one pixel onscreen. However your window.devicePixelRatio is probably 2 (2 device/screen pixels : 1 HTML/CSS pixel) unless you've used the approproiate viewport meta tag in your HTML header to ask for a 1 to 1 mapping between HTML pixels and screen pixels eg. <meta name="viewport" content="width=device-width, initial-scale=1">

Link to comment
Share on other sites

Thank you for answering chg.

 

I am using this meta tag, which I culled from a post on this board:

<meta name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width, height=device-height, target-densitydpi=device-dpi" />

 

It does contain all the settings you mentioned and a few more for good measure.  I have in fact tested with and without this meta tag and it makes little or no difference in terms of the effect I am describing.  For some reason, Retina display does not scrunch 2X images down to 1X.

 

I do very much appreciate your help though.  If you have further thoughts or if anyone else can chime in, that would be wonderful.

Link to comment
Share on other sites

Retina screens are a bit weird to explain, but once you understand them, they aren't too crazy.

 

The best way to think about it, is that you can't really access those pixels directly in html, css and javascript.

 

Lets say you have an image who's dimensions are 100px by 100px. If you display that on a normal screen (from here on referred to as a 1x screen) and a retina screen (a 2x screen), they will both 'appear' the same size. On the retina screen however, they will be using 4x the number of pixels to display (on a retina screen, 4 pixels are packed into the same space as 1 pixel). This will cause the image on the retina screen to appear blurry, or 'scaled up' even though it's visually the same size. This is because the CSS width and height dimensions on a 2x screen, are being relativized to a 1x screen and as a result, the image is being scaled up - there are more device pixels being used to render the image). If you want that 100px by 100px image to look sharp on a 2x screen, you would need to set its CSS width and height to 50px. By visually making it smaller, the browser magically knows it has extra pixels, and just uses those to match the pixels 1 for 1 from the image onto the device pixels.

 

If you wanted the image to maintain it's same visual size and appear sharp, you would need to provide a 200px by 200px image, and then set its CSS width and height to 100px.

 

I am using an image in this description, however conceptually it's very similar to a canvas element which I will get into in a second.

 

There's another issue with mobile screens in that they enable the view to pinch to zoom. The exemplified viewport meta tag you supplied above will stop this from happening, it will ALSO set the zoom level to 1. This is absolutely what you want to do with any html games in a mobile browser to help optimize performance and visual display.

 

You are also correct above in that you need to actually double the size of your canvas. When I say double, I mean actually doubling the canvas width and height attributes or using Phaser's width/heigh initialization properties. The part that you are missing however, is you then need to 'scale' the canvas back down using CSS width and height to maintain the same visual appearance. Just remember, with canvas elements, do not change their width and height attributes in the canvas tag, otherwise you actually reduce the number of available pixels (at least with Canvas2D), instead use CSS to change the visual appearance of its size.

 

The best way that I am aware of to do this in Phaser is using the Scale Manager

game.scale.scaleMode = Phaser.ScaleManager.USER_SCALE;game.scale.setUserScale(0.5, 0.5);

What we are doing here is telling Phaser that we want to manage how the canvas scales, and then 'scale' it down to half the size.

 

Of course you will still need to provide assets that are at this new 2x size to display, and there may even be some issues with movement and physics that you would have to scale as well, however I think that's outside the scope of this explanation.

 

Hope this helps.

Link to comment
Share on other sites

Thanks for the reply Amadeus.

 

It blows my mind that the way to do this is to double the size of the game (which I was not doing, I only doubled the image sizes) and then scale the game back down by half.  It seems really weird.   The whole CSS discussion also confuses me, since nowhere within the Phaser API do we deal with CSS and WebGL plus CSS is a non-sequitor, I thought.

Link to comment
Share on other sites

Re-reading my post, I realized I didn't really make something clear. If you forget about Phaser for a moment, and you wanted to achieve retina graphics on a canvas element, you would use CSS width/height properties to visually scale the canvas element down.

 

Phaser abstracts this away from you with the scale manager, so you don't need to worry about CSS directly when using Phaser. Phaser internally however, uses CSS to scale the canvas down, as CSS is a language used for styling elements in a web page, a canvas element being one such element.

Link to comment
Share on other sites

The amandeus' explanation is very nice to describe it. Yes you make your game larger as if you had tons of more resolution. Then just scale it down virtually ie. with CSS transformations. Browser then does the magic and uses the extra pixels in-between for more detail.

 

However the biggest problem here is that it requires a lot more processing power and to my experience (with production game) it's possible to "scale up" about to 1.25 on Macbook retina screen and on latest iPad Air about 1.5. On iPhone 6 plus you can go as far as 1.75 without affecting fps too much. Using the full 2 (or the insane 3 in iPhone 6 plus) is not going to work very well.

 

You probably could go further if using native application, but current with Javascript, even with WebGL, it's not possible. 

 

That said, even the 1.25 gives you pretty good impression of retina detail. Even that small amount helps very much.

Link to comment
Share on other sites

This is good info guys, thanks again amadeus and jounii.  As it happens, the graphics I am using are simple and thus resistant to density distortion, but I want to learn how to handle this scenario.   I'll fool around with it in the upcoming days and post a reply back to let folks know about my results.

Link to comment
Share on other sites

Ok, I finally got things working to my satisfaction and I finally "get it" with retina-like displays.  The posts of chg, jouniii, and in particular amadeus were instrumental in making the light dawn.  Thank you once again guys.

 

The upshot for any who have been, or will be reading this thread is this: 

 

When you load double density graphics (meaning width and height are multiplied times 2) in cases where the device at hand has a high density display, you must scale down the size of those graphics by half.  Likewise if you loaded triple density, you should scale down by 1/3.  It's that freaking simple.

 

You don't need to reset the game size... a good all around size seems to be 640 x 960 or 960 x 640, but others are possible.  I should add that I could not make setUserScale work in conjunction with Phaser.ScaleManager.SHOW_ALL.  I had to set scale individually on each  sprite that I handle responsively - but I don't care, I made a  nice function for this purpose and it works just fine.

 

I'm going to mark this puppy solved.

Link to comment
Share on other sites

  • 2 years later...

I got this working and it does NOT involve halving your textures!

It requires two things to work:

1) Instantiate the size of you Phaser game window based on the pixel density of the browser:

new Game(640 * window.devicePixelRatio, 480 * window.devicePixelRatio, './', document.getElementById('phaserGame'));

2) Set the scale of your game based on the pixel density of the browser:

if(window.devicePixelRatio === 2) {
  game.scale.setUserScale(.5, .5);
  game.scale.scaleMode = Phaser.ScaleManager.USER_SCALE;
}

 

Link to comment
Share on other sites

On 2/1/2015 at 0:40 AM, mwatt said:

I should add that I could not make setUserScale work in conjunction with Phaser.ScaleManager.SHOW_ALL

setUserScale only works with USER_SCALE.

SHOW_ALL only cares about the container's dimensions.

Link to comment
Share on other sites

 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...