Page 1 of 1

Resolution and Aspect Ratio independence?

Posted: Tue Jul 10, 2012 4:10 pm
by Zach
Hi guys,

This has been bugging me for a long time. Because I have briefly Googled on the topic on and off, and have never really found a satisfying answer to this problem... But it is clear to me that big commercial productions do have solutions for it, and I'm just not sure what I can do as an "indie" game developer, when I start making 2D or 3D Graphics based games.

It is really important to me to have a solution (and one I can actually understand/implement). Because as a gamer it bugs me when I play a game that doesn't support Widescreen (1920x1080/16:9) because of its age, and it was made in the 4:3 dominant era. There are some engines from that era that allow you to adjust the FOV and such, which is kind of a fix, but that is usually just for first person type games..

I really want to be able to design a game that looks the same, and has the same Viewport whether you are playing at 640x480, 1024x768, 1280x720, 1366x768, 1440x900, 1600x900, 1600x1200,1920x1080, or even 1900x1200.. Whether your monitor is a 4:3, 5:4, 16:9 or 16:10 Aspect Ratio (the most common ones).

I have seen examples here and there, where people just used some scaling algorithms, but I have no idea how to create one, and what kind of math to use, and also how different scaling (up from resolution A versus down from resolution B) may effect the final image, and where scaling should happen in the rendering loop (I assume at the end, once everything is drawn onto a Buffer).

Some games do this automatically behind the scenes based on the resolution you select, while others allow you to manually specify both your display resolution AND the aspect ratio you want (Lord of The Rings Online does this).

Have any of you had to tackle this problem? What was your solution?

Somewhat related to this, I also have concerns about Resolution independent assets in general, and how a game can capitalize on this efficiently.. i.e Do you design and create everything in a resolution larger than you ever intend to support and scale down? Or do you design for your highest support resolution, and then downscale those assets, to be used/scaled below a specific resolution? I know about Vector images and stuff, but I'm not really sure how I would use Vectors in a game engine (what is needed to support such a format) or if Vectors can be used for all the assets you are using. It would be nice if so, as you could have the game pre-scale the assets as part of the Setup routine, and re-compute them from a master cache each time the resolution is changed, but I'm not really sure how practical that is (for a small game it would work, but you could probably get away with doing it on the fly anyway. For larger games it would probably take lots of time).

If anyone has any thoughts on this secondary question as well, I would appreciate any input. But the primary question is the most important for me right now.

Re: Resolution and Aspect Ratio independence?

Posted: Tue Jul 10, 2012 5:24 pm
by kenmo
Zach wrote:Have any of you had to tackle this problem? What was your solution?
Oh yes. :D I have tried various methods in various PB/non-PB projects with varying success. It's actually sort of fun, experimenting with different screen configurations.
Because as a gamer it bugs me when I play a game that doesn't support Widescreen (1920x1080/16:9) because of its age, and it was made in the 4:3 dominant era. There are some engines from that era that allow you to adjust the FOV and such, which is kind of a fix, but that is usually just for first person type games..
If I understand correctly, then I agree. I expect games to run in any reasonable resolution (perhaps 640x480+) my display supports -- but whether it changes aspect ratio to fit the display depends on the type of game. For most 3D games, both 1st and 3rd person, I would expect the camera to naturally fill the available aspect ratio. For most 2D games, I prefer it to keep its original aspect ratio and just scale up or down. (more below)
I have seen examples here and there, where people just used some scaling algorithms, but I have no idea how to create one, and what kind of math to use, and also how different scaling (up from resolution A versus down from resolution B) may effect the final image, and where scaling should happen in the rendering loop (I assume at the end, once everything is drawn onto a Buffer).
Scaling isn't too tough. Easy example: say you design your game at 320x240, and later decide to allow user-selected resolutions. If the user picks 640x480 (exactly double the width and height), you just draw everything twice as large and twice as far apart (in screen coordinates). If you use a 3D engine, it's typically handled automatically. Everything is just in world coordinates, and the renderer scales it all properly. At the other end, if you're manually handling every bit of scaling and drawing at the exact pixel level, you need a lot of algebra. If you use something like the Sprite3D library, I'd call that somewhere in between.

(I think I mentioned this in another thread, but I recommend writing your game engine to use consistent "game coordinates", whatever they may be, and only worry about scaling/drawing/screen coordinates at the final render step.)
Somewhat related to this, I also have concerns about Resolution independent assets in general, and how a game can capitalize on this efficiently.. i.e Do you design and create everything in a resolution larger than you ever intend to support and scale down? Or do you design for your highest support resolution, and then downscale those assets, to be used/scaled below a specific resolution? ....
Typically, you're right, I think you design everything at some "max" resolution using hi-res raster images or even vector images. Then you scale down for lower resolution gameplay. But WHEN to do this depends on your design: Each time you change resolution? Do you save scaled assets to the drive for later? Does the graphics engine automatically scale for you in realtime? Do you distribute different resolution graphics with the original game, so you can ensure there are no scaling artifacts beforehand? I don't think I have enough traditional graphics experience to give specific advice.

Re: Resolution and Aspect Ratio independence?

Posted: Tue Jul 10, 2012 5:56 pm
by xorc1zt
on opengl or directx you must use a projection matrix which is updated when the window get a new size

Code: Select all

Procedure tickWindow()
    Select WindowEvent()
        Case #PB_Event_CloseWindow
            quitmainloop = #True
        Case #PB_Event_SizeWindow
            onResize( WindowWidth(0),  WindowHeight(0) )
    EndSelect
EndProcedure

Procedure onResize( width.i,  height.i )
    glViewport( 0, 0, width, height ) ; resize the viewport
    projmatrix\perspective( 70, 1, 100, width/height ) ; update the projection matrix (70 fov)
EndProcedure
http://en.wikipedia.org/wiki/3D_projection
http://www.mediafire.com/?ms936a01nea7p6c

Re: Resolution and Aspect Ratio independence?

Posted: Wed Jul 11, 2012 5:24 pm
by Zach
Interesting answers for sure.

Can you give me more information on setting up a "World Coordinates" type of system? I assume that would work in either 2D or 3D ?


Also, it's not very big but I think I finally found a Tutorial on 2D Game Engines that I might actually learn something from.
http://www.inverted-keystrokes.com/cate ... -tutorial/

Re: Resolution and Aspect Ratio independence?

Posted: Wed Jul 11, 2012 8:13 pm
by kenmo
By world coordinates, I mean whatever arbitrary coordinates your game uses... 2D, grid-based, isometric, 3D... just keep it separate from screen/display coordinates until the drawing step.

Here's a simple 2D example I just threw together that shows (a) scaling according to screen size and (b) forcing a desired aspect ratio, through black "matte" bars in this case.

Use WASD and the arrows to move the objects, mouse to move the "camera". These basic principles can be applied to sprites, GUI elements, etc.

Code: Select all


; Generic 2D object
Structure GameObject
  WorldX.f
  WorldY.f
  Shape.i
  Color.i
  Size.f
  Speed.f
EndStructure

; Screen parameters
#BGColor     = $F0F0F0
#FrameRate   = 60
#ScreenDepth = 32
#AspectRatio = 16/9.0 ; try 4/3.0, 2.85, 1/3.0, etc
#ViewScale   = 4/480.0 ; somewhat arbitrary
#MouseSpeed  = 0.5

; Shape constants
#Box    = 0
#Circle = 1




