news 2026/9/17 1:18:17

Rerun Quaternion 编码类型全解析:四元数在 3D 旋转数据中的表示、序列化与实战用法

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Rerun Quaternion 编码类型全解析:四元数在 3D 旋转数据中的表示、序列化与实战用法

Rerun Quaternion 编码类型全解析:四元数在 3D 旋转数据中的表示、序列化与实战用法

【免费下载链接】rerunVisualize, query, and stream to train on multimodal robotics data.项目地址: https://gitcode.com/GitHub_Trending/re/rerun

本文围绕 Rerun 数据模型中的Quaternion编码类型展开,说明它如何在 Rerun 中表示 3D 旋转、其 Arrow 内存布局(FixedSizeList(4 x non-null Float32))、跨 Python / Rust / C++ 三种 SDK 的构造与使用方式,并结合RotationQuat组件、Rotation3D辅助类型与Transform3DBoxes3D等 Archetype 的源码实现,给出可直接运行的实战示例。

Quaternion是 Rerun 数据模型中的一种核心编码类型(Encoding),用于以 4 个浮点数紧凑地表达 3D 旋转。它本身不是可以直接记录到数据存储中的组件,而是作为RotationQuat组件的底层表示存在,广泛服务于Transform3DBoxes3DCapsules3DEllipsoids3DGaussianSplats3DInstancePoses3DVolume3DVoxelGridMap等 Archetype 的旋转表达。本文将以 Rerun 仓库(crates、rerun_py、rerun_cpp 等目录)中的类型定义与序列化实现为依据,完整解析该类型的设计与用法。

类型定义:一个由 4 个实数表示的四元数

Rerun 对Quaternion的权威定义位于类型定义文件,它是一份被re_types_builder解析、用于生成 Rust / Python / C++ 三种语言绑定的"类型说明书":

/// A Quaternion represented by 4 real numbers. /// /// Note: although the x,y,z,w components of the quaternion will be passed through to the /// datastore as provided, when used in the Viewer Quaternions will always be normalized. #[rerun::rerun_type] #[arrow(transparent)] #[cpp(no_field_ctors)] #[python(array_aliases = "npt.NDArray[Any] | npt.ArrayLike | Sequence[Sequence[float]]")] #[rust(derive(Copy, PartialEq, PartialOrd, bytemuck::Pod, bytemuck::Zeroable))] #[rust(repr = "C")] #[rust(tuple_struct)] #[rerun(state = "stable")] pub struct Quaternion { pub xyzw: [f32; 4], }

这段定义透露了几个关键信息:

  • 字段顺序约定为 XYZW:四元数的四个分量按x, y, z, w顺序存储,其中w是标量(实部)。
  • #[arrow(transparent)]:该类型在 Arrow 序列化时采用"透明"表示——即直接暴露其内部字段[f32; 4],没有额外的嵌套包装层。
  • 状态为stable:该类型处于稳定状态,属于公开的稳定 API 面。
  • 派生CopyPartialOrdbytemuck::Pod/Zeroable等 trait,说明它在 Rust 中是一个可零拷贝、可字节级转换的轻量 POD 结构。

由该定义自动生成的 Rust 结构体位于 crates/store/re_sdk_types/src/encodings/quaternion.rs:

#[repr(C)] pub struct Quaternion(pub [f32; 4usize]);

可以看到生成代码以repr(C)的元组结构体形式保存一个长度为 4 的f32数组,正是"4 个实数"这一语义的最直接体现。

归一化语义:原样入库,Viewer 中归一化

原文档中特别强调了一条重要行为约定,这也是使用四元数时最容易踩的坑:

尽管x,y,z,w四个分量会原样写入数据存储(datastore),但在 Viewer 中使用时,四元数总是会被归一化

这意味着:

  1. 存储层不强制归一化:你记录什么值,数据存储中就保存什么值,不做任何预处理或校验。
  2. 可视化层归一化:Viewer 在渲染、计算变换时会先把四元数归一化到单位长度再使用,因此未归一化的输入在可视化时会被"纠正"。
  3. 归一化失败的后果:如果四元数的模长为 0(例如[0, 0, 0, 0]),无法归一化,此时该旋转会被视为无效变换。这一点在RotationQuat组件的文档(docs/content/reference/types/components/rotation_quat.md)中有着一致的表述:"If normalization fails the rotation is treated as an invalid transform."

