Chapter 212 · 3D 图形

场景与节点层级

3D 世界从一棵节点树开始。本章建立 XGE 3D 的坐标约定、节点生命周期与变换模型——它们是后续所有章节的地基。

212

坐标与单位约定

XGE 3D 采用右手坐标系、Y 轴向上,长度单位是米,角度是弧度,矩阵为列主序。场景变更与 GPU 调用由调用方在同一逻辑流中串行化——引擎不做隐式加锁,这保证了 API 行为可预测。

核心概念:节点句柄是 xge3d_node_t{ uint64_t slot, scene; } 双字结构。零值句柄代表"根父节点";失效句柄与外来句柄会被 API 拒绝,而不是崩溃。

创建场景与节点

// 场景是所有 3D 对象的容器
xge3d_scene *pScene;
xge3dSceneCreate(&pScene);

// 在根下挂一个节点,再挂子节点
xge3d_node_t tParent, tChild;
xge3dNodeCreate(pScene, (xge3d_node_t){0}, &tParent);
xge3dNodeCreate(pScene, tParent, &tChild);

// 设置 TRS 变换(位置 / 四元数旋转 / 缩放)
xge3d_transform_t t = XGE3D_TRANSFORM_IDENTITY;
t.position = (xge3d_vec3_t){ 10, 0, -4 };
xge3dNodeSetTransform(pScene, tChild, &t);

// 查询世界矩阵(父链复合后的结果)
xge3d_mat4_t tWorld;
xge3dNodeGetWorldMatrix(pScene, tChild, &tWorld);

变换有两种写法:xge3dNodeSetTransform 接受 TRS 结构体,语义清晰;xge3dNodeSetMatrix 接受精确仿射矩阵,能保留导入资源的原始变换(包括切变)。两者选其一即可,后设置的覆盖先设置的。

生命周期的三条铁律

  • 节点属于场景——不需要(也不能)手动释放单个节点数据,xge3dNodeDestroy 销毁节点及其全部后代。
  • 重挂父节点保留局部矩阵——xge3dNodeSetParent 只改变层级,不清空变换,适合装配与换装。
  • 场景先于资源释放——释放场景前,先释放挂接它的动画器等借用者;带已上传网格的场景销毁必须发生在 owning 上下文线程。

大世界的原点重定位

float 在 1e9 量级坐标下精度不足。XGE 的做法是场景持有双精度原点:xge3dSceneSetOrigin 设定附近全局原点,节点与相机都工作在相对坐标里;应用自己保管全局状态,需要时用 xge3dRelativePosition 与 xge3dCameraLookAtGlobal 在两套坐标间换算。

本章 API 速查

函数 / 类型说明
xge3dSceneCreate / SceneFree场景生命周期;析构级联全部节点
xge3dNodeCreate(scene, parent, out)创建节点;parent 零值为根
xge3dNodeDestroy / SetParent销毁(含后代)/ 重挂保留局部矩阵
xge3dNodeSetTransform / SetMatrixTRS 或精确仿射矩阵两种写法
xge3dNodeGetWorldMatrix父链复合后的世界矩阵
xge3dNodeSetVisible子树可见性开关
xge3dSceneSetOrigin / SceneOrigin双精度原点重定位(大世界)
xge3d_transform_t / XGE3D_TRANSFORM_IDENTITY位置 + 四元数 + 缩放
xge_3d_scene 场景与节点层级示例
图:本章示例对应 examples/xge_3d_scene,演示场景组合与节点变换;运行 build\3d\xge_3d_scene.exe --frames 100 --capture out.png 可自动退出并截图。

要点与常见陷阱

  • 不要缓存节点句柄跨场景使用——句柄内含 scene 校验字段,外来句柄会被拒绝。
  • 四元数 w 在最后——xge3d_quat_t{x,y,z,w},与 glTF 一致,别和某些库的 w-first 混淆。
  • CPU 场景 API 不依赖 xgeInit——可以在无窗口环境(如工具程序)里构建与查询场景。

进阶练习

  1. 构建三层节点链,给每层不同的平移,验证 GetWorldMatrix 的复合结果。
  2. 把一个子节点 SetParent 到另一分支,观察局部矩阵是否保留。
  3. 用 xge3dNodeSetMatrix 写一个带切变的矩阵,对比 SetTransform 的覆盖行为。