当前位置:   article > 正文

Qt 实现3D字体,并字体始终朝向屏幕_qt openglwidget 绘画三维文字

qt openglwidget 绘画三维文字

一、将QString转成3D字体

基本思路:获取字体的轮廓,使用OpenGL轮廓绘制
使用的类和api:QPainterPath,toSubpathPolygons;

static QMap<QString, QList<QPolygonF>> m_3DtextBuffer; //缓存,减少耗时
if (!m_3DtextBuffer.contains(m_Text)) {
        QPainterPath path;
        path.addText(0, 0, QFont(), m_Text);
        QTransform T;
        T.scale(1, -1); //Qt窗口坐标转OpenGL屏幕坐标
        T.translate(-path.boundingRect().width() / 2.0, 0); //移至中间
        m_3DtextBuffer[m_Text] = path.toSubpathPolygons(T);
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

二、字体朝向屏幕做的一些矩阵变换

基本思路:1、将字体的朝向转成相机的朝向;2、字体的高的方向转向屏幕Y轴的方向(或者宽的方向转向屏幕X轴的方向),这里屏幕Y轴(X轴)的方向实际上也就是相机的up方向和right方向;

//GLWidget继承自QOpenGLExtraFunctions; myPaint为自定义实现;
//projection透视矩阵,view视图矩阵
void GLWiget::myPaint(const QMatrix4x4& projection, const QMatrix4x4& view){
	QMatrix4x4 mt, mt2, mt3;
    mt.setToIdentity();
    mt2.setToIdentity();
    mt3.setToIdentity();

	//字体导入场景时的初始值,需要具体情况具体分析
    QVector3D NText { 0, 0, 1 }; //字体朝向 (字体厚度)
    // QVector3D WText{1,0,0}; //字体的宽方向
    QVector3D HText { 0, 1, 0 }; //字体的高方向

    QVector3D NCamera = m_CameraDir; //m_CameraDir相机的朝向,传入的值

    //求字体法线旋转
    QVector3D Naxis = QVector3D::crossProduct(NText, NCamera).normalized();
    auto theta = acos(QVector3D::dotProduct(NText, NCamera));
    mt.rotate(RADIAN_TO_DEGREE(theta), Naxis);

    //摆正字体
    QVector3D cameraUp = QVector3D::crossProduct(NCamera, QVector3D::crossProduct({ 0, 1, 0 }, NCamera));
    HText = (mt * HText);
    auto thetaH = acos(QVector3D::dotProduct(HText.normalized(), cameraUp.normalized()));
    auto angle = RADIAN_TO_DEGREE(thetaH);
    auto dir = QVector3D::dotProduct({ 1, 0, 0 }, cameraUp.normalized());
    mt2.rotate(angle * (dir < 0 ? 1 : -1), NCamera); //angel值始终都是正的,需要计算逆时针和顺时针下的旋转

    //往相机方向偏移一点
    mt3.translate(NCamera * 15);

    bool isDraw = true;
    QVector<QVector<QVector3D>> tempPolygons;

    for (auto polygon : m_3DtextBuffer.value(m_Text)) {
        if (polygon.isClosed()) {
            QVector<QVector3D> temp;
            for (int i = 0; i < polygon.size(); i++) {
                QVector3D oriantPos = QVector3D { (float)polygon[i].x(), (float)polygon[i].y(), 0 };
                QVector3D pos3d = mt3 * (mt2 * (mt * oriantPos)) + this->getPos();

                pos3d = projection * view * pos3d;
                if (pos3d.x() > 1 || pos3d.x() < -1 || pos3d.y() > 1 || pos3d.y() < -1) {
                    isDraw = false;
                    break;
                }
                temp.push_back(pos3d);
            }
            tempPolygons << temp;
        }
    }

    if (isDraw) {
        for (auto temp : tempPolygons) {
            glBegin(GL_LINE_LOOP);
            for (auto pos : temp) {
                glVertex3f(pos.x(), pos.y(), pos.z());
            }
            glEnd();
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62

虽然2D渲染文字即可实现相关效果(始终朝向屏幕),但是3D字体的方式,可以轻松利用场景的深度测试,将不渲染被遮住的字体;
且2D字体跟随屏幕缩放时,需要做额外的算法处理。

本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号