0

Im trying to retain the ratio and sizes of the rendered content when resizing my window/framebuffer texture on which im rendering exclusively on the xy-plane (z=0) and would like to have an orthographic projection.

Some general questions, do i need to resize both glm::ortho and viewport, or just one of them? Do both of them have to have the same amount of pixels or just the same aspect ratio? What about their x and y offsets?

I understand that i need to update the texture size.

What i have tried (among many other things):

One texture attachment on my framebuffer, a gl_RGB on GL_COLOR_ATTACHMENT0. I render my framebuffers attached texture to a ImGui window with imgui::image(), When this ImGui window is resized I resize the texture assignent to my FBO using this: (i do not reattach the texture with glFramebufferTexture2D!)

void Texture2D::SetSize(glm::ivec2 size)`
{
    Bind();
    this->size = size;
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, size.x, size.y, 0, GL_RGB, GL_UNSIGNED_BYTE, nullptr);
    Unbind();
}

I also update the member variable windowSize.

In my renderingloop (for the Framebuffer) i use

view = glm::lookAt(glm::vec3(0, 0, 1), glm::vec3(0, 0, 0), glm::vec3(0, 1, 0));

glm::vec2 projWidth = windowSize.x;
glm::vec2 projHeight = windowSize.y;
proj = glm::ortho(-projWidth/2, projWidth/2, -projHeight/2, projHeight/2, -1.f, 1.f);

shaderProgram.SetMat4("view", view, 1);
shaderProgram.SetMat4("proj", proj, 1);
shaderProgram.SetMat4("world", world, 1); // world is identity matrix for now

glViewport(-windowSize.x/2, -windowSize.y/2, windowSize.x, windowSize.y);

Now i now do have some variables here that i use to try to implement paning with but i first want to get resizing to work correctly.

EDIT:

ok i have now tried different parameters for the viewport and orthographic projection matrix:

auto aspect = (float)(windowSize.x)/(float)windowSize.y;
glViewport(0, 0, windowSize.x, windowSize.y);
proj = glm::ortho<float>(-aspect, aspect, -1/aspect, 1/aspect, 1, -1);

Resizing the window still stretches my renderTexture, but now it does it uniformely, x is scaled as much as y. My square sprites remain sqares, but becomes smaller as i decrease the window size. GIF

bonkt
  • 15
  • 1
  • 9
  • What is world ratio? – user253751 Jun 21 '22 at 09:02
  • Sorry, I have clarified the question now, my world Matrix is the identity matrix. so disregard that uniform. Also totalZoom = 1. With world ratio i mean the ratios of the geometry i render. i don't want them to stretch when resizing my window – bonkt Jun 21 '22 at 09:07
  • You get to choose your matrices. Right now you have it keeping not just the same aspect ratio, but also the same pixel size. So if the window is half as big, everything will take up the same number of pixels and half as much stuff will fit in the window. – user253751 Jun 21 '22 at 09:55
  • the glViewport parameters also make no sense – user253751 Jun 21 '22 at 09:55
  • Ok, i reverted back to using glviewport(0, 0, width, height); see my edit. There is still some scaling issues. – bonkt Jun 21 '22 at 13:24
  • https://stackoverflow.com/questions/4338729/ – genpfault Jun 21 '22 at 14:16
  • Many of the answers on that post is not useful for me, as I'm rendering to a Framebuffer. The top most one adds a margin to the viewport which is not what i want. The second (and accepted) solution is similiar to many other i have tried. The third adds offsets to the viewport, which i was told by the commentor above is not what i want. The fourth is broken. I have tried every example on SO and searched for similiar code to mine on GH for five days now. – bonkt Jun 21 '22 at 14:57

2 Answers2

0

I've found a way to resize the 2D interface to scale it based by aspect, give this a try and see if this solves your issue:

auto aspectx = windowSize.x/windowSize.y
auto aspecty = (aspectx < 16f / 9f ? aspectx : 16f / 9f) / (16f / 9f);
float srcaspect = 4f / 3f;
float scale = 0.5f*((float)windowSize.y);
proj = glm::ortho(scale - (scale * aspectx / aspecty) - (scale - (scale * srcaspect)), scale + (scale * aspectx / aspecty) - (scale - (scale * srcaspect)), scale - (scale / aspecty), scale + (scale / aspecty), -1.f, 1.f);

and as a future reference, do this if you want the orthographic scaled within the aspect ratio. The source aspect is what scales the object to be within the original screen aspect:

float srcaspect = 4f / 3f;
float dstaspect = (float)windowSize.x/(float)windowSize.y;
float scale = 0.5f*(bottom - top);
float offset = scale + top;
proj = glm::ortho<float>(offset - (scale * dstaspect / yscale) - (offset - (scale * srcaspect)), offset + (scale * dstaspect / yscale) - (offset - (scale * srcaspect)), offset - (scale / yscale), offset + (scale / yscale), 1, -1);
HolyBlackCat
  • 78,603
  • 9
  • 131
  • 207
PunkSnips
  • 1
  • 1
0

I believe there were problems with my handling of FBOs as i have now found a satisfactory solution, one that also seems to be the obvious one. Simply using the width and height of the viewport (and FBO attached texture) like this:

   proj = glm::ortho<float>(-zoom *viewportSize.x/(2) , zoom*viewportSize.x/(2) , -zoom*viewportSize.y/(2), zoom*viewportSize.y/(2), 1, -1);

You might also want to divide the four parameters by a constant (possibly much larger than 2) to make the zooming range more natural around 1.

While i tried this exact code before, I actually did not recreate the framebuffer, but simply used glTexImage2D(); on the attached texture. It seems as though one need to delete and recreate the whole Framebuffer, and this was also stated to be safer on some posts here on SO, but I never found any sources saying that it was actually required.

So, lesson learnt, delete and create a new framebuffer. Window resizing is not something that happens very often.

bonkt
  • 15
  • 1
  • 9