From 02cb0eb25f285da5f6509d56f3351b575f364d43 Mon Sep 17 00:00:00 2001 From: hiroj Date: Thu, 24 Dec 2020 17:31:55 +0900 Subject: [PATCH 1/2] add_animationImporter_interface --- .../Runtime/Extensions/glTFExtensions.cs | 29 ++ .../Runtime/UniGLTF/IO/AnimationImporter.cs | 334 ---------------- .../UniGLTF/IO/AnimationImporter.cs.meta | 3 - .../UniGLTF/IO/AnimationImporterUtil.cs | 362 ++++++++++++++++++ .../UniGLTF/IO/AnimationImporterUtil.cs.meta | 11 + .../Runtime/UniGLTF/IO/IAnimationImporter.cs | 7 + .../UniGLTF/IO/IAnimationImporter.cs.meta | 11 + .../Runtime/UniGLTF/IO/ImporterContext.cs | 22 +- .../UniGLTF/IO/RootAnimationImporter.cs | 10 + .../UniGLTF/IO/RootAnimationImporter.cs.meta | 11 + 10 files changed, 462 insertions(+), 338 deletions(-) delete mode 100644 Assets/UniGLTF/Runtime/UniGLTF/IO/AnimationImporter.cs delete mode 100644 Assets/UniGLTF/Runtime/UniGLTF/IO/AnimationImporter.cs.meta create mode 100644 Assets/UniGLTF/Runtime/UniGLTF/IO/AnimationImporterUtil.cs create mode 100644 Assets/UniGLTF/Runtime/UniGLTF/IO/AnimationImporterUtil.cs.meta create mode 100644 Assets/UniGLTF/Runtime/UniGLTF/IO/IAnimationImporter.cs create mode 100644 Assets/UniGLTF/Runtime/UniGLTF/IO/IAnimationImporter.cs.meta create mode 100644 Assets/UniGLTF/Runtime/UniGLTF/IO/RootAnimationImporter.cs create mode 100644 Assets/UniGLTF/Runtime/UniGLTF/IO/RootAnimationImporter.cs.meta diff --git a/Assets/UniGLTF/Runtime/Extensions/glTFExtensions.cs b/Assets/UniGLTF/Runtime/Extensions/glTFExtensions.cs index 7551e18e6..511af7b7c 100644 --- a/Assets/UniGLTF/Runtime/Extensions/glTFExtensions.cs +++ b/Assets/UniGLTF/Runtime/Extensions/glTFExtensions.cs @@ -316,6 +316,35 @@ namespace UniGLTF return result; } + public static float[] GetArrayFromAccessorAsFloat(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(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(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 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 85e2e9e08..000000000 --- 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 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[] keyframes = new List[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(); - 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(); - 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 ImportAnimationClip(ImporterContext ctx) - { - List animationClips = new List(); - 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(sampler.input); - var outputVector = ctx.GLTF.GetArrayFromAccessor(sampler.output); - var output = new float[outputVector.Count() * 3]; - ArrayExtensions.Copy( - new ArraySegment(outputVector), - new ArraySegment(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(sampler.input); - var outputVector = ctx.GLTF.GetArrayFromAccessor(sampler.output); - var output = new float[outputVector.Count() * 4]; - ArrayExtensions.Copy( - new ArraySegment(outputVector), - new ArraySegment(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(sampler.input); - var outputVector = ctx.GLTF.GetArrayFromAccessor(sampler.output); - var output = new float[outputVector.Count() * 3]; - ArrayExtensions.Copy( - new ArraySegment(outputVector), - new ArraySegment(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 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(sampler.input); - var output = ctx.GLTF.GetArrayFromAccessor(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(); - 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 8f83fec20..000000000 --- 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 000000000..221f289ab --- /dev/null +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/AnimationImporterUtil.cs @@ -0,0 +1,362 @@ +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 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[] keyframes = new List[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(); + 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(); + 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 nodes, glTFNode root, glTFNode target) + { + if (root == target) return ""; + var path = new List(); + return RelativePathFrom(nodes, root, target, path); + } + + private static string RelativePathFrom(List nodes, glTFNode root, glTFNode target, List 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 ImportAnimationClip(ImporterContext ctx, 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(ctx.GLTF.nodes, root, ctx.GLTF.nodes[channel.target.node]); + switch (channel.target.path) + { + case glTFAnimationTarget.PATH_TRANSLATION: + { + var sampler = animation.samplers[channel.sampler]; + var input = ctx.GLTF.GetArrayFromAccessor(sampler.input); + var output = ctx.GLTF.GetArrayFromAccessorAsFloat(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 = ctx.GLTF.GetArrayFromAccessor(sampler.input); + var output = ctx.GLTF.GetArrayFromAccessorAsFloat(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 = ctx.GLTF.GetArrayFromAccessor(sampler.input); + var output = ctx.GLTF.GetArrayFromAccessorAsFloat(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 = 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 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(sampler.input); + var output = ctx.GLTF.GetArrayFromAccessor(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; + } + + private static List ImportAnimationClips(ImporterContext ctx) + { + var animationClips = new List(); + for (var 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 = $"animation:{i}"; + } + + animationClips.Add(ImportAnimationClip(ctx, animation)); + } + + return animationClips; + } + + public static void ImportAnimation(ImporterContext ctx) + { + // animation + if (ctx.GLTF.animations != null && ctx.GLTF.animations.Any()) + { + var animation = ctx.Root.AddComponent(); + ctx.AnimationClips = ImportAnimationClips(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/AnimationImporterUtil.cs.meta b/Assets/UniGLTF/Runtime/UniGLTF/IO/AnimationImporterUtil.cs.meta new file mode 100644 index 000000000..70c082d51 --- /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 000000000..2c65bbd11 --- /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 000000000..83586e086 --- /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 8684aa54a..9bb7f3537 100644 --- a/Assets/UniGLTF/Runtime/UniGLTF/IO/ImporterContext.cs +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/ImporterContext.cs @@ -85,6 +85,26 @@ namespace UniGLTF } #endregion + #region Animation + 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 @@ namespace UniGLTF { 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 000000000..453d04122 --- /dev/null +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/RootAnimationImporter.cs @@ -0,0 +1,10 @@ +namespace UniGLTF +{ + public sealed class RootAnimationImporter : IAnimationImporter + { + public void Import(ImporterContext context) + { + AnimationImporterUtil.ImportAnimation(context); + } + } +} \ 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 000000000..2ea8cfbed --- /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: From bc56184c6f565eda8c4dddd3c15a241e679c2289 Mon Sep 17 00:00:00 2001 From: hiroj Date: Thu, 24 Dec 2020 18:18:08 +0900 Subject: [PATCH 2/2] code organization --- .../Runtime/Extensions/glTFExtensions.cs | 2 +- .../UniGLTF/IO/AnimationImporterUtil.cs | 70 ++++--------------- .../Runtime/UniGLTF/IO/ImporterContext.cs | 2 +- .../UniGLTF/IO/RootAnimationImporter.cs | 49 ++++++++++++- 4 files changed, 61 insertions(+), 62 deletions(-) diff --git a/Assets/UniGLTF/Runtime/Extensions/glTFExtensions.cs b/Assets/UniGLTF/Runtime/Extensions/glTFExtensions.cs index 511af7b7c..02edf3e12 100644 --- a/Assets/UniGLTF/Runtime/Extensions/glTFExtensions.cs +++ b/Assets/UniGLTF/Runtime/Extensions/glTFExtensions.cs @@ -316,7 +316,7 @@ namespace UniGLTF return result; } - public static float[] GetArrayFromAccessorAsFloat(this glTF self, int accessorIndex) + public static float[] GetFloatArrayFromAccessor(this glTF self, int accessorIndex) { var vertexAccessor = self.accessors[accessorIndex]; diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/AnimationImporterUtil.cs b/Assets/UniGLTF/Runtime/UniGLTF/IO/AnimationImporterUtil.cs index 221f289ab..9cd5fd680 100644 --- a/Assets/UniGLTF/Runtime/UniGLTF/IO/AnimationImporterUtil.cs +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/AnimationImporterUtil.cs @@ -185,7 +185,7 @@ namespace UniGLTF return string.Join("/", path); } - public static AnimationClip ImportAnimationClip(ImporterContext ctx, glTFAnimation animation, glTFNode root = null) + public static AnimationClip ConvertAnimationClip(glTF gltf, glTFAnimation animation, glTFNode root = null) { var clip = new AnimationClip(); clip.ClearCurves(); @@ -195,14 +195,14 @@ namespace UniGLTF foreach (var channel in animation.channels) { - var relativePath = RelativePathFrom(ctx.GLTF.nodes, root, ctx.GLTF.nodes[channel.target.node]); + 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 = ctx.GLTF.GetArrayFromAccessor(sampler.input); - var output = ctx.GLTF.GetArrayFromAccessorAsFloat(sampler.output); + var input = gltf.GetArrayFromAccessor(sampler.input); + var output = gltf.GetFloatArrayFromAccessor(sampler.output); AnimationImporterUtil.SetAnimationCurve( clip, @@ -224,8 +224,8 @@ namespace UniGLTF case glTFAnimationTarget.PATH_ROTATION: { var sampler = animation.samplers[channel.sampler]; - var input = ctx.GLTF.GetArrayFromAccessor(sampler.input); - var output = ctx.GLTF.GetArrayFromAccessorAsFloat(sampler.output); + var input = gltf.GetArrayFromAccessor(sampler.input); + var output = gltf.GetFloatArrayFromAccessor(sampler.output); AnimationImporterUtil.SetAnimationCurve( clip, @@ -250,8 +250,8 @@ namespace UniGLTF case glTFAnimationTarget.PATH_SCALE: { var sampler = animation.samplers[channel.sampler]; - var input = ctx.GLTF.GetArrayFromAccessor(sampler.input); - var output = ctx.GLTF.GetArrayFromAccessorAsFloat(sampler.output); + var input = gltf.GetArrayFromAccessor(sampler.input); + var output = gltf.GetFloatArrayFromAccessor(sampler.output); AnimationImporterUtil.SetAnimationCurve( clip, @@ -267,8 +267,8 @@ namespace UniGLTF case glTFAnimationTarget.PATH_WEIGHT: { - var node = ctx.GLTF.nodes[channel.target.node]; - var mesh = ctx.GLTF.meshes[node.mesh]; + var node = gltf.nodes[channel.target.node]; + var mesh = gltf.meshes[node.mesh]; var primitive = mesh.primitives.FirstOrDefault(); var targets = primitive.targets; @@ -283,8 +283,8 @@ namespace UniGLTF .ToArray(); var sampler = animation.samplers[channel.sampler]; - var input = ctx.GLTF.GetArrayFromAccessor(sampler.input); - var output = ctx.GLTF.GetArrayFromAccessor(sampler.output); + var input = gltf.GetArrayFromAccessor(sampler.input); + var output = gltf.GetArrayFromAccessor(sampler.output); AnimationImporterUtil.SetAnimationCurve( clip, relativePath, @@ -312,51 +312,5 @@ namespace UniGLTF } return clip; } - - private static List ImportAnimationClips(ImporterContext ctx) - { - var animationClips = new List(); - for (var 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 = $"animation:{i}"; - } - - animationClips.Add(ImportAnimationClip(ctx, animation)); - } - - return animationClips; - } - - public static void ImportAnimation(ImporterContext ctx) - { - // animation - if (ctx.GLTF.animations != null && ctx.GLTF.animations.Any()) - { - var animation = ctx.Root.AddComponent(); - ctx.AnimationClips = ImportAnimationClips(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/ImporterContext.cs b/Assets/UniGLTF/Runtime/UniGLTF/IO/ImporterContext.cs index 9bb7f3537..abf45ef75 100644 --- a/Assets/UniGLTF/Runtime/UniGLTF/IO/ImporterContext.cs +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/ImporterContext.cs @@ -86,7 +86,7 @@ namespace UniGLTF #endregion #region Animation - IAnimationImporter m_animationImporter; + protected IAnimationImporter m_animationImporter; public void SetAnimationImporter(IAnimationImporter animationImporter) { m_animationImporter = animationImporter; diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/RootAnimationImporter.cs b/Assets/UniGLTF/Runtime/UniGLTF/IO/RootAnimationImporter.cs index 453d04122..5c3b4e406 100644 --- a/Assets/UniGLTF/Runtime/UniGLTF/IO/RootAnimationImporter.cs +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/RootAnimationImporter.cs @@ -1,10 +1,55 @@ -namespace UniGLTF +using System.Collections.Generic; +using System.Linq; +using UnityEngine; + +namespace UniGLTF { public sealed class RootAnimationImporter : IAnimationImporter { public void Import(ImporterContext context) { - AnimationImporterUtil.ImportAnimation(context); + // animation + if (context.GLTF.animations != null && context.GLTF.animations.Any()) + { + var animation = context.Root.AddComponent(); + 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 ImportAnimationClips(glTF gltf) + { + var animationClips = new List(); + 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