diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/AnimationIO/AnimationImporterUtil.cs b/Assets/UniGLTF/Runtime/UniGLTF/IO/AnimationIO/AnimationImporterUtil.cs index 8c38c23a3..a1bcb52ec 100644 --- a/Assets/UniGLTF/Runtime/UniGLTF/IO/AnimationIO/AnimationImporterUtil.cs +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/AnimationIO/AnimationImporterUtil.cs @@ -1,7 +1,9 @@ using System; using System.Linq; using System.Collections.Generic; +using System.Threading.Tasks; using UnityEngine; +using VRMShaders; namespace UniGLTF { @@ -41,6 +43,7 @@ namespace UniGLTF { return; } + if (current < keyframes.Count) { var rightTangent = (keyframes[current].value - keyframes[back].value) / (keyframes[current].time - keyframes[back].time); @@ -61,10 +64,10 @@ namespace UniGLTF { return new Quaternion(-rot.x, -rot.y, -rot.z, -rot.w); } - } public delegate float[] ReverseFunc(float[] current, float[] last); + public static void SetAnimationCurve( AnimationClip targetClip, string relativePath, @@ -89,6 +92,7 @@ namespace UniGLTF { last[3] = 1.0f; } + for (inputIndex = 0; inputIndex < input.Length; ++inputIndex) { var time = input[inputIndex]; @@ -101,6 +105,7 @@ namespace UniGLTF { value[i] = output[outputIndex + elementNum + i]; } + var reversed = reverse(value, last); last = reversed; for (int i = 0; i < keyframes.Length; i++) @@ -122,6 +127,7 @@ namespace UniGLTF { value[i] = output[outputIndex + i]; } + var reversed = reverse(value, last); last = reversed; @@ -185,7 +191,8 @@ namespace UniGLTF return string.Join("/", path); } - public static AnimationClip ConvertAnimationClip(GltfData data, glTFAnimation animation, IAxisInverter inverter, glTFNode root = null) + public static async Task ConvertAnimationClipAsync(GltfData data, glTFAnimation animation, + IAxisInverter inverter, IAwaitCaller awaitCaller, glTFNode root = null) { var clip = new AnimationClip(); clip.ClearCurves(); @@ -199,120 +206,139 @@ namespace UniGLTF switch (channel.target.path) { case glTFAnimationTarget.PATH_TRANSLATION: - { - var sampler = animation.samplers[channel.sampler]; - var input = data.GetArrayFromAccessor(sampler.input); - var output = data.FlatternFloatArrayFromAccessor(sampler.output); - - AnimationImporterUtil.SetAnimationCurve( - clip, - relativePath, - new string[] { "localPosition.x", "localPosition.y", "localPosition.z" }, - input.ToArray(), - output.ToArray(), - sampler.interpolation, - typeof(Transform), - (values, last) => - { - Vector3 temp = new Vector3(values[0], values[1], values[2]); - return inverter.InvertVector3(temp).ToArray(); - } - ); - } + SetTranslationAnimationCurve(data, animation, inverter, channel, clip, relativePath); break; - case glTFAnimationTarget.PATH_ROTATION: - { - var sampler = animation.samplers[channel.sampler]; - var input = data.GetArrayFromAccessor(sampler.input); - var output = data.FlatternFloatArrayFromAccessor(sampler.output); - - AnimationImporterUtil.SetAnimationCurve( - clip, - relativePath, - new string[] { "localRotation.x", "localRotation.y", "localRotation.z", "localRotation.w" }, - input.ToArray(), - output.ToArray(), - sampler.interpolation, - typeof(Transform), - (values, last) => - { - Quaternion currentQuaternion = new Quaternion(values[0], values[1], values[2], values[3]); - Quaternion lastQuaternion = new Quaternion(last[0], last[1], last[2], last[3]); - return AnimationImporterUtil.GetShortest(lastQuaternion, inverter.InvertQuaternion(currentQuaternion)).ToArray(); - } - ); - - clip.EnsureQuaternionContinuity(); - } + SetRotationAnimationCurve(data, animation, inverter, channel, clip, relativePath); break; - case glTFAnimationTarget.PATH_SCALE: - { - var sampler = animation.samplers[channel.sampler]; - var input = data.GetArrayFromAccessor(sampler.input); - var output = data.FlatternFloatArrayFromAccessor(sampler.output); - - AnimationImporterUtil.SetAnimationCurve( - clip, - relativePath, - new string[] { "localScale.x", "localScale.y", "localScale.z" }, - input.ToArray(), - output.ToArray(), - sampler.interpolation, - typeof(Transform), - (values, last) => values); - } + SetScaleAnimationCurve(data, animation, channel, clip, relativePath); break; - case glTFAnimationTarget.PATH_WEIGHT: - { - var node = data.GLTF.nodes[channel.target.node]; - var mesh = data.GLTF.meshes[node.mesh]; - var primitive = mesh.primitives.FirstOrDefault(); - var targets = primitive.targets; - - if (!gltf_mesh_extras_targetNames.TryGet(mesh, out List targetNames)) - { - throw new UniGLTFNotSupportedException("glTF BlendShape Animation. targetNames invalid."); - } - - var keyNames = targetNames - .Where(x => !string.IsNullOrEmpty(x)) - .Select(x => "blendShape." + x) - .ToArray(); - - var sampler = animation.samplers[channel.sampler]; - var input = data.GetArrayFromAccessor(sampler.input); - var output = data.GetArrayFromAccessor(sampler.output); - AnimationImporterUtil.SetAnimationCurve( - clip, - relativePath, - keyNames, - input.ToArray(), - output.ToArray(), - sampler.interpolation, - typeof(SkinnedMeshRenderer), - (values, last) => - { - for (int j = 0; j < values.Length; j++) - { - values[j] *= 100.0f; - } - return values; - }); - - } + SetBlendShapeAnimationCurve(data, animation, channel, clip, relativePath); break; - default: Debug.LogWarningFormat("unknown path: {0}", channel.target.path); break; } + + await awaitCaller.NextFrameIfTimedOut(); } + return clip; } + private static void SetTranslationAnimationCurve(GltfData data, glTFAnimation animation, IAxisInverter inverter, + glTFAnimationChannel channel, AnimationClip clip, string relativePath) + { + var sampler = animation.samplers[channel.sampler]; + var input = data.GetArrayFromAccessor(sampler.input); + var output = data.FlatternFloatArrayFromAccessor(sampler.output); + + AnimationImporterUtil.SetAnimationCurve( + clip, + relativePath, + new string[] { "localPosition.x", "localPosition.y", "localPosition.z" }, + input.ToArray(), + output.ToArray(), + sampler.interpolation, + typeof(Transform), + (values, last) => + { + Vector3 temp = new Vector3(values[0], values[1], values[2]); + return inverter.InvertVector3(temp).ToArray(); + } + ); + } + + private static void SetRotationAnimationCurve(GltfData data, glTFAnimation animation, IAxisInverter inverter, + glTFAnimationChannel channel, AnimationClip clip, string relativePath) + { + var sampler = animation.samplers[channel.sampler]; + var input = data.GetArrayFromAccessor(sampler.input); + var output = data.FlatternFloatArrayFromAccessor(sampler.output); + + AnimationImporterUtil.SetAnimationCurve( + clip, + relativePath, + new string[] { "localRotation.x", "localRotation.y", "localRotation.z", "localRotation.w" }, + input.ToArray(), + output.ToArray(), + sampler.interpolation, + typeof(Transform), + (values, last) => + { + Quaternion currentQuaternion = new Quaternion(values[0], values[1], values[2], values[3]); + Quaternion lastQuaternion = new Quaternion(last[0], last[1], last[2], last[3]); + return AnimationImporterUtil + .GetShortest(lastQuaternion, inverter.InvertQuaternion(currentQuaternion)) + .ToArray(); + } + ); + + clip.EnsureQuaternionContinuity(); + } + + + private static void SetScaleAnimationCurve(GltfData data, glTFAnimation animation, glTFAnimationChannel channel, + AnimationClip clip, string relativePath) + { + var sampler = animation.samplers[channel.sampler]; + var input = data.GetArrayFromAccessor(sampler.input); + var output = data.FlatternFloatArrayFromAccessor(sampler.output); + + AnimationImporterUtil.SetAnimationCurve( + clip, + relativePath, + new string[] { "localScale.x", "localScale.y", "localScale.z" }, + input.ToArray(), + output.ToArray(), + sampler.interpolation, + typeof(Transform), + (values, last) => values); + } + + private static void SetBlendShapeAnimationCurve(GltfData data, glTFAnimation animation, + glTFAnimationChannel channel, + AnimationClip clip, string relativePath) + { + var node = data.GLTF.nodes[channel.target.node]; + var mesh = data.GLTF.meshes[node.mesh]; + var primitive = mesh.primitives.FirstOrDefault(); + var targets = primitive.targets; + + if (!gltf_mesh_extras_targetNames.TryGet(mesh, out List targetNames)) + { + throw new UniGLTFNotSupportedException("glTF BlendShape Animation. targetNames invalid."); + } + + var keyNames = targetNames + .Where(x => !string.IsNullOrEmpty(x)) + .Select(x => "blendShape." + x) + .ToArray(); + + var sampler = animation.samplers[channel.sampler]; + var input = data.GetArrayFromAccessor(sampler.input); + var output = data.GetArrayFromAccessor(sampler.output); + AnimationImporterUtil.SetAnimationCurve( + clip, + relativePath, + keyNames, + input.ToArray(), + output.ToArray(), + sampler.interpolation, + typeof(SkinnedMeshRenderer), + (values, last) => + { + for (int j = 0; j < values.Length; j++) + { + values[j] *= 100.0f; + } + + return values; + }); + } + public static IEnumerable EnumerateSubAssetKeys(glTF gltf) { foreach (var gltfAnimation in gltf.animations) @@ -321,4 +347,4 @@ namespace UniGLTF } } } -} +} \ No newline at end of file diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/ImporterContext.cs b/Assets/UniGLTF/Runtime/UniGLTF/IO/ImporterContext.cs index 23aba44ba..2a72caeac 100644 --- a/Assets/UniGLTF/Runtime/UniGLTF/IO/ImporterContext.cs +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/ImporterContext.cs @@ -136,10 +136,7 @@ namespace UniGLTF foreach (var (key, gltfAnimation) in Enumerable.Zip(AnimationImporterUtil.EnumerateSubAssetKeys(GLTF), GLTF.animations, (x, y) => (x, y))) { await AnimationClipFactory.LoadAnimationClipAsync(key, () => - { - var clip = AnimationImporterUtil.ConvertAnimationClip(Data, gltfAnimation, InvertAxis.Create()); - return Task.FromResult(clip); - }); + AnimationImporterUtil.ConvertAnimationClipAsync(Data, gltfAnimation, InvertAxis.Create(), awaitCaller)); } await awaitCaller.NextFrame();