在旧版的Qt中,有一个名为QGLWidget的类,其中有一个很好用的函数renderText。现在我正在使用QOpenGLWidget类,但渲染文本的功能却不见了。
是否有一种简单的方法可以使用QOpenGLWidget来渲染文本?我不想从头开始构建整个文本渲染过程...
是否有一种简单的方法可以使用QOpenGLWidget来渲染文本?我不想从头开始构建整个文本渲染过程...
我最终采用了与@jaba所写的类似的解决方案。我还注意到,除非在方法末尾调用painter.end(),否则会出现一些图形损坏。
void MapCanvas::renderText(double x, double y, double z, const QString &str, const QFont & font = QFont()) {
// Identify x and y locations to render text within widget
int height = this->height();
GLdouble textPosX = 0, textPosY = 0, textPosZ = 0;
project(x, y, 0f, &textPosX, &textPosY, &textPosZ);
textPosY = height - textPosY; // y is inverted
// Retrieve last OpenGL color to use as a font color
GLdouble glColor[4];
glGetDoublev(GL_CURRENT_COLOR, glColor);
QColor fontColor = QColor(glColor[0], glColor[1], glColor[2], glColor[3]);
// Render text
QPainter painter(this);
painter.setPen(fontColor);
painter.setFont(font);
painter.drawText(textPosX, textPosY, text);
painter.end();
}
void GLBox::renderText(D3DVECTOR &textPosWorld, QString text)
{
int width = this->width();
int height = this->height();
GLdouble model[4][4], proj[4][4];
GLint view[4];
glGetDoublev(GL_MODELVIEW_MATRIX, &model[0][0]);
glGetDoublev(GL_PROJECTION_MATRIX, &proj[0][0]);
glGetIntegerv(GL_VIEWPORT, &view[0]);
GLdouble textPosX = 0, textPosY = 0, textPosZ = 0;
project(textPosWorld.x, textPosWorld.y, textPosWorld.z,
&model[0][0], &proj[0][0], &view[0],
&textPosX, &textPosY, &textPosZ);
textPosY = height - textPosY; // y is inverted
QPainter painter(this);
painter.setPen(Qt::yellow);
painter.setFont(QFont("Helvetica", 8));
painter.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing);
painter.drawText(textPosX, textPosY, text); // z = pointT4.z + distOverOp / 4
painter.end();
}
项目:
inline GLint GLBox::project(GLdouble objx, GLdouble objy, GLdouble objz,
const GLdouble model[16], const GLdouble proj[16],
const GLint viewport[4],
GLdouble * winx, GLdouble * winy, GLdouble * winz)
{
GLdouble in[4], out[4];
in[0] = objx;
in[1] = objy;
in[2] = objz;
in[3] = 1.0;
transformPoint(out, model, in);
transformPoint(in, proj, out);
if (in[3] == 0.0)
return GL_FALSE;
in[0] /= in[3];
in[1] /= in[3];
in[2] /= in[3];
*winx = viewport[0] + (1 + in[0]) * viewport[2] / 2;
*winy = viewport[1] + (1 + in[1]) * viewport[3] / 2;
*winz = (1 + in[2]) / 2;
return GL_TRUE;
}
inline void GLBox::transformPoint(GLdouble out[4], const GLdouble m[16], const GLdouble in[4])
{
#define M(row,col) m[col*4+row]
out[0] =
M(0, 0) * in[0] + M(0, 1) * in[1] + M(0, 2) * in[2] + M(0, 3) * in[3];
out[1] =
M(1, 0) * in[0] + M(1, 1) * in[1] + M(1, 2) * in[2] + M(1, 3) * in[3];
out[2] =
M(2, 0) * in[0] + M(2, 1) * in[1] + M(2, 2) * in[2] + M(2, 3) * in[3];
out[3] =
M(3, 0) * in[0] + M(3, 1) * in[1] + M(3, 2) * in[2] + M(3, 3) * in[3];
#undef M
}
如果您需要使用renderText()函数,因为您需要将Qt4应用程序移植到Qt5,请确保更改此处提供的函数签名:
void GLBox::renderText(double x, double y, double z, const QString & str, const QFont & font = QFont(), int listBase = 2000)
gluProject
而不是重新实现它的 project
。 - Jason C如果您想绘制2D文本,请使用QPainter::drawText()。有关在QOpenGLWidget上使用QPainter的信息,请参见此处。要在QOpenGLWidgets上进行文本渲染抗锯齿处理,请参见此处。
如果您想绘制2.5D文本(即在3D场景中移动的2D文本),那么自己编写类并不是“太难”。使用QFont和QFontMetricsF来构建字体字形的纹理,将每个字形构建为一个VBO中的四边形,并绘制字符串中每个字形的正确四边形。
drawText
显示文本时,有些字母,有时整个单词都会消失。然而,提到的glPixelStorei
调用没有改变任何东西。QOpenGLFunction
相关的内容 - 实际上,在我们的情况下受影响的小部件尚未使用QOpenGLFunction,但显然直接调用了OpenGL函数 - 这导致了奇怪的文本显示。QOpenGLFunction
派生并在initializeGL
中调用initializeOpenGLFunctions
似乎已经解决了这些问题。在 QOpenGLWidget 上使用 QPainter::drawText 依赖于 GL_UNPACK_ALIGNMENT 被设置为 4,否则字符将会出现损坏/乱码。
如果您的应用程序遇到了这个问题,请确保调用
glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
for (int i = _Ymin; i <= _Ymax; i = i + _yGrid)
{
double yPos = (_Ymax-i)*_yscaleF*_yscalingF;
double xPos = -_xmin*_xscaleF-_shiftX;
if(yPos < (_Ymax-_Ymin)*_yscaleF-_shiftY+1)
{
glBegin(GL_LINES);
glVertex2f(xPos-2, yPos);
glVertex2f(xPos+2, yPos);
glEnd();
renderText (xPos - offset,yPos+5 , 0, QString::number(i/10.0));
}
}
glScalef(_xscalingF,_yscalingF,0);
renderText
函数了。
在网上搜索并调查renderText
的源代码后,我终于找到了解决方案,需要保存/加载GL状态。glBegin(GL_LINES);
glVertex2f(xPos-4, yPos);
glVertex2f(xPos+4, yPos);
glEnd();
qt_save_gl_state();
renderText(xPos - offset,yPos+5 , QString::number(i/10.0));
qt_restore_gl_state();
static void qt_save_gl_state()
{
glPushClientAttrib(GL_CLIENT_ALL_ATTRIB_BITS);
glPushAttrib(GL_ALL_ATTRIB_BITS);
glMatrixMode(GL_TEXTURE);
glPushMatrix();
glLoadIdentity();
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glShadeModel(GL_FLAT);
glDisable(GL_CULL_FACE);
glDisable(GL_LIGHTING);
glDisable(GL_STENCIL_TEST);
glDisable(GL_DEPTH_TEST);
glEnable(GL_BLEND);
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
}
static void qt_restore_gl_state()
{
glMatrixMode(GL_TEXTURE);
glPopMatrix();
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
glPopAttrib();
glPopClientAttrib();
}
void GLWidgetnew::renderText(double x, double y, const QString text)
{
GLdouble textPosX = x, textPosY = y;
// Retrieve last OpenGL color to use as a font color
GLdouble glColor[4];
glGetDoublev(GL_CURRENT_COLOR, glColor);
QColor fontColor = QColor(glColor[0]*255, glColor[1]*255,
glColor[2]*255, glColor[3]*255);
// Render text
QPainter painter(this);
painter.translate(float(_shiftX),float(_shiftY)); //This is for my own mouse event (scaling)
painter.setPen(fontColor);
QFont f;
f.setPixelSize(10);
painter.setFont(f);
painter.drawText(textPosX, textPosY, text);
painter.end();
}