opengl 在不拉伸渲染内容的情况下调整窗口(帧缓冲区)大小,(二维正交投影)

9udxz4iz  于 2022-11-04  发布在  其他
关注(0)|答案(2)|浏览(217)

我试图保持渲染内容的比例和大小时,调整我的窗口/帧缓冲区纹理,我渲染独家在xy平面(z=0),并希望有一个正交投影。
一些一般性的问题,我需要调整glm::ortho和viewport的大小,还是只调整其中一个的大小?两者必须有相同的像素数量还是只有相同的纵横比?它们的x和y偏移量呢?
我知道我需要更新纹理大小。
我所尝试的(在许多其他事情中):
我用imgui::image()将我的帧缓冲区附加的纹理渲染到一个ImGui窗口,当这个ImGui窗口被调整大小时,我用下面的方法调整分配给我的FBO的纹理:(我不使用glFramebufferTexture 2D重新附加纹理!)

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

我还更新了成员变量windowSize。
在我的渲染循环(用于帧缓冲区)中,我使用

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

现在,我这里有一些变量,我尝试用它们来实现平移,但我首先想让调整大小正常工作。

编辑:

现在我已经尝试了视口和正交投影矩阵的不同参数:

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

调整窗口的大小仍然会拉伸我的renderTexture,但现在它是均匀的,x和y的比例一样大。我的正方形精灵仍然是正方形,但随着我减小窗口大小而变小。GIF

jrcvhitl

jrcvhitl1#

我已经找到了一种方法来调整2D界面的大小,以根据纵横比进行缩放,给予一下,看看这是否能解决您的问题:

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

作为将来的参考,如果你想在宽高比范围内缩放正射图像,那么就这样做。源宽高比是将对象缩放到原始屏幕宽高比范围内的东西:

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

mspsb9vt2#

我相信我在处理FBO时会遇到一些问题,因为我现在找到了一个令人满意的解决方案,一个似乎也是显而易见的解决方案。简单地使用视口的宽度和高度(以及FBO附带的纹理),如下所示:

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

您可能还想将四个参数除以一个常数(可能比2大得多),以使缩放范围在1附近更自然。
虽然我以前尝试过这段代码,但实际上我并没有重新创建帧缓冲区,而是简单地使用了glTexImage 2D();在附加的纹理上。看起来好像需要删除和重新创建整个帧缓冲区,这也被说成是更安全的一些职位在这里的SO,但我从来没有发现任何来源说,它实际上是必需的。
所以,吸取教训,删除并创建一个新的帧缓冲区。窗口大小调整并不是经常发生的事情。

相关问题