使用 OpenGL 和纹理在同一窗口中查看 2x2 网格中的多个图像

Posted

技术标签:

【中文标题】使用 OpenGL 和纹理在同一窗口中查看 2x2 网格中的多个图像【英文标题】:Viewing multiple images in a 2x2 grid in the same window using OpenGL and textures 【发布时间】:2020-12-21 16:57:17 【问题描述】:

我正在学习 OpenGL 以尝试创建一些基本的可视化工具。我要做的第一件事是从 4 个摄像头渲染保存的图像。想要获得 2x2 图像的布局

我正在关注有关使用纹理的本教程(https://learnopengl.com/Getting-started/Textures 和完整源代码https://learnopengl.com/code_viewer_gh.php?code=src/1.getting_started/4.1.textures/textures.cpp)。我可以成功加载其中一张图像并将其显示到全尺寸窗口。我将示例中的vertices[] 数组更改为最大值(在所有方向上为-1 到1)以获得全屏显示。我的问题是,对 OpenGL 不熟悉

    这是使用顶点着色器和片段着色器的最佳/现代方法吗?大约 5 到 10 年前有很多图像示例做了不同的事情。

    如果我加载了四张图片,我可以为每张图片重复使用相同的顶点和片段着色器吗?

    我目前对在 2x2 网格中渲染图像的想法是为每个象限创建 4 个vertices[](-1 到 0、0 到 1 等)。这意味着我需要 4 个顶点 VAO 对象。这是最好的方法,还是可以做一些更简单的方法?

一旦我得到它的工作,我会为未来的读者分享/发布代码。

【问题讨论】:

您可以使用多重纹理,因此将每个图像绑定到不同的纹理单元,并且只有单个 VBO/VAO 和渲染调用。您也可以只传递单个 Quad -1,+1 并从中计算纹理坐标和顶点着色器中的源纹理,无需渲染 4 个四边形但是将每帧上的 4 个纹理加载到 GL 中可能会很慢......不是这方面的专家但是我认为在新的 GL api 中的 IIRC 有一些使用 PBO 或 FBO 进行更快传输的机制。如果您有大量 GPU 内存,您可以使用纹理数组并将整个或部分视频加载到 GPU 中,然后“延迟”加载每 n 帧 你也可以对 3D 纹理做同样的事情......这里是同时使用多个纹理的例子Normal mapping gone horribly wrong 这里是 3D 纹理的例子 3D voxel back raytracing 纹理数组几乎是一样的,这里是 GLSL debug prints是从片段着色器打印文本的示例(您可以使用它进行调试,或打印帧信息或其他)它还显示了如何从位置计算纹理坐标.. 【参考方案1】:

如果没有任何代码提供您正在尝试做的事情的进一步上下文,很难提供“最佳方法”。

    这是使用顶点着色器和片段着色器的最佳/现代方法吗?大约 5 到 10 年前有很多图像示例做了不同的事情。

没有看教程,很难给出答案。但是,我假设您指的是使用固定功能管道的示例。如果是这样,那么是的,坚持使用着色器。

    如果我加载了四张图片,我可以为每张图片重复使用相同的顶点和片段着色器吗?

假设您的片段着色器在某种程度上与您链接的那个 (4.1.texture.fs) 相匹配,即归结为如下内容:

#version 330 core

out vec4 fragColor;
in vec2 vTexCoord;
uniform sampler2D tex;

void main() 
    fragColor = texture(tex, vTexCoord);

那么是的,您可以重用着色器。假设您当前的方法涉及 4 个绘制调用,那么在绘制调用之前只需 bind 所需的纹理。

    我目前对在 2x2 网格中渲染图像的想法是为每个象限(-1 到 0、0 到 1 等)创建 4 个顶点[]。这意味着我需要 4 个顶点 VAO 对象。这是最好的方法,还是可以做一些更简单的方法?

据我了解,您的顶点数据不会因每个图像而改变。只有位置和实际图像。因此,您可以在顶点着色器中使用矩阵来转换顶点,而不是复制顶点数组和顶点数据。

您将在后续的 LearnOpenGL "Transformations" 教程中了解这一点。

简而言之,您需要将uniform mat4 mvp 添加到顶点着色器中,并将其与顶点位置相乘,如下所示:

#version 330 core

layout (location = 0) in vec3 pos;
uniform mat4 mvp;

void main() 
    gl_Position = mvp * vec4(pos, 1.0);


还有其他方法,您可以通过一次绘图调用来完成您想要做的事情。

您可以使用“texture atlas” 如果所有图片尺寸相同,您可以使用“array texture” 您还可以使用 uniform array 的纹理

要使用数组纹理,您的着色器需要指定sampler2DArray 而不是sampler2D。随着您的vTexCoord 需要提供第三个坐标,代表图层。

#version 330 core

out vec4 fragColor;
in vec3 vTexCoord;
uniform sampler2DArray tex;

void main() 
    fragColor = texture(tex, vTexCoord);

uniform 纹理数组相比。您需要将layer 属性添加到您的顶点数据和着色器中。

顶点着色器:

#version 330 core

layout (location = 0) in vec3 pos;
layout (location = 1) in vec2 texCoord;
layout (location = 2) in uint layer;

flat out uint vLayer;

uniform mat4 mvp;

void main() 
    vTexCoord = texCoord;
    vLayer = index;

    gl_Position = mvp * vec4(position, 0.0, 1.0);

片段着色器:

#version 330 core

out vec4 fragColor;

in vec2 vTexCoord;
flat in uint vLayer;

uniform sampler2D tex[4];

void main() 
    fragColor = texture(tex[vLayer], vTexCoord);

【讨论】:

以上是关于使用 OpenGL 和纹理在同一窗口中查看 2x2 网格中的多个图像的主要内容,如果未能解决你的问题,请参考以下文章

使用 OpenGL 和 QT 进行纹理映射 - C++

如何在 mac 中为 openGL 背景窗口使用纹理 .jpg 图像?

使用OpenGL显示图像?

不断更新OpenGL窗口

QT和OpenGL如何正确集成并显示纹理

OpenGL/OpenGLES 中的帧缓冲纹理行为