从源码看,Viewer 侧确实通过归一化路径消费四元数。例如在 crates/store/re_sdk_types/src/encodings/quaternion_ext.rs 中,Quaternionglam::Quat的转换就显式调用了try_normalize(),归一化失败(如零向量)时返回错误并拒绝构造:

#[cfg(feature = "glam")] impl TryFrom<Quaternion> for glam::Quat { type Error = (); fn try_from(q: Quaternion) -> Result<Self, ()> { glam::Vec4::from(q.0) .try_normalize() .map(Self::from_vec4) .ok_or(()) } }

这从实现层面印证了文档中"Viewer 中总会归一化、归一化失败视为无效"的约定。

Arrow 数据表示:FixedSizeList(4 x non-null Float32)

原文档给出了该编码类型的 Arrow 数据类型:

FixedSizeList(4 x non-null Float32)

其序列化实现可在生成代码 crates/store/re_sdk_types/src/encodings/quaternion.rs 中看到:

impl ::re_types_core::ArrowDataType for Quaternion { fn arrow_data_type() -> arrow::datatypes::DataType { use arrow::datatypes::*; DataType::FixedSizeList( std::sync::Arc::new(Field::new("item", DataType::Float32, false)), 4, ) } }

要点解读:

  • 外层是一个定长列表(FixedSizeList),长度为 4,元素类型为Float32,元素字段不可为 null(false)。
  • 定长列表的优点是内存紧凑:4 个f32连续排布,无需额外的 offsets 数组,适合表示在数量上"永远恰好是 4 个"的向量/四元数。
  • 反序列化时,代码会先校验value_length() == 4,不匹配则抛出datatype_mismatch错误(见 quaternion.rs),随后将内部 Float32 缓冲区直接按bytemuck::try_cast_slice零拷贝转换为[f32; 4]切片。

Python 侧同样采用 pyarrow 的FixedSizeListArray生成该表示。在 rerun_py/rerun_sdk/rerun/encodings/quaternion_ext.py 中:

@staticmethod def native_to_pa_array_override(data: QuaternionArrayLike, data_type: pa.DataType) -> pa.Array: quaternions = flat_np_float32_array_from_array_like(data, 4) return pa.FixedSizeListArray.from_arrays(quaternions, type=data_type)

输入先被规整为形状为(N, 4)float32ndarray,再封装成定长列表数组——这也解释了 Python 类型别名中npt.NDArray[Any] | npt.ArrayLike | Sequence[Sequence[float]]的由来:批量的四元数本质就是一个(N, 4)的数组。

核心常量与构造方法:XYZW 与 WXYZ 的约定

原文档正文只说明了"4 个实数"与归一化语义,而实际使用中还需掌握构造与分量顺序约定。Rerun 在手写扩展层 crates/store/re_sdk_types/src/encodings/quaternion_ext.rs 中提供了以下内容:

成员含义值 / 说明
IDENTITY单位四元数(无旋转)[0.0, 0.0, 0.0, 1.0]
INVALID无效变换四元数[0.0, 0.0, 0.0, 0.0]
from_xyzw([f32; 4])按 x,y,z,w 顺序构造内部存储顺序即输入顺序
from_wxyz([f32; 4])按 w,x,y,z 顺序构造自动重排为[x, y, z, w]
xyzw() -> [f32; 4]读取四个分量返回 x,y,z,w 顺序

Default实现直接返回IDENTITY,即"默认四元数 = 无旋转":

impl Default for Quaternion { fn default() -> Self { Self::IDENTITY } }

顺序约定提醒:数学社区与许多数学库(如 Eigen、部分 ROS 资料)习惯使用w, x, y, z(WXYZ)顺序,而 Rerun 内部统一使用x, y, z, w(XYZW)顺序。为此 Rerun 在 Rust 与 C++ 中都提供了from_wxyz便捷构造,避免手工重排出错。C++ 端实现见 rerun_cpp/src/rerun/encodings/quaternion.hpp,同时提供了x()/y()/z()/w()分量访问器与从float*指针构造的版本。

三种语言 SDK 的实战用法

Python:rr.Quaternion

Python 侧的扩展实现在 rerun_py/rerun_sdk/rerun/encodings/quaternion_ext.py,提供关键字构造、identity()invalid()工厂方法:

import rerun as rr rr.init("rerun_example_quaternion", spawn=True) # 关键字构造,按 XYZW 顺序 q = rr.Quaternion(xyzw=[0.0, 0.0, 0.382683, 0.923880]) # 绕 Z 轴 45° # 单位四元数 identity = rr.Quaternion.identity() # 无效四元数(归一化失败时表示无效变换) invalid = rr.Quaternion.invalid()

