opengl view, projections and orthographic aspect ratio
Asked Answered
H

1

6

There's a lot of great tutorials out there on opengl projection matrices for 3D but I am not doing 3D. I am really having a tough time getting orthographic projection setup to my liking.

int width = 320; int height = 480;

I create a view projection matrix with these settings.

//eyex, eyey, eyez, centerx, centery, centerz, upx, upy, upz//
matrix view = (0, 0, -20, 0, 0, -1, 0, 1, 0);

matrix projection = (0, width, 0, height, 1, 100);
glViewport(0, width, 0, -height);

After creating this view and projection matrix and passing them to the gpu.

Then I create a quad going from -1,-1 to 1, 1 so that it's origin is at the center.

then I make a scale matrix for the quad so that I can actually see it on the screen. It's rendering as a perfect square but of course the glViewport or the perspective matrix shouldn't be square. It should be rectangle.

How can I setup the glViewport as well as the perspective matrix so that I can maintain aspect ratio.

for example I now have the aspect ratio which is width/height. How do I use that with the projection matrix and the glviewport?

@Reto is probably correct that I am overthinking this but opengl application interface is a bit tricky for me.

edit I drew an image in hopes to help clarify things.

Let's say that I want my viewport to be 320x480 pixels. I'd like two different scaling modes that I can choose from. Either keep a fixed height where the width will grow to show more horizontal view or a fixed width with a growing height to show more vertically.

here's the imageenter image description here

Let's say I design a scene around 320x480 and I lay everything out and I know that I would like to scale the width larger but keep a fixed height.

How can I achieve that with the glViewport and orthographic projection matrix from my aspect ratio?

Hellraiser answered 5/3, 2016 at 6:11 Comment(2)
What are you trying to achieve? What coordinate range do you want to use for your 2D drawing? You're probably making this much more complicated than necessary, but it's not clear to me what you're actually trying to do.Excavate
@RetoKoradi I added an image and some more details to the question.Hellraiser
D
10

When using an onthogonal projection, you can simply think of the ortho matrix as defining some axis-aligned 2D rectangle in the xy-plane, which describes the area of the scene which is mapped to the viewport. If the aspect ratio of that rectangle does not match the aspect ratio of the viewport, the image will be distored accordingly.

Let us use the following definitions:

V: aspect of the viewport:
  V = viewport_width / viewport_height
P: aspect of the ortho projection:
  P = (right - left) / (top - bottom)
O: aspect of some axis-aligned rectangle which is drawn
  O = (x_max - x_min) / (y_max - y_min)

When the transformations are applied, the object will appear with aspect ratio O / P * V on the screen.

Usually, when speaking of "keeping aspect ratio", we set P == V so that V / P cancels each other out in the above formula, and objects appear with exactly that aspect ratio they are drawn in eye space.

And this is already exactly what you get with your code.:

Then I create a quad going from -1,-1 to 1, 1 so that it's origin is at the center.

That is a square, and I wonder how you ever can expect this to come out as a rectangle when the aspect ratio is preserved.

From your images, it is clear that your object of interest is a rectangle with aspect ratio 2/3. So you should also draw it as a rectangle with such an aspect ratio. There are multiple ways to achieve this. Since the viewport size seems to be a given, you can sill tweak O or P or both.

However, to me it seems like you are completely overcomplicating things. If I got you right, you have some "design space" of 320x480 pixels, which is your "region of interest" which you always want to be visible on the screen, no matter what the viewport size is. To achieve that, you could do the following:

float target_width = 320.f;
float target_height = 480.f;
float A = target_width / target_height; // target aspect ratio 
// ... calculate V as above
if (V >= A) {
    // wide viewport, use full height
    ortho(-V/A * target_width/2.0f, V/A * target_width/2.0f, -target_height/2.0f, target_height/2.0f, ...);
} else {
    // tall viewport, use full width
    ortho(-target_width/2.0f, target_width/2.0f, -A/V*target_height/2.0f, A/V*target_height/2.0f, ...);
}

Now, you can work in your "design range" in pixels. In that example, the always visible range will be from (-160, -240) to (160, 240)`, and if you draw an rectangle exactly with that coordinates, it will match the blue box in your image, in any of the viewports. If you don't want the origin in the center, you can of course translate it.

Disney answered 5/3, 2016 at 17:34 Comment(4)
thanks for the excellent answer. It's the most detail i've seen on the subject in once place. Especially about the 3 different places aspect ratio can come into play. When you say if you don't want the origin in the center you can translate it, is that translating the view projection? Also is there a book that goes into the details of these three different aspects in any concise manner like you did here? I really need to understand this so that I can move on with my opengl because no matter how well you render something, if it's not visible it's still a problem.Hellraiser
Well, in which matrix you put that translation is almost a philosophical matter. It will depend on how imagine those things. You could directly put it into the projection matrix (which would be equivalent of changing those parameters directly), so that the view volume in eye space is shifted, or you could put it in the view matrix, so that your "virtual camera" location still represents the center of the view rectangle, while the view voulme in world space moves. Or you could move all of your objects.Disney
Thanks, this is nice explanation but I found one mistake. Should be: ortho(-target_width/2.0f, target_width/2.0f, -A/Vtarget_height/2.0f, A/Vtarget_height/2.0f, ...); That is top without "-".Mince
@Umka: Thanks for spotting this, fixed it.Disney

© 2022 - 2024 — McMap. All rights reserved.