public void RelativePathFromTest() { var nodes = new List <glTFNode>(); for (var i = 0; i < 10; i++) { nodes.Add(new glTFNode() { name = $"node{i}" }); } nodes[0].children = new[] { 1, 2 }; nodes[2].children = new[] { 3, 4 }; nodes[4].children = new[] { 5, 6, 7 }; string res = null; res = AnimationImporterUtil.RelativePathFrom(nodes, null, nodes[0]); Assert.AreEqual("node0", res); res = AnimationImporterUtil.RelativePathFrom(nodes, null, nodes[8]); Assert.AreEqual("node8", res); res = AnimationImporterUtil.RelativePathFrom(nodes, null, nodes[4]); Assert.AreEqual("node0/node2/node4", res); res = AnimationImporterUtil.RelativePathFrom(nodes, null, nodes[7]); Assert.AreEqual("node0/node2/node4/node7", res); res = AnimationImporterUtil.RelativePathFrom(nodes, nodes[0], nodes[4]); Assert.AreEqual("node2/node4", res); res = AnimationImporterUtil.RelativePathFrom(nodes, nodes[0], nodes[7]); Assert.AreEqual("node2/node4/node7", res); res = AnimationImporterUtil.RelativePathFrom(nodes, nodes[2], nodes[7]); Assert.AreEqual("node4/node7", res); // rootとtargetが同じ場合は空になる。 res = AnimationImporterUtil.RelativePathFrom(nodes, nodes[4], nodes[4]); Assert.AreEqual("", res); // rootとtargetがnullの場合は空になる。 res = AnimationImporterUtil.RelativePathFrom(nodes, null, null); Assert.AreEqual("", res); // rootよりもtargetが下層の場合は、rootを無視する。 res = AnimationImporterUtil.RelativePathFrom(nodes, nodes[7], nodes[4]); Assert.AreEqual("node0/node2/node4", res); }
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 <float>(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 <float>(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 <float>(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; List <string> blendShapeNames = new List <string>(); var transform = ctx.Nodes[channel.target.node]; var skinnedMeshRenderer = transform.GetComponent <SkinnedMeshRenderer>(); if (skinnedMeshRenderer == null) { continue; } for (int j = 0; j < skinnedMeshRenderer.sharedMesh.blendShapeCount; j++) { blendShapeNames.Add(skinnedMeshRenderer.sharedMesh.GetBlendShapeName(j)); } var keyNames = blendShapeNames .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); 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); }
public void Import(ImporterContext context) { var animationClips = new AnimationClip[context.GLTF.animations.Count]; // node extension animation for (int i = 0; i < context.GLTF.nodes.Count; i++) { var node = context.GLTF.nodes[i]; if (node.extensions == null || node.extensions.VCAST_vci_animation == null) { continue; } var vciAnimation = node.extensions.VCAST_vci_animation; var root = context.Nodes[i]; var animation = root.gameObject.AddComponent <Animation>(); foreach (var animationReference in vciAnimation.animationReferences) { var gltfAnimation = context.GLTF.animations[animationReference.animation]; AnimationClip clip = null; if (animationClips[animationReference.animation] == null) { clip = AnimationImporterUtil.ImportAnimationClip(context, gltfAnimation, root); animationClips[animationReference.animation] = clip; } else { clip = animationClips[animationReference.animation]; } if (clip != null) { animation.AddClip(clip, clip.name); } } } // root animation var rootAnimation = context.Root.GetComponent <Animation>(); if (rootAnimation == null) { rootAnimation = context.Root.AddComponent <Animation>(); } for (int i = 0; i < animationClips.Length; i++) { if (animationClips[i] != null) { continue; } var gltfAnimation = context.GLTF.animations[i]; animationClips[i] = AnimationImporterUtil.ImportAnimationClip(context, gltfAnimation, context.Root.transform); rootAnimation.AddClip(animationClips[i], animationClips[i].name); } context.AnimationClips = new List <AnimationClip>(animationClips); }