The Skinny on Viewports and UI

Hey guys, I was wondering if someone could list some pitfalls when trying to render UI elements with OpenGL rather than a 3D scene. For example, you don't want to just call glViewport() when your window is resized because everything will be squished, but the devil is in the details.

I would like to know what people use for internal FBO resolution (if one is used), how the viewport is handled, what needs to be handled on window resize, where/how to implement pixel snapping, etc. Also, what do I have to know to manually handle things like DPI awareness?

Edited by Blake Martin on
You need to recalculate your projection matrix when window size changes. "Aspect ratio" is encoded in projection matrix.

So basically whenever window size changes you: 1) call glViewport, 2) update your projection matrix.

Edited by Mārtiņš Možeiko on
And this allows UI to naturally clip off the right side of the window?
By "clip off the right side of the window" you mean not render anything outside of window? That depends on how you set up projection matrix. OpenGL will automatically clip everything that goes outside [-1,+1] in clip space coordinates. Typically for UI you set orthographic projection matrix to map left and right window side to [-1,+1] in clip space.

If you want extra region to clip against, then in 2D UI you can use scissor test.
@mmozeiko Is it just the aspect ratio that's being used to update the projection matrix, not the actual pixel values? Assuming you projection matrix is generated from a POV, and so is in some game units, and so only the glViewport call knows about the new pixel resolution.

If your doing orthographic UI and using pixels as the unit, you probably want your matrix to be based off a dummy resolution (say 1920 x 1080) and then adjusted by the aspect ratio of the new resolution. So don't pass the new actual resolution in when you calculate your ortho matrix. If you do, it won't be resolution independent.

And also when you draw your UI, decide where to anchor them from. If they are meant to stay on the side of the screen, use the side as the datum point.

Does this sound right mmozeiko?

Edited by Oliver Marsh on
Not sure what you mean by "actual pixel values". Do you mean pixel sizes? If so then yes, projection matrix does not care about pixel sizes. It does not know anything about pixels.

If your doing orthographic UI and using pixels as the unit, you probably want your matrix to be based off a dummy resolution (say 1920 x 1080) and then adjusted by the aspect ratio of the new resolution.

It depends. Sometimes you want your UI to have more (or less) space when window is resized. To place more (or less) items on screen. Like list view in Explorer window - you don't ant UI stay the same based on resolution. You want to see more files on screen as your resolution increases. Up to some point, of course. After that you want to scale text/icons otherwise it will be to small.

But yeah, in some cases you may want fixed resolution.
Oh yea, I was wondering if you do want to display more (or less items), and so you set your matrix to take the new resolution size, and your using pixels as the unit for sizing, the UI elements would be smaller on high density monitors, (like 4K and mac retina screens). Is there a way to query how many pixels equate to centimetres on the monitor (pixels/centimetre)? I think like apple's point unit.
I think nowadays you can query OS for physical monitor size. So if you query also native monitor resolution, you can calculate pixel physical size if you need it.

But usually this kind of decision is done through DPI setting. Normally you use 96 DPI (on Windows) which means 100% size. If OS says that user wants 192 dpi you know that you need to draw UI elements 2x larger.

https://docs.microsoft.com/en-us/...pplication-development-on-windows
https://en.wikipedia.org/wiki/Dot...ch#Computer_monitor_DPI_standards

Edited by Mārtiņš Možeiko on
Thanks for the links Martins, I hadn't actually come across dpi before. Yea, looks like you probably don't want to query the monitor directly and calculate the dpi yourself since there is software dpi and a physical dpi. So the os can act like the monitor has 96 or 192 dpi depending on the user's setting. It looks like sdl has SDL_GetDisplayDPI.

Edited by Oliver Marsh on
I see where my misconception was. You just start laying UI elements out in pixel coordinates starting from the top-left (or wherever), and if you update your projection matrix to make the window resolution map to [-1, 1], pixel coordinates that lie outside the window resolution get clipped. It's just the fact that you often start laying out from pixel (0, 0) -- and that you say that (0, 0) maps to the top left of the screen -- that makes the top left the anchor point. You can internally layout some UI out to 16000 x 32000 if you wanted to, it just wouldn't make any sense to compute elements that you know are going to get clipped. Implementing scroll bars is a matter of checking whether a scrollable region will get clipped, and laying out scroll bar that changes the x and/or y offset(s) that the regions contents get rendered at.

Edited by Blake Martin on
Yes, that sounds like you've got it