A for loop, unless inside a coroutine with a yield statement in the loop body, will execute and complete all within the same frame. Actually if you would “delay” the execution of your for loop, the game couldn’t preceed and would freeze for this time since the current frame can only be completed when your callbacks are completed.
Coroutines are a different story since they are not methods but statemachine objects. They can actually yield the control back to Unity so Unity can complete the current frame. Unity will then automatically continue your coroutine when it’s time (based on what object you have yielded).
Keep in mind that your current setup will loop to one blendshape at a time and bring the weight down to 0. So if one blend shape takes lets say 2 seconds to reach 0, all 15 blend shapes would take 30 seconds. If you want to bring them down to 0 all at the same time, you should exchange the two for loops (So i is nested in j) and yield inside j and not the innermost loop.
Something like this:
IEnumerator ResetBlendshapes()
{
for(int i = 0; i < 15; i++)
{
for(float j = 100; j >= 0; j -= 20 * Time.deltaTime)
{
skinnedMeshRenderer.SetBlendShapeWeight(i, j);
yield return null;
}
skinnedMeshRenderer.SetBlendShapeWeight(i, 0);
}
}
Just call StartCoroutine(ResetBlendshapes());
once and it will loop through all blendshapes one by one and bring them down gradually. Note the time it takes for this coroutine to complete is 5 seconds per blendshape (since we go down 20 weight per second → 5 seconds to reach 0 from 100) and therefore it takes 1 minute and 15 seconds to complete all 16 blendshapes.
If you want to bring those 15 blendshapes down simultaneously, just switch the to loops as I said:
IEnumerator ResetBlendshapes()
{
for(float j = 100; j >= 0; j -= 20 * Time.deltaTime)
{
for(int i = 0; i < 15; i++)
{
skinnedMeshRenderer.SetBlendShapeWeight(i, j);
}
yield return null;
}
for(int i = 0; i < 15; i++)
{
skinnedMeshRenderer.SetBlendShapeWeight(i, 0);
}
}
This time the whole coroutine only takes 5 seconds in total. Each frame all 15 blend shapes are set to the same weight. So at the start they all have a weight at 100, after about 2.5 seconds they have all a weight of 50 and when the coroutine is completed they are all down at 0.
Note that the single line skinnedMeshRenderer.SetBlendShapeWeight(i, 0);
is necessary since your j loop does not bring the weight down to 0. The loop will end when j is equal or smaller than 0, so that last weight is never set otherwise. For example the previous j value could be 0.2. At a framerate of 60 fps we would subtract about 0.33 each frame. So we would get about -0.16 which is smaller than 0 so the loop ends. Though the last set weight was 0.2. That’s why we will explicitly set the weight to 0 at the end.