diff --git a/Assets/UniGLTF/Runtime/Extensions/glTFExtensions.cs b/Assets/UniGLTF/Runtime/Extensions/glTFExtensions.cs index 7551e18e63..02edf3e123 100644 --- a/Assets/UniGLTF/Runtime/Extensions/glTFExtensions.cs +++ b/Assets/UniGLTF/Runtime/Extensions/glTFExtensions.cs @@ -316,6 +316,35 @@ public static T[] GetArrayFromAccessor<T>(this glTF self, int accessorIndex) whe return result; } + public static float[] GetFloatArrayFromAccessor(this glTF self, int accessorIndex) + { + var vertexAccessor = self.accessors[accessorIndex]; + + if (vertexAccessor.count <= 0) return new float[] { }; + + var bufferCount = vertexAccessor.count * vertexAccessor.TypeCount; + var result = (vertexAccessor.bufferView != -1) + ? self.GetAttrib<float>(bufferCount, vertexAccessor.byteOffset, self.bufferViews[vertexAccessor.bufferView]) + : new float[bufferCount] + ; + + var sparse = vertexAccessor.sparse; + if (sparse != null && sparse.count > 0) + { + // override sparse values + var indices = self._GetIndices(self.bufferViews[sparse.indices.bufferView], sparse.count, sparse.indices.byteOffset, sparse.indices.componentType); + var values = self.GetAttrib<float>(sparse.count * vertexAccessor.TypeCount, sparse.values.byteOffset, self.bufferViews[sparse.values.bufferView]); + + var it = indices.GetEnumerator(); + for (int i = 0; i < sparse.count; ++i) + { + it.MoveNext(); + result[it.Current] = values[i]; + } + } + return result; + } + public static ArraySegment<Byte> GetImageBytes(this glTF self, IStorage storage, int imageIndex, out string textureName) { var image = self.images[imageIndex]; diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/AnimationImporter.cs b/Assets/UniGLTF/Runtime/UniGLTF/IO/AnimationImporter.cs deleted file mode 100644 index 85e2e9e080..0000000000 --- a/Assets/UniGLTF/Runtime/UniGLTF/IO/AnimationImporter.cs +++ /dev/null @@ -1,334 +0,0 @@ -using System; -using System.Linq; -using System.Collections.Generic; -using UnityEngine; - -namespace UniGLTF -{ - public static class AnimationImporter - { - private enum TangentMode - { - Linear, - Constant, - Cubicspline - } - - private static TangentMode GetTangentMode(string interpolation) - { - if (interpolation == glTFAnimationTarget.Interpolations.LINEAR.ToString()) - { - return TangentMode.Linear; - } - else if (interpolation == glTFAnimationTarget.Interpolations.STEP.ToString()) - { - return TangentMode.Constant; - } - else if (interpolation == glTFAnimationTarget.Interpolations.CUBICSPLINE.ToString()) - { - return TangentMode.Cubicspline; - } - else - { - throw new NotImplementedException(); - } - } - - private static void CalculateTangent(List<Keyframe> keyframes, int current) - { - int back = current - 1; - if (back < 0) - { - return; - } - if (current < keyframes.Count) - { - var rightTangent = (keyframes[current].value - keyframes[back].value) / (keyframes[current].time - keyframes[back].time); - keyframes[back] = new Keyframe(keyframes[back].time, keyframes[back].value, keyframes[back].inTangent, rightTangent); - - var leftTangent = (keyframes[back].value - keyframes[current].value) / (keyframes[back].time - keyframes[current].time); - keyframes[current] = new Keyframe(keyframes[current].time, keyframes[current].value, leftTangent, 0); - } - } - - public static Quaternion GetShortest(Quaternion last, Quaternion rot) - { - if (Quaternion.Dot(last, rot) > 0.0) - { - return rot; - } - else - { - return new Quaternion(-rot.x, -rot.y, -rot.z, -rot.w); - } - - } - - public delegate float[] ReverseZ(float[] current, float[] last); - public static void SetAnimationCurve( - AnimationClip targetClip, - string relativePath, - string[] propertyNames, - float[] input, - float[] output, - string interpolation, - Type curveType, - ReverseZ reverse) - { - var tangentMode = GetTangentMode(interpolation); - - var curveCount = propertyNames.Length; - AnimationCurve[] curves = new AnimationCurve[curveCount]; - List<Keyframe>[] keyframes = new List<Keyframe>[curveCount]; - - int elementNum = curveCount; - int inputIndex = 0; - //Quaternion用 - float[] last = new float[curveCount]; - if (last.Length == 4) - { - last[3] = 1.0f; - } - for (inputIndex = 0; inputIndex < input.Length; ++inputIndex) - { - var time = input[inputIndex]; - var outputIndex = 0; - if (tangentMode == TangentMode.Cubicspline) - { - outputIndex = inputIndex * elementNum * 3; - var value = new float[curveCount]; - for (int i = 0; i < value.Length; i++) - { - value[i] = output[outputIndex + elementNum + i]; - } - var reversed = reverse(value, last); - last = reversed; - for (int i = 0; i < keyframes.Length; i++) - { - if (keyframes[i] == null) - keyframes[i] = new List<Keyframe>(); - keyframes[i].Add(new Keyframe( - time, - reversed[i], - output[outputIndex + i], - output[outputIndex + i + elementNum * 2])); - } - } - else - { - outputIndex = inputIndex * elementNum; - var value = new float[curveCount]; - for (int i = 0; i < value.Length; i++) - { - value[i] = output[outputIndex + i]; - } - var reversed = reverse(value, last); - last = reversed; - - for (int i = 0; i < keyframes.Length; i++) - { - if (keyframes[i] == null) - keyframes[i] = new List<Keyframe>(); - if (tangentMode == TangentMode.Linear) - { - keyframes[i].Add(new Keyframe(time, reversed[i], 0, 0)); - if (keyframes[i].Count > 0) - { - CalculateTangent(keyframes[i], keyframes[i].Count - 1); - } - } - else if (tangentMode == TangentMode.Constant) - keyframes[i].Add(new Keyframe(time, reversed[i], 0, float.PositiveInfinity)); - } - } - } - - for (int i = 0; i < curves.Length; i++) - { - curves[i] = new AnimationCurve(); - for (int j = 0; j < keyframes[i].Count; j++) - { - curves[i].AddKey(keyframes[i][j]); - } - - targetClip.SetCurve(relativePath, curveType, propertyNames[i], curves[i]); - } - } - - public static List<AnimationClip> ImportAnimationClip(ImporterContext ctx) - { - List<AnimationClip> animationClips = new List<AnimationClip>(); - for (int i = 0; i < ctx.GLTF.animations.Count; ++i) - { - var clip = new AnimationClip(); - clip.ClearCurves(); - clip.legacy = true; - clip.name = ctx.GLTF.animations[i].name; - if (string.IsNullOrEmpty(clip.name)) - { - clip.name = "legacy_" + i; - } - clip.wrapMode = WrapMode.Loop; - - var animation = ctx.GLTF.animations[i]; - if (string.IsNullOrEmpty(animation.name)) - { - animation.name = string.Format("animation:{0}", i); - } - - foreach (var channel in animation.channels) - { - var targetTransform = ctx.Nodes[channel.target.node]; - var relativePath = targetTransform.RelativePathFrom(ctx.Root.transform); - switch (channel.target.path) - { - case glTFAnimationTarget.PATH_TRANSLATION: - { - var sampler = animation.samplers[channel.sampler]; - var input = ctx.GLTF.GetArrayFromAccessor<float>(sampler.input); - var outputVector = ctx.GLTF.GetArrayFromAccessor<Vector3>(sampler.output); - var output = new float[outputVector.Count() * 3]; - ArrayExtensions.Copy<Vector3, float>( - new ArraySegment<Vector3>(outputVector), - new ArraySegment<float>(output)); - - AnimationImporter.SetAnimationCurve( - clip, - relativePath, - new string[] { "localPosition.x", "localPosition.y", "localPosition.z" }, - input, - output, - sampler.interpolation, - typeof(Transform), - (values, last) => - { - Vector3 temp = new Vector3(values[0], values[1], values[2]); - return temp.ReverseZ().ToArray(); - } - ); - } - break; - - case glTFAnimationTarget.PATH_ROTATION: - { - var sampler = animation.samplers[channel.sampler]; - var input = ctx.GLTF.GetArrayFromAccessor<float>(sampler.input); - var outputVector = ctx.GLTF.GetArrayFromAccessor<Vector4>(sampler.output); - var output = new float[outputVector.Count() * 4]; - ArrayExtensions.Copy<Vector4, float>( - new ArraySegment<Vector4>(outputVector), - new ArraySegment<float>(output)); - - AnimationImporter.SetAnimationCurve( - clip, - relativePath, - new string[] { "localRotation.x", "localRotation.y", "localRotation.z", "localRotation.w" }, - input, - output, - 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 AnimationImporter.GetShortest(lastQuaternion, currentQuaternion.ReverseZ()).ToArray(); - } - ); - - clip.EnsureQuaternionContinuity(); - } - break; - - case glTFAnimationTarget.PATH_SCALE: - { - var sampler = animation.samplers[channel.sampler]; - var input = ctx.GLTF.GetArrayFromAccessor<float>(sampler.input); - var outputVector = ctx.GLTF.GetArrayFromAccessor<Vector3>(sampler.output); - var output = new float[outputVector.Count() * 3]; - ArrayExtensions.Copy<Vector3, float>( - new ArraySegment<Vector3>(outputVector), - new ArraySegment<float>(output)); - - AnimationImporter.SetAnimationCurve( - clip, - relativePath, - new string[] { "localScale.x", "localScale.y", "localScale.z" }, - input, - output, - sampler.interpolation, - typeof(Transform), - (values, last) => values); - } - break; - - case glTFAnimationTarget.PATH_WEIGHT: - { - var node = ctx.GLTF.nodes[channel.target.node]; - var mesh = ctx.GLTF.meshes[node.mesh]; - var primitive = mesh.primitives.FirstOrDefault(); - var targets = primitive.targets; - - if (!gltf_mesh_extras_targetNames.TryGet(mesh, out List<string> targetNames)) - { - throw new Exception("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 = ctx.GLTF.GetArrayFromAccessor<float>(sampler.input); - var output = ctx.GLTF.GetArrayFromAccessor<float>(sampler.output); - AnimationImporter.SetAnimationCurve( - clip, - relativePath, - keyNames, - input, - output, - sampler.interpolation, - typeof(SkinnedMeshRenderer), - (values, last) => - { - for (int j = 0; j < values.Length; j++) - { - values[j] *= 100.0f; - } - return values; - }); - - } - break; - - default: - Debug.LogWarningFormat("unknown path: {0}", channel.target.path); - break; - } - } - animationClips.Add(clip); - } - - return animationClips; - } - - public static void ImportAnimation(ImporterContext ctx) - { - // animation - if (ctx.GLTF.animations != null && ctx.GLTF.animations.Any()) - { - var animation = ctx.Root.AddComponent<Animation>(); - ctx.AnimationClips = ImportAnimationClip(ctx); - foreach (var clip in ctx.AnimationClips) - { - animation.AddClip(clip, clip.name); - } - if (ctx.AnimationClips.Count > 0) - { - animation.clip = ctx.AnimationClips.First(); - } - } - } - - } -} diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/AnimationImporter.cs.meta b/Assets/UniGLTF/Runtime/UniGLTF/IO/AnimationImporter.cs.meta deleted file mode 100644 index 8f83fec206..0000000000 --- a/Assets/UniGLTF/Runtime/UniGLTF/IO/AnimationImporter.cs.meta +++ /dev/null @@ -1,3 +0,0 @@ -fileFormatVersion: 2 -guid: d602384685dd4f179350052013659720 -timeCreated: 1537445972 \ No newline at end of file diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/AnimationImporterUtil.cs b/Assets/UniGLTF/Runtime/UniGLTF/IO/AnimationImporterUtil.cs new file mode 100644 index 0000000000..9cd5fd680d --- /dev/null +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/AnimationImporterUtil.cs @@ -0,0 +1,316 @@ +using System; +using System.Linq; +using System.Collections.Generic; +using UnityEngine; + +namespace UniGLTF +{ + public static class AnimationImporterUtil + { + private enum TangentMode + { + Linear, + Constant, + Cubicspline + } + + private static TangentMode GetTangentMode(string interpolation) + { + if (interpolation == glTFAnimationTarget.Interpolations.LINEAR.ToString()) + { + return TangentMode.Linear; + } + else if (interpolation == glTFAnimationTarget.Interpolations.STEP.ToString()) + { + return TangentMode.Constant; + } + else if (interpolation == glTFAnimationTarget.Interpolations.CUBICSPLINE.ToString()) + { + return TangentMode.Cubicspline; + } + else + { + throw new NotImplementedException(); + } + } + + private static void CalculateTanget(List<Keyframe> keyframes, int current) + { + int back = current - 1; + if (back < 0) + { + return; + } + if (current < keyframes.Count) + { + var rightTangent = (keyframes[current].value - keyframes[back].value) / (keyframes[current].time - keyframes[back].time); + keyframes[back] = new Keyframe(keyframes[back].time, keyframes[back].value, keyframes[back].inTangent, rightTangent); + + var leftTangent = (keyframes[back].value - keyframes[current].value) / (keyframes[back].time - keyframes[current].time); + keyframes[current] = new Keyframe(keyframes[current].time, keyframes[current].value, leftTangent, 0); + } + } + + public static Quaternion GetShortest(Quaternion last, Quaternion rot) + { + if (Quaternion.Dot(last, rot) > 0.0) + { + return rot; + } + else + { + return new Quaternion(-rot.x, -rot.y, -rot.z, -rot.w); + } + + } + + public delegate float[] ReverseZ(float[] current, float[] last); + public static void SetAnimationCurve( + AnimationClip targetClip, + string relativePath, + string[] propertyNames, + float[] input, + float[] output, + string interpolation, + Type curveType, + ReverseZ reverse) + { + var tangentMode = GetTangentMode(interpolation); + + var curveCount = propertyNames.Length; + AnimationCurve[] curves = new AnimationCurve[curveCount]; + List<Keyframe>[] keyframes = new List<Keyframe>[curveCount]; + + int elementNum = curveCount; + int inputIndex = 0; + //Quaternion用 + float[] last = new float[curveCount]; + if (last.Length == 4) + { + last[3] = 1.0f; + } + for (inputIndex = 0; inputIndex < input.Length; ++inputIndex) + { + var time = input[inputIndex]; + var outputIndex = 0; + if (tangentMode == TangentMode.Cubicspline) + { + outputIndex = inputIndex * elementNum * 3; + var value = new float[curveCount]; + for (int i = 0; i < value.Length; i++) + { + value[i] = output[outputIndex + elementNum + i]; + } + var reversed = reverse(value, last); + last = reversed; + for (int i = 0; i < keyframes.Length; i++) + { + if (keyframes[i] == null) + keyframes[i] = new List<Keyframe>(); + keyframes[i].Add(new Keyframe( + time, + reversed[i], + output[outputIndex + i], + output[outputIndex + i + elementNum * 2])); + } + } + else + { + outputIndex = inputIndex * elementNum; + var value = new float[curveCount]; + for (int i = 0; i < value.Length; i++) + { + value[i] = output[outputIndex + i]; + } + var reversed = reverse(value, last); + last = reversed; + + for (int i = 0; i < keyframes.Length; i++) + { + if (keyframes[i] == null) + keyframes[i] = new List<Keyframe>(); + if (tangentMode == TangentMode.Linear) + { + keyframes[i].Add(new Keyframe(time, reversed[i], 0, 0)); + if (keyframes[i].Count > 0) + { + CalculateTanget(keyframes[i], keyframes[i].Count - 1); + } + } + else if (tangentMode == TangentMode.Constant) + keyframes[i].Add(new Keyframe(time, reversed[i], 0, float.PositiveInfinity)); + } + } + } + + for (int i = 0; i < curves.Length; i++) + { + curves[i] = new AnimationCurve(); + for (int j = 0; j < keyframes[i].Count; j++) + { + curves[i].AddKey(keyframes[i][j]); + } + + targetClip.SetCurve(relativePath, curveType, propertyNames[i], curves[i]); + } + } + + public static string RelativePathFrom(List<glTFNode> nodes, glTFNode root, glTFNode target) + { + if (root == target) return ""; + var path = new List<string>(); + return RelativePathFrom(nodes, root, target, path); + } + + private static string RelativePathFrom(List<glTFNode> nodes, glTFNode root, glTFNode target, List<string> path) + { + if(path.Count == 0) path.Add(target.name); + + var targetIndex = nodes.IndexOf(target); + foreach (var parent in nodes) + { + if(parent.children == null || parent.children.Length == 0) continue; + + foreach(var child in parent.children) + { + if(child != targetIndex) continue; + + if(parent == root) return string.Join("/", path); + + path.Insert(0, parent.name); + return RelativePathFrom(nodes, root, parent, path); + } + } + + return string.Join("/", path); + } + + public static AnimationClip ConvertAnimationClip(glTF gltf, glTFAnimation animation, glTFNode root = null) + { + var clip = new AnimationClip(); + clip.ClearCurves(); + clip.legacy = true; + clip.name = animation.name; + clip.wrapMode = WrapMode.Loop; + + foreach (var channel in animation.channels) + { + var relativePath = RelativePathFrom(gltf.nodes, root, gltf.nodes[channel.target.node]); + switch (channel.target.path) + { + case glTFAnimationTarget.PATH_TRANSLATION: + { + var sampler = animation.samplers[channel.sampler]; + var input = gltf.GetArrayFromAccessor<float>(sampler.input); + var output = gltf.GetFloatArrayFromAccessor(sampler.output); + + AnimationImporterUtil.SetAnimationCurve( + clip, + relativePath, + new string[] { "localPosition.x", "localPosition.y", "localPosition.z" }, + input, + output, + sampler.interpolation, + typeof(Transform), + (values, last) => + { + Vector3 temp = new Vector3(values[0], values[1], values[2]); + return temp.ReverseZ().ToArray(); + } + ); + } + break; + + case glTFAnimationTarget.PATH_ROTATION: + { + var sampler = animation.samplers[channel.sampler]; + var input = gltf.GetArrayFromAccessor<float>(sampler.input); + var output = gltf.GetFloatArrayFromAccessor(sampler.output); + + AnimationImporterUtil.SetAnimationCurve( + clip, + relativePath, + new string[] { "localRotation.x", "localRotation.y", "localRotation.z", "localRotation.w" }, + input, + output, + 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, currentQuaternion.ReverseZ()).ToArray(); + } + ); + + clip.EnsureQuaternionContinuity(); + } + break; + + case glTFAnimationTarget.PATH_SCALE: + { + var sampler = animation.samplers[channel.sampler]; + var input = gltf.GetArrayFromAccessor<float>(sampler.input); + var output = gltf.GetFloatArrayFromAccessor(sampler.output); + + AnimationImporterUtil.SetAnimationCurve( + clip, + relativePath, + new string[] { "localScale.x", "localScale.y", "localScale.z" }, + input, + output, + sampler.interpolation, + typeof(Transform), + (values, last) => values); + } + break; + + case glTFAnimationTarget.PATH_WEIGHT: + { + var node = gltf.nodes[channel.target.node]; + var mesh = gltf.meshes[node.mesh]; + var primitive = mesh.primitives.FirstOrDefault(); + var targets = primitive.targets; + + if (!gltf_mesh_extras_targetNames.TryGet(mesh, out List<string> targetNames)) + { + throw new Exception("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 = gltf.GetArrayFromAccessor<float>(sampler.input); + var output = gltf.GetArrayFromAccessor<float>(sampler.output); + AnimationImporterUtil.SetAnimationCurve( + clip, + relativePath, + keyNames, + input, + output, + sampler.interpolation, + typeof(SkinnedMeshRenderer), + (values, last) => + { + for (int j = 0; j < values.Length; j++) + { + values[j] *= 100.0f; + } + return values; + }); + + } + break; + + default: + Debug.LogWarningFormat("unknown path: {0}", channel.target.path); + break; + } + } + return clip; + } + } +} diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/AnimationImporterUtil.cs.meta b/Assets/UniGLTF/Runtime/UniGLTF/IO/AnimationImporterUtil.cs.meta new file mode 100644 index 0000000000..70c082d51e --- /dev/null +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/AnimationImporterUtil.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a6e858fe43dba6342902d72392b1bdce +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/IAnimationImporter.cs b/Assets/UniGLTF/Runtime/UniGLTF/IO/IAnimationImporter.cs new file mode 100644 index 0000000000..2c65bbd110 --- /dev/null +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/IAnimationImporter.cs @@ -0,0 +1,7 @@ +namespace UniGLTF +{ + public interface IAnimationImporter + { + void Import(ImporterContext context); + } +} \ No newline at end of file diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/IAnimationImporter.cs.meta b/Assets/UniGLTF/Runtime/UniGLTF/IO/IAnimationImporter.cs.meta new file mode 100644 index 0000000000..83586e0860 --- /dev/null +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/IAnimationImporter.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4f950ba9271cbff4cbc4345f5a23a5d8 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/ImporterContext.cs b/Assets/UniGLTF/Runtime/UniGLTF/IO/ImporterContext.cs index 8684aa54a4..abf45ef75e 100644 --- a/Assets/UniGLTF/Runtime/UniGLTF/IO/ImporterContext.cs +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/ImporterContext.cs @@ -85,6 +85,26 @@ public string GetSpeedLog() } #endregion + #region Animation + protected IAnimationImporter m_animationImporter; + public void SetAnimationImporter(IAnimationImporter animationImporter) + { + m_animationImporter = animationImporter; + } + public IAnimationImporter AnimationImporter + { + get + { + if (m_animationImporter == null) + { + m_animationImporter = new RootAnimationImporter(); + } + return m_animationImporter; + } + } + + #endregion + IShaderStore m_shaderStore; public IShaderStore ShaderStore { @@ -588,7 +608,7 @@ protected virtual Schedulable<Unit> LoadAsync() { using (MeasureTime("AnimationImporter")) { - AnimationImporter.ImportAnimation(this); + AnimationImporter.Import(this); } }) .ContinueWithCoroutine(Scheduler.MainThread, OnLoadModel) diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/RootAnimationImporter.cs b/Assets/UniGLTF/Runtime/UniGLTF/IO/RootAnimationImporter.cs new file mode 100644 index 0000000000..5c3b4e406f --- /dev/null +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/RootAnimationImporter.cs @@ -0,0 +1,55 @@ +using System.Collections.Generic; +using System.Linq; +using UnityEngine; + +namespace UniGLTF +{ + public sealed class RootAnimationImporter : IAnimationImporter + { + public void Import(ImporterContext context) + { + // animation + if (context.GLTF.animations != null && context.GLTF.animations.Any()) + { + var animation = context.Root.AddComponent<Animation>(); + context.AnimationClips = ImportAnimationClips(context.GLTF); + + foreach (var clip in context.AnimationClips) + { + animation.AddClip(clip, clip.name); + } + if (context.AnimationClips.Count > 0) + { + animation.clip = context.AnimationClips.First(); + } + } + } + + private List<AnimationClip> ImportAnimationClips(glTF gltf) + { + var animationClips = new List<AnimationClip>(); + for (var i = 0; i < gltf.animations.Count; ++i) + { + var clip = new AnimationClip(); + clip.ClearCurves(); + clip.legacy = true; + clip.name = gltf.animations[i].name; + if (string.IsNullOrEmpty(clip.name)) + { + clip.name = $"legacy_{i}"; + } + clip.wrapMode = WrapMode.Loop; + + var animation = gltf.animations[i]; + if (string.IsNullOrEmpty(animation.name)) + { + animation.name = $"animation:{i}"; + } + + animationClips.Add(AnimationImporterUtil.ConvertAnimationClip(gltf, animation)); + } + + return animationClips; + } + } +} \ No newline at end of file diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/RootAnimationImporter.cs.meta b/Assets/UniGLTF/Runtime/UniGLTF/IO/RootAnimationImporter.cs.meta new file mode 100644 index 0000000000..2ea8cfbed7 --- /dev/null +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/RootAnimationImporter.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 27640e6274339664ea492827be5a2217 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: