如何使用QOpenGLWidget呈现文本
How to render text with QOpenGLWidget
在旧版本的Qt中,有QGLWidget,有一个很好的函数叫做renderText。现在我正在使用QOpenGLWidget类,并且缺少呈现文本的功能。
有没有一种简单的方法可以使用QOpenGLWidget呈现文本?我不想从头开始使用 OpenGL 构建整个文本渲染......
我最终做了一个类似于@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();
}
旧的Qt源代码自行实现此功能。
在从 QOpenGLWidget 继承的 OpenGL 小部件类中(在本例中为 GLBox),您必须实现以下方法:
渲染文本:
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)
而且您不必再担心这一点了。
由于您似乎想要绘制 2D 文本,请使用 QPainter::d rawText()。有关在 QOpenGLWidget 上使用 QPainter 的信息,请参阅此处。有关在QOpenGLWidgets上使用抗锯齿进行文本渲染的信息,请参见此处。
如果你想画2.5D文本(2D文本随3D场景移动),那么滚动自己的类并不"太难"。使用 QFont 和 QFontMetricsF 为您的字体字形构建纹理,将每个字形的一些四边形构建到 VBO 中,并在字符串中为字形绘制正确的四边形......
QOpenGLWidget上的QPainter::d rawText依赖于GL_UNPACK_ALIGNMENT设置为4,否则字符看起来会损坏/混乱。
如果您的应用程序中遇到此问题,请确保调用
glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
在绘制文本之前。(有关详细信息,请参阅 https://bugreports.qt.io/browse/QTBUG-65496)
供任何遇到类似问题的人将来参考 - 我遇到了类似的问题,如 Urs 的回答中所述:在 OpenGL 小部件上显示带有drawText
的文本时,缺少一些字母,有时是整个单词。然而,上述glPixelStorei
电话并没有改变任何事情。
我在阅读 QOpenGLWidget 绘画文档时注意到的是QOpenGLFunction
相关内容 - 事实上,在我们的案例中受影响的小部件还没有使用 QOpenGLFunction,但显然直接调用了 OpenGL 函数 - 这导致了奇怪的文本显示。
从QOpenGLFunction
派生并在initializeGL
中调用initializeOpenGLFunctions
似乎已经解决了问题。
编辑:没有运气 - 我的问题似乎是间歇性的,只是偶尔出现(每次运行程序时都无法重现)。我想我接下来会研究Qt OpenGL上下文调试。
- 文本文件中的单词链表
- 从命令行c++发送文本文件名
- 在C++程序中输入的文本文件将不起作用,除非文本被复制和粘贴
- 2D数组来自文本输入,中间有空格
- 如何将内容数组写入文本文件?
- 无法通过空白将文本文件行分隔为矢量
- 我正在使用嵌套的while循环来解析具有多行的文本文件,但由于某种原因,它只通过第一行,我不知道为什么
- C++将文本文件中的数据读取到结构数组中
- 在指针的帮助下,文本文件中单词的频率
- 将字符指针十六进制转换为字符串并保存在文本文件C++中
- 将值从二维数组输出到文本文件
- 如何在c++中从文本文件中逐行读取整数
- 如何创建一个QTableWidgetItem,用长文本右对齐,左边有省略号
- 从文本文件中读取时钟时间和事件时间并进行处理
- 如何从文本文件中读取值和数组
- 如何在C++中确定文本文件中的元素是字符还是数字
- 如何根据单词在文本中出现的概率输出单词
- 如何在C++中用std::cout正确显示带十六进制的字符串文本
- C++试图读取一个文件并输出到另一个文本文件
- 如何使用QOpenGLWidget呈现文本