Frustum v Display size

Anything libgdx related goes here!

Frustum v Display size

Postby numbskull » Mon Apr 11, 2011 12:11 pm

Total newbie to games development so please excuse the first (of many?) dumb questions ...

I'm working through SuperJumper to get me started with libgdx and games programming in general.

First burning question that I cannot figure out is how the Frustum is determined in relation to display size.

In SuperJumper the WorldRenderer specifies a 10*15 frustum whereas the MainMenuScreen defines an ortho camera with a view port 320*480.

Obviously the ratios are the same but what is the formula for determining what the actual values for the frustum should be?

Personally I'd like to be able to derive everything from Gdx.graphics.getHeight/getWidth, no hardcoded values, is that possible/sane?

Must add the I'm bowled over by the quality of libgdx and the ethos of the development community in general. Wish I'd joined in many moons ago ...

Thanks,
Numbskull
numbskull
 
Posts: 7
Joined: Mon Apr 11, 2011 11:46 am

Re: Frustum v Display size

Postby mzechner » Mon Apr 11, 2011 3:23 pm

This needs a more elaborate answer, i'll try to write a blog post about it (screen sizes, frustum sizes, viewports etc. etc. pp.)
mzechner
Site Admin
 
Posts: 4879
Joined: Sat Jul 10, 2010 3:50 pm

Re: Frustum v Display size

Postby numbskull » Mon Apr 11, 2011 7:56 pm

That would be great. Thanks Mario.
numbskull
 
Posts: 7
Joined: Mon Apr 11, 2011 11:46 am

Re: Frustum v Display size

Postby mzechner » Tue Apr 12, 2011 12:03 am

OK, i temporarily have some work related obligations so the blog post has to wait for a while i'm afraid :/ Here's a quick explanation (and ask away if it's missing something or if it's unclear):

- In most 2D games you have two type of visualizations: your world and your UI/HUD
- The former usually works in a non-pixel oriented coordinate system, e.g. units are meters. This is especially handy if you want to work with a physics engine like Box2D which demands "sane" sizes and units. Let's call this the world system.
- The later is usually pixel or at least dip (device independent pixel) based. Let's call this the UI system.

When you design your game world, that is the objects within it and the sizes, you want to do that in the world system. That means in meters for example. This looks like it is completely decoupled from the actual rendering, and it should be! However, at some point you have to create the graphical, pixel based, assets for your world's objects. That's when you have to think about your viewport. The viewport (or frustum, it's technically not exactly the same, but let's assume it is for a moment) defines a rectangular window into your world. You look at your world through this window and can only see what's framed by it. You also have a direct connection to your device's display! The viewport coincides with the entire screen (in 90% of all cases), so your display is actually the window into your world.

The problem is that the display works in pixels, where as our viewport dimensions are given in world system units (e.g. 10x15 meters in case of Super Jumper). How do we map one system (display pixels) to the other? Easy, OpenGL ES does this automatically for us if we define a proper projection & frustum. It will automatically scale our 10x15 viewport to whatever screen size we have. On a 320x480 screen the one unit on the x- or y-axis would therefor map to 32 pixels on screen. Even better, the aspect ratio of both our viewport and our screen are the same. This means that no stretching will occur, everything will have to the same width/height ratio.

What happens on a device with a different aspect ratio? One of the x- or y-axis will get stretched. A square in the world system will become a rectangle on screen. Many games take the easy way out and just use this method. The stretching is usually not a big deal and hardly noticeable (see Super Jumper, i think it looks good on HVGA and WVGA screens). For some games it might even be mandatory to use the same viewport (in world system units) so that all players see the same amount of the world, no matter the real screen's size. Games like Starcraft would give an unfair advantage to players with bigger monitos, hence they scale the viewport not matter the real screen size.

Another solution would be to extend to the viewport in one axis to fit the aspect ratio of the real screen. This means you will show more of the world to players with larger screens that have an aspect ratio != your viewports aspect ratio. Some games work like that (Replica Island for example), and as long as it does not give an unfair advantage or makes your work a lot harder it's usually the way to go.

