0
\$\begingroup\$

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.LoadIdentity();
GL.MatrixMode(MatrixMode.Modelview);
GL.LoadIdentity();
//Disable all depth stuff
GL.DepthMask(false);
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.DrawArrays(PrimitiveType.Quads, 0, 4);
GL.UseProgram(Game.pgmID);
//Make sure I can render 3D again
GL.BindBuffer(BufferTarget.ArrayBuffer, 0);
GL.DepthMask(true);
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 enter image description here

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

2 Answers 2

2
\$\begingroup\$

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.

\$\endgroup\$
5
  • \$\begingroup\$ A simple and well thought out answer, just the kind I like. Up-vote for this one :) \$\endgroup\$
    – user81509
    Commented Jan 4, 2017 at 19:58
  • \$\begingroup\$ 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. \$\endgroup\$
    – user81509
    Commented Jan 4, 2017 at 20:11
  • \$\begingroup\$ @Denver do you call GL.Identity before it? \$\endgroup\$
    – Bálint
    Commented Jan 4, 2017 at 21:34
  • \$\begingroup\$ Yes, I do call GL.Identity() before the Ortho call. Which looks like this now. GL.Ortho(-aspectratio, aspectratio, -aspectratio, aspectratio, 1, 100); \$\endgroup\$
    – user81509
    Commented Jan 4, 2017 at 21:47
  • \$\begingroup\$ @Denver You need to set only the left and right to aspectratio, the top and bottom should be -0.5 and 0.5. \$\endgroup\$
    – Bálint
    Commented Jan 5, 2017 at 6:54
0
\$\begingroup\$

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);

\$\endgroup\$

You must log in to answer this question.