Unity's Timeline function brightens up the production of games, but have you ever been bothered by a small freeze (processing slow spike) where the screen suddenly stops at the moment the Timeline is played for the first time, such as in a special move activation cut scene or a boss appearance production? This is a problem that tends to be ignored because it is difficult to identify the cause of the problem because the second time it is played back, or when the same performance is played in a loop, it runs smoothly as if nothing had happened. However, for the player, when the screen gets stuck during the ``first step of the production that you want to make look cool'', it can be considered a serious bug that significantly reduces the value of the game's experience. In this article, we will explain the internal mechanism that causes this first-time playback spike, using an easy-to-understand analogy of ``backstage at a theater,'' even for beginners, and present solutions and checklists that can be used immediately in practice.
1. Understand with an analogy: ``The opening bell of a theater and the wardrobe staff in a hurry''
To understand the essence of this problem, let's imagine that ``the moment the opening bell of a theater rings, actors are hurriedly sewing costumes backstage or assembling stage sets with manual labor.''
The theater audience (players) took their seats and the opening bell (Timeline started playing) rang. The moment the curtain went up, there was a huge panic behind the stage (GPU/CPU). The gorgeous costumes (shaders) that the actors (effects) are supposed to wear are still in the form of patterns, and the costumers (compilers) use sewing machines at full speed to sew them together on the spot. The props staff (particle calculations) have also been hurriedly assembling the clouds and sparks (particles) for the background since the play began. Naturally, there will be unnatural silence and sluggishness (decreased frame rate) in the first few seconds of the play. However, once the play begins, the costumes are complete and the tools have been assembled, so the second performance (second loop) will proceed smoothly without any problems.
This is the true nature of 'first play spike' in Timeline. Because they didn't do the "preparation" of putting on costumes and standing by (warming up) in the wings of the stage in advance, all the workload was concentrated at the moment the actual performance started.
2. Root cause: Shader compilation and Shuriken prewarm load
Technically speaking, the main factors causing this spike can be broadly divided into the following two:
Cause 1: GPU shader compilation (PSO construction)
Unity compiles the shader of the material used for the effect into a format that the GPU can understand through the graphics API (Vulkan, Metal, DirectX, etc.) the moment it is first drawn on the screen (or the moment it enters the field of view of the camera). This compilation process is extremely expensive and locks up the main thread momentarily. This is the biggest reason why "it gets lighter the second time around" (because once a shader is compiled, it is cached in memory).
Cause 2: Prewarm (pre-simulation) of Shuriken Particle System
The particle system has a useful feature called "Prewarm" that allows you to start playing with particles already spread across the screen. However, when a Prewarm-enabled particle is activated by a Timeline control track, Unity **burstly calculates the physics simulation of the particle's ``several seconds of life'' on the CPU within the first frame of playback.** For example, if 100 particles are generated per second and the lifespan is 3 seconds, 300 coordinate calculations will be performed in the first frame, and the CPU thread will be completely exhausted.
3. Specific solution and C# implementation steps
Approach A: Shader warmup using ShaderVariantCollection
The most important thing is "Shader Warmup", which compiles the shader of the effect to be used when loading the game or during a dark scene transition. Use Unity's `ShaderVariantCollection` to pre-warm it.
using UnityEngine;
public class ShaderWarmupController : MonoBehaviour
{
[SerializeField] private ShaderVariantCollection targetCollection;
void Start()
{
if (targetCollection != null)
{
// Called at loading screen or scene transition
targetCollection.WarmUp();
Debug.Log("Pre-compilation of all registered shader variants has been completed.");
}
}
}
Approach B: Asynchronous prewarm with "force 1 frame evaluation" before Timeline playback
Before the effect appears on camera, hide the spike in the loading screen by activating the Timeline object, advancing the playhead by one frame, and calling `Evaluate`. This prevents stuttering during gameplay.
using UnityEngine;
using UnityEngine.Playables;
public class TimelinePrewarm : MonoBehaviour
{
[SerializeField] private PlayableDirector director;
void Awake()
{
if (director != null)
{
// 1. Activate the object once and prepare for playback
director.gameObject.SetActive(true);
// 2. Set the timeline time to a minimum value (or 0)
director.time = 0.0;
// 3. Force evaluate graphics and particles for one frame
// This will trigger internal particle generation and shader loading at this point
director.Evaluate();
// 4. If autoplay is turned off, leave it paused until needed
director.Pause();
Debug.Log("Timeline's first dummy evaluation prewarm was successful.");
}
}
public void PlayTimeline()
{
if (director != null)
{
director.Play();
}
}
}
4. Performance Checklist for Practical Use
When incorporating particles into Timeline, be sure to follow the settings below as workflow rules.
| Check items | Settings to check | Countermeasure actions |
|---|---|---|
| Check Prewarm settings | Particle System -> Prewarm | If you don't need it, be sure to turn it off. If necessary, use Evaluate() in advance using C#. |
| Maximum number of particles limit | Max Particles | Do not leave it at the default 1000, but limit it to the minimum number necessary for the production (e.g. 50, etc.). |
| Shader preloading | ShaderVariantCollection | Register the effect shader as an asset in the build settings and WarmUp() at startup or scene load. |