OpenGL ES, orthopgraphics projection and viewport

| | August 4, 2015

I want to make some simple 2D game on iOS to familiarize myself with OpenGL ES.
I started with Ray Wenderlich tutorial (How To Create A Simple 2D iPhone Game with OpenGL ES 2.0 and GLKit). That tutorial is quite good, but I miss some parts of a puzzle.

Ray creates orthographic projection using some magic numbers like 480 and 320. It is not clear to me why did he take these numbers, and as far as I can see – sprite is not mapped to the ipad simulator screen one-to-one pixel. I tried to play with parameters with which ortho matrix is created, but I cannot figure out what math is here.

How can I calculate numbers (bottom, top, left, right, close, far) which will be parameters to orthographic projection matrix creation and have sprite on the screen shown in its original size?

2 Responses to “OpenGL ES, orthopgraphics projection and viewport”

  1. I did a lot of experimentation with this as well. When I first learned OpenGL I also wanted pixel for pixel relationships between the graphics I create in photoshop and my placement of those on the screen. For some games you will want exactly that. I’m not classically trained in OpenGL. Instead I taught myself. So I don’t know if it’s normal or kosher or whatever. And I guess I don’t care.

    But because all OpenGL variable have a precision hint, it’s actually better not to use the actual pixel values. Instead use math. Also, keep in mind that at least for another year or so we might want to support non-retina devices. So those don’t have the same number of pixels. But you don’t want your game to have to be coded for multiple screen resolutions. And OpenGL can do a very decent job of resizing your graphics, although it does come at a speed price.

    My suggestion is to pick a scale factor for your units. 1 unit = 10 pixels or 1 unit = 100 pixels. In my games, I’ve chosen 1 unit = 20 retina pixels at a specific depth.

    Another tip.. don’t do orthographic. Go ahead and do a perspective view. Why? This will give you the opportunity to move things in Z space if/when you want to. You’re just going to place your objects at a z depth that has pixel for pixel “unity” (not to be confused with the 3d game engine).

    If you do use ortho though you can use this frustum:

    int frustumScale = 400;
    
    if (retina) {
        frustumScale = 800;
    }
    
    matrixFrustum(-(float)backingWidth/frustumScale,(float)backingWidth/frustumScale,
                   -(float)backingHeight/frustumScale, (float)backingHeight/frustumScale, 40, 1000, frustProjection);
    

    Where frustumScale is 800 for a retina screen and 400 for a non-retina screen. Then at a distance of 800 from camera (-800) the sprite is pixel for pixel the same as photoshop.

    Check out this question and my answer here: In 3D camera math, calculate what Z depth is pixel unity for a given FOV

    Note.. I don’t use glKit. I didn’t want to learn an apple specific way of doing OpenGL. Instead I wrote my own math library and engine. But the basics are probably the same in glKit.

  2. In general i don’t think you will ever need to fiddle with the values inside a matrix unless you are writing a math library. So for this you should take a function that creates and orthographic projection and works (or take a math library that has everything)

    The orthographic projection is like a box has two main components width and height (your magic numbers i think) and those represent the size of the view frustrum(or box in case of orthographic) in world space. That’s why if you have fixed values there the picture will be the same on all screen sizes, but it will be of a different resolution because the content that fits in 480×320 units (inside your world) gets projected on a bigger/smaller surface.

    So now to make rendered content size(in pixels) match the screen size you must first know how big is your world and how many pixels you are fitting inside a unit. For this i will take you are rendering one sprite with 1024×1024 pixels over 2 world units. For a device that has the resolution 1024×768 the size of the view projection will be:
    (2 / 1024,2 / 768)

Leave a Reply