Camera setup

edited January 2012 in Help request
Hi guys,

Is it possible to simulate glOrtho using cameras?
What I'm looking for is a way to get iPhone in landscape mode but also so that the left-bottom corner of the screen is mapped to 0,0 and the top-right corner is 480,320.

A proper explanation (a bit of theory) along with an example/code snippet would be appreciated :)

Thanks in advance!
Alex

Comments

  • edited January 2012
    Hi Alex,

    Mmh, I don't think there's any easy way to do that. Orx uses a right handed system with Z pointing toward the screen.

    I guess the easiest work around would be to use a default shader on all your objects to do the Y coord reversal. The issue would then be for older devices with no shader support.
  • edited January 2012
    Let me put it another way. What's the closest I can get with cameras without hacking around? Can I get 0,0 = top-left, 480,320 = bottom-right?

    Thanks!
    Alex
  • edited January 2012
    Yes, that's pretty easy. Something like:
    [Camera]
    FrustumWidth  = 480
    FrustumHeight = 320
    FrustumNear   = 0
    FrustumFar    = 2
    Position      = (240, 160, -1)
    
  • edited January 2012
    Found any lead on the scaling issue you encountered, btw? Couldn't repro it with the simulator and I only have non-retina devices.
  • edited January 2012
    No i didn't.. I was busy doing other stuff. I'll give your camera config a go now and see if it changes anything at all :-)

    I'm not sure how to mix all that with the second camera and rotation to get landscape mode but I think i'll make it work.

    Thanks!
  • edited January 2012
    Actually the second camera trick is only is you want resolution-independent UI objects (that use the second camera as a parent).

    If you don't need that, no need for the second camera, even in landscape mode. :)
  • edited January 2012
    I guess what I need is better understanding of camera concept and underlying math.. I don't really follow how it works atm. :(
  • edited January 2012
    That makes me think, the config I gave you will work for landscape devices, ie. computer screens. :)

    For portrait devices (Android/iPhone), try this instead:
    [Camera]
    FrustumWidth  = 320
    FrustumHeight = 480
    FrustumNear   = 0
    FrustumFar    = 2
    Position      = (240, 160, -1)
    Rotation      = -90
    
  • edited January 2012
    Do i have to specify ParentCamera each time I want to use it's coordinates? I mean do I have to explicitly specify it to use my 0,0 -> 320,480 glOrtho emulation?
    Because any config atm. works exactly the same except for the background which is halfway off-screen and the buttons (UICamera is messed up i guess).
  • edited January 2012
    Ah sure, sorry, I assumed you knew how it worked.
    It's actually pretty straightforward and akin to how it works in most 3D engines.

    There are two spaces: screen space and world space.
    Unless your game is completely static, it's better not to care much about the screen space.

    Mouse/touch positions are the only ones defined in screen space with (0, 0) being top-left corner and (ScreenWidth, ScreenHeight) being the bottom-right one. And actually, if you want to use them, you'll have to transform them into world space first by calling orxRender_GetWorldPosition() which will try to find a viewport that would contain the screen position and use it to map it to world position. If no viewports are found, the function returns orxNULL.

    So everything now happens in a world space. There you have all your objects and your camera. As we're in 2D, you can see your camera as a Z-aligned box. Every object contained in that box will get rendered by the camera and mapped either to screen or to a texture via the viewport.

    If the camera aspect ratio is different than the viewport one, letter or pillar boxing will be automatically done by the renderer.

    Now for easy UI placement (or background or anything static in respect with a camera), one can defined a parent camera in config (or set it at run time). That means that this object, as being a child of the camera, will always move with it.

    So it's perfect for UI objects and backgrounds: the UI objects being very close to the camera so that they're rendered last and the backgrounds being very far so that they're rendered first.

    As we have to rotate a portrait-defined camera 90° to match a landscape display, we should also rotate all our UI objects 90° the other way to compensate for it (including the top left corner as (0, 0) would now be either the top right or the bottom left corner, depending on the rotation).
    If we didn't compensate, they'd looked sideways when the user is holding the device in landscape mode.

    So as to avoid this annoying compensation, there's a two camera trick. It's a dirty hack in the sense the second camera won't render anything. It's a camera as we can name them in config and they're unique at runtime (whereas objects aren't unique at runtime, there can be more than one object named "MyObject").

    This way, we can define a landscape box with the second camera, have it rotated 90° the other way, and define our UI objects as if we were using a regular landscape camera (which means 0,0 in the top left corner).
    Of course, there's another way of doing that, instead of defining a parent camera for each UI object, we can instead create a UI hierarchy the other way.
    We could define a "UIRoot", that would be attached to the main camera (no need for a second camera in this case), rotate it to compensate for the camera original rotation, make sure its size match the landscape box we want and then add all our UI objects as ChildList of this UIRoot.

    This looks cleaner but we loose the resolution-independent feature of using ParentCamera: when using ParentCamera in config, we can define position and scale of objects relatively to the parent's size. Ie, if I say the scale is relative to the parent and set Scale = 1, it means its size will be so that it'll cover exactly the 2D rectangle defined by the camera. No matter what the camera size is. Same for positioning, (0, 0) will always be the top left corner and (0.5, 0.5) the exact middle of the camera, no matter what its size is. That allows for resolution independent UI positioning. Even if your camera changes aspect ratio, your UI objects will look more or less close but always where you want them, without having to change any value in config.

    Sorry for that long post, but I hope it clarified a bit the concept of world/camera/viewport. :)

    If you have any questions, don't hesitate!
  • edited January 2012
    godexsoft wrote:
    Do i have to specify ParentCamera each time I want to use it's coordinates? I mean do I have to explicitly specify it to use my 0,0 -> 320,480 glOrtho emulation?
    Because any config atm. works exactly the same except for the background which is halfway off-screen and the buttons (UICamera is messed up i guess).

    You have to specify ParentCamera if you want to bind an object to the camera or if you want to not have to do the maths yourself as you can then use the camera's space instead of the world space.
  • edited January 2012
    Wow thanks for the explanation. The whole story is a bit more complicated than I could hope though :)

    So basically I can't use "screen space" coordinates to put my elements on screen, right? It's not very handy in terms of design->implementation :-)
    What I'm trying to say is that a designer will give you a 320x480 png image with all ui elements present on the "screen" and you will have to find the 0.0-1.0 mapping for them. It's not too hard though as it's just simple math.

    So if I understand correctly the "camera space" coordinates visible on screen are always 0.0->1.0 on both x and y, right? What about world space coordinates? how are they different from camera space?

    Thanks!
    Alex
  • edited January 2012
    godexsoft wrote:
    Wow thanks for the explanation. The whole story is a bit more complicated than I could hope though :)

    My pleasure! I should probably write a wiki entry to explain that more as it's a concept more frequent in 3D games and I can understand why it's confusing.
    So basically I can't use "screen space" coordinates to put my elements on screen, right? It's not very handy in terms of design->implementation :-)

    So yes, you can setup your camera so that your world space visually matches your screen space. You'll still actually work in the world space but the whole rendering process will give a 1->1 transformation in the end, making it look like screen space.
    What I'm trying to say is that a designer will give you a 320x480 png image with all ui elements present on the "screen" and you will have to find the 0.0-1.0 mapping for them. It's not too hard though as it's just simple math.

    Well, actually it's optional! The whole relatice positioning/scaling is only there to help achieve resolution-independence (which is nice when you're going on a devices with slightly different aspect ratio, like say, Android! ;)).
    If you don't want to use relative positioning, you can still go old school.
    When using relative coords, the camera's center is (0, 0), that means the top left corner is (-0.5, -0.5) and the bottom right one (0.5, 0.5).
    When going with non-relatice coords, the camera's center is still (0, 0), unfortunately (consider it as the camera's pivot), which means the top left corner is (-FrustumWidth/2, -FrustumHeight/2) and the bottom right one (FrustumWidth/2, FrustumHeight/2).

    Now how to specify that you don't want to use relative position?
    Easy, that's the UseParentSpace config property.

    By default its value is both, which means both positions and scales will be considered as being relative.
    You can specify none, position or scale as values to either go completely non-relative or have only one aspect defined as relative values.

    Now if you find annoying that the camera's center is (0, 0) instead of the top left corner, the easiest way is to use an intermediary agent. By inserting a main-in-the-middle object, you can add a transformation. Let's call this middle agent "UIRoot". For a (480, 320) camera:
    [UIRoot]
    ParentCamera   = Camera
    UseParentSpace = position
    Position       = (-240, -160, 0)
    Scale          = 1
    ChildList      = UIObject1 # ... ; Put all your UI items here
    

    Would compensate for (0, 0) being in the middle of the camera.
    In this case though, you should *not* add UseParentSpace to the UIObjects config as that would replace their UIRoot parent with the camera. :)

    In the same way, you can create containers, like a background + 2 buttons that are always together can be defined as a hierarchy with ChildList, which makes it very easy to move things around, either offline or even at runtime.
    So if I understand correctly the "camera space" coordinates visible on screen are always 0.0->1.0 on both x and y, right? What about world space coordinates? how are they different from camera space?

    The relative coords only exist when using ParentCamera and only at creation time. They're here to simplify resolution independent positioning. But orx will immediately transform them as real world space coords.

    That means that objects rendered are inside the rectangle going from top left (CameraPos.X - FrustumWidth/2, CameraPos.Y - FrustumHeight/2) to bottom right (CameraPos.X + FrustumWidth/2, CameraPos.Y + FrustumHeight/2) (world space), and mapped to your viewport on screen (screen space).

    That's why, if you have a static camera and set its CameraPos = (FrustumWidth/2, FrustumHeight/2) you end up of "matching" word space coordinates to screen space ones (assuming you're using only one fullscreen viewport of the same aspect ratio than the camera).
    When you go in landscape mode, all you want is actually to move your top left corner to the "next physical corner", which means rotation of 90°.
    Thanks!
    Alex

    My pleasure. If I weren't so bad with art (and lazy), I'd post a wiki entry with nice images to explain all this. :)
Sign In or Register to comment.