• Qt OpenGL 图形字体的纹理映射


    这次教程中,我们将在第14课的基础上创建带有纹理的字体,它真的很简单。也许你想知道如何才能给字体赋予纹理贴图?我们可以使用自动纹理坐标生成器,它会自动为字体上的每一个多边形生成纹理坐标。

    这次课中我们还将使用Wingdings字体来显示一个海盗旗(骷髅头和十字骨头)的标志,为此我们需要修改buildFont()函数代码。如果你想显示文字的话,就不用改动第14课中buildFont()函数的代码了,当然你也可以选择另一种字体,这都不是什么大事。

    程序运行时效果如下:

     下面进入教程:

    我们这次将在第14课的基础上修改代码,由于有前两课代码的基础,这节课会更简单。我只解释新增的代码,首先打开myglwidget.h文件,将类声明更改如下:

    CSDN QT技术栈大纲:Qt开发必备技术栈学习路线和资料

    1. 1 #ifndef MYGLWIDGET_H
    2. 2 #define MYGLWIDGET_H
    3. 3
    4. 4 #include <QWidget>
    5. 5 #include <QGLWidget>
    6. 6
    7. 7 class MyGLWidget : public QGLWidget
    8. 8 {
    9. 9 Q_OBJECT
    10. 10 public:
    11. 11 explicit MyGLWidget(QWidget *parent = 0);
    12. 12 ~MyGLWidget();
    13. 13
    14. 14 protected:
    15. 15 //3个纯虚函数的重定义
    16. 16 void initializeGL();
    17. 17 void resizeGL(int w, int h);
    18. 18 void paintGL();
    19. 19
    20. 20 void keyPressEvent(QKeyEvent *event); //处理键盘按下事件
    21. 21
    22. 22 private:
    23. 23 void buildFont(); //创建字体
    24. 24 void killFont(); //删除显示列表
    25. 25 void glPrint(const char *fmt, ...); //输出字符串
    26. 26
    27. 27 private:
    28. 28 bool fullscreen; //是否全屏显示
    29. 29 HDC m_HDC; //储存当前设备的指针
    30. 30
    31. 31 GLYPHMETRICSFLOAT m_Gmf[256]; //记录256个字符的信息
    32. 32 GLfloat m_Deep; //移入屏幕的距离
    33. 33 GLuint m_Base; //储存绘制字体的显示列表的开始位置
    34. 34 GLfloat m_Rot; //用于旋转字体
    35. 35
    36. 36 QString m_FileName; //图片的路径及文件名
    37. 37 GLuint m_Texture; //储存一个纹理
    38. 38 };
    39. 39
    40. 40 #endif // MYGLWIDGET_H

    注意到唯一的变化就是最后增加了两个变量,这个两个变量相信大家已经很熟悉了,m_FileName用来保存我们将用于纹理映射的图片路径名,m_Texture用于储存纹理。

    接下来我们需要打开myglwidget.cpp,先修改构造函数初始化m_FileName,不多解释了,具体代码如下:

    1. 1 MyGLWidget::MyGLWidget(QWidget *parent) :
    2. 2 QGLWidget(parent)
    3. 3 {
    4. 4 fullscreen = false;
    5. 5 m_Deep = -3.0f;
    6. 6 m_Rot = 0.0f;
    7. 7 m_FileName = "D:/QtOpenGL/QtImage/Lights.bmp"; //应根据实际存放图片的路径进行修改
    8. 8
    9. 9 HWND hWND = (HWND)winId(); //获取当前窗口句柄
    10. 10 m_HDC = GetDC(hWND); //通过窗口句柄获得HDC
    11. 11
    12. 12 QTimer *timer = new QTimer(this); //创建一个定时器
    13. 13 //将定时器的计时信号与updateGL()绑定
    14. 14 connect(timer, SIGNAL(timeout()), this, SLOT(updateGL()));
    15. 15 timer->start(10); //10ms为一个计时周期
    16. 16 }

    继续,我们需要略微修改一下buildFont()函数,修改后代码如下:

    1. 1 void MyGLWidget::buildFont() //创建位图字体
    2. 2 {
    3. 3 HFONT font; //字体句柄
    4. 4 m_Base = glGenLists(256); //创建256个显示列表
    5. 5 font = CreateFont(-18, //字体高度
    6. 6 0, //字体宽度
    7. 7 0, //字体的旋转角度
    8. 8 0, //字体底线的旋转角度
    9. 9 FW_BOLD, //字体的重量
    10. 10 FALSE, //是否斜体
    11. 11 FALSE, //是否使用下划线
    12. 12 FALSE, //是否使用删除线
    13. 13 SYMBOL_CHARSET, //设置字符集
    14. 14 OUT_TT_PRECIS, //输出精度
    15. 15 CLIP_DEFAULT_PRECIS, //剪裁精度
    16. 16 ANTIALIASED_QUALITY, //输出质量
    17. 17 FF_DONTCARE | DEFAULT_PITCH, //Family and Pitch的设置
    18. 18 LPCWSTR("Wingdings")); //字体名称(电脑中已装的)
    19. 19
    20. 20 SelectObject(m_HDC, font); //选择字体
    21. 21
    22. 22 wglUseFontOutlines(m_HDC, //当前HDC
    23. 23 0, //从ASCII码第一个字符开始
    24. 24 255, //字符数
    25. 25 m_Base, //第一个显示列表的名称
    26. 26 0.1f, //字体光滑度,越小越光滑
    27. 27 0.2f, //在z方向突出的距离(字体的厚度)
    28. 28 WGL_FONT_POLYGONS, //使用多边形来生成字符,每个顶点具有独立法线
    29. 29 m_Gmf); //用于储存字形度量数据(高度,宽度等)
    30. 30 }

    注意到我们只是修改了CreateFont()函数的第9个参数(设置字符集)和最后一个参数(字体名称),修改最后一个参数好理解,因为我们要使用字体Wingdings嘛。但其实这样修改后,我们想用的Wingdings字体并不会工作。这是由于Wingdings里的字体都不是标准字符字体,我们必须告诉Windows这种字体是一种符号字体而不是一种标准字符字体,因此我们在设置字符集时,把参数改为SYMBOL_CHARSET,如此Wingdings字体就能正常工作了。

    然后我们需要来修改initializeGL()函数, 这是本节课的重点部分,具体代码如下:

    1. 1 void MyGLWidget::initializeGL() //此处开始对OpenGL进行所以设置
    2. 2 {
    3. 3 //自动生成纹理
    4. 4 glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
    5. 5 glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
    6. 6 glEnable(GL_TEXTURE_GEN_S);
    7. 7 glEnable(GL_TEXTURE_GEN_T);
    8. 8
    9. 9 m_Texture = bindTexture(QPixmap(m_FileName)); //载入位图并转换成纹理
    10. 10 glEnable(GL_TEXTURE_2D); //启用纹理映射
    11. 11
    12. 12 glClearColor(0.0, 0.0, 0.0, 0.0); //黑色背景
    13. 13 glShadeModel(GL_SMOOTH); //启用阴影平滑
    14. 14 glClearDepth(1.0); //设置深度缓存
    15. 15 glEnable(GL_DEPTH_TEST); //启用深度测试
    16. 16 glDepthFunc(GL_LEQUAL); //所作深度测试的类型
    17. 17 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); //告诉系统对透视进行修正
    18. 18
    19. 19 buildFont(); //创建字体
    20. 20 }

    注意到,我们一开始增加了四行新代码,这四行代码将为我们绘制在屏幕上的任何物体自动生成纹理坐标。函数glTexGen非常强大,而且复杂,在这里我们没法完全讲清楚。我们只需要知道GL_S和GL_T是纹理坐标就可以了。默认状态下,它被设置为提取物体此刻在屏幕上的x坐标和y坐标,并把它们装换为顶点坐标。我们运行程序时会发现到物体在z平面没有纹理,只显示一些斑纹,而正面和反面都被赋予了纹理,这些都是由glTexGen函数产生的。

    GL_TEXTURE_GEN_MODE允许我们选择我们想在S和T纹理坐标上使用的纹理映射模式,我们有三种选择:GL_EYE_LINEAR - 会使纹理固定在屏幕上,它不会移动,物体将被赋予处于它通过的地区的那一块纹理;GL_OBJECT_LINEAR - 纹理被固定于屏幕上运动的物体上;GL_SPHERE_MAP - 创建一种有金属质感的物体(大家可以变化着试试,效果都很不错)。

    当然下面增加的两行用于生成纹理和启用纹理映射,和第06课的代码一样的,不解释了。

    最后,我们来修改一下paintGL()函数,具体代码如下:

    1. 1 void MyGLWidget::paintGL() //从这里开始进行所以的绘制
    2. 2 {
    3. 3 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //清除屏幕和深度缓存
    4. 4 glLoadIdentity(); //重置当前的模型观察矩阵
    5. 5 glBindTexture(GL_TEXTURE_2D, m_Texture);
    6. 6
    7. 7 glTranslatef(1.1f*float(cos(m_Rot/16.0f)),
    8. 8 0.8f*float(sin(m_Rot/20.0f)), m_Deep); //物体移动及控制大小
    9. 9 glRotatef(m_Rot, 1.0f, 0.0f, 0.0f); //绕x轴旋转
    10. 10 glRotatef(m_Rot*1.2f, 0.0f, 1.0f, 0.0f); //绕y轴旋转
    11. 11 glRotatef(m_Rot*1.4f, 0.0f, 0.0f, 1.0f); //绕z轴旋转
    12. 12 //输出文字到屏幕上
    13. 13 glPrint("N");
    14. 14 m_Rot += 0.1f; //旋转变量增加
    15. 15 }

    首先是绑定我们已经生产的纹理,接着由于我们这次纹理不需要融合颜色,于是去掉了选择颜色的代码。然后是物体移动和旋转的代码,我也不解释了,这只是其中一种变换方式,使得能产生动画,大家完全可以自己设计平移和旋转部分的代码(如加上键盘控制等)。然后就需要来输出我们的“海盗旗”了,如果你不知道我是如何从字母“N”中得到海盗旗符号的,那就打开写字板,在字体出选择Wingdings字体。输入大写字母“N”,就会显示出海盗旗符号了。

    现在可以运行程序查看效果了!

    本文福利,费领取Qt开发学习资料包、技术视频,内容包括(C++语言基础,Qt编程入门,QT信号与槽机制,QT界面开发-图像绘制,QT网络,QT数据库编程,QT项目实战,QT嵌入式开发,Quick模块等等)↓↓↓↓↓↓见下面↓↓文章底部点击费领取↓↓

  • 相关阅读:
    CentOS 7.9.2009 数据盘挂载
    Numpy数组中的维度和轴
    【C进阶】——预处理详解
    复现 MMDetection
    计算机毕业设计(附源码)python悠哈出租车管理系统
    Java毕业设计-停车场管理系统
    java毕业设计房屋租赁系统Mybatis+系统+数据库+调试部署
    学习笔记【Java 虚拟机④】内存模型
    【AGC】开放式测试示例
    骨传导耳机怎么听到声音?骨传导耳机是否会对听力造成损害?
  • 原文地址:https://blog.csdn.net/m0_73443478/article/details/128189517