【OSG学习笔记】Day 7: Group类与MatrixTransform类

0 阅读6分钟

去除图片水印 (1).png

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 
  (自动变换节点,增强自动旋转/缩放能力)

关键继承逻辑解读

  1. MatrixTransform 继承: AutoTransform 完全复用了 MatrixTransform 的「手动矩阵变换」能力(如 setMatrix() 设置平移/旋转),同时新增自动变换逻辑——你可以理解为:

    AutoTransform = MatrixTransform + 自动旋转 + 自动缩放

  2. Group 继承: 支持 addChild() 添加子节点(如文本、模型),这也是为什么我们能把文本 Geode 节点加入 AutoTransform。
  3. 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();
}

image.png

总结

  1. 继承核心:AutoTransform 继承自 MatrixTransform,是「手动变换 + 自动旋转/缩放」的增强版变换节点;
  2. 核心价值:无需手动计算旋转矩阵,一行代码实现节点「始终朝向屏幕/相机」,大幅简化 3D 标签、UI 开发;
  3. 使用逻辑:创建 AutoTransform → 配置自动变换规则 → 添加子节点 → 加入场景树,完全兼容 OSG 场景管理体系。

AutoTransform 是 OSG 中「轻量化解决复杂需求」的典型设计,掌握它能快速实现 3D 场景中的动态标签、UI 元素,是 OSG 开发者必备的核心组件之一。

去除图片水印.png