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.

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