Rust:rerun::Quaternion

Rust 侧直接使用生成的rerun::Quaternion,配合常量与构造方法。完整可运行示例见 docs/snippets/all/archetypes/boxes3d_batch.rs:

let rec = rerun::RecordingStreamBuilder::new("rerun_example_box3d_batch").spawn()?; rec.log( "batch", &rerun::Boxes3D::from_centers_and_half_sizes( [(2.0, 0.0, 0.0), (-2.0, 0.0, 0.0), (0.0, 0.0, 2.0)], [(2.0, 2.0, 1.0), (1.0, 1.0, 0.5), (2.0, 0.5, 1.0)], ) .with_quaternions([ rerun::Quaternion::IDENTITY, rerun::Quaternion::from_xyzw([0.0, 0.0, 0.382683, 0.923880]), // 45 degrees around Z ]), )?;

注意 Rust 批量 API(with_quaternions)接收一个四元数数组,其长度需要与centers/half_sizes的数量对齐。

C++:rerun::encodings::Quaternion

C++ 头文件 rerun_cpp/src/rerun/encodings/quaternion.hpp 提供同名结构体与丰富构造器:

#include <rerun.hpp> auto q = rerun::encodings::Quaternion::from_xyzw(0.0f, 0.0f, 0.382683f, 0.923880f); auto q2 = rerun::encodings::Quaternion::from_wxyz(0.923880f, 0.0f, 0.0f, 0.382683f); // 等价 auto identity = rerun::encodings::Quaternion::IDENTITY;

from_wxyz的重载同时支持四个标量、std::array<float, 4>const float*指针三种入参形式,便于与既有数学库互操作。

四元数如何进入 Rerun 数据模型:从 Encoding 到 Component 到 Archetype

原文档末尾给出了Quaternion的唯一直接消费者:RotationQuat组件(docs/content/reference/types/components/rotation_quat.md)。其完整的引用链如下:

1. Encoding → Component

Rust 生成代码中,RotationQuat是一个透明的包装组件,内部持有encodings::Quaternion

#[repr(transparent)] pub struct RotationQuat(pub crate::encodings::Quaternion); impl ::re_types_core::WrapperComponent for RotationQuat { type Encoding = crate::encodings::Quaternion; fn name() -> ComponentType { "rerun.components.RotationQuat".into() } fn into_inner(self) -> Self::Encoding { self.0 } }

它实现了Deref/DerefMutQuaternion,因此组件可直接复用编码类型的所有方法与常量。

2. Component → Rotation3D 辅助类型

在 crates/store/re_sdk_types/src/rotation3d.rs 中定义了一个非组件的辅助枚举Rotation3D,用于填充Transform3D

pub enum Rotation3D { Quaternion(components::RotationQuat), // 四元数表达 AxisAngle(components::RotationAxisAngle), // 轴角表达 }

它提供从components::RotationQuatencodings::Quaternion以及(启用glamfeature 时)glam::QuatFrom转换,Rotation3D::IDENTITY也定义为以四元数形式表示的单位旋转。

3. Rotation3D → Transform3D Archetype

transform3d_ext.rs 中的with_rotation方法接收任意实现了Into<Rotation3D>的类型,四元数与轴角可以无缝混用:

pub fn with_rotation(self, rotation: impl Into<Rotation3D>) -> Self { match rotation.into() { Rotation3D::Quaternion(quaternion) => self.with_quaternion(quaternion), Rotation3D::AxisAngle(rotation_axis_angle) => self.with_rotation_axis_angle(rotation_axis_angle), } }

于是,在 Python 中可以用rr.Transform3D(rotation=rr.Quaternion(xyzw=[...]))rr.Transform3D(rotation=rr.RotationAxisAngle(...))表达同一种旋转——四元数只是 Rerun 支持的两种旋转编码之一。

4. 更广的消费面

根据RotationQuat组件的文档,使用四元数旋转的 Archetype 还包括Boxes3DCapsules3DCylinders3DEllipsoids3DGaussianSplats3DGridMapInstancePoses3DVolume3DVoxelGridMap等。以 Python 侧的批量包围盒示例 docs/snippets/all/archetypes/boxes3d_batch.py 为例:

rr.log( "batch", rr.Boxes3D( centers=[[2, 0, 0], [-2, 0, 0], [0, 0, 2]], half_sizes=[[2.0, 2.0, 1.0], [1.0, 1.0, 0.5], [2.0, 0.5, 1.0]], quaternions=[ rr.Quaternion.identity(), rr.Quaternion(xyzw=[0.0, 0.0, 0.382683, 0.923880]), # 45 degrees around Z ], ... ), )

可见一个未旋转的盒子与一个绕 Z 轴旋转 45° 的盒子可以同时记录在同一个 Archetype 实例中。

与外部数学库的互操作

Quaternion在设计上充分考虑了与常见 Rust 数学库的双向转换(见 quaternion_ext.rs):

  • glam(启用glamfeature 时):Quaternion → glam::Quat使用TryFrom(归一化失败返回错误);glam::Quat → Quaternion使用From(直接取to_array()的 XYZW 顺序)。
  • mint(启用mintfeature 时):与mint::Quaternion<f32>双向From转换。

mint 是 Rust 生态中用于跨数学库互操作的标准类型约定,这意味着用户完全可以在自己的代码中使用任意数学库计算四元数,再在记录前转换为rerun::Quaternion

此外,仓库的re_sdk_types测试(crates/store/re_sdk_types/tests/types/mint_conversions.rs)也覆盖了包括四元数在内的 mint 转换路径,可作进一步参考。

实践要点与注意事项

综合文档与源码,使用Quaternion时建议注意以下几点:

  1. 分量顺序统一为 XYZW:Rerun 内部约定是x, y, z, w;若你的数据源是 WXYZ 顺序(如部分数学库),请使用from_wxyz/from_wxyz构造器或自行重排,避免静默错位。
  2. 记录时无需归一化:存储层会原样保存你提供的 4 个浮点数,Viewer 负责归一化;但为了一致性与可读性,建议记录前自行归一化。
  3. 零模长四元数 = 无效变换[0, 0, 0, 0](即Quaternion::invalid())无法归一化,会被 Viewer 视为无效旋转。这也是IDENTITY[0,0,0,1])与INVALID两个常量需要区分的原因。
  4. 内存表示紧凑FixedSizeList(4 x non-null Float32)意味着每个四元数固定占用 16 字节(4 × f32),批量记录时适合按(N, 4)的数组一次性传入,Python 侧会通过flat_np_float32_array_from_array_like自动规整。
  5. 二选一的旋转表达Transform3D中四元数与轴角(RotationAxisAngle)通过Rotation3D枚举统一收口,同一变换只能选择其中一种表达,二者共用with_rotation接口。

Quaternion编码类型虽小,却是 Rerun 3D 数据模型中旋转语义的基石:它定义了四元数的存储顺序(XYZW)、Arrow 表示(定长 4 元 Float32 列表)、归一化行为(原样入库、Viewer 归一化、失败视为无效)以及跨语言的一致性 API。理解这一定义,是正确使用Transform3DBoxes3D等一切涉及旋转的 Archetype 的前提。

【免费下载链接】rerunVisualize, query, and stream to train on multimodal robotics data.项目地址: https://gitcode.com/GitHub_Trending/re/rerun

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/17 1:13:46

Hyper-V内部网络外网连通:路由模式替代NAT的实战方案

1. 这不是“配个IP”那么简单&#xff1a;Hyper-V内部网络固定IP外网连通的真实场景与核心矛盾你搜到这个标题&#xff0c;大概率正卡在某个具体环节&#xff1a;虚拟机里装好了CentOS Stream 10&#xff0c;nmcli配了静态IP&#xff0c;ping 192.168.137.1通了&#xff0c;但p…

作者头像 李华
网站建设 2026/9/17 1:12:06

2026 国内 AI 科研平台选型指南:沁言学术功能与适用性解析

引言&#xff1a;随着人工智能技术与科研工作的深度融合&#xff0c;AI 工具已成为众多高校师生及科研人员提升效率的重要辅助手段。然而&#xff0c;面对市场上琳琅满目的产品&#xff0c;如何甄别其实际能力、选择契合自身研究需求的平台&#xff0c;成为许多研究者面临的难题…

作者头像 李华
网站建设 2026/9/17 1:08:17

VineCopulaCPP实战:Matlab中藤Copula建模与尾部依赖分析

简介&#xff1a;这是一份藤Copula建模工具&#xff0c;底层基于C实现&#xff0c;并通过Matlab接口封装&#xff0c;面向需要量化多元随机变量依赖关系的研究者与从业者&#xff0c;适用于金融工程、风险管理与统计建模等场景。压缩包共23个文件&#xff0c;以17个cpp源码与3个…

作者头像 李华