Files
UnityAI/modules/frameworks/微信小游戏渲染规则.md

219 lines
13 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.
# 微信小游戏渲染规则
## 一、定位与适用范围
本文档定义 StrayFog 接入微信小游戏时需要长期遵守的渲染与 Shader 规则,适用于 Unity URP、手写 Shader、Shader Graph、材质、Shader 变体和 AssetBundle 资源。
微信小游戏 Unity 快适配以 WebGL/WebAssembly 构建为基础,再由微信转换插件接入小游戏运行环境。Editor、普通 WebGL 和桌面平台表现不能替代微信开发者工具与真机验证。
本文档不规定具体画面风格,也不替代:
- [微信小游戏资源接入方案](资源管理/微信小游戏资源接入方案.md)中的 CDN、AssetBundle、缓存和卸载规则。
- [相机系统](相机系统/README.md)中的 Base/Overlay Camera Stack 生命周期。
- 具体业务项目的 URP Asset、Renderer Feature、质量等级和材质参数。
## 二、能力基线
### 2.1 图形 API
- Unity 2022.3 WebGL 2 对应 OpenGL ES 3.0 级别的渲染能力。
- 微信转换配置启用 WebGL 2 时,导出流程必须使用 `OpenGLES3`;关闭时才退回 `OpenGLES2`。
- 新项目默认以 WebGL 2 / OpenGLES3 为目标,不为 WebGL 1 主动增加复杂兼容分支。
- 若业务必须支持 WebGL 1,应单独确认设备范围、色彩空间、Shader 循环与索引限制,并建立独立真机验收。
- 运行时可用 `SystemInfo.graphicsDeviceType`、`SystemInfo.graphicsDeviceName` 和 `SystemInfo.graphicsMemorySize` 记录真实设备能力,不能只读取构建配置。
### 2.2 平台宏
Shader 中优先使用 Unity 已定义的图形平台宏:
```hlsl
#if defined(SHADER_API_GLES3)
// WebGL 2 / OpenGL ES 3 路径
#endif
#if defined(SHADER_API_MOBILE)
// 移动 GPU 低成本路径
#endif
```
C# 中微信 SDK 调用继续使用项目约定的 `WeChat` 宏。不要为了 Shader 再建立 `HF_WECHAT_SHADER`、`isMiniGameShader` 等第二套平台开关。
Shader 平台能力和微信业务 API 是两个边界:
- Shader 使用图形 API 宏决定可编译能力和质量分支。
- C# 使用 `WeChat` 宏隔离微信 SDK。
- 不在 Shader 中依赖业务项目名、渠道或微信登录状态。
## 三、Shader 编写规则
### 3.1 通用规则
- URP Shader 必须声明正确的 `RenderPipeline`、`RenderType`、`Queue` 和 `LightMode`。
- 手写 URP Shader 的材质属性放入 `UnityPerMaterial` CBUFFER,并保持所有 Pass 布局一致,以兼容 SRP Batcher。
- 颜色、法线和普通权重优先使用 `half`;世界坐标、裁剪坐标、深度重建和大范围 UV 计算使用 `float`。
- 限制纹理采样、透明叠加、屏幕空间读取、插值变量、动态分支和高次数循环。
- 循环次数可确定时使用常量上限;不要依赖无法在 GLES 路径稳定展开的复杂动态循环。
- 不使用 Geometry Shader、Tessellation Shader 或桌面平台专属 Shader Model 作为微信小游戏核心表现。
- 需要计算深度时必须处理 Reversed-Z、透视除法和线性深度转换,优先使用 URP 提供的深度函数。
- 自定义 HLSL 和 Shader Graph Custom Function 必须同时在目标 Unity 版本、WebGL 构建和真机验证,不能只看节点预览。
### 3.2 Shader Graph
- Shader Graph 目标必须选择 Universal,并明确 Surface Type、Depth Write、Depth Test、Render Face 和 Cast/Receive Shadows。
- Blackboard Keyword 默认选择能剥离未使用组合的定义方式;只有运行时确实会切换所有组合时才保留对应变体。
- 控制 Custom Interpolator 数量,避免为少量计算增加大量顶点到片元数据。
- 节点预览成功不代表生成的 GLES Shader 一定可用;最终以 WebGL/小游戏构建日志和真机画面为准。
- Shader Graph 生成的 Pass 和关键字较多时,应检查生成变体数,不以“图里节点不多”判断成本。
### 3.3 透明、深度与排序
- 透明物体默认 `ZWrite Off`,通过 Sorting Layer、Order、Render Queue 或透明排序轴控制顺序。
- 只有确实需要参与深度遮挡的透明对象才启用 `ZWrite On`,并验证半透明重叠、Alpha 边缘和粒子遮挡。
- 镂空卡片、植被和围栏优先使用 Alpha Clipping 配合深度写入,避免大面积半透明 Overdraw。
- 修改 Vertex Position 的 Z 会真实改变几何位置、裁剪和阴影,不等同于只修改透明排序。
- 2D/2.5D 场景按 Y 排序时,优先使用 Graphics Settings 的 Custom Axis 或 Renderer 排序字段;只有要与不透明物体进行真实深度测试时才映射顶点深度。
- Camera Depth Texture 和 Opaque Texture 会增加带宽或拷贝成本,只在确有深度、水体、折射或屏幕颜色需求时启用。
- 使用 Scene Depth 的透明 Shader 必须检查目标相机是否生成深度纹理,以及 Overlay Camera 是否继承了正确结果。
## 四、URP 与 Renderer 配置
- 使用单一、明确的 URP Asset 作为微信构建基线,质量等级不得无意覆盖为另一套 Render Pipeline Asset。
- 关闭未使用的主光阴影、附加光阴影、软阴影、Light Cookies、HDR、Opaque Texture、Depth Texture 和 Renderer Feature。
- Renderer Feature 必须有明确的 LayerMask、Render Queue、Pass Event 和目标 Camera;`LayerMask = 0` 的 Feature 应删除或说明保留原因。
- 开启 SRP Batcher,并用 Frame Debugger 或真机渲染分析确认材质布局兼容。
- GPU Instancing 只在相同 Mesh/Material 的重复渲染确实受益时启用;必须验证微信目标设备,不把 Editor 批次数直接当作结论。
- 移动端默认避免 Deferred;使用 Forward 或项目验证过的 Forward+ 配置。
- Render Scale、MSAA、HDR 和后处理一起评估。降低 Render Scale 往往比继续压缩单个片元 Shader 更直接,但必须验证 UI 清晰度。
## 五、Shader 变体与加载
### 5.1 变体控制
- 优先使用 `shader_feature`,只在运行时必须覆盖全部组合时使用 `multi_compile`。
- 关键字尽量限制到实际影响的 Shader Stage。
- URP Asset 中关闭未使用能力,让 URP 构建预过滤和 Shader Stripping 生效。
- 不把 URP Lit、Standard 或其他高变体 Shader 整体加入 Always Included Shaders。
- 动态启用关键字时,构建中必须存在对应材质组合或精确的 ShaderVariantCollection。
- 调试剥离问题时可以临时开启 Strict Shader Variant Matching;确认完成后再决定正式配置。
### 5.2 AssetBundle
- AssetBundle 材质使用的 Shader 必须由主包材质、精确的 ShaderVariantCollection 或经过验证的包含策略保留。
- Bundle 中的 Shader、材质和主包 URP 版本必须一致,不能混用不同 Unity/URP 版本生成的结果。
- ShaderVariantCollection 只记录真实使用组合,不把所有可能关键字做笛卡尔积。
- Bundle 卸载遵循资源管理生命周期;仍有材质或 Renderer 引用时不能假设 Shader GPU 资源已经释放。
### 5.3 首次使用卡顿
Unity 第一次渲染某个 Shader 变体时,图形驱动可能创建并上传 GPU 程序,产生可见卡顿。处理顺序:
1. 先减少无用 Shader 和变体。
2. 收集首屏、战斗、场景切换实际使用的变体。
3. 在可控加载阶段分批预热必要集合。
4. 避免一次性 WarmUp 全项目变体导致启动峰值。
5. 在微信真机记录首帧、场景首开和特效首次播放时间。
## 六、纹理、色彩与 RenderTexture
- WebGL 2 才支持可靠的 Linear 色彩空间路径;项目选择 Linear 后不得保留未经验证的 WebGL 1 回退。
- 纹理的 sRGB、Normal Map、Alpha 和压缩格式必须按用途配置,不能只靠文件名约定。
- 微信转换插件的压缩纹理功能和 Unity Texture Importer 是两层配置,启用前应确认产物格式、设备支持、下载体积和运行时内存。
- 不把 DXT 当作移动设备通用格式;ASTC、ETC2 和无压缩回退需要按微信设备覆盖范围验证。
- 压缩纹理不可用时可能发生解压或回退,导致显存和加载峰值显著增加。
- RenderTexture 的格式、MSAA、Depth Buffer 和 sRGB 必须使用目标设备支持的组合。
- 临时 RenderTexture 使用 `GetTemporary`/`ReleaseTemporary` 成对管理;长期 RenderTexture 在生命周期结束时显式释放。
- 全屏 Blit、Grab、Opaque Texture 和多层后处理按像素数消耗带宽,小游戏上应优先减少次数和分辨率。
## 七、性能预算与诊断
性能判断以真机 GPU/CPU 帧时间、内存和发热为准,不只看 Draw Call。
重点指标:
- SetPass Calls、Draw Calls、Batches。
- Triangles、Vertices。
- 透明 Overdraw 和全屏 Pass 数量。
- RenderTexture 数量、尺寸和格式。
- Shader/Material 数量和首次使用卡顿。
- URP 阴影、附加光、后处理和 Renderer Feature 成本。
- 纹理下载体积、解码峰值、CPU 内存和 GPU 估算内存。
微信转换配置提供 Render Analysis、性能分析和 Profile Stats 时,可以在诊断构建中启用;正式包是否保留以开销实测为准。
推荐定位顺序:
1. 确认设备、基础库、WebGL 版本和分辨率。
2. 确认问题属于 CPU、GPU、内存、下载还是 Shader 首次编译。
3. 用 Unity Frame Debugger/Profiler 找到 Pass、材质和 RenderTexture。
4. 用微信开发者工具和真机复现。
5. 每次只改变一类 URP 或 Shader 配置,记录前后数据。
## 八、构建与验收流程
### 8.1 构建前
- 确认 Unity、URP、Shader Graph 和微信转换插件版本。
- 确认微信转换配置启用 WebGL 2。
- 检查目标 Quality Level 和实际 URP Asset。
- 检查 Graphics Settings 的 Always Included Shaders、Preloaded Shaders、透明排序轴和剥离配置。
- 检查 URP Asset、Renderer Feature、Depth/Opaque Texture、HDR、MSAA 和 Render Scale。
- 构建日志开启 Shader Variant 统计时,记录编译前后变体数量。
### 8.2 最低验证场景
- 冷启动首屏。
- 首次打开主要 UI 和 Spine 动画。
- 首次进入每个使用独立 Shader 的场景。
- 透明 Quad、粒子、Alpha Clipping 和 UI 遮挡。
- 水体、Scene Depth、Opaque Texture 和反射效果。
- Base/Overlay Camera Stack。
- AssetBundle 首次加载、缓存命中和卸载后重新加载。
- Android 与 iOS 微信真机至少各一台中低端设备。
- 前后台切换、分辨率变化和长时间运行。
### 8.3 通过标准
- 没有粉色材质、缺失 Pass、错误关键字或不支持的 RenderTexture 格式。
- Editor、普通 WebGL 和微信小游戏的核心画面含义一致。
- 首次使用 Shader 不产生不可接受的主线程或 GPU 卡顿。
- 透明排序、深度遮挡和 Camera Stack 符合设计。
- 变体、纹理和 RenderTexture 不造成不可接受的启动或场景内存峰值。
- Unity Console、WebGL 浏览器日志、微信开发者工具和真机日志无本次新增 Shader Error。
## 九、FFCard_WeChat 当前基线
以下是项目基线,不是所有 StrayFog 项目的强制配置:
- Unity:`2022.3.29f1`。
- URP:`14.0.11`。
- Shader Graph:`14.0.11`。
- 微信转换配置:WebGL 2 开启。
- URP:SRP Batcher、Depth Texture、Opaque Texture、HDR 和 2x MSAA 开启。
- WebGL Quality Level:High。
- WebGL Static Batching、Dynamic Batching 和 Graphics Jobs 关闭。
- Graphics Settings 使用 Custom Transparency Sort Axis `(0, 0, 1)`。
- Preloaded Shaders 为空,Strict Shader Variant Matching 关闭。
- 微信压缩纹理、Render Analysis、Emscripten GLX 和 Render Thread 当前关闭。
这些配置只是后续优化的测量起点。调整前必须保存目标设备、测试场景和基线数据,调整后在微信真机对比。
## 十、外部依据
- [微信小游戏 Unity/团结引擎快适配文档](https://wechat-miniprogram.github.io/minigame-unity-webgl-transform/)
- [Unity 2022.3 WebGL](https://docs.unity3d.com/cn/2022.3/Manual/webgl.html)
- [Unity 2022.3 WebGL Graphics](https://docs.unity3d.com/2022.3/Documentation/Manual/webgl-graphics.html)
- [Unity Shader Variant Stripping](https://docs.unity3d.com/cn/2022.3/Manual/shader-variant-stripping.html)
- [Unity Shader Loading](https://docs.unity3d.com/cn/2022.3/Manual/shader-loading.html)
- [Unity Graphics Settings](https://docs.unity3d.com/cn/2022.3/Manual/class-GraphicsSettings.html)
## 十一、文档关联
| 文档 | 关联原因 |
|---|---|
| [FFCard_WeChat 卡牌 Shader 框架](../../business-reference/ffcard-wechat/卡牌Shader框架.md) | 本规则在 FFCard_WeChat 中的卡牌业务实现 |
| [微信小游戏资源接入方案](资源管理/微信小游戏资源接入方案.md) | Shader、材质和 AssetBundle 的加载与卸载边界 |
| [相机系统](相机系统/README.md) | URP Camera Stack 和渲染顺序 |
| [第三方插件](第三方插件.md) | Spine、UI 特效和微信转换插件的 Shader 风险 |
| [工作流清单](../../rules/40-工作流清单.md) | Unity、平台与真机验证流程 |
| [开发规则](../../rules/20-开发规则.md) | 平台、资源和生成代码约束 |