Qt 实现3D字体,并字体始终朝向屏幕

一、将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、字体的高的方向转向屏幕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();
        }
    }
}

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

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值