QWidget支持CPU绘图,使用paintEvent绘制图像。
优点:快速便捷,易懂
缺点:非常耗资源。
QOpenGLWidget使用GPU绘图,基于OpenGl。
优点:减少cpu端开销,Qt集成度高,只需要专注于着色器代码的编写
缺点:不易理解。
CPU版本代码:
void DisplayWgt::paintEvent(QPaintEvent* event) {
QStyleOption opt;
opt.init(this);
QPainter p(this);
style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
p.setRenderHint(QPainter::Antialiasing, true);
QRect target(0, 0, this->width(), this->height());
uchar* m_img8bit = BllData::getImg8bit();
quint16* img = BllData::getSingleImg();
BllData::converToGray(img, m_img8bit, m_width, m_center);
QImage image(m_img8bit, Detector::ImageSizeColumn, Detector::ImageSizeRow, QImage::Format_Grayscale8);
p.drawImage(target, image);
}
void DisplayWgt::updateImgSlot() {
quint16* img = BllData::getSingleImg();
int min, max;
BllData::getMinMaxData(img, min, max);
m_width = max - min;
m_center = (min + max) / 2;
m_paintEnable = true;
update();
}
GPU版本代码:
顶点着色器:
#version 330 core
layout(location = 0) in vec3 aPos;
layout(location = 1) in vec3 aColor;
layout(location = 2) in vec2 aTexCord;
out vec3 ourColor;
out vec2 TexCord;
void main(){
gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0f);
ourColor=aColor;
TexCord=aTexCord;
}
片段着色器:
#version 330 core
out vec4 FragColor;
in vec3 ourColor;
in vec2 TexCord;
uniform sampler2D textureWall;
void main(){
FragColor = texture(textureWall,TexCord);
}
坐标:
float vertices[] = {
// positions // colors // texture coords
1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, // top right
1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, // bottom right
-1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, // bottom left
-1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f // top left
};
unsigned int indices[] = { // note that we start from 0!
0, 1, 3, // first triangle
1, 2, 3 // second triangle
};
初始化,绘图等函数:
void DisplayGlWgt::initializeGL() {
initializeOpenGLFunctions();
//创建VBO和VAO对象,并赋予ID
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
//绑定VBO和VAO对象
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
//为当前绑定到target的缓冲区对象创建一个新的数据存储。
//如果data不是NULL,则使用来自此指针的数据初始化数据存储
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
//告知显卡如何解析缓冲里的属性值
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0);
//开启VAO管理的第一个属性值
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(3 * sizeof(float)));
glEnableVertexAttribArray(1);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float)));
glEnableVertexAttribArray(2);
glBindBuffer(GL_ARRAY_BUFFER, 0);
bool success;
shaderProgram.addShaderFromSourceFile(QOpenGLShader::Vertex, "shaders/shapes.vert");
shaderProgram.addShaderFromSourceFile(QOpenGLShader::Fragment, "shaders/shapes.frag");
success = shaderProgram.link();
if (!success)
qDebug() << "ERR:" << shaderProgram.log();
// glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
glGenBuffers(1, &EBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_DYNAMIC_DRAW);
GLuint m_texture;
glGenTextures(1, &m_texture);
glBindTexture(GL_TEXTURE_2D, m_texture);
glBindVertexArray(0);
}
void DisplayGlWgt::paintGL() {
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
shaderProgram.bind();
glBindVertexArray(VAO);
if (m_paintEnable) {
uchar* m_img8bit = BllData::getImg8bit();
quint16* img = BllData::getSingleImg();
BllData::converToGray(img, m_img8bit, m_width, m_center);
QImage image(m_img8bit, Detector::ImageSizeColumn, Detector::ImageSizeRow, QImage::Format_Grayscale8);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, image.width(), image.height(),
0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, image.bits());
glGenerateMipmap(GL_TEXTURE_2D);
}
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, NULL);
}
void DisplayGlWgt::resizeGL(int w, int h) {
Q_UNUSED(w); Q_UNUSED(h);
}
void DisplayGlWgt::updateImgSlot() {
quint16* img = BllData::getSingleImg();
int min, max;
BllData::getMinMaxData(img, min, max);
m_width = max - min;
m_center = (min + max) / 2;
m_paintEnable = true;
update();
}
DisplayGlWgt::~DisplayGlWgt()
{
makeCurrent();
glDeleteBuffers(1, &VBO);
glDeleteBuffers(1, &EBO);
glDeleteVertexArrays(1, &VAO);
doneCurrent();
}
CPU版本演示:
GPU版本演示:
如上所示,cpu10用于数据交换的消耗,cpu2为实际绘图消耗,cpu版本中,paintevent绘图机制占用cpu资源引起较大的消耗,gpu版本中,cpu2消耗下降至原来的三分之一,同时gpu消耗增加。