AutoTransform 自动变换节点
在 OpenSceneGraph(OSG)开发中,AutoTransform 是实现「广告牌(Billboard)」效果的核心类——它能让节点(如文本、图标、模型)自动朝向屏幕/相机,或根据屏幕大小自适应缩放,广泛应用于 3D 标签、UI 文本、动态图标等场景。
本文将从继承关系、核心特性、实战代码三个维度,全面解析 AutoTransform 的使用方法。
AutoTransform 核心定位
AutoTransform 直译是「自动变换节点」,本质是 OSG 中对 MatrixTransform 的增强——它在普通矩阵变换的基础上,增加了自动旋转和自动缩放能力:
- 自动旋转:让节点始终朝向屏幕/相机,无需手动计算旋转矩阵;
- 自动缩放:根据节点到相机的距离,自适应调整大小(或固定大小)。
最典型的应用场景:3D 场景中的文本标签(如「Fly To Sky」),无论怎么旋转视角,文本始终正对观察者。
AutoTransform 继承关系(核心类层级)
AutoTransform 属于 OSG 变换节点体系,其完整继承链如下(从父类到子类):
osg::Object
↓ (核心基类,所有OSG对象的根)
osg::Node
↓ (所有场景节点的基类,可加入场景树)
osg::Group
↓ (组节点,可包含子节点)
osg::Transform
↓ (变换节点基类,定义坐标变换接口)
osg::MatrixTransform
↓ (矩阵变换节点,通过Matrix实现平移/旋转/缩放)
osg::AutoTransform
(自动变换节点,增强自动旋转/缩放能力)
关键继承逻辑解读
- 从
MatrixTransform继承: AutoTransform 完全复用了MatrixTransform的「手动矩阵变换」能力(如setMatrix()设置平移/旋转),同时新增自动变换逻辑——你可以理解为:AutoTransform = MatrixTransform + 自动旋转 + 自动缩放
- 从
Group继承: 支持addChild()添加子节点(如文本、模型),这也是为什么我们能把文本 Geode 节点加入 AutoTransform。 - 从
Node继承: 可直接加入场景树(如root->addChild(at.get())),符合 OSG 场景管理的统一逻辑。
AutoTransform 核心特性与API
1. 自动旋转模式(最核心)
通过 setAutoRotateMode() 设置,支持 3 种核心模式:
| 模式常量 | 效果 | 适用场景 |
|---|---|---|
ROTATE_TO_SCREEN | 节点始终朝向屏幕(忽略相机位置) | 2D/3D 文本标签、UI 图标 |
ROTATE_TO_CAMERA | 节点始终朝向相机位置(三维朝向) | 3D 模型广告牌(如树木、广告牌) |
NO_ROTATION | 关闭自动旋转,仅保留手动矩阵变换 | 需固定姿态的节点(对比测试) |
2. 自动缩放控制
| API | 作用 |
|---|---|
setAutoScaleToScreen(true/false) | true:固定节点在屏幕上的大小(距离再远也不变小);false:按 3D 空间规则缩放 |
setMinimumScale(float) | 自动缩放的最小比例(防止节点过小) |
setMaximumScale(float) | 自动缩放的最大比例(防止节点过大) |
3. 基础变换(继承自 MatrixTransform)
| API | 作用 |
|---|---|
setPosition(osg::Vec3) | 设置节点位置(等价于 Matrix::makeTranslate) |
setMatrix(osg::Matrix) | 手动设置变换矩阵(平移/旋转/缩放) |
实战解析:AutoTransform + 3D 文本
结合前文的实战代码,我们拆解 AutoTransform 的核心使用步骤:
步骤1:创建 AutoTransform 节点
// 创建 AutoTransform 自动变换节点(核心对象)
osg::ref_ptr<osg::AutoTransform> at = new osg::AutoTransform();
- 这里利用
osg::ref_ptr管理内存(OSG 推荐方式),避免内存泄漏。
步骤2:配置自动变换规则
// 设置自动旋转模式:始终朝向屏幕
at->setAutoRotateMode(osg::AutoTransform::ROTATE_TO_SCREEN);
// 关闭「固定屏幕大小」,按 3D 空间规则缩放
at->setAutoScaleToScreen(false);
// 设置缩放范围:0~5 倍
at->setMinimumScale(0.0f);
at->setMaximumScale(5.0f);
// 设置节点位置(继承自 MatrixTransform)
at->setPosition(pos1);
- 核心:
ROTATE_TO_SCREEN保证文本始终正对观察者。
步骤3:添加子节点(文本 Geode)
// 将承载文本的 Geode 节点加入 AutoTransform
at->addChild(geode.get());
- AutoTransform 作为组节点(继承自 Group),可添加任意子节点(文本、模型、几何体)。
步骤4:加入场景树
// 将 AutoTransform 节点加入根节点(继承自 Node)
root->addChild(at.get());
get()取出ref_ptr管理的裸指针,符合 OSG 接口要求(addChild接收osg::Node*)。
关键对比:AutoTransform vs MatrixTransform
在之前的「双奶牛」案例中,我们用 MatrixTransform 手动设置旋转/平移:
// MatrixTransform:手动设置旋转矩阵
mt1->setMatrix(m.makeRotate(45.0f, 1.0f, 0.0f, 0.0f));
而 AutoTransform 无需手动计算旋转——只需一行代码,就能实现「始终朝向屏幕」:
// AutoTransform:自动朝向屏幕,无需手动旋转
at->setAutoRotateMode(osg::AutoTransform::ROTATE_TO_SCREEN);
完整可运行代码
项目链接:autotranform
#include <osgViewer/Viewer>
#include <osg/Node>
#include <osg/Geometry>
#include <osg/Geode>
#include <osg/Group>
#include <osg/AutoTransform>
#include <osgDB/ReadFile>
#include <osgDB/WriteFile>
#include <osgText/Text>
#include <osgUtil/Optimizer>
#include <iostream>
// 创建自动变换节点(封装文本+自动变换逻辑)
osg::ref_ptr<osg::Node> createAutoTransform(
osg::Vec3& position,
float size,
std::string& label,
osg::AutoTransform::AutoRotateMode autoMode,
osgText::Text::AxisAlignment axisAlignment
) {
// 创建 Geode 节点(用于承载可绘制对象)
osg::ref_ptr<osg::Geode> geode = new osg::Geode();
// 字体路径(根据你的系统调整,这里用 cour.ttf 示例)
std::string font("fonts/cour.ttf");
// 创建 Text 对象
osg::ref_ptr<osgText::Text> text = new osgText::Text();
geode->addDrawable(text.get());
// 设置字体
text->setFont(font);
// 设置字体分辨率(默认 32*32,这里提高清晰度)
text->setFontResolution(128.0f, 128.0f);
// 设置字体大小
text->setCharacterSize(size);
// 设置对齐方式(居中)
text->setAlignment(osgText::Text::CENTER_CENTER);
// 设置方向对齐
text->setAxisAlignment(axisAlignment);
// 设置文本内容
text->setText(label);
// 关闭光照(文本不受光照影响,保证清晰)
geode->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
// 创建 AutoTransform 自动变换节点
osg::ref_ptr<osg::AutoTransform> at = new osg::AutoTransform();
// 添加子节点(文本 Geode)
at->addChild(geode.get());
// 设置自动旋转模式
at->setAutoRotateMode(autoMode);
// 根据屏幕大小缩放(false:可缩放;true:固定大小)
at->setAutoScaleToScreen(false);
// 设置缩放的最小/最大比例
at->setMinimumScale(0.0f);
at->setMaximumScale(5.0f);
// 设置位置
at->setPosition(position);
// 返回自动变换节点(裸指针)
return at.get();
}
int main() {
// 创建 Viewer 对象
osg::ref_ptr<osgViewer::Viewer> viewer = new osgViewer::Viewer();
// 创建场景根节点
osg::ref_ptr<osg::Group> root = new osg::Group();
// 要显示的文本
std::string text("Fly To Sky");
/*
3 种变换模式:
ROTATE_TO_SCREEN 自动朝向屏幕
ROTATE_TO_CAMERA 自动朝向相机
NO_ROTATION 无自动旋转
*/
// 添加 ROTATE_TO_SCREEN 模式变换节点
osg::Vec3 pos1(0.0f, 0.0f, 0.0f);
root->addChild(createAutoTransform(
pos1,
60.0f,
text,
osg::AutoTransform::ROTATE_TO_SCREEN,
osgText::Text::XY_PLANE
));
// 添加 NO_ROTATION 模式变换节点
osg::Vec3 pos2(0.0f, 0.0f, 60.0f);
root->addChild(createAutoTransform(
pos2,
60.0f,
text,
osg::AutoTransform::NO_ROTATION,
osgText::Text::YZ_PLANE
));
// 添加 ROTATE_TO_CAMERA 模式变换节点(可选)
// osg::Vec3 pos3(0.0f, 0.0f, -60.0f);
// root->addChild(createAutoTransform(
// pos3,
// 60.0f,
// text,
// osg::AutoTransform::ROTATE_TO_CAMERA,
// osgText::Text::XY_PLANE
// ));
// 优化场景数据
osgUtil::Optimizer optimizer;
optimizer.optimize(root.get());
// 设置场景数据
viewer->setSceneData(root.get());
// 初始化并创建窗口
viewer->realize();
// 开始渲染循环
return viewer->run();
}
总结
- 继承核心:AutoTransform 继承自
MatrixTransform,是「手动变换 + 自动旋转/缩放」的增强版变换节点; - 核心价值:无需手动计算旋转矩阵,一行代码实现节点「始终朝向屏幕/相机」,大幅简化 3D 标签、UI 开发;
- 使用逻辑:创建 AutoTransform → 配置自动变换规则 → 添加子节点 → 加入场景树,完全兼容 OSG 场景管理体系。
AutoTransform 是 OSG 中「轻量化解决复杂需求」的典型设计,掌握它能快速实现 3D 场景中的动态标签、UI 元素,是 OSG 开发者必备的核心组件之一。