前言

osgText 库定义了一个命名空间,osgText。在这个命名空间中有一些十分实
用的字体加载和文字渲染类。
osgText 库的核心组件是osgText::Text 类。Text 继承自Drawable,因此用户
程序应当使用addDrawable()方法把Text 实例添加到Geode 中(与添加Geometry
实例的方法相同)。Text 可用于显示一个任意长度的字符串。因此,用户程序可
以为每个将要显示的字符串创建一个相应的Text 对象。
osgText 库的另一个核心组件是osgText::Font 类。osgText 的函数可以根据字
体文件的名称来创建Font 对象。Font 类使用FreeType 插件来读取字体文件。用
户程序将Font 对象和Text 对象相关联时,Font 将创建一个用于绘制字符串图形
的纹理贴图。在渲染时,Text 将使用与该图形相符的纹理坐标,为文本中的每一
个字符绘制一个已添加纹理的四边形。osgText 库还定义了一个String 类,以支
持多字节字符(multibyte)和各类文字编码。

代码

#include "osg/Group"
#include "osgText/Text"
#include "osg/Geode"
#include "osg/Geometry"
#include "osgText/Font"
#include "osgDB/WriteFile"
#include "osgDB/ReadFile"
#include "osg/Node"
#include "osg/ref_ptr"
#include "osgViewer/View"
#include "osgViewer/Viewer"
#include "osg/Matrix"
#include "osg/MatrixTransform"

//创建背板
osg::ref_ptr<osg::Drawable> createBase()
{
osg::ref_ptr<osg::Geometry> geom = new osg::Geometry;

osg::Matrix m;
osg::ref_ptr<osg::MatrixTransform> mt = new osg::MatrixTransform();
/*m.makeRotate(m,)*/


osg::ref_ptr<osg::Vec3Array> v = new osg::Vec3Array;
geom->setVertexArray(v.get());
v->push_back(osg::Vec3(-1.f, 0.f, -1.f));
v->push_back(osg::Vec3(1.f, 0.f, -1.f));
v->push_back(osg::Vec3(1.f, 0.f, 1.f));
v->push_back(osg::Vec3(-1.f, 0.f, 1.f));

osg::ref_ptr<osg::Vec4Array> c = new osg::Vec4Array;
geom->setColorArray(c.get());
/*setColorBinding()和setNormalBinding() - 这些方法用于设置Geometry 类
中颜色和法线数据的绑定方式。其输入参数为Geometry 类的枚举量。
清单2 - 1 中,颜色绑定方式为osg::Geometry::BIND_PER_VERTEX,即
每种颜色对应一个顶点。而法线的绑定方式为
osg::Geometry::BIND_OVERALL,即整个Geometry 几何体对应唯一的
一个法线数据。*/
geom->setColorBinding(osg::Geometry::BIND_PER_VERTEX);
c->push_back(osg::Vec4(1.f, 1.f, 0.f, 1.f));
c->push_back(osg::Vec4(0.f, 1.f, 0.f, 1.f));
c->push_back(osg::Vec4(0.f, 0.f, 1.f, 1.f));
c->push_back(osg::Vec4(1.f, 1.f, 1.f, 1.f));

//法线
osg::ref_ptr<osg::Vec3Array> n = new osg::Vec3Array;
geom->setNormalArray(n.get());
/*而法线的绑定方式为
osg::Geometry::BIND_OVERALL,即整个Geometry 几何体对应唯一的
一个法线数据。*/
geom->setNormalBinding(osg::Geometry::BIND_OVERALL);
n->push_back(osg::Vec3(0.f, 1.f, 0.f));

geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS, 0, 4));

return (geom.release());

}

osg::ref_ptr<osg::Node> createSceneGraph()
{
// Create the root (and only) node.
osg::ref_ptr<osg::Geode> geode = new osg::Geode;
geode->addDrawable(createBase());

//字体
osg::ref_ptr<osgText::Font> font = new osgText::Font;
font = osgText::readFontFile("fonts/arial.ttf");




osg::Vec4 white(osg::Vec4(1.f, 1.f, 1.f, 1.f));
{
//Text.osg文件中有个默认参数:autoRotateToScreen,始终保持字体面向屏幕
osg::ref_ptr<osgText::Text> text = new osgText::Text;
text->setFont(font.get());
text->setColor(osg::Vec4(0.f, 1.f, 1.f, 1.f)); //青色
text->setCharacterSize(.15f);
text->setPosition(osg::Vec3(1.f, 0.f, 1.f));
/*如果要创建一个一直朝向视口的广告牌形式的文
字,可以使用Text::SCREEN。*/
text->setAxisAlignment(osgText::Text::XY_PLANE);//因为没有设置SCREEN,所以在Text.osg文件中没有autoRotateToScreen TRUE 属性
text->setAlignment(osgText::Text::LEFT_TOP); //左上基准点开始的字体
text->setText("right_right");
geode->addDrawable(text.get());
}

{
osg::ref_ptr<osgText::Text> text = new osgText::Text;
text->setFont(font.get());
text->setColor(osg::Vec4(1.f, 0.f, 0.f, 1.f));
text->setCharacterSize(.15f);
text->setPosition(osg::Vec3(-1.f, 0.f, 0.f));
text->setAxisAlignment(osgText::Text::SCREEN); //因为没有设置SCREEN,所以在Text.osg文件中有autoRotateToScreen TRUE 属性
text->setText("right_right");
text->setText("Top_left");
geode->addDrawable(text.get());
}

{
osg::ref_ptr<osgText::Text> text = new osgText::Text;
text->setFont(font.get());
text->setColor(osg::Vec4(0.f, 1.f, 0.f, 1.f));
text->setCharacterSize(.15f);
text->setPosition(osg::Vec3(-1.f, -1.f, 0.f));
text->setAxisAlignment(osgText::Text::SCREEN);
text->setText("Bottom_left");
geode->addDrawable(text.get());
}

{
osg::ref_ptr<osgText::Text> text = new osgText::Text;
text->setFont(font.get());
text->setColor(osg::Vec4(0.f, 0.f, 1.f, 1.f));
text->setCharacterSize(.15f);
text->setPosition(osg::Vec3(1.f, -1.f, 0.f));
text->setAxisAlignment(osgText::Text::SCREEN); //因为没有设置SCREEN,所以在Text.osg文件中有autoRotateToScreen TRUE 属性
text->setText("Bottom_right");
geode->addDrawable(text.get());
}

{
osg::ref_ptr<osgText::Text> text = new osgText::Text;
text->setFont(font.get());
/*用户程序通常需要改变字体纹理贴图的图形分辨率,以避免文字出现模糊。
缺省情况下,osgText 为每个图形分配了32×32 个像素元。要改变这个数值的话,
可以使用Text::setFontResolution()方法。下面的代码增加了字体的分辨率,osgText
将因此为每个图形分配128×128 个像素元。*/
text->setFontResolution(128, 128);
text->setColor(osg::Vec4(1.f, 0.f, 1.f, 1.f));
text->setCharacterSize(.15f);
text->setPosition(osg::Vec3(0.f, 0.f, 0.f));
//text->setAxisAlignment(osgText::Text::SCREEN);
text->setAxisAlignment(osgText::Text::XZ_PLANE); //沿xz平面,倒下
/*文字相对于自身坐标位置*/
text->setAlignment(osgText::Text::CENTER_TOP);
text->setText("Hello osg world");
geode->addDrawable(text.get());
}

return geode.release();
}

int main(int argc, char** argv)
{
osg::ref_ptr<osg::Node> root = createSceneGraph();
if (!root.valid())
{
osg::notify(osg::FATAL) << "Failed in createSceneGraph()." << std::endl;
return 1;
}

std::string out("Text.osg");
if (!(osgDB::writeNodeFile(*(root.get()), out))) //这里不能有封号, 切记 切记 切记!!!!!
{
osg::notify(osg::FATAL) << "Failed in osgDB::writeNodeFile()." << std::endl;
return 1;
}

osg::notify(osg::ALWAYS) << "Successfully wrote \"" << out << "\". Execute \" osgviewer " << out << "\" to view." << std::endl;

osgViewer::Viewer viewer;
viewer.setSceneData(osgDB::readNodeFile("Text.osg"));
return viewer.run();

/*osg::ref_ptr<osgViewer::View> viewer = new osgViewer::View;
auto node = osgDB::readNodeFile("Text.osg");
return viewer.run();*/

return 0;
}

里面包含大量注释

源码下载

源码工程下载地址

运行效果
osgText使用版本osg3.6.5_osg字体渲染