Quick summary so far: define a viewport in your world system units, then use that as the viewport width/height of your OrthographicCamera. It will setup all the matrices and stretch things. If you don't want the stretching you simply extend one of the viewport dimensions to get the same aspect ratio as the physical screen has. You will show more of your world (or less, depending on the device) but get rid of any stretching.

Now, we only briefly looked at creating the actual graphical assets (e.g. sprites). we know how many pixels one units takes up on each axis on the screen (screenWidth / viewportWidth, screenHeight / viewportHeight). In the Super Jumper example we have a viewport of size (10,15). On a 320x480 screen we'd map one unit to 32 pixels on each axis. On a WVGA device with say 480x800 pixels we have a problem:

pixelsPerUnitX = 480 / 10 = 48
pixelsPerUnitY = 800 / 15 = 53,3

As you can see the stretching has an effect on the pixel to unit mapping. One unit on the y-axis maps to more pixels than one unit on the x-axis. We can work around that by extending our viewport so that it has the same aspect ratio as the screen. That will make the pixel to unit mapping the same on both axis. If you are fine with the stretching you don't have to take any action. However, there's another problem.

When you design your graphical assets you have to use the pixels to unit mapping to figure out how many pixels say a sprite should take up in the image you will later load as a texture. In Super Jumper Bob has a size of 1x1 units in world system units. On a 320x480 screen that would map to 32x32 pixel. On a 480x800 screen that would map to 48x53 pixels or 48x48 if you extend the viewport to remove the stretching)! There are two solutions: create a version of Bob for different screen resolution classes (e.g. 32x32 for HVGA, 48x48 for WVGA etc.). Depending on the screen size, load the appropriate version as a texture and render all your objects in world system units (using an OrthographicCamera with a viewport of say 10x15 as in Super Jumper). OpenGL ES will take care of any scaling and stretching that's needed, it's as simple as that. This will most likely give you the best visual quality as your drawing is (mostly) pixel perfect but can incure a cost in terms of assets creation as well as total size of your apk.

Many 2D games thus go an easier route: you define a target resolution for which you create your assets, in Super Jumper i chose 320x480. All the graphics are drawn with the pixel to unit mapping above (1 unit == 32 pixels). OpenGL ES plus the OrthographicCamera with the constant viewport will do all the scaling for us automatically. If you extend the viewport you get rid of the stretch as well without any additional effort. The downside to this is that on screens with a higher resolution than the target resolution the images get scaled up, resulting in a pixelated appreance. For many 2D games that's actually desireable. Replica Island was designed that way as well and it still looks pretty slick on WVGA devices.

To summarize:
Code: Select all
- Define your world system units (e.g. meters)
- Define your objects within this system
- Define your viewport in world system units, which tells you how much of your world is shown on screen. Think of it as a window into your world.
- Now chose one of the two options for asset creation
   - Define a target resolution (e.g. 320x480, or 480x800) and create all your graphical assets (sprites etc.) with the viewport to resolution mapping as defined above (e.g. 1x1 units = 32x32 pixels).
   - Define which resolution classes you want to target (e.g. HVGA (320x480), WVGA (480x800) etc.) and create versions of your assets for each of these resolutions (e.g. 1x1 units = 32x32 pixels on HVGA, 1x1 units = 48x53 pixels on WVGA etc.). If you extend your viewport so that it has the same aspect ratio as the screen on WVGA in that example you can map 1x1 units to 48x48 pixels to make things square again.
- Setup your OrthographicCamera with the appropriate viewport (constant for all screens -> stretching, extended to fit screen aspect ratio -> no stretch, but more/less of the world is visible) and draw all your objects in world system units!


That's pretty much all there is to it.

Now, if you followed closely you should see that the same applies to UIs! The only different is that you'd want to work with a unit system that is closer to pixels than meters in that case. All the rules outlined above are the same. The only difference is that you'd chose your viewport to be say 480x320 dip (device independent pixels) instead of the meter based viewport of the world. Thinks like buttons, labels etc. would be defined in dips. Assets would be created in the same way you'd create them for objects in the world system. viewport -> pixels mapping. That's all the magic that needs to happen.

I hope this helps. It would have made a nice blog post, but for that it lacks the images. I hope it's descriptive and easy enought to follow though :)
mzechner
Site Admin
 
Posts: 4879
Joined: Sat Jul 10, 2010 3:50 pm

