# How to position/transform vertices for 2D UI in shaders?

I am building a 3D engine and have a rendering abstraction that focuses on writing shaders. Most my 3D shaders have gl_Position output like:

gl_Position = projection * view * model * vec4(position, 1);

I would like to draw some 2D UI on top of all the 3D draw calls. I am having a hard time understanding how to do this.

Let's say I wanted to draw a HUD player life bar that is fixed to the bottom left corner of the screen. I can imagine drawing a quad. and maybe applying a texture to it. I would have 4 vertices for the quad to feed to the shader. How would I change the gl_Position calculation to handle drawing only to 2D screen space? Would I update the transformation to only apply the projection matrix?

gl_Position = projection * vec4(position, 0, 1);

How to determine the local coordinates of the quad verts? When the screen scales or resolution varies, How to ensure the quad stays positioned to the lower bottom screen? How to ensure the quad dimensions stay the same ratio?

For 2D UI you typically achieve this by using an orthographic projection matrix, and setting view and model to identity, which collapses the typical transform:

gl_Position = projection * view * model * vec4(position, 1);


To:

gl_Position = projection * vec4(position, 1);


So yes, this approach is correct.

To lay out the UI elements, there are a number of possible approaches, but one simple and commonly used one is to set up your ortho matrix like so:

glOrtho (0, width, height, 0, -1, 1);


Or if you prefer:

glm::ortho (0, width, height, 0, -1, 1);


And you can then lay out your UI using screen co-ordinates. note 1

What might not be immediately obvious is that width and height here need not be the width and height of your window (or screen); they can be any arbitrary values. So you could, for example, decide to use width 640 and height 480 and then lay out your UI as if you had a 640x480 screen, and the ortho matrix will automatically scale and position all UI elements for you.

640x480 obviously assumes a 4:3 aspect ratio, which - on most computers from the last 15-odd years - you and your users probably don't have, so just adjust the numbers to the correct aspect ratio; e.g. for a 16:9 aspect ratio you might use 800x450 instead.

note 1: If this causes your UI to be upside-down onscreen, simply reverse the bottom and top params, like so: (0, width, 0, height, -1, 1).

• Should a ui library use pixel coordinates or ndc coordinates (-1 :1) in opengl? Commented Dec 29, 2022 at 13:52
• @ihsan - there are no rules here. Just use whichever is best for your own program. If you're writing a library for others to use you might want to offer both options. Commented Dec 30, 2022 at 2:17
• i tried this code, but it is not working. glm::mat4 ortho = glm::ortho(0, 1920, 1080, 0, -1, 1); glm::vec4 position = { 243, 324, 0, 1 }; position = ortho * position; It returns {-1, 1, 0, 1} Commented Dec 31, 2022 at 15:43