# 微信小游戏渲染规则 ## 一、定位与适用范围 本文档定义 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) | 平台、资源和生成代码约束 |