Reputation: 35
I use coroutines for my animation work. And I must be sure that timings are perfect. For example I need to increase value overtime.I set time and stepCount to perform this. My code looks like this:
IEnumerator ScaleDown(float time)
{
print(Time.time);
float value = 0f;
float deltaValue = 1 / (stepCount*time);
float deltaTime = 1/stepCount;
while (value < 1f)
{
value += deltaValue;
meshRenderer.SetBlendShapeWeight(1, value * 100f);
yield return new WaitForSeconds(deltaTime);
}
print(Time.time);
}
So when I set time=1f and stepCount=1 then real time between start and end print are 1 second. But when I increase stepCount to 100 or more keeping time=1, then real time is more then 1 second. Something about ~1.67f
So I have question: How can I use coroutines with specific stepCount and have perfect timing? I use stepCount for more smooth transition on blenshapes, shader variables like opacity. And must use stepCount>=100.
Upvotes: 0
Views: 1046
Reputation: 90739
I use stepCount for more smooth transition on blenshapes, shader variables like opacity. And must use stepCount>=100.
These steps shall all happen in 1
second ... but:
Your code runs with a certain framerate optimal about 60 f/s
(on a PC and within the editor mostly higher) which results in a "standard" Time.deltaTime
of about 0.017 seconds
between two frames!
yield return new WaitForSeconds(XY);
or in general anything using yield
waits at least for one frame!
So of course your functionality breaks as soon as deltaTime
becomes smaller then the actual possible framerate and real time between two frames. Especially for example when you say you want this to be executed >=100
times per second.
It also makes no sense to update a value more often then the framerate since no changes will be ever noted by the user faster then the frames are actually rendered.
Additionally SetBlendShapeWeight
might be a performance intense call (don't know to be honest) so it might also slow down the execution causing additional lag.
How can I use coroutines with specific stepCount and have perfect timing
Beyond a certain limit you just can't.
But why do you need/want to use fixed steps for the value
at all?
Since value
is a float
and what it seems you actually want is rather a smooth transition you could simply do
IEnumerator ScaleDown(float duration)
{
print(Time.time);
timePassed = 0f;
do
{
// a linear interpolated value between 0 and 1
var value = timePassed / duration;
// optionaly you could even add some ease-in and ease-out
//value = SmoothStep(0, 1, value);
meshRenderer.SetBlendShapeWeight(1, value * 100f);
// increase by the time passed since last frame
// to avoid overshooting use Mathf.Min with the remaining difference
// between duration and passedTime
timePassed += Mathf.Min(duration - timePassed, Time.deltaTime);
yield return null;
} while (timePassed < duration);
print(Time.time);
}
I you still want to fake it the other way round and make it update in fixed steps for stepCount
< framerate you could simply round the smoothly transitioned values to that value like e.g.
value = Mathf.Round(value / deltaValue)) * deltaValue;
which should round up or down to the next full step of deltaValue
.
Also note that in newer Unity versions the SetBlendShapeWeight
is not automatically limited to the range [0; 100]
anymore as it was in previous versions.
Though, most 3D modelling programs export models with the range [0;100]
in Unity
The BlendShape weight range includes values between the minimum and the maximum weights defined in the model.
Upvotes: 0