c++ 如何使用QOpenGLWidget渲染文本

idfiyjo8  于 12个月前  发布在  其他
关注(0)|答案(6)|浏览(205)

在旧版本的Qt中有QGLWidget,有一个很好的函数renderText。现在我使用的是QOpenGLWidget类,而渲染文本的功能缺失了。
有没有一个简单的方法来渲染文本使用QOpenGLWidget?我不喜欢从头开始用OpenGL构建整个文本渲染.

mbzjlibv

mbzjlibv1#

我最终做了一个类似于@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();
}
dced5bon

dced5bon2#

您可以基于旧的Qt源代码自行实现此功能。
在从QOpenGLWidget继承的OpenGL widget类(在本例中是GLBox)中,必须实现以下方法:
renderText:

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;
}

最后transformPoint:

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)

你不用再担心这个了

ttisahbt

ttisahbt3#

如果你想绘制2D文本,可以使用QPainter::drawText()。有关在QOpenGLWidget上使用QPainter的信息,请参阅此处。有关在QOpenGLWidgets上对文本渲染使用抗锯齿的信息,请参见here
如果你想绘制2.5D文本(2D文本随着3D场景移动),滚动你自己的类并不“太难”。使用QFont和QFontMetricsF为您的字体字形构建纹理,为每个字符串构建一些四边形到VBO中,并为字符串中的字形绘制适当的四边形。

tjvv9vkg

tjvv9vkg4#

QOpenGLWidget上的QPainter::drawText依赖于GL_UNPACK_ALIGNMENT设置为4,否则字符看起来会损坏/混乱。
如果您的应用程序中存在此问题,请确保调用

glPixelStorei(GL_UNPACK_ALIGNMENT, 4);

在画出文字之前。(更多信息请参见https://bugreports.qt.io/browse/QTBUG-65496

eagi6jfj

eagi6jfj5#

对于未来的任何人来这里与类似的问题参考-我有一个类似的问题,如Urs's answer中所述:当使用drawText在OpenGL小部件上显示文本时,丢失了一些字母,有时是整个单词。然而,提到的glPixelStorei调用并没有改变任何事情。
当我阅读QOpenGLWidget绘图文档时,我注意到了与QOpenGLFunction相关的东西--在我们的例子中,确实受影响的小部件还没有使用QOpenGLFunction,但显然直接调用了OpenGL函数--这导致了奇怪的文本显示。
QOpenGLFunction派生并在initializeGL中调用initializeOpenGLFunctions似乎已经解决了这些问题。
编辑:没有运气-我的问题似乎是一个间歇性的,只是偶尔出现(它不是重现每次我运行程序)。我想接下来我会研究一下Qt OpenGL上下文调试。

pexxcrt2

pexxcrt26#

我有这个问题时,我需要绘制轴和相应的刻度。在Qt 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);

然而,当我尝试将代码迁移到Qt 6时,再也没有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();

下面是qt_保存_gl_state,renderText,qt_restore_gl_state的def:

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();
}

项目的src代码可以在这里找到QtSignalProcessing

相关问题