# 2D HUD over 3D scene

I'm trying to create a 2D Heads up Display for my players in a 3D OpenTK environment. How I'm doing it is by drawing my 3D elements and then running this code.

GL.MatrixMode(MatrixMode.Projection);
GL.Ortho(-0.5, 0.5, -0.5, 0.5, 1, 100);
GL.MatrixMode(MatrixMode.Modelview);
//Disable all depth stuff
GL.Disable(EnableCap.DepthTest);
GL.Disable(EnableCap.CullFace);
//Pass texture to shaders
GL.ActiveTexture(TextureUnit.Texture0);
GL.BindTexture(TextureTarget.Texture2D, TextureImg.Handle);
GL.Uniform1(GL.GetUniformLocation(Game.pgmID, "texUnit"), 0.0);
GL.Uniform1(GL.GetUniformLocation(Game.pgmID, "texture"), 1.0);
//Enable vertex attributes
GL.EnableVertexAttribArray(Game.attribute_vpos);
GL.EnableVertexAttribArray(GL.GetAttribLocation(Game.pgmID, "texcoord"));
GL.EnableClientState(ArrayCap.VertexArray);
GL.EnableClientState(ArrayCap.TextureCoordArray);
//MVP matrix is only translation of HUD position
Matrix4 c = Matrix4.CreateTranslation(new Vector3(Position.X, Position.Y, 0)) * Matrix4.CreateScale(0.1f);
GL.UniformMatrix4(Game.uniform_mview, false, ref c);
//Send vertices and uvs to shader
GL.BindBuffer(BufferTarget.ArrayBuffer, vbo);
GL.BufferData(BufferTarget.ArrayBuffer, (IntPtr)(verts.Length * Vector2.SizeInBytes), verts, BufferUsageHint.StaticDraw);
GL.VertexAttribPointer(Game.attribute_vpos, 2, VertexAttribPointerType.Float, false, 0, 0);

Vector2[] uvs = new Vector2[]
{
new Vector2(0,0),
new Vector2(1,0),
new Vector2(1,1),
new Vector2(0,1)
};

GL.BindBuffer(BufferTarget.ArrayBuffer, vbo);
GL.BufferData(BufferTarget.ArrayBuffer, (IntPtr)(uvs.Length * Vector2.SizeInBytes), uvs, BufferUsageHint.StaticDraw);
GL.VertexAttribPointer(GL.GetAttribLocation(Game.pgmID, "texcoord"), 2, VertexAttribPointerType.Float, false, 0, 0);
//Draw
GL.UseProgram(Game.pgmID);
//Make sure I can render 3D again
GL.BindBuffer(BufferTarget.ArrayBuffer, 0);
GL.Enable(EnableCap.DepthTest);


It works exactly how it's supposed to, except the quad that I draw to the screen is slightly stretched out. It's annoying the absolute heck out of me, and I have no idea what I'm doing wrong.

Edit: Picture

• Ypu always create a new array buffer everytime you render something? That's going to take up a lot of memory overtime. – Bálint Jan 4 '17 at 6:56
• Are you talking about the UVs? I'll put them in my class instead. It does seem inefficient now that I think about it. – user81509 Jan 4 '17 at 20:00

GL.Ortho creates a screen that is as wide and tall as you specified it. In your case both the width and height is 1 unit.

Because your screen is wider than taller, a width unit is bigger than a height unit, and thus the square becomes stretched.

You need to get the screen's sizes, calculate it's aspect ratio (width / height), then you need to set the left clipping plane to -aspectRatio / 2 and the right to simply aspectRatio / 2. You also need to load the ortographic matrix after the identity matrix.

You should store aspectRatio somewhere in case you wnt to put something at the edge of the screen, because that's not 1 anymore.

• A simple and well thought out answer, just the kind I like. Up-vote for this one :) – user81509 Jan 4 '17 at 19:58
• I just tried what you said, but unfortunately the stretched out quad persists. GL.Viewport seemed to have some effect. If I set it to GL.Viewport(0,0,800,800) I can render the quad perfectly, but only in the left hundred pixels. – user81509 Jan 4 '17 at 20:11
• @Denver do you call GL.Identity before it? – Bálint Jan 4 '17 at 21:34
• Yes, I do call GL.Identity() before the Ortho call. Which looks like this now. GL.Ortho(-aspectratio, aspectratio, -aspectratio, aspectratio, 1, 100); – user81509 Jan 4 '17 at 21:47
• @Denver You need to set only the left and right to aspectratio, the top and bottom should be -0.5 and 0.5. – Bálint Jan 5 '17 at 6:54

After a lot of searching about, the answer was amazingly stupid. All I needed to do was send the translation of my HUD element multiplied by an orthographic matrix to the shader. The code looks like this for other people with my problem.

Matrix4 c = Matrix4.CreateTranslation(new Vector3(Position.X, Position.Y, 0)) * Matrix4.CreateScale(100) * ortho * Matrix4.Identity; GL.UniformMatrix4(Game.uniform_mview, false, ref c);