/// <summary> /// AnimationClip を収集する。 /// </summary> static List <AnimationClip> GetAnimationClips(GameObject Copy) { var clips = new List <AnimationClip>(); var animator = Copy.GetComponent <Animator>(); var animation = Copy.GetComponent <Animation>(); if (animator != null) { clips = AnimationExporter.GetAnimationClips(animator); } else if (animation != null) { clips = AnimationExporter.GetAnimationClips(animation); } return(clips); }
public void Export(ExportingGltfData _data, GameObject Copy, List <Transform> Nodes) { var clips = GetAnimationClips(Copy); foreach (AnimationClip clip in clips) { var animationWithCurve = AnimationExporter.Export(clip, Copy.transform, Nodes); foreach (var kv in animationWithCurve.SamplerMap) { var sampler = animationWithCurve.Animation.samplers[kv.Key]; var inputAccessorIndex = _data.ExtendBufferAndGetAccessorIndex(kv.Value.Input); sampler.input = inputAccessorIndex; var outputAccessorIndex = _data.ExtendBufferAndGetAccessorIndex(kv.Value.Output); sampler.output = outputAccessorIndex; // modify accessors var outputAccessor = _data.Gltf.accessors[outputAccessorIndex]; var channel = animationWithCurve.Animation.channels.First(x => x.sampler == kv.Key); switch (glTFAnimationTarget.GetElementCount(channel.target.path)) { case 1: outputAccessor.type = "SCALAR"; //outputAccessor.count = ; break; case 3: outputAccessor.type = "VEC3"; outputAccessor.count /= 3; break; case 4: outputAccessor.type = "VEC4"; outputAccessor.count /= 4; break; default: throw new NotImplementedException(); } } animationWithCurve.Animation.name = clip.name; _data.Gltf.animations.Add(animationWithCurve.Animation); } }
public static IEnumerable <Validation> Validate(GameObject root) { if (root == null) { yield break; } var animationClips = new List <AnimationClip>(); var animator = root.GetComponent <Animator>(); var animation = root.GetComponent <UnityEngine.Animation>(); if (animator != null) { animationClips = AnimationExporter.GetAnimationClips(animator); } else if (animation != null) { animationClips = AnimationExporter.GetAnimationClips(animation); } if (!animationClips.Any()) { yield break; } foreach (var animationClip in animationClips) { foreach (var editorCurveBinding in AnimationUtility.GetCurveBindings(animationClip)) { // is root included in animation? if (string.IsNullOrEmpty(editorCurveBinding.path)) { yield return(Validation.Error(ExporterValidatorMessages.ROOT_ANIMATED.Msg())); yield break; } } } }
public virtual void Export(ITextureSerializer textureSerializer) { Nodes = Copy.transform.Traverse() .Skip(1) // exclude root object for the symmetry with the importer .ToList(); var uniqueUnityMeshes = new MeshExportList(); uniqueUnityMeshes.GetInfo(Nodes, m_settings); #region Materials and Textures ReportProgress("Materials and Textures", 0.2f); Materials = uniqueUnityMeshes.GetUniqueMaterials().ToList(); _textureExporter = new TextureExporter(textureSerializer); var materialExporter = CreateMaterialExporter(); _gltf.materials = Materials.Select(x => materialExporter.ExportMaterial(x, TextureExporter, m_settings)).ToList(); #endregion #region Meshes ReportProgress("Meshes", 0.4f); MeshBlendShapeIndexMap = new Dictionary <Mesh, Dictionary <int, int> >(); foreach (var unityMesh in uniqueUnityMeshes) { if (!unityMesh.CanExport) { continue; } var(gltfMesh, blendShapeIndexMap) = m_settings.DivideVertexBuffer ? MeshExporter_DividedVertexBuffer.Export(_data, unityMesh, Materials, m_settings.InverseAxis.Create(), m_settings) : MeshExporter_SharedVertexBuffer.Export(_data, unityMesh, Materials, m_settings.InverseAxis.Create(), m_settings) ; _gltf.meshes.Add(gltfMesh); Meshes.Add(unityMesh.Mesh); if (!MeshBlendShapeIndexMap.ContainsKey(unityMesh.Mesh)) { // 重複防止 MeshBlendShapeIndexMap.Add(unityMesh.Mesh, blendShapeIndexMap); } } #endregion #region Nodes and Skins ReportProgress("Nodes and Skins", 0.8f); var skins = uniqueUnityMeshes .SelectMany(x => x.Renderers) .Where(x => x.Item1 is SkinnedMeshRenderer && x.UniqueBones != null) .Select(x => x.Item1 as SkinnedMeshRenderer) .ToList() ; foreach (var node in Nodes) { var gltfNode = ExportNode(node, Nodes, uniqueUnityMeshes, skins); _gltf.nodes.Add(gltfNode); } _gltf.scenes = new List <gltfScene> { new gltfScene { nodes = Copy.transform.GetChildren().Select(x => Nodes.IndexOf(x)).ToArray(), } }; foreach (var x in uniqueUnityMeshes) { foreach (var(renderer, uniqueBones) in x.Renderers) { if (uniqueBones != null && renderer is SkinnedMeshRenderer smr) { var matrices = x.GetBindPoses().Select(m_settings.InverseAxis.Create().InvertMat4).ToArray(); var accessor = _data.ExtendBufferAndGetAccessorIndex(matrices, glBufferTarget.NONE); var skin = new glTFSkin { inverseBindMatrices = accessor, joints = uniqueBones.Select(y => Nodes.IndexOf(y)).ToArray(), skeleton = Nodes.IndexOf(smr.rootBone), }; var skinIndex = _gltf.skins.Count; _gltf.skins.Add(skin); foreach (var z in Nodes.Where(y => y.Has(renderer))) { var nodeIndex = Nodes.IndexOf(z); var node = _gltf.nodes[nodeIndex]; node.skin = skinIndex; } } } } #endregion #if UNITY_EDITOR #region Animations ReportProgress("Animations", 0.9f); var clips = new List <AnimationClip>(); var animator = Copy.GetComponent <Animator>(); var animation = Copy.GetComponent <Animation>(); if (animator != null) { clips = AnimationExporter.GetAnimationClips(animator); } else if (animation != null) { clips = AnimationExporter.GetAnimationClips(animation); } if (clips.Any()) { foreach (AnimationClip clip in clips) { var animationWithCurve = AnimationExporter.Export(clip, Copy.transform, Nodes); foreach (var kv in animationWithCurve.SamplerMap) { var sampler = animationWithCurve.Animation.samplers[kv.Key]; var inputAccessorIndex = _data.ExtendBufferAndGetAccessorIndex(kv.Value.Input); sampler.input = inputAccessorIndex; var outputAccessorIndex = _data.ExtendBufferAndGetAccessorIndex(kv.Value.Output); sampler.output = outputAccessorIndex; // modify accessors var outputAccessor = _gltf.accessors[outputAccessorIndex]; var channel = animationWithCurve.Animation.channels.First(x => x.sampler == kv.Key); switch (glTFAnimationTarget.GetElementCount(channel.target.path)) { case 1: outputAccessor.type = "SCALAR"; //outputAccessor.count = ; break; case 3: outputAccessor.type = "VEC3"; outputAccessor.count /= 3; break; case 4: outputAccessor.type = "VEC4"; outputAccessor.count /= 4; break; default: throw new NotImplementedException(); } } animationWithCurve.Animation.name = clip.name; _gltf.animations.Add(animationWithCurve.Animation); } } #endregion #endif ExportExtensions(textureSerializer); // Extension で Texture が増える場合があるので最後に呼ぶ var exported = _textureExporter.Export(); for (var exportedTextureIdx = 0; exportedTextureIdx < exported.Count; ++exportedTextureIdx) { var(unityTexture, colorSpace) = exported[exportedTextureIdx]; GltfTextureExporter.PushGltfTexture(_data, unityTexture, colorSpace, textureSerializer); } FixName(_gltf); }
public void FromGameObject(glTF gltf, GameObject go, bool useSparseAccessorForMorphTarget = false) { var bytesBuffer = new ArrayByteBuffer(new byte[50 * 1024 * 1024]); var bufferIndex = gltf.AddBuffer(bytesBuffer); GameObject tmpParent = null; if (go.transform.childCount == 0) { tmpParent = new GameObject("tmpParent"); go.transform.SetParent(tmpParent.transform, true); go = tmpParent; } try { Nodes = go.transform.Traverse() .Skip(1) // exclude root object for the symmetry with the importer .ToList(); #region Materials and Textures Materials = Nodes.SelectMany(x => x.GetSharedMaterials()).Where(x => x != null).Distinct().ToList(); var unityTextures = Materials.SelectMany(x => TextureIO.GetTextures(x)).Where(x => x.Texture != null).Distinct().ToList(); List <Texture> exportTextures = null; Textures = unityTextures.Select(y => y.Texture).ToList(); var materialExporter = CreateMaterialExporter(); gltf.materials = Materials.Select(x => materialExporter.ExportMaterial(x, Textures, out exportTextures)).ToList(); for (int i = 0; i < unityTextures.Count; ++i) { var unityTexture = unityTextures[i]; TextureIO.ExportTexture(gltf, bufferIndex, exportTextures[i], unityTexture.TextureType); } #endregion #region Meshes var unityMeshes = Nodes .Select(x => new MeshWithRenderer { Mesh = x.GetSharedMesh(), Rendererer = x.GetComponent <Renderer>(), }) .Where(x => { if (x.Mesh == null) { return(false); } if (x.Rendererer.sharedMaterials == null || x.Rendererer.sharedMaterials.Length == 0) { return(false); } return(true); }) .ToList(); ExportMeshes(gltf, bufferIndex, unityMeshes, Materials, useSparseAccessorForMorphTarget); Meshes = unityMeshes.Select(x => x.Mesh).ToList(); #endregion #region Skins var unitySkins = Nodes .Select(x => x.GetComponent <SkinnedMeshRenderer>()).Where(x => x != null && x.bones != null && x.bones.Length > 0) .ToList(); gltf.nodes = Nodes.Select(x => ExportNode(x, Nodes, unityMeshes.Select(y => y.Mesh).ToList(), unitySkins)).ToList(); gltf.scenes = new List <gltfScene> { new gltfScene { nodes = go.transform.GetChildren().Select(x => Nodes.IndexOf(x)).ToArray(), } }; foreach (var x in unitySkins) { var matrices = x.sharedMesh.bindposes.Select(y => y.ReverseZ()).ToArray(); var accessor = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, matrices, glBufferTarget.NONE); var skin = new glTFSkin { inverseBindMatrices = accessor, joints = x.bones.Select(y => Nodes.IndexOf(y)).ToArray(), skeleton = Nodes.IndexOf(x.rootBone), }; var skinIndex = gltf.skins.Count; gltf.skins.Add(skin); foreach (var z in Nodes.Where(y => y.Has(x))) { var nodeIndex = Nodes.IndexOf(z); var node = gltf.nodes[nodeIndex]; node.skin = skinIndex; } } #endregion #if UNITY_EDITOR #region Animations var clips = new List <AnimationClip>(); var animator = go.GetComponent <Animator>(); var animation = go.GetComponent <Animation>(); if (animator != null) { clips = AnimationExporter.GetAnimationClips(animator); } else if (animation != null) { clips = AnimationExporter.GetAnimationClips(animation); } if (clips.Any()) { foreach (AnimationClip clip in clips) { var animationWithCurve = AnimationExporter.Export(clip, go.transform, Nodes); foreach (var kv in animationWithCurve.SamplerMap) { var sampler = animationWithCurve.Animation.samplers[kv.Key]; var inputAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, kv.Value.Input); sampler.input = inputAccessorIndex; var outputAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, kv.Value.Output); sampler.output = outputAccessorIndex; // modify accessors var outputAccessor = gltf.accessors[outputAccessorIndex]; var channel = animationWithCurve.Animation.channels.First(x => x.sampler == kv.Key); switch (glTFAnimationTarget.GetElementCount(channel.target.path)) { case 1: outputAccessor.type = "SCALAR"; outputAccessor.count = 1; break; case 3: outputAccessor.type = "VEC3"; outputAccessor.count /= 3; break; case 4: outputAccessor.type = "VEC4"; outputAccessor.count /= 4; break; default: throw new NotImplementedException(); } } gltf.animations.Add(animationWithCurve.Animation); } } #endregion #endif } finally { if (tmpParent != null) { tmpParent.transform.GetChild(0).SetParent(null); if (Application.isPlaying) { GameObject.Destroy(tmpParent); } else { GameObject.DestroyImmediate(tmpParent); } } } }
public virtual void Export(MeshExportSettings meshExportSettings, ITextureSerializer textureSerializer) { var bytesBuffer = new ArrayByteBuffer(new byte[50 * 1024 * 1024]); var bufferIndex = glTF.AddBuffer(bytesBuffer); Nodes = Copy.transform.Traverse() .Skip(1) // exclude root object for the symmetry with the importer .ToList(); var unityMeshes = MeshWithRenderer.FromNodes(Nodes).Where(x => x.Mesh.vertices.Any()).ToList(); var uniqueUnityMeshes = new List <MeshWithRenderer>(); foreach (var um in unityMeshes) { if (!uniqueUnityMeshes.Any(x => x.IsSameMeshAndMaterials(um))) { uniqueUnityMeshes.Add(um); } } #region Materials and Textures Materials = uniqueUnityMeshes.SelectMany(x => x.Renderer.sharedMaterials).Where(x => x != null).Distinct().ToList(); TextureExporter = new TextureExporter(textureSerializer); var materialExporter = CreateMaterialExporter(); glTF.materials = Materials.Select(x => materialExporter.ExportMaterial(x, TextureExporter)).ToList(); #endregion #region Meshes MeshBlendShapeIndexMap = new Dictionary <Mesh, Dictionary <int, int> >(); foreach (var unityMesh in uniqueUnityMeshes) { var(gltfMesh, blendShapeIndexMap) = MeshExporter.ExportMesh(glTF, bufferIndex, unityMesh, Materials, meshExportSettings, m_axisInverter); glTF.meshes.Add(gltfMesh); Meshes.Add(unityMesh.Mesh); if (!MeshBlendShapeIndexMap.ContainsKey(unityMesh.Mesh)) { // 同じmeshが複数回現れた MeshBlendShapeIndexMap.Add(unityMesh.Mesh, blendShapeIndexMap); } } #endregion #region Nodes and Skins var unitySkins = uniqueUnityMeshes .Where(x => x.UniqueBones != null) .ToList(); glTF.nodes = Nodes.Select(x => ExportNode(x, Nodes, uniqueUnityMeshes, unitySkins.Select(y => y.Renderer as SkinnedMeshRenderer).ToList())).ToList(); glTF.scenes = new List <gltfScene> { new gltfScene { nodes = Copy.transform.GetChildren().Select(x => Nodes.IndexOf(x)).ToArray(), } }; foreach (var x in unitySkins) { var matrices = x.GetBindPoses().Select(m_axisInverter.InvertMat4).ToArray(); var accessor = glTF.ExtendBufferAndGetAccessorIndex(bufferIndex, matrices, glBufferTarget.NONE); var renderer = x.Renderer as SkinnedMeshRenderer; var skin = new glTFSkin { inverseBindMatrices = accessor, joints = x.UniqueBones.Select(y => Nodes.IndexOf(y)).ToArray(), skeleton = Nodes.IndexOf(renderer.rootBone), }; var skinIndex = glTF.skins.Count; glTF.skins.Add(skin); foreach (var z in Nodes.Where(y => y.Has(x.Renderer))) { var nodeIndex = Nodes.IndexOf(z); var node = glTF.nodes[nodeIndex]; node.skin = skinIndex; } } #endregion #if UNITY_EDITOR #region Animations var clips = new List <AnimationClip>(); var animator = Copy.GetComponent <Animator>(); var animation = Copy.GetComponent <Animation>(); if (animator != null) { clips = AnimationExporter.GetAnimationClips(animator); } else if (animation != null) { clips = AnimationExporter.GetAnimationClips(animation); } if (clips.Any()) { foreach (AnimationClip clip in clips) { var animationWithCurve = AnimationExporter.Export(clip, Copy.transform, Nodes); foreach (var kv in animationWithCurve.SamplerMap) { var sampler = animationWithCurve.Animation.samplers[kv.Key]; var inputAccessorIndex = glTF.ExtendBufferAndGetAccessorIndex(bufferIndex, kv.Value.Input); sampler.input = inputAccessorIndex; var outputAccessorIndex = glTF.ExtendBufferAndGetAccessorIndex(bufferIndex, kv.Value.Output); sampler.output = outputAccessorIndex; // modify accessors var outputAccessor = glTF.accessors[outputAccessorIndex]; var channel = animationWithCurve.Animation.channels.First(x => x.sampler == kv.Key); switch (glTFAnimationTarget.GetElementCount(channel.target.path)) { case 1: outputAccessor.type = "SCALAR"; //outputAccessor.count = ; break; case 3: outputAccessor.type = "VEC3"; outputAccessor.count /= 3; break; case 4: outputAccessor.type = "VEC4"; outputAccessor.count /= 4; break; default: throw new NotImplementedException(); } } animationWithCurve.Animation.name = clip.name; glTF.animations.Add(animationWithCurve.Animation); } } #endregion #endif ExportExtensions(textureSerializer); // Extension で Texture が増える場合があるので最後に呼ぶ for (int i = 0; i < TextureExporter.Exported.Count; ++i) { var(unityTexture, colorSpace) = TextureExporter.Exported[i]; glTF.PushGltfTexture(bufferIndex, unityTexture, colorSpace, textureSerializer); } }
public static AnimationWithSampleCurves Export(AnimationClip clip, Transform root, List <Transform> nodes) { var animation = new AnimationWithSampleCurves { Animation = new glTFAnimation(), }; List <AnimationCurveData> curveDatas = new List <AnimationCurveData>(); foreach (var binding in AnimationUtility.GetCurveBindings(clip)) { var curve = AnimationUtility.GetEditorCurve(clip, binding); var property = AnimationExporter.PropertyToTarget(binding.propertyName); if (property == glTFAnimationTarget.AnimationPropertys.NotImplemented || property == glTFAnimationTarget.AnimationPropertys.BlendShape) { Debug.LogWarning("Not Implemented keyframe property : " + binding.propertyName); continue; } if (property == glTFAnimationTarget.AnimationPropertys.EulerRotation) { Debug.LogWarning("Interpolation setting of AnimationClip should be Quaternion"); continue; } var nodeIndex = GetNodeIndex(root, nodes, binding.path); var samplerIndex = animation.Animation.AddChannelAndGetSampler(nodeIndex, property); // 同一のsamplerIndexが割り当てられているcurveDataがある場合はそれを使用し、無ければ作る var curveData = curveDatas.FirstOrDefault(x => x.SamplerIndex == samplerIndex); if (curveData == null) { curveData = new AnimationCurveData(AnimationUtility.GetKeyRightTangentMode(curve, 0), property, samplerIndex); curveDatas.Add(curveData); } // 全てのキーフレームを回収 var elementOffset = AnimationExporter.GetElementOffset(binding.propertyName); for (int i = 0; i < curve.keys.Length; i++) { curveData.SetKeyframeData(curve.keys[i].time, curve.keys[i].value, elementOffset); } } //キー挿入 foreach (var curve in curveDatas) { if (curve.Keyframes.Count == 0) { continue; } curve.RecountEmptyKeyframe(); var elementNum = curve.Keyframes.First().MValues.Length; var values = default(InputOutputValues); if (!animation.SamplerMap.TryGetValue(curve.SamplerIndex, out values)) { values = new InputOutputValues(); values.Input = new float[curve.Keyframes.Count]; values.Output = new float[curve.Keyframes.Count * elementNum]; animation.SamplerMap[curve.SamplerIndex] = values; animation.Animation.samplers[curve.SamplerIndex].interpolation = curve.GetInterpolation(); } int keyframeIndex = 0; foreach (var keyframe in curve.Keyframes) { values.Input[keyframeIndex] = keyframe.Time; Buffer.BlockCopy(keyframe.GetRightHandCoordinate(), 0, values.Output, keyframeIndex * elementNum * sizeof(float), elementNum * sizeof(float)); keyframeIndex++; } } return(animation); }
public virtual void Export(MeshExportSettings meshExportSettings) { var bytesBuffer = new ArrayByteBuffer(new byte[50 * 1024 * 1024]); var bufferIndex = glTF.AddBuffer(bytesBuffer); GameObject tmpParent = null; if (Copy.transform.childCount == 0) { tmpParent = new GameObject("tmpParent"); Copy.transform.SetParent(tmpParent.transform, true); Copy = tmpParent; } try { Nodes = Copy.transform.Traverse() .Skip(1) // exclude root object for the symmetry with the importer .ToList(); #region Materials and Textures Materials = Nodes.SelectMany(x => x.GetSharedMaterials()).Where(x => x != null).Distinct().ToList(); var unityTextures = Materials.SelectMany(x => TextureIO.GetTextures(x)).Where(x => x.Texture != null).Distinct().ToList(); TextureManager = new TextureExportManager(unityTextures.Select(x => x.Texture)); var materialExporter = CreateMaterialExporter(); glTF.materials = Materials.Select(x => materialExporter.ExportMaterial(x, TextureManager)).ToList(); for (int i = 0; i < unityTextures.Count; ++i) { var unityTexture = unityTextures[i]; TextureIO.ExportTexture(glTF, bufferIndex, TextureManager.GetExportTexture(i), unityTexture.TextureType); } #endregion #region Meshes var unityMeshes = MeshWithRenderer.FromNodes(Nodes).ToList(); MeshBlendShapeIndexMap = new Dictionary <Mesh, Dictionary <int, int> >(); foreach (var(mesh, gltfMesh, blendShapeIndexMap) in MeshExporter.ExportMeshes( glTF, bufferIndex, unityMeshes, Materials, meshExportSettings)) { glTF.meshes.Add(gltfMesh); if (!MeshBlendShapeIndexMap.ContainsKey(mesh)) { // 同じmeshが複数回現れた MeshBlendShapeIndexMap.Add(mesh, blendShapeIndexMap); } } Meshes = unityMeshes.Select(x => x.Mesh).ToList(); #endregion #region Nodes and Skins var unitySkins = unityMeshes .Where(x => x.UniqueBones != null) .ToList(); glTF.nodes = Nodes.Select(x => ExportNode(x, Nodes, unityMeshes.Select(y => y.Renderer).ToList(), unitySkins.Select(y => y.Renderer as SkinnedMeshRenderer).ToList())).ToList(); glTF.scenes = new List <gltfScene> { new gltfScene { nodes = Copy.transform.GetChildren().Select(x => Nodes.IndexOf(x)).ToArray(), } }; foreach (var x in unitySkins) { var matrices = x.GetBindPoses().Select(y => y.ReverseZ()).ToArray(); var accessor = glTF.ExtendBufferAndGetAccessorIndex(bufferIndex, matrices, glBufferTarget.NONE); var renderer = x.Renderer as SkinnedMeshRenderer; var skin = new glTFSkin { inverseBindMatrices = accessor, joints = x.UniqueBones.Select(y => Nodes.IndexOf(y)).ToArray(), skeleton = Nodes.IndexOf(renderer.rootBone), }; var skinIndex = glTF.skins.Count; glTF.skins.Add(skin); foreach (var z in Nodes.Where(y => y.Has(x.Renderer))) { var nodeIndex = Nodes.IndexOf(z); var node = glTF.nodes[nodeIndex]; node.skin = skinIndex; } } #endregion #if UNITY_EDITOR #region Animations var clips = new List <AnimationClip>(); var animator = Copy.GetComponent <Animator>(); var animation = Copy.GetComponent <Animation>(); if (animator != null) { clips = AnimationExporter.GetAnimationClips(animator); } else if (animation != null) { clips = AnimationExporter.GetAnimationClips(animation); } if (clips.Any()) { foreach (AnimationClip clip in clips) { var animationWithCurve = AnimationExporter.Export(clip, Copy.transform, Nodes); foreach (var kv in animationWithCurve.SamplerMap) { var sampler = animationWithCurve.Animation.samplers[kv.Key]; var inputAccessorIndex = glTF.ExtendBufferAndGetAccessorIndex(bufferIndex, kv.Value.Input); sampler.input = inputAccessorIndex; var outputAccessorIndex = glTF.ExtendBufferAndGetAccessorIndex(bufferIndex, kv.Value.Output); sampler.output = outputAccessorIndex; // modify accessors var outputAccessor = glTF.accessors[outputAccessorIndex]; var channel = animationWithCurve.Animation.channels.First(x => x.sampler == kv.Key); switch (glTFAnimationTarget.GetElementCount(channel.target.path)) { case 1: outputAccessor.type = "SCALAR"; //outputAccessor.count = ; break; case 3: outputAccessor.type = "VEC3"; outputAccessor.count /= 3; break; case 4: outputAccessor.type = "VEC4"; outputAccessor.count /= 4; break; default: throw new NotImplementedException(); } } animationWithCurve.Animation.name = clip.name; glTF.animations.Add(animationWithCurve.Animation); } } #endregion #endif } finally { if (tmpParent != null) { tmpParent.transform.GetChild(0).SetParent(null); if (Application.isPlaying) { GameObject.Destroy(tmpParent); } else { GameObject.DestroyImmediate(tmpParent); } } } }
public static AnimationWithSampleCurves Export(AnimationClip clip, Transform root, List <Transform> nodes) { var animation = new AnimationWithSampleCurves { Animation = new glTFAnimation(), }; List <AnimationCurveData> curveDatum = new List <AnimationCurveData>(); foreach (var binding in AnimationUtility.GetCurveBindings(clip)) { var curve = AnimationUtility.GetEditorCurve(clip, binding); if (!curve.keys.Any()) { throw new Exception("There is no keyframe in AnimationCurve : " + clip.name); } var property = AnimationExporter.PropertyToTarget(binding.propertyName); if (property == glTFAnimationTarget.AnimationProperties.NotImplemented) { Debug.LogWarning("Not Implemented keyframe property : " + binding.propertyName); continue; } if (property == glTFAnimationTarget.AnimationProperties.EulerRotation) { Debug.LogWarning("Interpolation setting of AnimationClip should be Quaternion"); continue; } var nodeIndex = GetNodeIndex(root, nodes, binding.path); var samplerIndex = animation.Animation.AddChannelAndGetSampler(nodeIndex, property); var elementCount = 0; if (property == glTFAnimationTarget.AnimationProperties.BlendShape) { var mesh = nodes[nodeIndex].GetComponent <SkinnedMeshRenderer>().sharedMesh; elementCount = mesh.blendShapeCount; } else { elementCount = glTFAnimationTarget.GetElementCount(property); } // 同一のsamplerIndexが割り当てられているcurveDataがある場合はそれを使用し、無ければ作る var curveData = curveDatum.FirstOrDefault(x => x.SamplerIndex == samplerIndex); if (curveData == null) { curveData = new AnimationCurveData(AnimationUtility.GetKeyRightTangentMode(curve, 0), property, samplerIndex, elementCount); curveDatum.Add(curveData); } // 全てのキーフレームを回収 int elementOffset = 0; float valueFactor = 1.0f; if (property == glTFAnimationTarget.AnimationProperties.BlendShape) { var mesh = nodes[nodeIndex].GetComponent <SkinnedMeshRenderer>().sharedMesh; var blendShapeName = binding.propertyName.Replace("blendShape.", ""); elementOffset = mesh.GetBlendShapeIndex(blendShapeName); valueFactor = 0.01f; } else { elementOffset = AnimationExporter.GetElementOffset(binding.propertyName); } if (elementOffset >= 0 && elementOffset < elementCount) { for (int i = 0; i < curve.keys.Length; i++) { curveData.SetKeyframeData(curve.keys[i].time, curve.keys[i].value * valueFactor, elementOffset); } } } //キー挿入 foreach (var curve in curveDatum) { if (curve.Keyframes.Count == 0) { continue; } curve.RecountEmptyKeyframe(); var elementNum = curve.Keyframes.First().Values.Length; var values = default(InputOutputValues); if (!animation.SamplerMap.TryGetValue(curve.SamplerIndex, out values)) { values = new InputOutputValues(); values.Input = new float[curve.Keyframes.Count]; values.Output = new float[curve.Keyframes.Count * elementNum]; animation.SamplerMap[curve.SamplerIndex] = values; animation.Animation.samplers[curve.SamplerIndex].interpolation = curve.GetInterpolation(); } int keyframeIndex = 0; foreach (var keyframe in curve.Keyframes) { values.Input[keyframeIndex] = keyframe.Time; Buffer.BlockCopy(keyframe.GetRightHandCoordinate(), 0, values.Output, keyframeIndex * elementNum * sizeof(float), elementNum * sizeof(float)); keyframeIndex++; } } return(animation); }