GameTech/URP 渲染实战

案例 29.3用 ShaderVariantCollection 分帧预热入门

Shader 变体在运行时第一次被用到时,驱动才会把它编译成 GPU 指令(尤其在 OpenGL ES、Vulkan 这类驱动编译开销大的平台),表现为第一次放技能、第一次进入某个场景时卡一下。解决办法是在加载界面里提前“用一下”这些变体,称为预热(Warmup)。

  1. 在编辑器里把游戏完整跑一遍(尽量覆盖所有效果),然后在 Edit › Project Settings › Graphics 底部的 Shader Loading 区域点击 Save to asset,得到一个 ShaderVariantCollection 资源,里面记录了这次运行中用到的变体。
  2. 把它交给下面的组件,在加载界面分帧预热。
Assets/Cookbook/Ch29/ShaderWarmup.cs(节选:warmup)
IEnumerator Start()
{
    foreach (var svc in collections)
    {
        if (svc == null) continue;
        // WarmUpProgressively 每次预热指定数量的变体,全部完成时返回 true
        while (!svc.WarmUpProgressively(variantsPerFrame))
            yield return null;
        Debug.Log($"[ShaderWarmup] {svc.name}: {svc.warmedUpVariantCount}/{svc.variantCount} variants");
    }
    onFinished?.Invoke();
}

WarmUpProgressively(n) 每次只预热 n 个变体,全部完成时返回 true,配合协程就能把预热摊到多帧,不至于让加载界面本身卡死。需要注意:在 Vulkan、Metal、D3D12 这类现代图形 API 上,“编译好的 GPU 程序”还和渲染状态(顶点格式、混合、渲染目标格式)有关,只用 WarmUp 不一定能完全消除首次卡顿;Unity 2022.3 提供了实验性的 UnityEngine.Experimental.Rendering.ShaderWarmup.WarmupShader,可以按指定的顶点布局预热,具体效果以实际版本和平台为准。