主题
GameGraph 附加模型挂载
GameGraph 附加模型挂载是自动挂载模型表现的下钻接口。 两者复用同一套模型挂载、骨骼跟随及可选的宿主网格裁剪机制,适用于手持物、装备、背饰、披风、头饰和其他外观部件。区别在于谁选择宿主、何时挂载以及谁管理生命周期。
“附加模型”是被挂到宿主上的外观模型;“自动挂载模型表现”是上层通过 Actor 和数据配置管理这些模型的功能。GameGraph 下钻后仍使用这项表现能力,但挂载时机与清理由调用方管理。ActorAdditionModel 继续属于 Actor 层。
上层配置与下钻接口的关系
| 维度 | 自动挂载模型表现(Actor 层) | 附加模型挂载(GameGraph 下钻) |
|---|---|---|
| 入口 | GameDataActorAdditionModel + ActorArray | 指定 AnimatedModelComponent 的 AttachAdditionModel(...) |
| 模型来源 | GameDataModel 引用 | GameCore.ResourceType.Prefab 或已加载的 GameGraph.ResourceSystem.Prefab |
| 宿主选择 | 由 ActorScope、单位或物品槽位关联 | 调用方持有具体宿主主骨骼模型组件 |
| 显示与清理 | 框架按单位、槽位、Buff 等生命周期维护 | 调用方保存 AdditionModelAttachment,调用 Detach() / Dispose() 清理 |
| 裁剪选项 | GameDataActorAdditionModel.CullHostMesh | AdditionModelOptions.CullHostMesh |
| 典型用途 | 已有单位/物品系统的装备外观、Buff 外观 | 直接 GameGraph 角色、换装预览、代码控制的外观组合 |
已有单位、物品槽位或 Buff 自动外观时优先使用 Actor 路线。直接操作 GameGraph 角色,或确实需要自己控制挂载生命周期时,使用下钻接口;同一份外观不要同时由两条路线重复创建。下钻调用不需要创建 GameDataActorAdditionModel 或传入 model link。
支持边界与资源要求
- 所有挂载代码仅客户端可用,放在
#if CLIENT中。服务端没有这组骨骼模型表现 API。 - 宿主必须来自 Prefab 实例(Prefab-backed),调用对象必须是该实例的主骨骼模型组件。只用
new AnimatedModelComponent()或Mesh.Load(...)装配的模型不满足条件。 - 附加资源也必须是包含骨骼模型的 Prefab;普通静态模型不能直接当作该接口的骨骼附加模型。不要假设任意嵌套 Prefab 都能完整作为附加模型使用。
- 挂载入口属于具体组件,不是
Node.AttachAdditionModel(...)。节点可以包含多个模型组件;持有组件并不意味着它一定是有效的主骨骼宿主。 - 自动对齐沿用上层的资源制作约定:使用宿主骨架、匹配骨骼名、Bind Pose、坐标轴、厘米单位、初始变换与蒙皮权重。程序侧无需指定手、头或背部槽位。详细制作步骤见自动挂载模型表现的资源约定。
- 附加模型是客户端表现,不会自动获得网络同步、装备属性、伤害或碰撞判定。联机时同步外观选择等玩法状态,各客户端根据该状态维护自己的挂载句柄。
如果需求是把普通静态物件或特效挂到指定骨骼/Socket,并手动设置局部偏移,应使用 GetBoneNode(...) / GetSocket(...) 的子节点挂接方式,见骨骼动画指南。它与这里按资源骨架自动对齐的附加模型用途不同。
获取明确的宿主
Prefab 实例根节点负责组织结构,模型组件通常位于子节点。下面的示例假定宿主资源已确认只有一个主骨骼模型,并在附加任何模型前取得该组件;hostPath 是调用方提供的真实 Prefab 资源路径。
csharp
#if CLIENT
using System;
using GameGraph.NodeSystem;
using GameGraph.NodeSystem.Component.Graphics;
using PrefabPath = GameCore.ResourceType.Prefab;
using PrefabResource = GameGraph.ResourceSystem.Prefab;
static AnimatedModelComponent CreateHost(Node parent, PrefabPath hostPath)
{
var prefab = PrefabResource.Load(hostPath)
?? throw new InvalidOperationException("宿主 Prefab 加载失败");
var instance = prefab.CreateInstance(parent);
return instance.GetComponentInChildren<AnimatedModelComponent>()
?? throw new InvalidOperationException("宿主 Prefab 中没有骨骼模型");
}
#endifGetComponentInChildren<T>() 返回首个匹配项,不负责识别主骨骼模型。复杂 Prefab 应根据已确认的资源层级获取并保存真正的主骨骼模型;不要任意选取其他子模型或附加模型,也不要在每次换装时重新搜索首个模型。宿主实例由创建它的角色/场景所有者负责清理。
挂载、换装与解除
下面的辅助类接收已经确认的主骨骼宿主组件,保存一次挂载,并在换装或释放时解除。additionPath 由调用方提供,无需建立 Actor/model link。
csharp
#if CLIENT
using System;
using GameGraph.NodeSystem.Component.Graphics;
using PrefabPath = GameCore.ResourceType.Prefab;
public sealed class CharacterAppearance : IDisposable
{
private readonly AnimatedModelComponent host;
private AdditionModelAttachment? attachment;
public CharacterAppearance(AnimatedModelComponent host)
{
this.host = host;
}
public void Equip(PrefabPath additionPath, bool cullHostMesh = false)
{
Clear();
attachment = host.AttachAdditionModel(
additionPath, new AdditionModelOptions { CullHostMesh = cullHostMesh });
}
public void Clear()
{
attachment?.Detach();
attachment = null;
}
public void Dispose() => Clear();
}
#endif这是先卸下旧外观再挂新外观的示例;新挂载失败时保持无附加模型,调用方应根据产品需求显示错误或恢复已知可用的外观。
如果已经加载了附加 Prefab,可以复用资源对象。以下片段中的 host 为已确认的宿主,additionPath 为真实资源路径:
csharp
#if CLIENT
var addition = GameGraph.ResourceSystem.Prefab.Load(additionPath)
?? throw new System.InvalidOperationException("附加 Prefab 加载失败");
var first = host.AttachAdditionModel(addition);
var second = host.AttachAdditionModel(addition);
first.Detach(); // 只解除 first 对应的挂载
second.Dispose(); // 解除另一次挂载
#endif同一 Prefab 可以创建多个独立挂载;每次调用返回的句柄只管理本次挂载。重叠的相同模型可能看不出区别,实际需求中应避免意外重复创建。
生命周期与失败处理
| 项目 | 契约与处理 |
|---|---|
Detach() / Dispose() | 解除当前句柄对应的挂载,可重复调用 |
IsAttached | 表示句柄仍有效且持有挂载标识;不是原生宿主存活或屏幕可见性查询 |
| 换装、角色移除、场景销毁 | 在替换/销毁宿主之前显式解除其全部挂载;不要依赖 GC 作为外观生命周期管理 |
| 宿主 Prefab 被替换 | 为新实例重新取得主骨骼模型并重新挂载,不复用旧宿主组件或句柄 |
| Prefab 路径加载失败 | 路径重载抛出 InvalidOperationException;检查路径、资源包与发布内容 |
| 已加载资源参数为 null | 抛出 ArgumentNullException |
| 宿主不受支持或附加资源未提供可挂载骨骼模型 | 挂载失败并抛出 InvalidOperationException;检查主骨骼宿主与两侧 Prefab 条件 |
AdditionModelAttachment 是挂载生命周期句柄,不是新的 Node 或组件,也不暴露附加模型的玩法状态。
宿主网格裁剪
AdditionModelOptions.CullHostMesh 默认 false,对应上层 GameDataActorAdditionModel.CullHostMesh。保持关闭时附加模型仍正常参与骨骼跟随与渲染。
外套或整套外观覆盖宿主主体、资源具备裁剪条件时,可开启宿主网格裁剪。它不是通用的防穿模开关,也不等于隐藏整个宿主;普通手持物、背饰、头饰通常保持关闭。开启后应实际检查裁剪范围、动作和解除挂载后的宿主显示,不承诺任意资源都能获得正确的裁剪效果。
资源发布与验收
使用已存在的宿主和附加资源验证;上面的参数名不代表 SDK 自带示例资源。项目资源放在 res/ 下时,逻辑路径不带 res/ 前缀,其内容随项目打包。云资源则需确保宿主、所有可选附加 Prefab 及其依赖进入发布清单。ResourceType.Prefab 可以表达资源引用,但动态拼路径或只传已加载资源对象不代表所有候选资源已被收集;检查资源统计与最终发布内容,见资源清单排查。
验收至少覆盖待机与运动中的骨骼跟随、换装与解除、同资源两次挂载后分别解除、销毁/重建宿主,以及开启裁剪时的宿主显示。只编译成功不能证明资源骨架适配或实际渲染正确。运行端须同时具备匹配的 SDK、依赖库和客户端/编辑器二进制。