2015-04-12 356 views
2

我想在QOpenGLWidget上绘制文本标签。我试图用QPainter来完成这项任务,但没有成功 - 文本看起来很丑并且没有反锯齿。在Qt OpenGL/2dpainting示例中,它看起来也很丑陋。然而,在也使用OpenGL后端的QML控件中,文本渲染效果更好。这里http://blog.qt.io/blog/2011/07/15/text-rendering-in-the-qml-scene-graph/我发现了一种在QML中使用的技术。有没有办法使用这种技术在QOpenGLWidget中绘制文本?Qt:QOpenGLWidget中的文本渲染

PS:可能正确的方法是将我所有的场景嵌入到QQuickWidget的QSGSceneGraph中?

回答

2

确保您创建QGL/QopenGLWidget与表面格式,支持多重采样抗锯齿:

QSurfaceFormat format = QSurfaceFormat::defaultFormat(); 
format.setSamples(4); 
QOpenGLWidget * glWidget = new QOpenGLWidget; 
glWidget->setFormat(format); 

然后,使用对窗口部件的QPainter时,一定要开启抗锯齿:

QPainter painter(paintDevice); 
painter.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing); 

然后画你的文字。

1

重新实现旧的QOGLWidget的renderText()以方便文本渲染。 这种方式文本将随场景一起移动。如果你想要一个静态版本,你可以简化它。

从QOpenGLWidget继承一个类(在本例中是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 
}