You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Describe the bug
When loading models with animation at runtime, I'm seeing rather large spikes in time
The issue is that AnimationCurve.AddKey does a sort every time you call it. I get a 2x speedup by allocating arrays and then doing new AnimationCurve(keys); Unfortunately, that is a lot of extra allocations. However, on Unity 6, one can use ArrayPool.Shared.Rent and then use AnimationCurve.SetKeys and use AsSpan on the rented arrays.
Example Fix:
This is a non-unity 6 fix with the tradeoff being an increase in memory:
static void AddVec3Curves(AnimationClip clip, string animationPath, string propertyPrefix, NativeArray<float> times, NativeArray<float3> values, InterpolationType interpolationType) {
Profiler.BeginSample("AnimationUtils.AddVec3Curves");
var keysX = ArrayPool<Keyframe>.Shared.Rent(times.Length);
var keysY = ArrayPool<Keyframe>.Shared.Rent(times.Length);
var keysZ = ArrayPool<Keyframe>.Shared.Rent(times.Length);
int actualCount;
#if DEBUG
uint duplicates = 0;
#endif
switch (interpolationType) {
case InterpolationType.Step: {
for (var i = 0; i < times.Length; i++) {
var time = times[i];
var value = values[i];
keysX[i] = new Keyframe(time, value.x, float.PositiveInfinity, 0);
keysY[i] = new Keyframe(time, value.y, float.PositiveInfinity, 0);
keysZ[i] = new Keyframe(time, value.z, float.PositiveInfinity, 0);
}
actualCount = times.Length;
break;
}
case InterpolationType.CubicSpline: {
for (var i = 0; i < times.Length; i++) {
var time = times[i];
var inTangent = values[i*3];
var value = values[i*3 + 1];
var outTangent = values[i*3 + 2];
keysX[i] = new Keyframe(time, value.x, inTangent.x, outTangent.x, .5f, .5f);
keysY[i] = new Keyframe(time, value.y, inTangent.y, outTangent.y, .5f, .5f);
keysZ[i] = new Keyframe(time, value.z, inTangent.z, outTangent.z, .5f, .5f);
}
actualCount = times.Length;
break;
}
default: { // LINEAR
var prevTime = times[0];
var prevValue = values[0];
var inTangent = new float3(0f);
actualCount = 0;
for (var i = 1; i < times.Length; i++) {
var time = times[i];
var value = values[i];
if (prevTime >= time) {
// Time value is not increasing, so we ignore this keyframe
// This happened on some Sketchfab files (see #298)
#if DEBUG
duplicates++;
#endif
continue;
}
var dT = time - prevTime;
var dV = value - prevValue;
float3 outTangent;
if (dT < k_TimeEpsilon) {
bool dTNeg = dT < 0f;
outTangent.x = (dV.x < 0f) ^ dTNeg ? float.NegativeInfinity : float.PositiveInfinity;
outTangent.y = (dV.y < 0f) ^ dTNeg ? float.NegativeInfinity : float.PositiveInfinity;
outTangent.z = (dV.z < 0f) ^ dTNeg ? float.NegativeInfinity : float.PositiveInfinity;
} else {
outTangent = dV / dT;
}
keysX[actualCount] = new Keyframe(prevTime, prevValue.x, inTangent.x, outTangent.x);
keysY[actualCount] = new Keyframe(prevTime, prevValue.y, inTangent.y, outTangent.y);
keysZ[actualCount] = new Keyframe(prevTime, prevValue.z, inTangent.z, outTangent.z);
actualCount++;
inTangent = outTangent;
prevTime = time;
prevValue = value;
}
keysX[actualCount] = new Keyframe(prevTime, prevValue.x, inTangent.x, 0);
keysY[actualCount] = new Keyframe(prevTime, prevValue.y, inTangent.y, 0);
keysZ[actualCount] = new Keyframe(prevTime, prevValue.z, inTangent.z, 0);
actualCount++;
break;
}
}
AnimationCurve curveX;
AnimationCurve curveY;
AnimationCurve curveZ;
if (actualCount != keysX.Length || actualCount != keysY.Length || actualCount != keysZ.Length)
{
// AnimationCurve requires an exact-length array; one allocation shared across all three copies.
Keyframe[] tempKeys = new Keyframe[actualCount];
Array.Copy(keysX, tempKeys, actualCount);
curveX = new AnimationCurve(tempKeys);
Array.Copy(keysY, tempKeys, actualCount);
curveY = new AnimationCurve(tempKeys);
Array.Copy(keysZ, tempKeys, actualCount);
curveZ = new AnimationCurve(tempKeys);
}
else // exact match, just straight up use the rented arrays without copying
{
curveX = new AnimationCurve(keysX);
curveY = new AnimationCurve(keysY);
curveZ = new AnimationCurve(keysZ);
}
ArrayPool<Keyframe>.Shared.Return(keysX);
ArrayPool<Keyframe>.Shared.Return(keysY);
ArrayPool<Keyframe>.Shared.Return(keysZ);
clip.SetCurve(animationPath, typeof(Transform), $"{propertyPrefix}x", curveX);
clip.SetCurve(animationPath, typeof(Transform), $"{propertyPrefix}y", curveY);
clip.SetCurve(animationPath, typeof(Transform), $"{propertyPrefix}z", curveZ);
Files
Attach or link to .gltf/.glb files that trigger the bug.
In addition, make sure to run those files through the glTF Validator first. If you encounter errors or warnings, try to make sure they are not responsible for the issue and file a bug report with the software that generated the glTF file as well.
Tip
You have to ZIP archive them first in order for GitHub to accept the upload.
If your files are confidential:
Try to create a similar, but intellectual-property-free glTF that reproduces the bug in the same way (so any community member can have a look)
Otherwise, still create this issue and send the files (or a link to them) discretely via email
To Reproduce
Steps to reproduce the behavior:
Go to '...'
Click on '....'
Scroll down to '....'
See error
Expected behavior
A clear and concise description of what you expected to happen.
Screenshots
If applicable, add screenshots to help explain your problem.
Desktop (please complete the following information):
glTFast version
Unity Editor version [e.g. 2021.2.1f1]
Render Pipeline and version [e.g. Universal Render Pipeline 12.0]
Platform: [e.g. Editor, Windows Player, iOS]
additionally (if significant for the bug):
Device: [e.g. iPhone6]
OS: [e.g. iOS8.1]
For WebGL: Browser [e.g. stock browser, safari]
Additional context
Add any other context about the problem here.
Describe the bug
When loading models with animation at runtime, I'm seeing rather large spikes in time
The issue is that AnimationCurve.AddKey does a sort every time you call it. I get a 2x speedup by allocating arrays and then doing new AnimationCurve(keys); Unfortunately, that is a lot of extra allocations. However, on Unity 6, one can use ArrayPool.Shared.Rent and then use AnimationCurve.SetKeys and use AsSpan on the rented arrays.
Example Fix:
This is a non-unity 6 fix with the tradeoff being an increase in memory:
#if DEBUG
uint duplicates = 0;
#endif
#if DEBUG
duplicates++;
#endif
continue;
}
Files
Attach or link to .gltf/.glb files that trigger the bug.
In addition, make sure to run those files through the glTF Validator first. If you encounter errors or warnings, try to make sure they are not responsible for the issue and file a bug report with the software that generated the glTF file as well.
Tip
You have to ZIP archive them first in order for GitHub to accept the upload.
If your files are confidential:
To Reproduce
Steps to reproduce the behavior:
Expected behavior
A clear and concise description of what you expected to happen.
Screenshots
If applicable, add screenshots to help explain your problem.
Desktop (please complete the following information):
additionally (if significant for the bug):
Additional context
Add any other context about the problem here.