; Initialize
If InitSprite() And InitMouse() And InitKeyboard() And ExamineScreenModes()

  ; Create screen select window
  If OpenWindow(0, 0, 0, 300, 300, "Screen Select", #PB_Window_ScreenCentered|#PB_Window_SystemMenu)
    AddKeyboardShortcut(0, #PB_Shortcut_Return, 0)
    AddKeyboardShortcut(0, #PB_Shortcut_Escape, 1)
    ListViewGadget(0, 0, 0, WindowWidth(0), WindowHeight(0))
    While NextScreenMode()
      If ScreenModeDepth() = #ScreenDepth
        AddGadgetItem(0, -1, Str(ScreenModeWidth()) + "x" + Str(ScreenModeHeight()))
      EndIf
    Wend

    ; Repeat select window --> open screen sequence
    Repeat
      HideWindow(0, 0)
      Cancel = #True
      Repeat
        Event = WaitWindowEvent()
        If Event = #PB_Event_CloseWindow
          Break
        ElseIf Event = #PB_Event_Menu
          If EventMenu() = 0
            If (GetGadgetState(0) >= 0)
              Cancel = #False
              Break
            EndIf
          Else
            Break
          EndIf
        ElseIf Event = #PB_Event_Gadget
          If EventType() = #PB_EventType_LeftDoubleClick
            If (GetGadgetState(0) >= 0)
              Cancel = #False
              Break
            EndIf
          EndIf
        EndIf
      ForEver
      HideWindow(0, #True)
      
      
      
      
      
      
      
      
      
      
      
      ; Begin "Game"
      If (Not Cancel)
        TempS.s = GetGadgetItemText(0, GetGadgetState(0))
        ScreenW.i = Val(StringField(TempS, 1, "x"))
        ScreenH.i = Val(StringField(TempS, 2, "x"))
        If (OpenScreen(ScreenW, ScreenH, #ScreenDepth, ""))
          SetFrameRate(#FrameRate)
          
          ; Force aspect ratio
          CorrectH.i = ScreenW / #AspectRatio
          If (CorrectH > ScreenH)
            ; Your display is wider than expected!
            ViewW = ScreenH * #AspectRatio
            ViewH = ScreenH
            MatteW.i = (ScreenW - ViewW)/2
            MatteH.i = 0
          Else
            ; Your display is correct, or too tall
            ViewW = ScreenW
            ViewH = CorrectH
            MatteW.i = 0
            MatteH.i = (ScreenH - ViewH)/2
          EndIf
          
          
          ; Initialize viewport
          ScaleFactor.f = ViewH * #ViewScale
          ViewX.f = 0.0
          ViewY.f = 0.0
          
          ; Initialize game
          Global NewList Obj.GameObject()
          AddElement(Obj())
            Obj()\WorldX = -5
            Obj()\WorldY =  2
            Obj()\Shape  = #Box
            Obj()\Size   =  5
            Obj()\Color  = #Blue
            Obj()\Speed  = 1.0
          AddElement(Obj())
            Obj()\WorldX = 10
            Obj()\WorldY =  -3
            Obj()\Shape  = #Circle
            Obj()\Size   =  8
            Obj()\Color  = #Red
            Obj()\Speed  = 1.5
          
          
          
          
          
          
          ; Main game loop
          Repeat
            
            
            ; Input logic
            ExamineKeyboard()
            ExamineMouse()
            If (KeyboardPushed(#PB_Key_Escape))
              Cancel = #True
            Else
              ; Move "Player 1"
              SelectElement(Obj(), 0)
              If (KeyboardPushed(#PB_Key_W))
                Obj()\WorldY + Obj()\Speed
              ElseIf (KeyboardPushed(#PB_Key_S))
                Obj()\WorldY - Obj()\Speed
              EndIf
              If (KeyboardPushed(#PB_Key_A))
                Obj()\WorldX - Obj()\Speed
              ElseIf (KeyboardPushed(#PB_Key_D))
                Obj()\WorldX + Obj()\Speed
              EndIf
              
              ; Move "Player 2"
              SelectElement(Obj(), 1)
              If (KeyboardPushed(#PB_Key_Up))
                Obj()\WorldY + Obj()\Speed
              ElseIf (KeyboardPushed(#PB_Key_Down))
                Obj()\WorldY - Obj()\Speed
              EndIf
              If (KeyboardPushed(#PB_Key_Left))
                Obj()\WorldX - Obj()\Speed
              ElseIf (KeyboardPushed(#PB_Key_Right))
                Obj()\WorldX + Obj()\Speed
              EndIf
              
              ; Move "Camera"
              ViewX + (MouseDeltaX() * #MouseSpeed)
              ViewY - (MouseDeltaY() * #MouseSpeed)
            EndIf
            
            
            
            
            ; Scaling and render logic
            ClearScreen(#BGColor)
            If (StartDrawing(ScreenOutput()))
              ForEach Obj()
                DrawX.i = ScreenW/2 + (Obj()\WorldX - ViewX) * ScaleFactor
                DrawY.i = ScreenH/2 - (Obj()\WorldY - ViewY) * ScaleFactor
                Select (Obj()\Shape)
                  Case #Box
                    HalfW.i = Obj()\Size * ScaleFactor
                    Box(DrawX - HalfW, DrawY - HalfW, 2*HalfW, 2*HalfW, Obj()\Color)
                  Case #Circle
                    Circle(DrawX, DrawY, Int(Obj()\Size * ScaleFactor), Obj()\Color)
                EndSelect
              Next
              
              ; Draw "matte" bars
              If (MatteH > 0)
                Box(0, 0, ScreenW, MatteH, $000000)
                Box(0, ScreenH - MatteH, ScreenW, MatteH, $000000)
              ElseIf (MatteW > 0)
                Box(0, 0, MatteW, ScreenH, $000000)
                Box(ScreenW - MatteW, 0, MatteW, ScreenH, $000000)
              EndIf
              StopDrawing()
            EndIf
            FlipBuffers()
            
            
            
            
          Until Cancel
          CloseScreen()
        Else
          MessageRequester("Error", "Could not open screen!")
        EndIf
      EndIf
    Until (Cancel)
  EndIf
EndIf

[/size]

Re: Resolution and Aspect Ratio independence?

Posted: Wed Jul 11, 2012 8:30 pm
by Zach
Thanks for that example, I'll play around with it when I have some time. (Very busy, prepping for data backup of my PC before I do a rebuild project that will leave me with my main/gaming rig and a dedicated File Server/ Emulator Gaming/Multimedia system for my TV).

I did understand what you meant by a World Coordinate system, I just meant I don't know how to implement such a thing, how to use it internally with all the game objects/assets and then to tie it in with the final rendering stage, etc..

Re: Resolution and Aspect Ratio independence?

Posted: Mon Aug 06, 2012 11:42 pm
by darius
maybe this tiny example (out of my actual gameengine) may help for sprite3d :

what do you need:

the base for the scaler is your developement resolution.
if the gamers resolution is different the scaler will take effekt.
you do not need to scale it every frame. just call it once you load the map/level.

there is one restriction: the scaler wants to create a 16:10(9) ratio. so if you use a 4:3 screen you will see more graphics on screen, or you can use the "letterbox" to hide
level graphics out of the 16:10(9) screen.

the scaler works fine for my project. (if you want try parasite II, https://skydrive.live.com/?cid=6F5D709B ... B241%21121 .just change
you can use the code section after "default" if you do not want to use "letterbox". so you will get 4:3 fullscreen without aspectratio problems.
the value for fullscreen. you will find it core\user.crc
open it with text editor....

APPSMOOTH
1
BLOOM
0
VSYNC
1
FULLSCREEN
1 ------> change this value if you want any value (0.1....) is possible.
TEXTSMOOTH
1

;USER/PLAYER SETTINGS WHICH CAN BE CHANGED IN THE GAMES OPTIONS MENU (IF GAME/ENGINE IS PAUSED/CHANGES WILL USE AUTOSAFE FEATURE)

Code: Select all

Procedure __SCALER(_scal.l)

;///////////////////////////////////////////////////////////////////////////////////
;/////////////////////////////SOFTWARE SCALER /////////////////////////////////////
;
_scr_scaleX.f=_width.f/_defWidth.f
_scr_scaleY.f=_height.f/_defHeight.f
_aspectFactor.f=_defWidth.f/_defHeight.f
_aspectCorr.f=_width.f/_height.f


If _aspectFactor.f<>_aspectCorr.f
;letterbox:
_aspectFactorstring$=StrF(_aspectFactor.f,2) ;convert to string for simple handling...

Select _aspectFactorstring$

Case "1.25","1.33","1.3","1.66","1.6","1.67","1.60","1.77","1.70","1.7","1.78","1.80"
_hor.f=_width.f/16
_newheight.f=_hor.f*10
_boxHeight.f=Abs((_height.f-_newheight.f)/2) ;(we need To split so we have the right height For top And bottom letterbox)
_scr_scaleY.f=_newheight.f/_defHeight.f


Default ;nothing found? nothing valid....
_hor.f=_width.f/16
_newheight.f=_hor.f*10
_boxHeight.f=(_height.f-_newheight.f)
_scr_scaleY.f=_newheight.f/_defHeight.f
_scr_scaleY.f-(_aspectCorr.f-_aspectFactor.f)
_boxHeight.f=Abs((_defHeight.f-_height.f))

EndSelect



EndIf  ;aspectcorrector

;OBJECT POSITION

_3DGFXOBJECT(_scal.l)\worldFH*(_scr_scaleX.f);keep in center
_3DGFXOBJECT(_scal.l)\worldFH=Round(_3DGFXOBJECT(_scal.l)\worldFH,1)
_3DGFXOBJECT(_scal.l)\worldFTileXPOS=_3DGFXOBJECT(_scal.l)\worldFH
_3DGFXOBJECT(_scal.l)\worldFV*(_scr_scaleY.f);+_boxHeight.f;(userScaleY.f*maxAspect/2)*-1 +_boxHeight.f ;CORERECTED OFFSET  FIT THE GFX BETWEEN THE LETTERBOX
_3DGFXOBJECT(_scal.l)\worldFV=Round(_3DGFXOBJECT(_scal.l)\worldFV,1)
_3DGFXOBJECT(_scal.l)\worldFTileYPOS=_3DGFXOBJECT(_scal.l)\worldFV
;OBJECT SIZE
_3DGFXOBJECT(_scal.l)\worldFTileW*(_scr_scaleX.f)
_3DGFXOBJECT(_scal.l)\worldFTileH*(_scr_scaleY.f)
;do some rounding and float to integer optimizing....
_3DGFXOBJECT(_scal.l)\worldFTileW=Round(_3DGFXOBJECT(_scal.l)\worldFTileW,1)
_3DGFXOBJECT(_scal.l)\worldFTileH=Round(_3DGFXOBJECT(_scal.l)\worldFTileH,1)
;speed settings:
_3DGFXOBJECT(_scal.l)\worldFTileVELO=_3DGFXOBJECT(_scal.l)\worldFTileVELO*((_scr_scaleX.f/_scr_scaleY.f))
_3DGFXOBJECT(_scal.l)\worldFTileVELOH=_3DGFXOBJECT(_scal.l)\worldFTileVELOH*_scr_scaleX.f
_3DGFXOBJECT(_scal.l)\worldFTileVELOV=_3DGFXOBJECT(_scal.l)\worldFTileVELOV*_scr_scaleY.f

;///////////////////////////////////////////////////////////////////////////////////
;work around for the maximum framesize used in collsion is update in animplay/usable for other size calculations
_3DGFXOBJECT(_scal.l)\maxW=_3DGFXOBJECT(_scal.l)\worldFTileW
_3DGFXOBJECT(_scal.l)\maxH=_3DGFXOBJECT(_scal.l)\worldFTileH
_3DGFXOBJECT(_scal.l)\worldFTileORIGW=_3DGFXOBJECT(_scal.l)\worldFTileW ;internal systemvaribale to use with some effects
_3DGFXOBJECT(_scal.l)\worldFTileORIGH=_3DGFXOBJECT(_scal.l)\worldFTileH ;internal systemvaribale to use with some effects

 ;internal systemvaribale to use with some effects
 

EndProcedure

Re: Resolution and Aspect Ratio independence?

Posted: Tue Aug 07, 2012 12:19 pm
by Zach
Thanks, I will check that out some time :)