/// <summary> /// モーションクリップをアセットとして保存する。 /// </summary> static void save(UnityEngine.Object[] selectedObjects, MotionClip motionClip) { // 渡されたアセットと同じ場所のパス生成 var srcFilePath = AssetDatabase.GetAssetPath(selectedObjects.OfType <GameObject>().First()); var folderPath = Path.GetDirectoryName(srcFilePath); var fileName = Path.GetFileNameWithoutExtension(srcFilePath); var dstFilePath = folderPath + $"/Motion {fileName}.asset"; // アセットとして MotionClip を生成 AssetDatabase.CreateAsset(motionClip, dstFilePath); AssetDatabase.Refresh(); }
static public void ConvertFrom(this MotionDataInNative dst, MotionClip src) { // ボーン var qParentBones = from parentPath in src.StreamPaths.Select(path => getParent(path)) // ペアレントパス列挙 join pathIndex in src.StreamPaths.Select((path, i) => (path, i)) // 順序数を保持する索引と外部結合する on parentPath equals pathIndex.path into pathIndexes from pathIndex in pathIndexes.DefaultIfEmpty((path: "", i: -1)) // 結合できないパスは -1 select pathIndex.i ; string getParent(string path) => Path.GetDirectoryName(path).Replace("\\", "/"); // モーション var qMotions = from motion in src.MotionData.Motions select new MotionUnitInNative { TimeLength = motion.TimeLength }; // ソース全キー var qKeys = from motion in src.MotionData.Motions from section in motion.Sections from stream in section.Streams from key in Enumerable.Zip(stream.keys.Append(new KeyDataUnit()), stream.keys, (pre, now) => (pre, now)) select new KeyUnitInNative { // Time = new float4( key.now.Time - key.pre.Time, 0.0f, 0.0f, 0.0f ), Time = new float4(key.now.Time, 0.0f, 0.0f, 0.0f), Value = key.now.Value }; // インクリメンタルなキー位置を返す。苦肉の策。 var iKeyInPool = 0; Func <StreamDataUnit, int> indexResolver = stream => { var i = iKeyInPool; iKeyInPool += stream.keys.Length; return(i); }; //var baseSectionList = new [] { "m_LocalPosition", "m_LocalRotation", "m_LocalScale" }; // ストリームスライスの構築 var qStreamSlices = // モーションごとの3セクション配列を生成する。 from motion in src.MotionData.Motions let sections = motion.Sections.ToDictionary(section => section.SectionName) select new [] { sections.GetOrDefault("m_LocalPosition"), sections.GetOrDefault("m_LocalRotation"), sections.GetOrDefault("m_LocalScale") } into sectionArray // セクションは空の場合がある。空セクションのストリームも確保し、すべてデフォルトスライスを配置させる。 from section in sectionArray let streams = section.Streams?.ToDictionary(stream => stream.StreamPath) // ストリームも空の場合がある。空はデフォルトスライス。また並び順は src.StreamPaths の通り。 from streamPath in src.StreamPaths let stream = streams?.GetOrDefault(streamPath) ?? new StreamDataUnit() select new StreamSliceInNative { Stream = stream.keys != null ? new NativeSlice <KeyUnitInNative>(dst.pool.Keys, indexResolver(stream), stream.keys.Length) : new NativeSlice <KeyUnitInNative>() }; // 実体を確保 dst.pool.Motions = qMotions.ToNativeArray(Allocator.Persistent); dst.pool.Keys = qKeys.ToNativeArray(Allocator.Persistent); dst.pool.StreamSlices = qStreamSlices.ToNativeArray(Allocator.Persistent); dst.pool.BoneParents = qParentBones.ToNativeArray(Allocator.Persistent); dst.boneLength = src.StreamPaths.Length; }