Re: Frustum v Display size

Postby numbskull » Tue Apr 12, 2011 5:15 am

Awesome! Now that's what I call an answer. :D

And relates well to your blog on view ports (wish I had the link handy) which contained a great analogy regarding the stretching of a canvas onto its frame; it made the abstract tangible for a newbie like me.

Keep up the great work!

Thanks,
Numbskull
numbskull
 
Posts: 7
Joined: Mon Apr 11, 2011 11:46 am

Re: Frustum v Display size

Postby tonoman » Sun May 29, 2011 2:17 pm

sorry mr.

i still dont understand about these things..

i'm still new in open gl..

i'm confused about
- screen coordinate
- resolution
- stretching in stage..
- frustum? what is that? and about view port

i am still dont get it...
i am really beginner..
T_T

my phone has resolution 320 x 240
and my friend has phone with resolution higher than me..480 x 320..

i use stage = new Stage(480,320,true);
the image (actor) is stretching too..

but i'm confused when i wanted to draw with spritebatch.. the drawing is not strectching..
tonoman
 
Posts: 1
Joined: Fri May 27, 2011 1:25 pm

Re: Frustum v Display size

Postby jaddison » Mon May 30, 2011 3:37 am

Mario, great response! It really explains things well, I think. Now, if only I had seen that 2 weeks ago... ;) Thanks!

Edit: This should be a starred/sticky topic! Great for beginners.
jaddison
 
Posts: 2
Joined: Mon May 16, 2011 4:38 am

Re: Frustum v Display size

Postby boblemarin » Mon May 30, 2011 7:39 pm

Great writing. Thank you Mario.
boblemarin
 
Posts: 11
Joined: Thu Feb 24, 2011 8:09 pm
Location: Liège-Belgium

Re: Frustum v Display size

Postby mzechner » Mon May 30, 2011 10:57 pm

Tonoman, i'll try to break down the terms you listed again. I'd also suggest to re-read what i've written above.

- Resolution: your display is composed of pixels, laid out in a grid. Many Android phones have a display with 800 pixels per row and 480 pixels per column. The resolution is then given as 800x480 pixels. When working with OpenGL you are not bound to that physical display resolution but can perform some tricks to work with any resolution you want.
- Screen coordinate: when you want to specify the location of a pixel you give it in terms of its x and y coordinate. If you think of the display as a grid again the x gives you the column the pixel is located in, the y gives you the row it is located in. These two values together define the unique position of the pixel.
- A viewport is usually an area on your display through which you look onto your game world. Think of it as a window you are looking through.
- A frustum is a bit more complex. Close one of your eyes and keep looking with your other eye. Your eye can only look around for a certain degree (you can't look at what's happening behind you. The area or volume in front of your eye that you can actually see is what is usually called the view frustum. In 3D graphics it looks like a pyramid. You can find a nice explanation of that with images on wikipedia.
- Stretching the stage is a bit more involved. I'd suggest getting comfortable with really basic 2D graphics at first, then check out the Stage API which is a bit more complex.

hth
mzechner
Site Admin
 
Posts: 4879
Joined: Sat Jul 10, 2010 3:50 pm

Re: Frustum v Display size

Postby kolslorr » Sat Jun 11, 2011 3:46 am

Thank you Mario, thats really helpful.

In my case, I am trying to make "Bob" in SuperJumper react to touch event, meaning if I touch on Bob, I alter his state and velocity to make it jump. I did this by adding in some touch event codes in GameScreen.java, but I can only get the precise touch coordinates IF I define my Frustum width and height to be identical to the World width and height.

In other words, the coordinate system of Bob (10,15) and the touchpoint (320,480) is different, hence I couldnt simply use OverlapTester to check for the touch coordinates of Bob and respond accordingly. The way I got around it is to use the same coordinate system for both, and then the OverlapTester works. However, in doing so brings other problems, particularly it screws up the physics system (gravity, velocity).

May I get some pointers from you? What would be the easiest solution?

Thanks.
kolslorr
 
Posts: 10
Joined: Sun Feb 06, 2011 1:49 pm

Next

Return to Libgdx

Who is online

Users browsing this forum: No registered users and 1 guest