C++/QT环境下图像在窗口下等比例渲染绘制
本文中通过QT获取到opengl上下文环境,通过opengl3.0
API将图像等比例渲染到QOpenGLWidget组件上面,相比cpu,渲染能力更强。
有以下四步骤。opengl基本知识点可参照之前文章OPENGL初学习
- 定义opengl渲染表面属性
- 通过
initializeGL
接口初始化opengl
上下文环境,然后加载并链接着色器程序,创建顶点以及纹理, - 通过
paintGL
接口完成单帧渲染 - 通过``接口实现窗口缩放逻辑,这一步比较简单,只需要接口内调用
glViewport(0, 0, w, h);
即可
下面展开步骤讲解
定义opengl渲染表面属性
通过QSurfaceFormat
的设置,QSurfaceFormat 用于定义 OpenGL 渲染表面的属性,例如缓冲区大小、颜色深度、双缓冲、OpenGL 版本等。
这些属性必须在 OpenGL 上下文创建之前设置,因为它们是创建 OpenGL 上下文的基础。
如果尝试在 initializeGL() 中设置 QSurfaceFormat,OpenGL 上下文已经创建,此时修改格式是无效的。
- OpenGL 版本兼容性:
确保硬件和驱动程序支持指定的 OpenGL 版本(如 3.3)。
如果不支持,OpenGL 上下文将无法创建。 - 缓冲区大小:
深度缓冲区和模板缓冲区的大小应根据应用程序的需求设置。
24 位深度缓冲区和 8 位模板缓冲区是常见的配置。 - 核心模式:
核心模式仅支持现代 OpenGL 功能,确保代码不使用已弃用的功能(如固定功能管线)。 - 默认格式:
通过 QSurfaceFormat::setDefaultFormat(format) 设置默认格式后,所有后续创建的 OpenGL 表面都会使用此格式。
QSurfaceFormat format;
format.setDepthBufferSize(24);
format.setStencilBufferSize(8);
format.setVersion(3, 3);
format.setProfile(QSurfaceFormat::CoreProfile);
format.setSwapBehavior(QSurfaceFormat::DoubleBuffer);
QSurfaceFormat::setDefaultFormat(format);
initializeGL
这一步中要对顶点信息、纹理以及着色器程序进行初始化
顶点信息用于映射顶点以及纹理坐标,以此实现将图像等比例显示在窗口中心,顶点着色器程序将顶点位置转换为齐次坐标,并将将顶点颜色和纹理坐标传递给片段着色器;片段着色器程序使用纹理坐标从纹理中采样颜色赋值给 FragColor
进行渲染
顶点
-
创建顶点数据,4*8,每一行数据分别代表右上 右下 左下 左上顶点。每行数据有8个元素,前三个数据是顶点坐标,由于是二维图像,因此z是0,;中间三个是颜色数据,最后两个是纹理坐标。
GLfloat vertices_tmp[] = { 2.0f, 2.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, // 右上 2.0f, -2.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, // 右下 -2.0f, -2.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, // 左下 -2.0f, 2.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f // 左上 }; memcpy(vertices, vertices_tmp, sizeof(vertices));
-
纹理坐标映射:映射逻辑是保持纹理坐标不变,将图像等比例四个点在宽度与高度方向计算图像缩放比,然后将缩放值填充到vertices对应位置,即是将图像渲染到窗口等比例显示的区域
void GLShowPicWidget::generate_vertex(int img_w, int img_h) { float w_delta_ratio1 = 1; float h_delta_ratio1 = 1; if (img_w != -1 && img_h != -1) { float w_ratio = (float)img_w / width(); float h_ratio = (float)img_h / height(); float ratio = std::max(w_ratio, h_ratio); _img_label_fix_width = img_w / ratio; _img_label_fix_height = img_h / ratio; w_delta_ratio1 = (float)_img_label_fix_width / width(); h_delta_ratio1 = (float)_img_label_fix_height / height(); } else { _img_label_fix_width = width(); _img_label_fix_height = height(); } _img_lx = (width() - _img_label_fix_width) / 2; _img_ly = (height() - _img_label_fix_height) / 2; vertices[0] = w_delta_ratio1; vertices[1] = h_delta_ratio1; vertices[8] = w_delta_ratio1; vertices[9] =