UnityGLTF icon indicating copy to clipboard operation
UnityGLTF copied to clipboard

GLTF/GLB with multiple Animations Doesn't work

Open KhizarAziz opened this issue 6 years ago • 7 comments

Using GLTFComponent Script to Load GLB from Assets... I tried several files which contain some animations..... *File which contained only 1 animation loaded fine. an example file is robot.glb.zip

*Files which contained more animations didn't loaded. : e.g Bee.glb.zip

I got these Errors:

Errors

Error 1. (IndexOutOfRangeException: Index was outside the bounds of the array.) in Code Below

private static void SetTangentMode(AnimationCurve curve, int keyframeIndex, InterpolationType interpolation)
		{
			var key = curve.keys[keyframeIndex]; // On this line
			switch (interpolation)
			{
				case InterpolationType.CATMULLROMSPLINE:
					key.inTangent = 0;
					key.outTangent = 0;
					break;
				case InterpolationType.LINEAR:
					key.inTangent = GetCurveKeyframeLeftLinearSlope(curve, keyframeIndex);
					key.outTangent = GetCurveKeyframeLeftLinearSlope(curve, keyframeIndex + 1);
					break;
				case InterpolationType.STEP:
					key.inTangent = float.PositiveInfinity;
					key.outTangent = float.PositiveInfinity;
					break;
				default:
					throw new NotImplementedException();
			}
			curve.MoveKey(keyframeIndex, key);			
		}

Error 2: (Unity does not allow you to put two keyframes in with the same time, so this should never occur) In Code Below:

private static float GetCurveKeyframeLeftLinearSlope(AnimationCurve curve, int keyframeIndex)
		{
			if (keyframeIndex <= 0 || keyframeIndex >= curve.keys.Length)
			{
				return 0;
			}
			var valueDelta = curve.keys[keyframeIndex].value - curve.keys[keyframeIndex - 1].value;
			var timeDelta = curve.keys[keyframeIndex].time - curve.keys[keyframeIndex - 1].time;
			Debug.Assert(timeDelta > 0, "Unity does not allow you to put two keyframes in with the same time, so this should never occur.");

			return valueDelta / timeDelta;
		}

Issue Details: So basically the problem is when i try to load the file with more than 1 animations, UnityGLTF cant load it. and it crashes on line "var key = curve.keys[keyframeIndex];" in method named "SetTangentMode()" in script "GLTFSceneImporter.cs."

I tried to debug, and the error is due to the array "curve.key[]" because the length of this array is being reduced in size after some iterations in loop. i couldn't figure out why... e.g initially it's length was 34, but after 8th iteration.. the size becomes 33... and after a while 32.... i have no clue why... and when the loop tries to access the 33th index.... its fails.

you can reproduce the error by using the attached files below.

Bee.glb.zip blue_whale_-_textured.zip wolf.glb.zip

KhizarAziz avatar Aug 04 '19 22:08 KhizarAziz

Has anyone got a fix for this? I have been trying for multiple animations and it's not going anywhere.Only one is getting played from many animations on load of .gltf file.

supriyarasal avatar Sep 25 '19 14:09 supriyarasal

I am also facing this issue.

ravip avatar Sep 27 '19 06:09 ravip

I am using a different GLTF loader written by a third party and it can import all animations

HenkHull avatar Sep 30 '19 14:09 HenkHull

HenkHull, what loader are you using?

jmo7 avatar Oct 04 '19 21:10 jmo7

@HenkHull I would also be interested to hear how you integrated a third-party loader within UnityGLTF.

nodermatt avatar Nov 25 '19 08:11 nodermatt

Hi! I came across the same problem a few weeks ago and as I don't see any other solution this is my approach: As @khizerawan commented "the error is due to the array "curve.key[]" because the length of this array is being reduced in size after some iterations in loop". That's because according to Unity documentation "If a keyframe already exists at key.time, then the time of the old keyframe's position key[index].time will be used instead" https://docs.unity3d.com/ScriptReference/AnimationCurve.MoveKey.html so whenever two keyframes share the same time, it discards one of them and the array shrinks one size. To solve it, I've just added a quick check to verify key.inTangent and key.outTangent values are not NaN or Infinite (divided by zero in GetCurveKeyframeLeftLinearSlope) before the curve.MoveKey().

private static void SetTangentMode(AnimationCurve curve, Keyframe[] keyframes, int keyframeIndex, InterpolationType interpolation)
        {
            ...

            if (!float.IsNaN(key.inTangent) && !float.IsNaN(key.outTangent) && !float.IsInfinity(key.inTangent) && !float.IsInfinity(key.outTangent))
                 curve.MoveKey(keyframeIndex, key);
        }

I don't know if there is a better solution out there but I've tested with a couple of models and they work now :)

enaraartetxe avatar Jun 16 '20 12:06 enaraartetxe

Hi.

I tested this fix, that's also work for the models I have. Thank you for that.

Is there an official fix or maybe you can create a PR ?

Best, Eric

Please update to the latest version and open a new issue if the problem persists. Thanks!

robertdorn83 avatar Feb 09 '24 08:02 robertdorn83