Jump to content
  • Advertisement
Sign in to follow this  

OpenGL Having trouble working out how to adjust 2D coordinates to OpenGL's coordinate system

This topic is 1270 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I have a set of textured quads for text and user interface elements, very carefully positioned in relation to a top-left origin. OpenGL's y axis is inverted though, and I'm having a lot of trouble getting the calculations right so that the user interface elements retain their top-left relative positions when rendered.

Here's my default view and projection matrices:

auto projmat = glm::ortho<float>(0.0f, window.width, 0.0f, window.height, 0.0f, 1000.0f);
auto viewMatrix = glm::translate(glm::mat4(1.0), glm::vec3(0)

I'm aware that the ortho values are wrong, as they put my glyphs at the bottom of the screen, with the offsets pushing my glyphs upwards, instead of pushing them downwards from the top, which is what is supposed to happen:


If I change the projection to:

auto projmat = glm::ortho<float>(0.0f, window.width, -window.height, 0.0f, 0.0f, 1000.0f);

then my glyphs end up offset from each other correctly, but the baseline is now at the very top of the client area:


Here's my shader code:

#version 450

layout(location=0) in vec4 in_Position;
layout(location=1) in vec4 in_Color;
layout(location=2) in vec4 in_Normal;
layout(location=3) in vec2 in_TexCoord;

out VSOutput
	vec4 color;
	vec2 texCoord;

} vs_output;

struct InstanceData
	vec2 pos;
	vec2 scale;
	vec2 uvScale;
	vec2 uvOffset;

layout (std430) buffer instance_data
	InstanceData instances[];

uniform mat4 viewMatrix;
uniform mat4 projectionMatrix;

void main(void)
	InstanceData instance = instances[gl_InstanceID];

	float magnification = 50.0f; // TO DO: replace with uniform input

	// these are text glyphs so I need to scale the unit quad to the correct aspect ratio
	vec4 aspectScaling = vec4(instance.scale.x, instance.scale.y, 0, 0);
	vec4 scaledOriginalPosition = aspectScaling * magnification * in_Position;

	// we now translate the quad to the position specified by the current draw instance
	vec4 instancePosition = vec4(instance.pos.x, instance.pos.y, 0, 0);
	vec4 actualPosition = scaledOriginalPosition + instancePosition;
	actualPosition.w = 1; // set w to 1 because scaling would have screwed it up

	// perform the final world-view-projection transformation
	vec4 pos = projectionMatrix * ((viewMatrix * actualPosition));
	gl_Position = pos;

	vs_output.texCoord = (in_TexCoord * instance.uvScale) + instance.uvOffset;
	vs_output.color = in_Color;

Note that the texture coordinate calculation works just fine - it's just the y axis stuff that's giving me issues.

Any assistance would be appreciated. I want something that ideally is applied on the GL side of things - this concern shouldn't bleed back into the UI layout code, which I'd prefer to keep relative to normal screen coordinates.

Share this post

Link to post
Share on other sites

Simply revert the top and the bottom values:

auto projmat = glm::ortho<float>(0.0f, window.width, window.height, 0.0f, 0.0f, 1000.0f);

Share this post

Link to post
Share on other sites

I am working on a sprite batcher.


My sprites live in a top-left corner screen coordinates (we will abreviate by TLCSC). Meaning 0,0 is the top-left corner of the screen, the x-axis goes right and the y-axis goes down. The unit of each axis is the pixel.


OpenGL has a center normalized screen coordinates (we will abreviate by CNSC). Meaning 0,0 is at the center of the screen, x-axis going right and y-axis going up. No fixed units here, just know that  in-screen coordinates are pairs (x, y) such that x in [-1 ; 1] and y in [-1 ; 1].


From that, I wrote a matrix screenMat  doing conversion from TLCSC to CNSC:


glm::mat4 screenScaleMat = glm::scale(glm::mat4(1.0f), glm::vec3(2.0f/screenWidth, 2.0f/screenHeight, 1.0f));
glm::mat4 screenTransMat = glm::translate(glm::mat4(1.0f), glm::vec3(-1.0f, -1.0f, 0.0f));
glm::mat4 screenAxisMat = glm::scale(glm::mat4(1.0f), glm::vec3(1.0f, -1.0f, 1.0f));
glm::mat4 screenMat = screenAxisMat*screenTransMat*screenScaleMat;
I can apply screenMat  to any vec4(x, y, 0.0f, 1.0f).
Hoping it will help you.
Edited by Totologic

Share this post

Link to post
Share on other sites
Thanks for your suggestions. @Totologic - not sure if you're aware, but your calculations produce the same output as Mr.A's:


I tried inverting the texture coordinates but something to do with the inversion causes a bunch of the letters to miss the baseline by one pixel, causing the result to look... dodgy. I have another idea I am going to try; I'll report back with the results.

Share this post

Link to post
Share on other sites
Sign in to follow this  

  • Advertisement

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!