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

Started by
3 comments, last by NathanRidley 9 years, 1 month ago
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:

02.25.2015-22.38.png

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:

02.25.2015-22.40.png


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.
Advertisement

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

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.

My blog about games, AI...

http://totologic.blogspot.com/

Thanks for your suggestions. @Totologic - not sure if you're aware, but your calculations produce the same output as Mr.A's:

02.26.2015-07.12.png

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.
Actually inverting the texture coordinates does work. I have a different problem related to my scaling values. Thanks for the help.

This topic is closed to new replies.

Advertisement