MetaCore/docs/designs/metacore-material-meshrenderer-data-structure-design.md

480 lines
9.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# MetaCore 材质资源与 MeshRenderer 数据结构设计
生成时间2026-03-28
状态:草案
范围M2 资源与模型导入循环、M3 场景编辑、材质与光照工作流
## 目的
这份文档用于把后续会真正落到代码里的几类核心结构定清楚:
- `Material Asset` 应该有哪些字段
- `Mesh Asset` 应该有哪些字段
- `MeshRenderer` 应该如何从当前简化结构演进
- 这些结构如何参与场景保存、资源引用和打包
这一步的目标不是讨论渲染效果,而是先锁定数据模型。
因为对引擎来说,数据结构一旦定错,后面:
- 模型导入
- Inspector
- Scene 保存
- Prefab
- Cook
- Player 渲染
都会一起返工。
## 当前代码现状
当前 `MeshRenderer` 组件大致是:
- `BuiltinMesh`
- `BaseColor`
- `Visible`
这适合原型验证,但不足以支撑真实模型与材质工作流。
当前仓库里还没有正式的:
- `Material Asset Document`
- `Mesh Asset Document`
- `Texture Asset Document`
- `MeshRenderer` 的资源引用结构
因此第一阶段必须先完成“从原型组件到正式资源引用组件”的演进设计。
## 设计目标
第一阶段数据结构要同时满足下面几个要求:
- 能支撑 `glTF/.glb` 首批导入
- 能支撑简单模型和多材质槽模型
- 能在 Scene 中稳定保存引用
- 能被 Editor Inspector 编辑
- 能被 Cook 和 Package 依赖分析
- 能接入 `simplepbr`
- 不锁死未来类 URP 的演进空间
## 资源与组件的关系
```mermaid
flowchart TD
A["Mesh Asset"] --> C["MeshRenderer Component"]
B["Material Asset (0..N)"] --> C
C --> D["Scene Document"]
A --> E["Cook / Package"]
B --> E
D --> F["Player Runtime"]
E --> F
```
含义是:
- `MeshRenderer` 不再直接保存完整材质内容
- `MeshRenderer` 只保存对资源的引用
- 资源本体由资产系统管理
## 第一阶段 Material Asset 结构
第一阶段建议定义正式的 `MetaCoreMaterialAssetDocument`
### 核心字段
- `AssetGuid`
- `Name`
- `ShaderModel`
- `BaseColor`
- `BaseColorTexture`
- `NormalTexture`
- `Metallic`
- `Roughness`
- `MetallicRoughnessTexture`
- `AoTexture`
- `EmissiveColor`
- `EmissiveTexture`
- `AlphaMode`
- `AlphaCutoff`
- `DoubleSided`
### 字段说明
#### AssetGuid
材质资源的稳定身份。
这是 Scene、Prefab、Cook、重导入能够持续引用它的基础。
#### Name
材质资源名,主要用于:
- Project 面板显示
- Inspector 显示
- 调试与错误提示
#### ShaderModel
第一阶段建议不要设计成任意 shader 名字字符串,而是明确一个有限枚举,例如:
- `PbrMetalRough`
- `UnlitColor`
- `UnlitTexture`
第一阶段主打 `PbrMetalRough`
这样做的好处是:
- 数据更稳定
- Inspector 更清楚
- 后续再映射到不同 render backend 更容易
#### BaseColor
基础颜色乘子。
#### BaseColorTexture
对纹理资源的引用。建议类型为:
- `std::optional<MetaCoreAssetGuid>`
不要在材质里直接存文件路径。
#### NormalTexture
法线贴图资源引用。
#### Metallic / Roughness
金属度与粗糙度标量参数。
#### MetallicRoughnessTexture
金属粗糙度复合图资源引用。
#### AoTexture
AO 贴图资源引用。
#### EmissiveColor / EmissiveTexture
自发光颜色和自发光贴图引用。
#### AlphaMode
第一阶段建议枚举化,例如:
- `Opaque`
- `Mask`
- `Blend`
#### AlphaCutoff
用于 `Mask` 模式。
#### DoubleSided
双面渲染开关。
### 第一阶段不建议直接放进去的内容
这些不要在第一阶段过早塞进正式材质结构:
- 任意 shader 参数字典
- 自定义 render feature 列表
- 任意 pass 配置
- 大而全的 keyword 系统
这些都会把第一阶段数据结构做得又重又不稳。
## 第一阶段 Mesh Asset 结构
第一阶段建议定义正式的 `MetaCoreMeshAssetDocument`
### 核心字段
- `AssetGuid`
- `Name`
- `BoundsMin`
- `BoundsMax`
- `VertexCount`
- `IndexCount`
- `SubMeshes`
如果当前阶段还不想把大块几何数据直接暴露在文档结构里,也可以让文档描述元信息,而实际几何 buffer 落在 package payload。
### SubMesh 结构
第一阶段建议有明确的 `MetaCoreSubMeshDescriptor`
- `Name`
- `IndexOffset`
- `IndexCount`
- `MaterialSlotIndex`
这个结构非常关键,因为它把:
- 一个网格中的多个几何段
- 和材质槽位的关系
固定了下来。
### 顶点流建议
第一阶段至少支持:
- Position
- Normal
- UV0
- Tangent
如果导入格式缺少某些数据,可以在导入阶段:
- 自动补全
- 或给出警告
但不要让运行时数据结构含糊不清。
## 第一阶段 Texture Asset 结构
即使暂时不做完整纹理编辑器,也建议正式定义 `MetaCoreTextureAssetDocument`,至少有:
- `AssetGuid`
- `Name`
- `Width`
- `Height`
- `Format`
- `ColorSpace`
- `Usage`
其中 `Usage` 第一阶段建议枚举化,例如:
- `BaseColor`
- `Normal`
- `LinearMask`
- `Emissive`
- `Ao`
这有利于:
- 导入校验
- Inspector 提示
- simplepbr 映射
## MeshRenderer 组件演进设计
这是最关键的组件演进点。
### 当前结构
- `BuiltinMesh`
- `BaseColor`
- `Visible`
### 第一阶段目标结构
建议演进为:
- `MeshSourceKind`
- `BuiltinMesh`
- `MeshAssetGuid`
- `MaterialAssetGuids`
- `Visible`
### 推荐字段解释
#### MeshSourceKind
建议新增一个枚举,明确当前对象使用的是:
- `Builtin`
- `Asset`
这样可以兼容当前已有的内置立方体、球体等原型对象,也可以平滑接入正式模型资源。
#### BuiltinMesh
保留现有字段,但只在 `MeshSourceKind == Builtin` 时生效。
这有利于:
- 继续保留最小原型能力
- 不阻塞后面正式资源化
#### MeshAssetGuid
`MeshSourceKind == Asset` 时,引用正式网格资源。
建议类型:
- `std::optional<MetaCoreAssetGuid>`
#### MaterialAssetGuids
一个数组,长度 ideally 对应 `SubMesh` 的材质槽数量。
建议类型:
- `std::vector<MetaCoreAssetGuid>`
第一阶段如果导入模型只有一个材质,也仍建议用数组,而不是单个字段。
因为多材质槽模型在工业场景里非常常见。
#### Visible
保留。
### 第一阶段允许保留的兼容字段
为了兼容已有原型代码,第一阶段可以短期保留:
- `BaseColor`
但需要明确它的定位只能是:
- 调试覆盖色
- RuntimeData 的临时驱动入口
它不应继续作为正式材质系统的核心字段。
也就是说,后续优先级应该是:
- 资源材质主导
- `BaseColor` 仅作为可选 override
## Scene 保存策略
Scene 中不应内嵌完整的网格和材质内容。
Scene 对 `MeshRenderer` 的保存应以“引用”为主:
- `MeshSourceKind`
- `BuiltinMesh`
- `MeshAssetGuid`
- `MaterialAssetGuids`
- `Visible`
这样好处是:
- 场景更轻
- 资源可复用
- 材质统一修改后能反映到多个对象
- Cook 更容易做依赖分析
## Prefab 保存策略
Prefab 与 Scene 一样,建议保存资源引用,而不是内嵌资源内容。
这样设备、阀门、管段、告警灯等 prefab 才能真正复用:
- 同一 Mesh
- 同一 Material
- 不同 Transform
- 不同业务逻辑组件
## Cook 与 Package 策略
Cook 阶段应能够从 Scene / Prefab 中追踪依赖:
- MeshRenderer -> MeshAssetGuid
- MeshRenderer -> MaterialAssetGuids
- MaterialAsset -> TextureAsset 引用
这样最终打包时,才能把真正运行所需资源闭包带全。
## Inspector 建议
### 对象 Inspector
第一阶段最少应支持:
- 切换 Builtin / Asset Mesh
- 选择 Mesh Asset
- 查看材质槽数量
- 为每个材质槽选择 Material Asset
- `Visible`
### 材质资源 Inspector
第一阶段最少应支持:
- BaseColor
- BaseColorTexture
- NormalTexture
- Metallic
- Roughness
- EmissiveColor
- EmissiveTexture
- AlphaMode
- DoubleSided
### 不建议的做法
不要让对象 Inspector 同时承担:
- 对象引用管理
- 材质参数完整编辑
这会让工作流非常乱。
## 与 RuntimeData 的关系
材质资源化之后,`RuntimeData` 仍然可以继续驱动:
- `MeshRenderer.Visible`
- 材质 override 颜色
- 灯光参数
但不建议第一阶段直接让 RuntimeData 去改材质资源本体。
更合理的做法是:
- Runtime 改对象实例级显示状态
- Asset 仍然由资源系统管理
## 推荐实现顺序
建议按下面顺序推进:
1. 定义 `Material Asset Document`
2. 定义 `Mesh Asset Document`
3. 定义 `Texture Asset Document`
4. 扩展 `MeshRenderer` 数据结构
5. 更新 Scene / Prefab 序列化
6. 更新 Inspector
7. 再接模型导入与材质映射
8. 最后接 `simplepbr` 参数映射
## 第一阶段 Definition of Done
当下面这些都成立时,可以认为这套数据结构设计已经真正落地:
- Scene 中的 `MeshRenderer` 不再只依赖 `BuiltinMesh`
- 导入模型能够生成正式 Mesh/Material 资源
- 对象可以引用 Mesh Asset 和多个 Material Asset
- Inspector 能指派和编辑材质
- Scene / Prefab 保存的是资源引用
- Cook 能正确追踪 Mesh/Material/Texture 依赖
- Player 能基于这些资源正确渲染
## 最终建议
第一阶段最关键的不是“效果做多炫”,而是先把结构做对。
所以最合理的方向是:
**把 Mesh、Material、Texture 正式变成 MetaCore 资源,把 MeshRenderer 正式变成资源引用组件再让导入、Inspector、Cook 和 simplepbr 全部围绕这套结构协作。**
这一步一旦定稳,后续:
- 模型导入
- 材质编辑
- 场景保存
- 打包运行
- RuntimeData 显示驱动
都会顺很多。