- OSG文字
适当的文字信息对于显示场景信息是非常重要的。在 OSG中,osgText 提供了向场景中添加文字的强大功能,由于有第三方插件 FreeType 的支持,它完全支持TrueType字体。
读者可能对 FreeType和TrueType还不太了解,下面进行具体介绍(下面的资料都来自网络,笔者觉得这样介绍会更加专业和准确)。
TrueType是由AppleComputer 公司和Microsoft 公司联合提出的一种新型数学字形描述技术。它用数学函数描述字体轮廓外形,含有字形构造、颜色填充、数字描述函数、流程条件控制、栅格处理控制和附加提示控制等指令。TrueType 采用几何学中的二次B样条曲线及直线来描述字体的外形轮廓,其特点是:既可以用作打印字体,又可以用作屏幕显示;由于它由指令对字形进行描述,因此与分辨率无关,输出时总是按照打印机的分辨率输出;无论放大或缩小,字符总是光滑的,不会有锯齿出现;但相对 PostScript 字体来说,其质量要差一些,特别是在文字太小时,就表现得不是很清楚。
FreeType 是一种字体服务但没有提供为实现文字布局或图形化处理这样高阶的功能使用的API(如带色文字渲染之类的)。然而,它提供一个简单、易用且统一的接口实现对多种字体文件的访问,从而大大简化了这些高级的任务。FreeType支持TrueType和OpenType规格定义的全部字符映射。同时,它也完全有能力自动合成Type使用的Unicode字符表,这种表要求必须把一个供转换编码时使用的结束符放置在表的末尾一这在 Type 使用的格式中是很常见的(当然,如果读者需要,原始的编码方式也是可用的)。FreeType 是一个完整且有效率的 TrueType字节码解释器,这个引擎可以用很小的点产生极好的输出。由于 TrueType 规格极其令人费解且十分含糊,所以其组件想要成功完成输出是极其困难的。但无论如何我们现在已经能使Windows 的显示质量达到 Mac的水平。
-
- osgText
在 OSG 中,为了显示高质量的文字,专门定义了一个新的名字空间来管理场景中文字的渲染,这个名字空间中的类主要用于加载字体和控制文字各种渲染属性。该空间主要包括下面几个类:
class FadeText // 渐变文字
class Font // 字体
class Font3D // 3D字体
class VectorUInt // 向量单元
class String // 字符串-用于多字节字符和各类文字编码
class Text // 文字
class Text3D // 3D文字
class TextBase // 文字基类
文字显示效果主要分为两大类,即二维平面文字和三维立体文字。osgText::Text 类负责二维平面文字的渲染,osgText::Text3D负责三维立体文字的渲染。
-
-
- osgText::Text类
-
osgText::Text类继承自osgText::TextBase类,继承关系图如图9-1所示:
图9-1 osgText:Text 的继承关系图
从继承关系图可以看出,osgText::Text类间接继承自osg::Drawable类因此在应用程序中想把文字信息加到场景中,就要像添加一个Geometry 实例一样添加一个Geode。
osgText::TextBase 是一个基类,定义了文字渲染的基本接口。文字的主要属性包括颜色、位置方向、大小模式、分辨率、对齐方式、输出格式、绘制模式、背景类型和颜色倾斜模式等
- 颜色
设置颜色可以直接调用如下成员函数
void setColor(const osg::Vec4 &clr);
- 位置设置
位置可以直接调用如下成员函数
void setPosition(const osg::Vec3 &pos);
- 方向
设置文字方向可以直接调用如下成员函数:
void Text::setAxisAlignment(AxisAlignment axis);
文字方向枚举模式如下:
enum AxisAlignment
{
XY_PLANE, // xy面
REVERSED_XY_PLANE, // xy面的反面
XZ_PLANE, // xz面
REVERSED_XZ_PLANE, // xz面的反面
YZ_PLANE, // yz面
REVERSED_YZ_PLANE, // yz面的反面
SCREEN, // 屏幕
USER_DEFINED_ROTATION,// 用户自定义旋转
};
- 大小模式
设置大小模式可以直接调用如下成员函数:
void setCharacterSizeMode(CharacterSizeMode mode);
文字大小模式枚举变量如下:
enum CharacterSizeMode
{OBJECT_COORDS, // 默认模式SCREEN_COORDS, // 根据屏幕坐标自动缩放OBJECT_COORDS_WITH_MAXIMUM_SCREEN_SIZE_CAPPED_BY_FONT_HEIGHT // 根据视点自动缩放
};
- 分辨率
设置文字分辨率可以直接调用如下成员函数:
void setFontResolution(unsigned int width, unsigned int height);
在默认的情况下,OSG为每个文字图形分配32x32个像素单元。通过改变字体纹理贴图的分辨率可以调整文字的清晰程度,通常,分辨率越大,越清晰,但是渲染负担就越大。建议在用户程序中可以清晰显示文字的情况下,默认使用最小的分辨率就可以满足需要了。
- 对齐方式
设置对齐方式可以直接调用如下成员函数
void Text::setAlignment(AlignmentType alignment);
对齐方式枚举模式如下:
enum AlignmentType
{LEFT_TOP, //左上LEFT_CENTER,//左中LEFT_BOTTOM,/左下CENTER_TOP,//中上CENTER_CENTER,//中中CENTER BOTTOM,//中下RIGHT_TOP,//右上RIGHT_CENTER,//右中RIGHT_BOTTOM,//右下LEFT_BASE_LINE,//左基线CENTER_BASE_LINE,//中间的基线RIGHT_BASE_LINE,//右基线LEFT_BOTTOM_BASE_LINE,/左下基线CENTER_BOTTOM_BASE_LINE,//中下基线RIGHT_BOTTOM_BASE_LINE,/右下基线BASE_LINE=LEFT_BASE_LINE//default,左基线为默认方式
};
- 输出格式
设置输出格式可以直接调用如下成员函数
void setLayout(Layout layout);
文字输出格式枚举模式如下:
enum Layout
{LEFT_TO_RIGHT, // default,默认格式从左到右RIGHT_TO_LEFT, // 从右到左VERTICAL // 垂直
};
绘制模式
设置绘制模式可以直接调用如下成员函数:
void sctDrawMode(unsigned int mode);
绘制模式枚举模式如下::
enum DrawModeMask
{TEXT = 1, // 默认模式文字BOUNDINGBOX = 2,// 包围盒ALIGNMENT = 4 // 对齐
};
- 背景类型
设置背景类型可以直接调用如下成员函数:
void setBackdropType(BackdropType type)
背景类型枚举模式如下:
enum BackdropType
{DROP_SHADOW_BOTTOM_RIGHT=0,//款认阴影DROP_SHADOW_CENTER_RIGHT,DROP_SHADOW_TOP_RIGHT,DROP_SHADOW_BOTTOM_CENTER,DROP_SHADOW_TOP_CENTER,DROP_SHADOW_BOTTOM_LEFTDROP_SHADOW_CENTER_LEFTDROP_SHADOWTOP_LEFT,OUTLINE,NONE
}
- 颜色倾斜模式
设置颜色倾斜模式可以直接调用如下成员函数:
void sctColorGradientMode(ColorGradientMode mode)
颜色倾斜枚举模式如下:
enum ColorGradientMode
{SOLID=0,//立体,实心模式PER_CHARACTER,/每一个字OVERALL//全部
}
从上面的介绍可以看出,文字的属性比较多,但并不是每一个都需要设置,可以选择设置,有些使用系统默认的即可。通常需要设置的有位置、内容、大小、对齐方式和颜色等。
osgText::Font类
osgText::Font类直接继承自osg::Object类,继承关系图如图9-2所示
图9-2 osgText::Font 的继承关系图
该类主要用于对字体的管理,使用 FreeType 插件来读取字体文件,根据字体文件构建字体贴图,同时创建一个字体对象。读取字体可以用下面的函数:
osgText:readFontFile(conststd::string &filename, const osgDB::ReaderWriter::Options *userOptions-0);
该类在读取字体后,可以设置字体的轮廓和纹理等。不过,在实际应用中,这些采用系统默认的设置就可以了,不合理的设置反而会导致文字变形等不正常的现象发生。
在OSG中文字显示的机制是:创建一个 Font 对象读取字体文件,把 Font与对应的文字相关联,创建绘制字符串图形的纹理贴图。在文字渲染时,文字会根据该字符的形状生成纹理坐标,并为每一个字符绘制一个已添加纹理的四边形。
在场景中添加文字的主要步骤如下:
(1)创建一个Font字体对象,并读取字体。
(2)创建一个osgText::Text 对象,设置文字的属性,同时关联字体,在默认情况下,系统有默认的字体。
(3)调用 addDrawable()方法将步骤(2)创建的osgText::Text 实例对象添加到一个Geode实例,如果要多处添加文字,可以多次创建osgText::Text 对象,也可以创建多个Geode,然后逐个添加添加后再到场景中进行渲染。
在场景中显示文字很简单,但显示中文会有一些难度,需要先将中文变成宽字符(方法有很多,如L或W2A()),字体需要使用中文字体simhei.ttf具体的方法参看第9.1.3节的示例。
显示汉字示例
显示汉字(osgText::Text示例的代码如程序清单9-1所示
1. /****************** 显示汉字(osgText::Text)示例代码 ******************/
2. /// 创建文字
3. osg::ref_ptr<osg::Geode> createText();
4.
5. void showChineseText_9_1(const string &strDataFolder);
6.
7. /// 创建文字
8. osg::ref_ptr<osg::Geode> createText()
9. {
10. osg::ref_ptr<osgText::Text> text = new osgText::Text;
11. osg::ref_ptr<osgText::Font> font = new osgText::Font();
12.
13. //读取字体
14. string strFontPath = "D:\\WorkAndStudy\\SDK\\VS2013\\OSG\\Data\\font\\simhei.ttf";
15. font = osgText::readFontFile(strFontPath);
16.
17. // 设置字体文件
18. text->setFont(font.get());
19.
20. // 设置文字信息
21. text->setText(L"全民实现中华民族的伟大复兴!");
22.
23. // 设置字体大小
24. text->setCharacterSize(0.5f);
25. text->setAutoRotateToScreen(true);
26.
27. // 设置字体颜色
28. text->setColor(osg::Vec4(1.0f, 0.0, 0.0, 1.0));
29.
30. // 设置显示的位置
31. osg::Vec3f position = osg::Vec3f(0.0, -10.0, 0.0);
32. text->setPosition(position);
33.
34. // 设置对齐方式
35. text->setAlignment(osgText::Text::CENTER_TOP);
36.
37. // 设置旋转方式
38. text->setAxisAlignment(osgText::Text::SCREEN);
39.
40. // 添加到叶节点中
41. osg::ref_ptr<osg::Geode> geode = new osg::Geode();
42.
43. geode->addDrawable(text.get());
44.
45. return geode.get();
46. }
47.
48. void showChineseText_9_1(const string &strDataFolder)
49. {
50. osg::ref_ptr<osgViewer::Viewer> viewer = new osgViewer::Viewer();
51. osg::ref_ptr<osg::GraphicsContext::Traits> traits = new osg::GraphicsContext::Traits;
52. traits->x = 40;
53. traits->y = 40;
54. traits->width = 600;
55. traits->height = 480;
56. traits->windowDecoration = true;
57. traits->doubleBuffer = true;
58. traits->sharedContext = 0;
59.
60. osg::ref_ptr<osg::GraphicsContext> gc = osg::GraphicsContext::createGraphicsContext(traits.get());
61.
62. osg::ref_ptr<osg::Camera> camera = new osg::Camera;
63. camera->setGraphicsContext(gc.get());
64. camera->setViewport(new osg::Viewport(0, 0, traits->width, traits->height));
65. GLenum buffer = traits->doubleBuffer ? GL_BACK : GL_FRONT;
66. camera->setDrawBuffer(buffer);
67. camera->setReadBuffer(buffer);
68.
69. viewer->addSlave(camera.get());
70.
71. osg::ref_ptr<osg::Group> root = new osg::Group();
72.
73. // 创建文字
74. osg::ref_ptr<osg::Geode> node = createText();
75. root->addChild(node.get());
76.
77. // 优化场景数据
78. osgUtil::Optimizer optimizer;
79. optimizer.optimize(root.get());
80.
81. viewer->setSceneData(root.get());
82.
83. viewer->realize();
84. viewer->run();
85. }
运行程序,截图如图9-3所示
图9-3显示汉示例截图