使用QT搭建点云显示框架系列八---如何利用opengl在界面上绘制QImage
这篇文章是上一篇的继续,摸不着头脑的童鞋先静下心来好好看看上一篇。
好我们直接走起:
首先你需要有一个QImage,我们需要在界面上绘制这样一个QImage:
然后我先放了一个效果上来,我们首先要生成这样的一个QImage显示出来:
void ScarletGLViewer::do_CreateLinearImage()
{
int myheight = 400;
int mywidth = 100;
int border = 10;
QLinearGradient gr(0, 0, 1, myheight - 2 * border);
gr.setColorAt(1.0f, Qt::black);
gr.setColorAt(0.8f, Qt::darkGreen);
gr.setColorAt(0.6f, Qt::green);
gr.setColorAt(0.4f, Qt::yellow);
gr.setColorAt(0.2f, Qt::red);
gr.setColorAt(0.0f, Qt::darkRed);
QPixmap *m_LinearPm = new QPixmap(mywidth, myheight);
m_LinearPm->fill(Qt::transparent);
QPainter pmp(m_LinearPm);
pmp.setBrush(QBrush(gr));
pmp.setPen(Qt::NoPen);
pmp.drawRect(border, border, 35, myheight - 2 * border);//如果border增加,就会往另外一边错开
QImage *m_LinearRect=new QImage(QGLWidget::convertToGLFormat(m_LinearPm->toImage()));
QPainter pmp2(m_LinearRect);
pmp2.setPen(Qt::black);
int step = (myheight - 2 * border) / 5;
for (int i = 0; i < 6; i++)
{
int yPos = i * step + border;
pmp2.drawLine(border, yPos, 55, yPos);
pmp2.drawText(60, yPos + 2, QString("%1 m").arg(550 - (i * 110)));
}
QLabel *myLabel = new QLabel();
myLabel->setPixmap(QPixmap::fromImage(*m_LinearRect));
myLabel->show();
glGenTextures(2, &m_texture[1]); // 为第i个位图创建纹理
glBindTexture(GL_TEXTURE_2D, m_texture[1]);// 将生成的纹理的名称绑定到指定的纹理上
// Bind the img texture...
glTexImage2D(GL_TEXTURE_2D, 0, 4, m_LinearRect->width(), m_LinearRect->height(), 0,
GL_RGBA, GL_UNSIGNED_BYTE, m_LinearRect->bits());
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
}
我先解释一下上面代码,首先我必须把QImage手动画出来,我先利用 QLinearGradient 建立一个画刷,然后调用这句话:
m_LinearPm->fill(Qt::transparent);
意思就是说这幅图像是透明的。如果没有这句话,或者替换成别的,你的效果就会变成这样:
其实你可以选择的参数有很多,是下面这些参数的其中之一:我们可以看到transparent实际上是最后一个。
enum GlobalColor {
color0, color1, black,white,darkGray, gray,
lightGray,red, green, blue, cyan, magenta, yellow,
darkRed, darkGreen, darkBlue, darkCyan, darkMagenta, darkYellow, transparent
};
然后利用这三句话,图像就变成了渐变的:
QPainter pmp(m_LinearPm);
pmp.setBrush(QBrush(gr));
pmp.setPen(Qt::NoPen);
再然后,我们可以看到现在图像还没有文字,那么下面我们添加文字:
for (int i = 0; i < 6; i++)
{
int yPos = i * step + border;
pmp2.drawLine(border, yPos, 55, yPos);
pmp2.drawText(60, yPos + 2, QString("%1 m").arg(550 - (i * 110)));
}
那么效果就成了这样:
聪明的同学可能会发现,两个条颜色不一样啊,我们是按照绿色-黄色-红色显示出来的,为什么用QLabel显示出来,黄色变成了青色,而红色变成了蓝色呢?其实很简单,因为这句话:
QImage *m_LinearRect=new QImage(QGLWidget::convertToGLFormat(m_LinearPm->toImage()));为什么要将QImage转换成GLFormat呢?因为opengl的RGB存储格式为BGR,和QImage是恰恰相反的,但是绿色通道都在中间。我们程序中先执行了这句话,然后再显示,那么就变成这种效果了。还有,我们必须在转换成这种格式之后再进行文字绘制,不然这句话会把文字全都变成反向的了。
然后下面就比较关键了:
glGenTextures(2, &m_texture[1]); // 为第i个位图创建纹理
glBindTexture(GL_TEXTURE_2D, m_texture[1]);// 将生成的纹理的名称绑定到指定的纹理上
// Bind the img texture...
glTexImage2D(GL_TEXTURE_2D, 0, 4, m_LinearRect->width(), m_LinearRect->height(), 0,
GL_RGBA, GL_UNSIGNED_BYTE, m_LinearRect->bits());
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
然后就是opengl的固定套路了,我们首先分配一个ID,这里是2,然后绑定纹理。最后将QImage的bits直接塞进去即可。比较关键的地方是,在这句话之后必须要设置一下纹理的属性,如果没有这一步,纹理似乎是不可用的。。。。。本人也是查了很久才发现的。
现在我们有了纹理,如何使用的,只需要在你的绘制函数里面添加下面代码即可:
void ScarletGLViewer::do_drawlinearRectangle()
{
glBindTexture(GL_TEXTURE_2D, m_texture[1]);// 将生成的纹理的名称绑定到指定的纹理上
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glEnable(GL_BLEND);
//glDisable(GL_LIGHTING);
glEnable(GL_TEXTURE_2D);
//glColor3f(0.5,0.4,0.3);
glColor3f(1.0,1.0,1.0);//参与混合的颜色,还是白色比较好,比较亮
//glDisable(GL_BLEND);//必须开启混合否则背景是黑色的
startScreenCoordinatesSystem(true);
glNormal3f(0.0, 0.0, 1.0);
QPoint UpLeftP,RightDownP;
// UpLeftP.setX(width()-m_LinearRect->width()-50);
// RightDownP.setX(width()-50);
// UpLeftP.setY(height()/2-m_LinearRect->height()/2);
// RightDownP.setY(height()/2+m_LinearRect->height()/2);
UpLeftP.setX(width()-100-10);
RightDownP.setX(width()-10);
UpLeftP.setY(height()/2-400/2);
RightDownP.setY(height()/2+400/2);
glBegin(GL_QUADS);
glTexCoord2f(0.0,1.0); glVertex2i(UpLeftP.x(),UpLeftP.y());
glTexCoord2f(0.0,0.0); glVertex2i(UpLeftP.x(),RightDownP.y());
glTexCoord2f(1.0,0.0); glVertex2i(RightDownP.x(),RightDownP.y());
glTexCoord2f(1.0,1.0); glVertex2i(RightDownP.x(),UpLeftP.y());
glEnd();
stopScreenCoordinatesSystem();
// Depth clear is not absolutely needed. An other option would have been to draw the
// QUAD with a 0.999 z value (z ranges in [0, 1[ with startScreenCoordinatesSystem()).
glClear(GL_DEPTH_BUFFER_BIT);
glDisable(GL_TEXTURE_2D);
glEnable(GL_LIGHTING);
glEnable(GL_BLEND);
}
emmmm别忘了在这之前开启混合,这样你前面设置的透明QImage才能真正体现出来。如果你没有开启混合,效果会是这样的:
emmm好了,完整的代码就看这一个吧,注意日期哦,因为我的代码也是今后也要更新的。这一次是1018-4-9日最新添加的。