OSG核心节点:osg::Group与PositionAttitudeTransform
OpenSceneGraph(OSG)作为高性能的跨平台3D图形引擎,其核心设计思想是场景图(Scene Graph) ——通过树形结构组织所有渲染对象,而osg::Group及其子类是构建场景图的基石。
本文将从继承关系、核心功能、代码实践三个维度,详解osg::Group类,并重点分析其重要子类PositionAttitudeTransform(PAT)的使用场景与实现逻辑。
osg::Group:场景图的“骨架”节点
1 继承关系:OSG节点体系的核心分支
osg::Group是OSG场景图中组节点的基类,其完整继承链如下:
osg::Referenced(引用计数基类)
↓
osg::Object(OSG对象基类,提供命名/克隆等基础功能)
↓
osg::Node(所有场景节点的根类)
↓
osg::Group(组节点基类)
- 核心父类说明:
osg::Referenced:为所有OSG对象提供线程安全的引用计数内存管理,避免手动new/delete导致的内存泄漏;osg::Node:定义了场景节点的核心接口(如遍历、渲染状态、更新回调),是所有可加入场景图的对象的基类;osg::Group:在osg::Node基础上扩展了子节点管理能力,是唯一能包含其他节点的核心类。
2 核心功能:场景图的“容器”
osg::Group的核心价值是管理子节点集合,它本身不包含可渲染的几何数据,仅负责组织、遍历和传递渲染状态,主要能力包括:
- 子节点增删查改:提供
addChild()/removeChild()/getChild()/getNumChildren()等接口,支持动态维护子节点列表; - 渲染状态继承:组节点设置的渲染状态(如纹理、材质)会自动传递给所有子节点(可通过
StateSet控制); - 遍历控制:支持设置
NodeVisitor遍历回调,自定义子节点的遍历逻辑(如裁剪、拣选); - 线程安全:基于
osg::Referenced的线程安全设计,多线程环境下增删子节点仍能保证稳定。
3 关键特性与使用场景
- 无数量限制:一个
osg::Group可包含任意数量的子节点(包括其他osg::Group或osg::Geode),形成多层级树形结构; - 场景分块管理:常用于按功能划分场景(如“地形组”“模型组”“特效组”),便于批量控制显隐、更新;
- 不可渲染:
osg::Group本身无几何数据,若需渲染需结合osg::Geode(几何节点)使用。
PositionAttitudeTransform:节点变换的“核心工具”
PositionAttitudeTransform(简称PAT)是osg::Group的最重要子类之一,专门用于控制子节点的空间变换(位置、姿态、缩放),是OSG中实现模型位移、旋转、缩放的核心类。
1 继承关系:基于Group的变换扩展
PAT的继承链在osg::Group基础上进一步扩展:
osg::Referenced
↓
osg::Object
↓
osg::Node
↓
osg::Group
↓
osg::Transform(变换节点基类)
↓
osg::PositionAttitudeTransform
- 关键中间类:osg::Transform:
osg::Transform是所有变换节点的基类,定义了“矩阵变换”的核心接口(computeLocalToWorldMatrix()/computeWorldToLocalMatrix()),但未封装具体的变换参数; - PositionAttitudeTransform:在
osg::Transform基础上,将变换拆解为位置(Position)、姿态(Attitude)、缩放(Scale) 三个直观参数,简化了3D空间变换的使用。
2 核心功能:三维空间变换的“封装器”
PAT将复杂的矩阵变换封装为三个易用的参数,避免手动计算变换矩阵,核心参数如下:
| 参数 | 类型 | 作用 |
|---|---|---|
| Position | osg::Vec3 | 控制子节点在世界坐标系中的位置(X/Y/Z轴偏移) |
| Attitude | osg::Quat | 控制子节点的姿态(旋转),基于四元数实现无万向节死锁的3D旋转 |
| Scale | osg::Vec3 | 控制子节点在X/Y/Z轴上的缩放比例(1.0为原始大小,0.5为缩小一半) |
| Pivot Point | osg::Vec3 | 旋转/缩放的中心点(默认是节点局部坐标系原点) |
3 核心优势
- 直观易用:无需手动构建4×4变换矩阵,直接设置位置、旋转、缩放参数即可;
- 四元数旋转:基于
osg::Quat的姿态控制,避免欧拉角的万向节死锁问题; - 子节点批量变换:PAT的变换会作用于所有子节点,可批量控制多个模型的空间状态;
- 动态更新:支持运行时修改变换参数(如动画中实时调整位置/旋转),立即生效。
代码实践:Group与PAT的综合使用
下面通过完整示例,展示如何基于osg::Group构建场景图,并通过PositionAttitudeTransform实现模型的空间变换:
源码库:osg_transform
1 完整代码
#include <osgViewer/Viewer>
#include <osg/Group>
#include <osg/PositionAttitudeTransform>
#include <osg/Geode>
#include <osgDB/ReadFile>
#include <osgUtil/Optimizer>
#include <osg/Notify>
// 创建一个带PAT变换的模型节点
osg::ref_ptr<osg::Node> createTransformedModel(const std::string& modelPath,
const osg::Vec3& pos,
const osg::Vec3& scale,
const osg::Quat& attitude)
{
// 1. 加载模型(返回osg::Node,可能是Group/Geode)
osg::ref_ptr<osg::Node> model = osgDB::readNodeFile(modelPath);
if (!model)
{
osg::notify(osg::FATAL) << "模型加载失败:" << modelPath << std::endl;
return nullptr;
}
// 2. 创建PAT变换节点
osg::ref_ptr<osg::PositionAttitudeTransform> pat = new osg::PositionAttitudeTransform();
pat->setPosition(pos); // 设置位置
pat->setScale(scale); // 设置缩放
pat->setAttitude(attitude); // 设置旋转姿态
// 3. 将模型添加为PAT的子节点(变换作用于模型)
pat->addChild(model.get());
return pat;
}
int main()
{
// 1. 创建场景根节点(osg::Group)
osg::ref_ptr<osg::Group> root = new osg::Group();
root->setName("SceneRoot"); // 设置节点名称(osg::Object的能力)
// 2. 定义变换参数
osg::Vec3 pos1(-10.0f, 0.0f, 0.0f); // 左侧模型位置
osg::Vec3 scale1(0.5f, 0.5f, 0.5f); // 缩小为0.5倍
osg::Quat rot1(0.0f, osg::Vec3(0, 1, 0)); // 无旋转(绕Y轴0度)
osg::Vec3 pos2(10.0f, 0.0f, 0.0f); // 右侧模型位置
osg::Vec3 scale2(1.0f, 1.0f, 1.0f); // 原始大小
osg::Quat rot2(osg::PI/2, osg::Vec3(0, 1, 0)); // 绕Y轴旋转90度
// 3. 创建两个带不同变换的模型节点
osg::ref_ptr<osg::Node> model1 = createTransformedModel("cow.osg", pos1, scale1, rot1);
osg::ref_ptr<osg::Node> model2 = createTransformedModel("cow.osg", pos2, scale2, rot2);
if (model1 && model2)
{
// 4. 将变换节点添加到根节点(osg::Group的核心能力)
root->addChild(model1.get());
root->addChild(model2.get());
}
// 5. 优化场景图(提升渲染性能)
osgUtil::Optimizer optimizer;
optimizer.optimize(root.get());
// 6. 创建Viewer并运行
osg::ref_ptr<osgViewer::Viewer> viewer = new osgViewer::Viewer();
viewer->setSceneData(root.get());
viewer->realize(); // 初始化窗口
return viewer->run(); // 启动渲染循环
}
2 代码解析
-
场景结构: 示例中场景图的树形结构为: root (osg::Group) ├─ PAT1 (PositionAttitudeTransform) │ └─ cow.osg (模型节点) └─ PAT2 (PositionAttitudeTransform) └─ cow.osg (模型节点) 同一个模型被两个PAT节点包裹,实现不同的空间变换,且共享模型数据(OSG引用计数自动管理)。
-
核心API说明:
setPosition(osg::Vec3(x,y,z)):设置PAT节点的世界位置,子节点会跟随位移;setScale(osg::Vec3(x,y,z)):沿X/Y/Z轴独立缩放,示例中model1缩小为0.5倍;setAttitude(osg::Quat(angle, axis)):基于四元数旋转,osg::PI/2表示90度,osg::Vec3(0,1,0)表示绕Y轴旋转;root->addChild():osg::Group的核心接口,将变换后的节点加入场景根节点。
-
运行效果: 程序运行后会显示两个牛模型:
- 左侧牛:位置X=-10,缩放0.5倍,无旋转;
- 右侧牛:位置X=10,原始大小,绕Y轴旋转90度。
总结
- osg::Group 是OSG场景图的“骨架”,核心作用是组织子节点,本身不可渲染,但支持渲染状态继承和批量控制,是构建复杂场景的基础;
- PositionAttitudeTransform 是
osg::Group的核心子类,封装了3D空间变换的核心逻辑,通过位置、姿态、缩放三个参数简化了矩阵变换的使用,是实现模型位移/旋转/缩放的首选工具; - 继承关系的设计体现了OSG的模块化思想:
Referenced管内存、Node管节点基础能力、Group管子节点管理、Transform管变换、PAT管具体的空间变换参数,层层封装,兼顾易用性和扩展性。
掌握osg::Group和PositionAttitudeTransform的使用,是构建OSG场景图的核心基础,在此之上可进一步扩展到更复杂的变换(如MatrixTransform)、节点回调(如UpdateCallback)等高级功能。