private void ImportSprites(AssetImportContext ctx, AseFile aseFile, SpriteImportData[] spriteImportData) { int spriteCount = spriteImportData.Length; Sprite[] sprites = new Sprite[spriteCount]; for (int i = 0; i < spriteCount; i++) { Sprite sprite = Sprite.Create(atlas, spriteImportData[i].rect, spriteImportData[i].pivot, textureSettings.pixelsPerUnit, textureSettings.extrudeEdges, textureSettings.meshType, spriteImportData[i].border, textureSettings.generatePhysics); sprite.name = string.Format("{0}_{1}", name, spriteImportData[i].name); ctx.AddObjectToAsset(sprite.name, sprite); //AssetDatabase.CreateAsset(sprite, GetFolderPath(ctx.assetPath) + "/" + sprite.name + ".asset"); //AssetDatabase.Refresh(); sprites[i] = sprite; } //如果有Tag if (aseFile.GetAnimations().Length > 0) { GenerateAnimations(ctx, aseFile, sprites); } else { GenerateAnimation(ctx, aseFile, sprites); } }
//导入 public override void OnImportAsset(AssetImportContext ctx) { name = GetFileName(ctx.assetPath); AseFile aseFile = ReadAseFile(ctx.assetPath); Texture2D[] frames = aseFile.GetFrames(); //翻转贴图 //if (textureSettings.flipTexture) { // for (int i = 0; i < frames.Length; i++) { // frames[i] = FlipTexture(frames[i]); // } //} SpriteImportData[] spriteImportData = new SpriteImportData[0]; Vector2Int size = new Vector2Int(aseFile.Header.Width, aseFile.Header.Height); atlas = AseAtlasGenerator.GenerateAtlas(frames, out spriteImportData, size, textureSettings); atlas.filterMode = FilterMode.Point; ctx.AddObjectToAsset("Texture", atlas); //生成贴图文件 GenerateSprites(ctx, aseFile, spriteImportData); ctx.SetMainObject(atlas); }
private static AseFile ReadAseFile(string assetPath) { var fileStream = new FileStream(assetPath, FileMode.Open, FileAccess.Read); var aseFile = new AseFile(fileStream); fileStream.Close(); return(aseFile); }
public override void OnImportAsset(AssetImportContext ctx) { name = GetFileName(ctx.assetPath); AseFile aseFile = ReadAseFile(ctx.assetPath); int frameCount = aseFile.Header.Frames; SpriteAtlasBuilder atlasBuilder = new SpriteAtlasBuilder(textureSettings, aseFile.Header.Width, aseFile.Header.Height); Texture2D[] frames = null; if (importType != AseFileImportType.LayerToSprite) { frames = aseFile.GetFrames(); } else { frames = aseFile.GetLayersAsFrames(); } SpriteImportData[] spriteImportData = new SpriteImportData[0]; //if (textureSettings.transparentMask) //{ // atlas = atlasBuilder.GenerateAtlas(frames, out spriteImportData, textureSettings.transparentColor, false); //} //else //{ // atlas = atlasBuilder.GenerateAtlas(frames, out spriteImportData, false); //} atlas = atlasBuilder.GenerateAtlas(frames, out spriteImportData, textureSettings.transparentMask, false); atlas.filterMode = textureSettings.filterMode; atlas.alphaIsTransparency = false; atlas.wrapMode = TextureWrapMode.Clamp; atlas.name = "Texture"; ctx.AddObjectToAsset("Texture", atlas); ctx.SetMainObject(atlas); switch (importType) { case AseFileImportType.LayerToSprite: case AseFileImportType.Sprite: ImportSprites(ctx, aseFile, spriteImportData); break; case AseFileImportType.Tileset: ImportTileset(ctx, atlas); break; } ctx.SetMainObject(atlas); }
static List <FrameImage> LoadFrameImage(string baseName, AseFile file, Frame frame) { var cels = frame.Cels.OrderBy(it => it.LayerIndex).ToList(); var subImages = file.SubImages.ToList(); var images = new List <FrameImage>(); for (var subImageIndex = 0; subImageIndex < subImages.Count; subImageIndex++) { var subImage = subImages[subImageIndex]; var spriteName = string.IsNullOrEmpty(subImage.ImageName) ? baseName : subImage.ImageName; var image = new FrameImage(frame.FrameId, spriteName, subImageIndex, file.Width, file.Height); foreach (var cel in cels) { var layer = subImage.FindLayer(cel.LayerIndex); if (layer == null || layer.Type != LayerType.Content) { continue; } Debug.Log($"Cel size: {cel.X}, {cel.Y}, {cel.Width}, {cel.Height}"); // Cels can have data outside of the visible frame area. // As we are manipulating image data, not cel data, this // can cause problems if we dont check bounds carefully. var maxX = Math.Min(image.Width - cel.X, cel.Width); var maxY = Math.Min(image.Height - cel.Y, cel.Height); var minX = Math.Max(0, -cel.X); var minY = Math.Max(0, -cel.Y); Debug.Log($"Cel processing: {minX}, {minY}, {maxX}, {maxY}"); for (int cy = minY; cy < maxY; ++cy) { for (int cx = minX; cx < maxX; ++cx) { var x = cx + cel.X; var y = cy + cel.Y; var layerColor = cel.GetPixel(x, y); if (layerColor.a > 0f) { image[x, y] = AlphaBlend(image[x, y], layerColor); } } } } images.Add(image); } return(images); }
public override void OnImportAsset(AssetImportContext ctx) { texture = null; name = GetFileName(ctx.assetPath); AseFile file = ReadAseFile(ctx.assetPath); CurrentImporter.Import(ctx, file); CleanUp(); }
public static List <FrameImage> LoadImages(string baseName, AseFile file) { var retval = new List <FrameImage>(); foreach (var frame in file) { var loadFrameImage = LoadFrameImage(baseName, file, frame); retval.AddRange(loadFrameImage); } return(retval); }
static List <IntRect> ComputeFrameBoundingBoxes(Layer layer, AseFile file) { var frameRects = new List <IntRect>(); foreach (var frame in file) { Cel cel; var boundingBox = frame.TryGetCel(layer.Index, out cel) ? cel.GetBoundingBox() : new IntRect(); frameRects.Add(boundingBox); } return(frameRects); }
//生成动画组 void GenerateAnimations(AssetImportContext ctx, AseFile aseFile, AseFrame[] frames) { FrameTag[] tags = aseFile.GetAnimations(); List <AseAnimationSettings> settingList; //如果当前没有保存的动画设置 if (animationSettings == null || animationSettings.Length == 0) { settingList = new List <AseAnimationSettings>(); } //已有保存的动画设置 else { //去除其中已失效的动画 RemoveUnusedAnimationSettings(tags); settingList = new List <AseAnimationSettings>(animationSettings); } //如果一个Tag都没有 if (tags.Length == 0) { //直接以文件命名 //生成动画 AseAnimationSettings animationSetting = GenerateAnimation(ctx, name, frames); if (!settingList.Contains(animationSetting)) { settingList.Add(animationSetting); } } //有Tag else { for (int i = 0; i < tags.Length; i++) { FrameTag tag = tags[i]; string animationName = GetAnimationName(tag.TagName); //生成动画 AseAnimationSettings animationSetting = GenerateAnimation(ctx, animationName, frames, tag.FrameFrom, tag.FrameTo); if (!settingList.Contains(animationSetting)) { settingList.Add(animationSetting); } } } animationSettings = settingList.ToArray(); }
static HashSet <int> ComputeEventFrameSet(Layer layer, AseFile file) { var eventFrames = new HashSet <int>(); foreach (var frame in file) { Cel ignored; if (frame.TryGetCel(layer.Index, out ignored)) { eventFrames.Add(frame.FrameId); } } return(eventFrames); }
public ImportContext([NotNull] string path, [NotNull] RuntimeSettings settings) { if (path == null) { throw new ArgumentNullException(nameof(path)); } if (settings == null) { throw new ArgumentNullException(nameof(settings)); } this.AseFile = AseFileParser.Parse(path); this.BaseName = Path.GetFileNameWithoutExtension(path); this.Settings = settings; }
private void ImportSprites(AssetImportContext ctx, AseFile aseFile, SpriteImportData[] spriteImportData) { int spriteCount = spriteImportData.Length; Sprite[] sprites = new Sprite[spriteCount]; for (int i = 0; i < spriteCount; i++) { Sprite sprite = Sprite.Create(atlas, spriteImportData[i].rect, spriteImportData[i].pivot, textureSettings.pixelsPerUnit, textureSettings.extrudeEdges, textureSettings.meshType, spriteImportData[i].border, textureSettings.generatePhysics); sprite.name = string.Format("{0}_{1}", name, spriteImportData[i].name); ctx.AddObjectToAsset(sprite.name, sprite); sprites[i] = sprite; } GenerateAnimations(ctx, aseFile, sprites); }
private void GenerateSeparateTexturesFromLayers(AssetImportContext ctx, AseFile aseFile) { SpriteAtlasBuilder atlasBuilder = new SpriteAtlasBuilder(textureSettings, aseFile.Header.Width, aseFile.Header.Height); SpriteImportData[] spriteImportData = new SpriteImportData[0]; List <LayerChunk> layers = aseFile.GetChunks <LayerChunk>(); for (int i = 0; i < layers.Count; i++) { List <Texture2D> layerFrames = aseFile.GetLayerTexture(i, layers[i]); Texture2D layerAtlas; layerAtlas = atlasBuilder.GenerateAtlas(layerFrames.ToArray(), out spriteImportData, textureSettings.transparentMask, false); layerAtlas.filterMode = textureSettings.filterMode; layerAtlas.alphaIsTransparency = false; layerAtlas.wrapMode = TextureWrapMode.Clamp; layerAtlas.name = layers[i].LayerName; //AssetDatabase.CreateAsset( layerAtlas, Path.GetDirectoryName( ctx.assetPath ) + "/" + Path.GetFileNameWithoutExtension( ctx.assetPath ) + "-" + layers[i].LayerName + ".asset" ); ctx.AddObjectToAsset(layers[i].LayerName, layerAtlas); if (i == 0) { // assign member "atlas" for ImportSprites() etc below atlas = layerAtlas; ctx.SetMainObject(layerAtlas); } } switch (importType) { case AseFileImportType.LayerToSprite: case AseFileImportType.Sprite: ImportSprites(ctx, aseFile, spriteImportData); break; case AseFileImportType.Tileset: ImportTileset(ctx); break; } }
//生成贴图文件 void GenerateSprites(AssetImportContext ctx, AseFile aseFile, SpriteImportData[] spriteImportData) { int spriteCount = spriteImportData.Length; AseFrame[] frames = new AseFrame[spriteImportData.Length]; FrameTag[] tags = aseFile.GetAnimations(); for (int i = 0; i < spriteCount; i++) { Sprite sprite = Sprite.Create(atlas, spriteImportData[i].rect, spriteImportData[i].pivot, textureSettings.pixelsPerUnit, 1, SpriteMeshType.Tight, spriteImportData[i].border); sprite.name = string.Format("{0}_{1}", name, i); ctx.AddObjectToAsset(sprite.name, sprite); frames[i] = new AseFrame(sprite, aseFile.Frames[i].FrameDuration / 1000f); } //生成动画文件 GenerateAnimations(ctx, aseFile, frames); }
private void GenerateSeparateTexturesFromLayers(AssetImportContext ctx, AseFile aseFile) { SpriteAtlasBuilder atlasBuilder = new SpriteAtlasBuilder(textureSettings, aseFile.Header.Width, aseFile.Header.Height); List <LayerChunk> layers = aseFile.GetChunks <LayerChunk>(); SpriteImportData[] spriteImportData = new SpriteImportData[0]; { List <Texture2D> layerFrames = aseFile.GetLayerTexture(0, layers[0]); Texture2D layerAtlas = atlasBuilder.GenerateAtlas(layerFrames.ToArray(), out spriteImportData, textureSettings.transparentMask, false); layerAtlas.filterMode = textureSettings.filterMode; layerAtlas.alphaIsTransparency = false; layerAtlas.wrapMode = TextureWrapMode.Clamp; layerAtlas.name = layers[0].LayerName; //string assetpath = Path.GetDirectoryName( ctx.assetPath ) + "/" + Path.GetFileNameWithoutExtension( ctx.assetPath ) + "-" + layers[0].LayerName + ".asset"; //AssetDatabase.CreateAsset( layerAtlas, assetpath ); ctx.AddObjectToAsset(layers[0].LayerName, layerAtlas); switch (importType) { case AseFileImportType.LayerToSprite: case AseFileImportType.Sprite: ImportSprites(ctx, aseFile, spriteImportData, layerAtlas); break; case AseFileImportType.Tileset: ImportTileset(ctx, layerAtlas); break; } } for (int i = 1; i < layers.Count; i++) { List <Texture2D> layerFrames = aseFile.GetLayerTexture(i, layers[i]); Texture2D layerAtlas = atlasBuilder.GenerateAtlas(layerFrames.ToArray(), out _, textureSettings.transparentMask, false); layerAtlas.filterMode = textureSettings.filterMode; layerAtlas.alphaIsTransparency = false; layerAtlas.wrapMode = TextureWrapMode.Clamp; layerAtlas.name = layers[i].LayerName; ctx.AddObjectToAsset(layers[i].LayerName, layerAtlas); /* * string imagepath = Path.GetDirectoryName( ctx.assetPath ) + "/" + Path.GetFileNameWithoutExtension( ctx.assetPath ) + "-" + layers[i].LayerName + ".png"; * * Texture2D texture = AssetDatabase.LoadAssetAtPath<Texture2D>( imagepath ); * if( texture == null ) * { * File.WriteAllBytes( imagepath, layerAtlas.EncodeToPNG() ); * AssetDatabase.SaveAssets(); * } * else * { * * //texture.SetPixelData( layerAtlas.GetRawTextureData(), 0 ); * //EditorUtility.SetDirty( texture ); * } * AssetDatabase.Refresh(); * Texture2D asdf = AssetDatabase.LoadAssetAtPath<Texture2D>( imagepath ); * * //AssetDatabase.CreateAsset( layerAtlas, assetpath ); * * * TextureImporter textureImporter = GetAtPath( imagepath ) as TextureImporter; * if( textureImporter != null ) * { * SecondarySpriteTexture[] sst = new SecondarySpriteTexture[1]; * sst[0].name = "_NormalMap"; * sst[0].texture = layerAtlas; * textureImporter.secondarySpriteTextures = sst; * * EditorUtility.SetDirty( textureImporter ); * textureImporter.SaveAndReimport(); * * } */ } }
static int Main(string[] args) { if (!Options.CollectOptions(args)) { PrintBanner(); PrintUsage(); return(1); } else { //if (Options["nobanner"] == null) PrintBanner(); VerboseOutput("Source: " + Options["source"]); VerboseOutput("Target: " + Options["target"]); Options.CollectExtraOptions(); VerboseOutput("X-Name: " + Options["xname"]); VerboseOutput("Loading source..."); DataCollector dc = new DataCollector(); RealGeometryFile rgf = null; FileInfo fileInfo = new FileInfo(Options["source"]); if (fileInfo.Extension.ToLower() == ".mwr") { RawGeometryFile rg = new RawGeometryFile(); rg.Read(Options["source"]); VerboseOutput("Collecting data [Most Wanted Raw]..."); try { rgf = dc.Collect(rg); } catch (Exception e) { ErrorOutput("Exception: " + e.Message); return(1); } } else if (fileInfo.Extension.ToLower() == ".ase") { AseFile ase = new AseFile(); try { ase.Open(Options["source"]); } catch (Exception e) { ErrorOutput("ASE Exception: " + e.Message); return(1); } VerboseOutput("Collecting data [Ascii Scene Export]..."); try { rgf = dc.Collect(ase); } catch (Exception e) { ErrorOutput("Exception: " + e.Message); } } else { ErrorOutput("Unsupported source file extension."); return(1); } if (rgf == null) { ErrorOutput("Failed to collect data."); return(1); } else { VerboseOutput("Writing target file..."); rgf.Save(Options["target"]); VerboseOutput("Completed successfully."); } } if (Options["nowait"] == null) { Console.WriteLine(); Console.WriteLine("Press any key to continue..."); Console.ReadLine(); } return(0); }
private void GenerateAnimations(AssetImportContext ctx, AseFile aseFile, Sprite[] sprites) { if (animationSettings == null) { animationSettings = new AseFileAnimationSettings[0]; } var animSettings = new List <AseFileAnimationSettings>(animationSettings); var animations = aseFile.GetAnimations(); if (animations.Length <= 0) { return; } if (animationSettings != null) { RemoveUnusedAnimationSettings(animSettings, animations); } int index = 0; foreach (var animation in animations) { AnimationClip animationClip = new AnimationClip(); animationClip.name = name + "_" + animation.TagName; animationClip.frameRate = 25; AseFileAnimationSettings importSettings = GetAnimationSettingFor(animSettings, animation); importSettings.about = GetAnimationAbout(animation); EditorCurveBinding spriteBinding = new EditorCurveBinding(); spriteBinding.type = typeof(SpriteRenderer); spriteBinding.path = ""; spriteBinding.propertyName = "m_Sprite"; int length = animation.FrameTo - animation.FrameFrom + 1; ObjectReferenceKeyframe[] spriteKeyFrames = new ObjectReferenceKeyframe[length + 1]; // plus last frame to keep the duration float time = 0; int from = (animation.Animation != LoopAnimation.Reverse) ? animation.FrameFrom : animation.FrameTo; int step = (animation.Animation != LoopAnimation.Reverse) ? 1 : -1; int keyIndex = from; for (int i = 0; i < length; i++) { if (i >= length) { keyIndex = from; } ObjectReferenceKeyframe frame = new ObjectReferenceKeyframe(); frame.time = time; frame.value = sprites[keyIndex]; time += aseFile.Frames[keyIndex].FrameDuration / 1000f; keyIndex += step; spriteKeyFrames[i] = frame; } float frameTime = 1f / animationClip.frameRate; ObjectReferenceKeyframe lastFrame = new ObjectReferenceKeyframe(); lastFrame.time = time - frameTime; lastFrame.value = sprites[keyIndex - step]; spriteKeyFrames[spriteKeyFrames.Length - 1] = lastFrame; AnimationUtility.SetObjectReferenceCurve(animationClip, spriteBinding, spriteKeyFrames); AnimationClipSettings settings = AnimationUtility.GetAnimationClipSettings(animationClip); switch (animation.Animation) { case LoopAnimation.Forward: animationClip.wrapMode = WrapMode.Loop; settings.loopTime = true; break; case LoopAnimation.Reverse: animationClip.wrapMode = WrapMode.Loop; settings.loopTime = true; break; case LoopAnimation.PingPong: animationClip.wrapMode = WrapMode.PingPong; settings.loopTime = true; break; } if (!importSettings.loopTime) { animationClip.wrapMode = WrapMode.Once; settings.loopTime = false; } AnimationUtility.SetAnimationClipSettings(animationClip, settings); ctx.AddObjectToAsset(animation.TagName, animationClip); index++; } animationSettings = animSettings.ToArray(); }
public LinkedCelChunk(uint length, ushort layerIndex, short x, short y, byte opacity, Frame frame, BinaryReader reader) : base(length, layerIndex, x, y, opacity, CelType.Linked) { file = frame.File; FramePosition = reader.ReadUInt16(); }
private void GenerateAseAnimations(UnityEditor.AssetImporters.AssetImportContext ctx, AseFile aseFile, Sprite[] sprites) { if (animationSettings == null) { animationSettings = new AseFileAnimationSettings[0]; } var animSettings = new List <AseFileAnimationSettings>(animationSettings); var animations = aseFile.GetAnimations(); if (animations.Length <= 0) { return; } if (animationSettings != null) { RemoveUnusedAnimationSettings(animSettings, animations); } foreach (var animation in animations) { // AseAnim AseAnimation aseAnim = new AseAnimation(); aseAnim.name = aseAnim.Name = animation.TagName; AseFileAnimationSettings importSettings = GetAnimationSettingFor(animSettings, animation); importSettings.about = GetAnimationAbout(animation); int length = animation.FrameTo - animation.FrameFrom + 1; aseAnim.Points = new AseAnimation.KeyPoint[length]; aseAnim.LoopType = (AseAnimation.LoopAnimation)animation.Animation; aseAnim.Loop = length > 1; float time = 0; int from = (animation.Animation != LoopAnimation.Reverse) ? animation.FrameFrom : animation.FrameTo; int step = (animation.Animation != LoopAnimation.Reverse) ? 1 : -1; int keyIndex = from; for (int i = 0; i < length; i++) { if (i >= length) { keyIndex = from; } aseAnim.Points[i] = new AseAnimation.KeyPoint(sprites[keyIndex], aseFile.Frames[keyIndex].FrameDuration / 1000f); time += aseFile.Frames[keyIndex].FrameDuration / 1000f; keyIndex += step; } ctx.AddObjectToAsset(aseAnim.Name, aseAnim); } animationSettings = animSettings.ToArray(); }
public override void OnImportAsset(AssetImportContext ctx) { name = GetFileName(ctx.assetPath); AseFile aseFile = ReadAseFile(ctx.assetPath); int frameCount = aseFile.Header.Frames; SpriteAtlasBuilder atlasBuilder = new SpriteAtlasBuilder(textureSettings, aseFile.Header.Width, aseFile.Header.Height); Texture2D[] frames = null; if (importType != AseFileImportType.LayerToSprite) { frames = aseFile.GetFrames(textureSettings.ignoreBackground); } else { frames = aseFile.GetLayersAsFrames(); } SpriteImportData[] spriteImportData; //if (textureSettings.transparentMask) //{ // atlas = atlasBuilder.GenerateAtlas(frames, out spriteImportData, textureSettings.transparentColor, false); //} //else //{ // atlas = atlasBuilder.GenerateAtlas(frames, out spriteImportData, false); //} atlas = atlasBuilder.GenerateAtlas(frames, name, out spriteImportData, textureSettings.transparencyMode, false); atlas.filterMode = textureSettings.filterMode; atlas.alphaIsTransparency = textureSettings.transparencyMode == TransparencyMode.Alpha; atlas.wrapMode = textureSettings.wrapMode; atlas.name = "Texture"; MetaData[] metadatas = aseFile.GetMetaData(textureSettings.spritePivot, textureSettings.pixelsPerUnit); List <SecondarySpriteTexture> secondarySpriteTextures = new List <SecondarySpriteTexture>(); // Find any metadata with a secondary texture foreach (var metadata in metadatas) { if (metadata.Type == MetaDataType.SECONDARY_TEXTURE) { var textureName = metadata.Args[0]; var secondaryTextureFrames = aseFile.GetLayerTexture(metadata.LayerIndex, metadata.Layer); Texture2D secondaryTexture = atlasBuilder.GenerateAtlas(secondaryTextureFrames.ToArray(), name, out _, textureSettings.transparencyMode, false); secondaryTexture.alphaIsTransparency = textureSettings.transparencyMode == TransparencyMode.Alpha;; secondaryTexture.wrapMode = textureSettings.wrapMode; secondaryTexture.filterMode = textureSettings.filterMode; secondaryTexture.name = textureName; secondarySpriteTextures.Add(new SecondarySpriteTexture() { name = textureName, texture = secondaryTexture }); } } TextureGenerationSettings generationSettings = new TextureGenerationSettings(); generationSettings.platformSettings = new TextureImporterPlatformSettings(); generationSettings.spriteImportData = spriteImportData; generationSettings.secondarySpriteTextures = secondarySpriteTextures.ToArray(); generationSettings.sourceTextureInformation = new SourceTextureInformation() { width = atlas.width, height = atlas.height, containsAlpha = true, }; generationSettings.textureImporterSettings = new TextureImporterSettings { textureType = TextureImporterType.Sprite, textureShape = TextureImporterShape.Texture2D, alphaIsTransparency = textureSettings.transparencyMode == TransparencyMode.Alpha, alphaSource = TextureImporterAlphaSource.FromInput, spritePixelsPerUnit = textureSettings.pixelsPerUnit, spritePivot = textureSettings.spritePivot, spriteMeshType = SpriteMeshType.Tight, convertToNormalMap = false, mipmapEnabled = false, sRGBTexture = true, readable = false, fadeOut = false, wrapMode = TextureWrapMode.Clamp, wrapModeU = TextureWrapMode.Clamp, wrapModeV = TextureWrapMode.Clamp, wrapModeW = TextureWrapMode.Clamp }; var imageBuffer = atlas.GetRawTextureData <Color32>(); var generatedOutput = TextureGenerator.GenerateTexture(generationSettings, imageBuffer); generatedOutput.texture.name = "Texture"; // Main texture atlas ctx.AddObjectToAsset("Texture", generatedOutput.texture); ctx.SetMainObject(generatedOutput.texture); // Add secondary textures foreach (var secondarySpriteTexture in secondarySpriteTextures) { ctx.AddObjectToAsset("SecondaryTex_" + secondarySpriteTexture.name, secondarySpriteTexture.texture); } // Add sprites foreach (var sprite in generatedOutput.sprites) { ctx.AddObjectToAsset(sprite.name, sprite); } // Add animations if (importType == AseFileImportType.Sprite) { GenerateAnimations(ctx, aseFile, generatedOutput.sprites, metadatas); } switch (importType) { case AseFileImportType.LayerToSprite: case AseFileImportType.Sprite: // ImportSprites(ctx, aseFile, spriteImportData, metadatas); break; case AseFileImportType.Tileset: ImportTileset(ctx, atlas); break; } }
public AnimationImporter(AseFile aseFile) { this.aseFile = aseFile; }
public RealGeometryFile Collect(AseFile aseFile) { RealGeometryFile geom = new RealGeometryFile(); Hashtable MatTex = new Hashtable(); LoadMaterialHT(); for (int i = 0; i < aseFile.MaterialList.Count; i++) { MatTex.Add(i.ToString(), GetMatTexPair(aseFile.MaterialList[i].Name)); if (aseFile.MaterialList[i].HasSubMaterials) { for (int j = 0; j < aseFile.MaterialList[i].SubMaterialCount; j++) { MatTex.Add(string.Format("{0}/{1}", i, j), GetMatTexPair(aseFile.MaterialList[i][j].Name)); } } } ArrayList mountPointObjects = new ArrayList(); //ArrayList transparentObjects = new ArrayList(new string[] {"base_a","kit00_front_window_a","kit00_left_headlight_a"}); ArrayList transparentObjects = new ArrayList(); int diffuse; ArrayList basePartObjects = new ArrayList(); for (int i = 0; i < aseFile.ObjectCount; i++) { Compiler.VerboseOutput(string.Format("Compiling object {0}: {1}", i + 1, aseFile[i].Name)); if (aseFile[i].Name.StartsWith("#")) { string mountName; uint mountHash; mountName = aseFile[i].Name.Substring(1).ToUpper(); if (mountName.IndexOf("[") > -1) { mountName = mountName.Substring(0, mountName.IndexOf("[")); } if (mountName.StartsWith("0x")) { mountHash = uint.Parse(mountName.Substring(2), NumberStyles.HexNumber); } else { mountHash = RealHash(mountName); } Compiler.VerboseOutput(string.Format(" + Mount Point Name: {0}", mountName)); Compiler.VerboseOutput(string.Format(" + Compiled Hash: 0x{0:x}", mountHash)); RealMountPoint mp = new RealMountPoint(); mp.Hash = mountHash; mp.Transform = new RealMatrix(); mp.Transform.m = new float[16]; float[] transform = aseFile[i].Transform.Matrix; mp.Transform.m[0] = 1.0f; mp.Transform.m[5] = 1.0f; mp.Transform.m[10] = 1.0f; mp.Transform.m[15] = 1.0f; mp.Transform.m[12] = -transform[13]; //y mp.Transform.m[13] = transform[12]; //x mp.Transform.m[14] = transform[14]; //z mountPointObjects.Add(mp); } else { Hashtable subMeshes = new Hashtable(); UniqueList textures = new UniqueList(); UniqueList materials = new UniqueList(); if (transparentObjects.Contains(aseFile[i].Name)) { diffuse = 0x7FFFFFFF; } else { diffuse = -1; } for (int j = 0; j < aseFile[i].Mesh.FaceList.Count; j++) { SubMesh subMesh; AseFace face = aseFile[i].Mesh.FaceList[j]; string matId = aseFile[i].MaterialReference.ToString(); if (aseFile.MaterialList[aseFile[i].MaterialReference].HasSubMaterials) { matId += string.Format("/{0}", face.MaterialID); } MatTexPair pair = new MatTexPair(); MatTexStringPair strPair = (MatTexStringPair)MatTex[matId]; pair.Material = materials.Add(strPair.Material); pair.Texture = textures.Add(strPair.Texture); if (subMeshes.ContainsKey(pair)) { subMesh = subMeshes[pair] as SubMesh; } else { subMesh = new SubMesh(); subMesh.TextureId = pair.Texture; subMesh.MaterialId = pair.Material; subMeshes.Add(pair, subMesh); } AseVertex v1 = aseFile[i].Mesh.VertexList[face.A]; AseVertex v2 = aseFile[i].Mesh.VertexList[face.B]; AseVertex v3 = aseFile[i].Mesh.VertexList[face.C]; AseVertex nv1 = face.NormalA; AseVertex nv2 = face.NormalB; AseVertex nv3 = face.NormalC; AseVertex tv1 = aseFile[i].Mesh.TextureVertexList[face.TextureA]; AseVertex tv2 = aseFile[i].Mesh.TextureVertexList[face.TextureB]; AseVertex tv3 = aseFile[i].Mesh.TextureVertexList[face.TextureC]; RealVertex rv; // rv.Z controls UP/DOWN from front view // rv.Y controls LEFT/RIGHT from front view // rv.X controls IN/OUT from front view // v1 rv = new RealVertex(); rv.Initialize(true, 0); rv.Position.x = -v1.Y; rv.Position.y = v1.X; rv.Position.z = v1.Z; rv.Normal.x = -nv1.Y; rv.Normal.y = nv1.X; rv.Normal.z = nv1.Z; rv.Diffuse = diffuse; rv.UV.u = tv1.U; rv.UV.v = tv1.V; subMesh.IndexList.Add((ushort)subMesh.VertexList.Add(rv)); // v2 rv = new RealVertex(); rv.Initialize(true, 0); rv.Position.x = -v2.Y; rv.Position.y = v2.X; rv.Position.z = v2.Z; rv.Normal.x = -nv2.Y; rv.Normal.y = nv2.X; rv.Normal.z = nv2.Z; rv.Diffuse = diffuse; rv.UV.u = tv2.U; rv.UV.v = tv2.V; subMesh.IndexList.Add((ushort)subMesh.VertexList.Add(rv)); // v3 rv = new RealVertex(); rv.Initialize(true, 0); rv.Position.x = -v3.Y; rv.Position.y = v3.X; rv.Position.z = v3.Z; rv.Normal.x = -nv3.Y; rv.Normal.y = nv3.X; rv.Normal.z = nv3.Z; rv.Diffuse = diffuse; rv.UV.u = tv3.U; rv.UV.v = tv3.V; subMesh.IndexList.Add((ushort)subMesh.VertexList.Add(rv)); } Compiler.VerboseOutput(string.Format(" + Compiled into {0} submeshes", subMeshes.Count)); SubMesh[] subMeshList = new SubMesh[subMeshes.Count]; subMeshes.Values.CopyTo(subMeshList, 0); for (int j = 0; j < subMeshes.Count; j++) { SubMesh subMesh = subMeshList[j]; Compiler.VerboseOutput(string.Format(" + Submesh {0}:", j + 1)); Compiler.VerboseOutput(string.Format(" + Material: {0}", materials[subMesh.MaterialId])); Compiler.VerboseOutput(string.Format(" + Texture: {0}", textures[subMesh.TextureId])); Compiler.VerboseOutput(string.Format(" + Vertices: {0}", subMesh.VertexList.Count)); Compiler.VerboseOutput(string.Format(" + Triangles: {0}", subMesh.IndexList.Count / 3)); } Compiler.VerboseOutput(string.Format("Creating part data for binary object file...")); RealGeometryPart part = new RealGeometryPart(); //----- part info ---------- RealVector4 boundsMin; RealVector4 boundsMax; if (aseFile[i].Name.ToUpper().StartsWith("BASE_")) { basePartObjects.Add(part); } string resolvedName = ResolveRealNameForce(aseFile[i].Name); part.PartInfo.Hash = RealHash(resolvedName); part.PartInfo.PartName = new FixedLenString(resolvedName); part.PartInfo.ShaderCount = (byte)materials.Count; part.PartInfo.Shaders = new uint[materials.Count]; for (int j = 0; j < materials.Count; j++) { string matName = materials[j] as string; if (matName.StartsWith("0x")) { part.PartInfo.Shaders[j] = uint.Parse(matName.Substring(2), NumberStyles.HexNumber); } else { part.PartInfo.Shaders[j] = RealHash(matName); } } part.PartInfo.TextureCount = (byte)textures.Count; part.PartInfo.Textures = new uint[textures.Count]; for (int j = 0; j < textures.Count; j++) { string texName = textures[j] as string; if (texName.StartsWith("0x")) { part.PartInfo.Textures[j] = uint.Parse(texName.Substring(2), NumberStyles.HexNumber); } else { part.PartInfo.Textures[j] = RealHash(ResolveRealName(texName)); } } part.PartInfo.Transform.m = aseFile[i].Transform.Matrix; /* * part.PartInfo.Transform.m = new float[16]; * part.PartInfo.Transform.m[0] = 1.0f; * part.PartInfo.Transform.m[5] = 1.0f; * part.PartInfo.Transform.m[10] = 1.0f; * part.PartInfo.Transform.m[15] = 1.0f; */ part.PartInfo.TriangleCount = aseFile[i].Mesh.FaceList.Count; part.PartInfo.Unk1 = 0x00400018; part.PartInfo.Unk2 = 0x000EA550; part.PartInfo.Unk3 = 0x000EA550; part.PartInfo.Unk4_MW = 0; part.PartInfo.Unk5_MW = 1; part.PartInfo.Unk6_MW = part.PartInfo.TriangleCount; //----- part data ---------- part.PartData.Flags = 0x000080 + /* 0x000100 */ +0x004000 /* + 0x010000*/; part.PartData.GroupCount = subMeshList.Length; part.PartData.Groups = new RealShadingGroup[subMeshList.Length]; int indexOffset = 0; for (int j = 0; j < subMeshList.Length; j++) { SubMesh subMesh = subMeshList[j]; part.PartData.Groups[j] = new RealShadingGroup(); boundsMin = new RealVector4(); boundsMax = new RealVector4(); if (subMesh.VertexList.Count > 0) { RealVector3 v = ((RealVertex)subMesh.VertexList[0]).Position; boundsMin.x = v.x; boundsMin.y = v.y; boundsMin.z = v.z; boundsMax = boundsMin; } for (int k = 1; k < subMesh.VertexList.Count; k++) { RealVector3 v = ((RealVertex)subMesh.VertexList[k]).Position; if (v.x > boundsMax.x) { boundsMax.x = v.x; } if (v.y > boundsMax.y) { boundsMax.y = v.y; } if (v.z > boundsMax.z) { boundsMax.z = v.z; } if (v.x < boundsMin.x) { boundsMin.x = v.x; } if (v.y < boundsMin.y) { boundsMin.y = v.y; } if (v.z < boundsMin.z) { boundsMin.z = v.z; } } part.PartData.Groups[j].BoundsMax = new RealVector3(boundsMax.x, boundsMax.y, boundsMax.z); part.PartData.Groups[j].BoundsMin = new RealVector3(boundsMin.x, boundsMin.y, boundsMin.z); part.PartData.Groups[j].Length = subMesh.IndexList.Count; part.PartData.Groups[j].TextureIndex0 = (byte)subMesh.TextureId; part.PartData.Groups[j].TextureIndex1 = (byte)subMesh.TextureId; part.PartData.Groups[j].TextureIndex2 = (byte)subMesh.TextureId; part.PartData.Groups[j].TextureIndex3 = (byte)subMesh.TextureId; part.PartData.Groups[j].TextureIndex4 = (byte)subMesh.TextureId; part.PartData.Groups[j].ShaderIndex0 = (byte)subMesh.MaterialId; part.PartData.Groups[j].Unk1 = 0x4; part.PartData.Groups[j].Flags = part.PartData.Flags; part.PartData.Groups[j].VertexCount = subMesh.VertexList.Count; part.PartData.Groups[j].TriangleCount = subMesh.IndexList.Count / 3; part.PartData.Groups[j].Offset = indexOffset; indexOffset += subMesh.IndexList.Count; } // -- bit of partinfo here -- caclulate bounds boundsMin = new RealVector4(); boundsMax = new RealVector4(); if (part.PartData.Groups.Length > 0) { RealVector3 v = part.PartData.Groups[0].BoundsMin; boundsMin.x = v.x; boundsMin.y = v.y; boundsMin.z = v.z; v = part.PartData.Groups[0].BoundsMax; boundsMax.x = v.x; boundsMax.y = v.y; boundsMax.z = v.z; } for (int j = 1; j < part.PartData.Groups.Length; j++) { RealVector3 v = part.PartData.Groups[j].BoundsMax; if (v.x > boundsMax.x) { boundsMax.x = v.x; } if (v.y > boundsMax.y) { boundsMax.y = v.y; } if (v.z > boundsMax.z) { boundsMax.z = v.z; } v = part.PartData.Groups[j].BoundsMin; if (v.x < boundsMin.x) { boundsMin.x = v.x; } if (v.y < boundsMin.y) { boundsMin.y = v.y; } if (v.z < boundsMin.z) { boundsMin.z = v.z; } } part.PartInfo.BoundMax = boundsMax; part.PartInfo.BoundMin = boundsMin; // -- end -- part.PartData.IndexCount = indexOffset; part.PartData.Indices = new ushort[indexOffset]; int vertexOffset = 0; indexOffset = 0; for (int j = 0; j < subMeshList.Length; j++) { for (int k = 0; k < subMeshList[j].IndexList.Count; k++) { part.PartData.Indices[indexOffset++] = (ushort)((ushort)subMeshList[j].IndexList[k] + vertexOffset); } vertexOffset += subMeshList[j].VertexList.Count; } part.PartData.TriangleCount = indexOffset / 3; part.PartData.Unk1 = 0x12; part.PartData.VBCount = 1; part.PartData.Vertices = new RealVertex[vertexOffset]; vertexOffset = 0; for (int j = 0; j < subMeshList.Length; j++) { for (int k = 0; k < subMeshList[j].VertexList.Count; k++) { part.PartData.Vertices[vertexOffset++] = (RealVertex)subMeshList[j].VertexList[k]; } } geom.AddPart(part); } Compiler.VerboseOutput(" + Complete."); } if (mountPointObjects.Count > 0) { Compiler.VerboseOutput("Merging mount points into base parts..."); if (basePartObjects.Count == 0) { Compiler.WarningOutput("Mount points provided without any base parts! Ignoring mount points."); } else { RealMountPoint[] mountPoints = new RealMountPoint[mountPointObjects.Count]; mountPointObjects.CopyTo(mountPoints); foreach (RealGeometryPart part in basePartObjects) { part.PartInfo.MountPoints = mountPoints; } } Compiler.VerboseOutput(" + Complete."); } Compiler.VerboseOutput("Collecting part cross links..."); LoadCrossLinks(geom); geom.GeometryInfo.PartCount = geom.PartCount; geom.GeometryInfo.Unk1 = 0x1D; geom.GeometryInfo.Unk2 = 0x80; geom.GeometryInfo.ClassType = new FixedLenString("DEFAULT", 0x20); geom.GeometryInfo.RelFilePath = new FixedLenString("GEOMETRY.BIN", 0x38); Compiler.VerboseOutput("Data successfully collected."); return(geom); }
public void GenerateAnimation(AssetImportContext ctx, AseFile aseFile, Sprite[] sprites) { AnimationClip animationClip = new AnimationClip { name = name, frameRate = 25 }; EditorCurveBinding spriteBinding = new EditorCurveBinding(); spriteBinding.type = typeof(SpriteRenderer); spriteBinding.path = ""; spriteBinding.propertyName = "m_Sprite"; int length = sprites.Length; ObjectReferenceKeyframe[] spriteKeyFrames = new ObjectReferenceKeyframe[length + 1]; // plus last frame to keep the duration float time = 0; int from = 0; int step = 1; int keyIndex = from; for (int i = 0; i < length; i++) { if (i >= length) { keyIndex = from; } ObjectReferenceKeyframe frame = new ObjectReferenceKeyframe { time = time, value = sprites[keyIndex] }; time += aseFile.Frames[keyIndex].FrameDuration / 1000f; keyIndex += step; spriteKeyFrames[i] = frame; } float frameTime = 1f / animationClip.frameRate; ObjectReferenceKeyframe lastFrame = new ObjectReferenceKeyframe(); lastFrame.time = time - frameTime; lastFrame.value = sprites[keyIndex - step]; spriteKeyFrames[spriteKeyFrames.Length - 1] = lastFrame; AnimationUtility.SetObjectReferenceCurve(animationClip, spriteBinding, spriteKeyFrames); AnimationClipSettings settings = AnimationUtility.GetAnimationClipSettings(animationClip); //switch (animation.Animation) //{ // case LoopAnimation.Forward: // animationClip.wrapMode = WrapMode.Loop; // settings.loopTime = true; // break; // case LoopAnimation.Reverse: // animationClip.wrapMode = WrapMode.Loop; // settings.loopTime = true; // break; // case LoopAnimation.PingPong: // animationClip.wrapMode = WrapMode.PingPong; // settings.loopTime = true; // break; //} //if (!importSettings.loopTime) //{ // animationClip.wrapMode = WrapMode.Once; // settings.loopTime = false; //} AnimationUtility.SetAnimationClipSettings(animationClip, settings); ctx.AddObjectToAsset(name, animationClip); //在同一路径创建动画文件 //AssetDatabase.CreateAsset(animationClip, GetFolderPath(ctx.assetPath) + "/" + name + ".anim"); //AssetDatabase.Refresh(); }
public override void OnImportAsset(AssetImportContext ctx) { name = GetFileName(ctx.assetPath); AseFile aseFile = ReadAseFile(ctx.assetPath); //Debug.Log(string.Format("导入Ase动画文件:{0},帧间隔为{1}(相当于动画帧率{2})", name, aseFile.Header.Speed, Mathf.RoundToInt(1000 / aseFile.Header.Speed))); this.aseFile = aseFile; SpriteAtlasBuilder atlasBuilder = new SpriteAtlasBuilder(textureSettings, aseFile.Header.Width, aseFile.Header.Height); Texture2D[] frames; if (importType != AseFileImportType.LayerToSprite) { frames = aseFile.GetFrames(); } else { frames = aseFile.GetLayersAsFrames(); } SpriteImportData[] spriteImportData = new SpriteImportData[0]; //if (textureSettings.transparentMask) //{ // atlas = atlasBuilder.GenerateAtlas(frames, out spriteImportData, textureSettings.transparentColor, false); //} //else //{ // atlas = atlasBuilder.GenerateAtlas(frames, out spriteImportData, false); //} //翻转贴图 if (textureSettings.flipTexture) { for (int i = 0; i < frames.Length; i++) { frames[i] = FlipTexture(frames[i]); } } atlas = atlasBuilder.GenerateAtlas(frames, out spriteImportData, textureSettings.transparentMask, false); atlas.filterMode = textureSettings.filterMode; atlas.alphaIsTransparency = false; atlas.wrapMode = TextureWrapMode.Clamp; atlas.name = "Texture"; ctx.AddObjectToAsset("Texture", atlas); ctx.SetMainObject(atlas); switch (importType) { case AseFileImportType.LayerToSprite: case AseFileImportType.Sprite: ImportSprites(ctx, aseFile, spriteImportData); break; case AseFileImportType.Tileset: ImportTileset(ctx, atlas); break; } ctx.SetMainObject(atlas); }
private List <AnimationClip> GenerateAnimations(AseFile aseFile, List <Sprite> sprites) { List <AnimationClip> res = new List <AnimationClip>(); var animations = aseFile.GetAnimations(); if (animations.Length <= 0) { return(res); } var metadatas = aseFile.GetMetaData(Settings.spritePivot, Settings.pixelsPerUnit); int index = 0; foreach (var animation in animations) { var path = directoryName + "/" + fileName + "_" + animation.TagName + ".anim"; AnimationClip clip = AssetDatabase.LoadAssetAtPath <AnimationClip>(path); if (clip == null) { clip = new AnimationClip(); AssetDatabase.CreateAsset(clip, path); clip.wrapMode = GetDefaultWrapMode(animation.TagName); } else { AnimationClipSettings animSettings = AnimationUtility.GetAnimationClipSettings(clip); clip.wrapMode = animSettings.loopTime ? WrapMode.Loop : WrapMode.Once; } clip.name = fileName + "_" + animation.TagName; clip.frameRate = 25; EditorCurveBinding editorBinding = new EditorCurveBinding(); editorBinding.path = ""; editorBinding.propertyName = "m_Sprite"; switch (Settings.bindType) { case AseAnimationBindType.SpriteRenderer: editorBinding.type = typeof(SpriteRenderer); break; case AseAnimationBindType.UIImage: editorBinding.type = typeof(Image); break; } // plus last frame to keep the duration int length = animation.FrameTo - animation.FrameFrom + 1; ObjectReferenceKeyframe[] spriteKeyFrames = new ObjectReferenceKeyframe[length + 1]; Dictionary <string, AnimationCurve> transformCurveX = new Dictionary <string, AnimationCurve>(), transformCurveY = new Dictionary <string, AnimationCurve>(); float time = 0; int from = (animation.Animation != LoopAnimation.Reverse) ? animation.FrameFrom : animation.FrameTo; int step = (animation.Animation != LoopAnimation.Reverse) ? 1 : -1; int keyIndex = from; for (int i = 0; i < length; i++) { if (i >= length) { keyIndex = from; } ObjectReferenceKeyframe frame = new ObjectReferenceKeyframe(); frame.time = time; frame.value = sprites[keyIndex]; time += aseFile.Frames[keyIndex].FrameDuration / 1000f; spriteKeyFrames[i] = frame; foreach (var metadata in metadatas) { if (metadata.Type == MetaDataType.TRANSFORM && metadata.Transforms.ContainsKey(keyIndex)) { var childTransform = metadata.Args[0]; if (!transformCurveX.ContainsKey(childTransform)) { transformCurveX[childTransform] = new AnimationCurve(); transformCurveY[childTransform] = new AnimationCurve(); } var pos = metadata.Transforms[keyIndex]; transformCurveX[childTransform].AddKey(i, pos.x); transformCurveY[childTransform].AddKey(i, pos.y); } } keyIndex += step; } float frameTime = 1f / clip.frameRate; ObjectReferenceKeyframe lastFrame = new ObjectReferenceKeyframe(); lastFrame.time = time - frameTime; lastFrame.value = sprites[keyIndex - step]; spriteKeyFrames[spriteKeyFrames.Length - 1] = lastFrame; foreach (var metadata in metadatas) { if (metadata.Type == MetaDataType.TRANSFORM && metadata.Transforms.ContainsKey(keyIndex - step)) { var childTransform = metadata.Args[0]; var pos = metadata.Transforms[keyIndex - step]; transformCurveX[childTransform].AddKey(spriteKeyFrames.Length - 1, pos.x); transformCurveY[childTransform].AddKey(spriteKeyFrames.Length - 1, pos.y); } } AnimationUtility.SetObjectReferenceCurve(clip, editorBinding, spriteKeyFrames); foreach (var childTransform in transformCurveX.Keys) { EditorCurveBinding bindingX = new EditorCurveBinding { path = childTransform, type = typeof(Transform), propertyName = "m_LocalPosition.x" }, bindingY = new EditorCurveBinding { path = childTransform, type = typeof(Transform), propertyName = "m_LocalPosition.y" }; MakeConstant(transformCurveX[childTransform]); AnimationUtility.SetEditorCurve(clip, bindingX, transformCurveX[childTransform]); MakeConstant(transformCurveY[childTransform]); AnimationUtility.SetEditorCurve(clip, bindingY, transformCurveY[childTransform]); } AnimationClipSettings clipSettings = AnimationUtility.GetAnimationClipSettings(clip); clipSettings.loopTime = (clip.wrapMode == WrapMode.Loop); AnimationUtility.SetAnimationClipSettings(clip, clipSettings); EditorUtility.SetDirty(clip); index++; res.Add(clip); } return(res); }
private void GenerateAnimations(AssetImportContext ctx, AseFile aseFile, Sprite[] sprites, MetaData[] metadatas) { if (animationSettings == null) { animationSettings = new AseFileAnimationSettings[0]; } var animSettings = new List <AseFileAnimationSettings>(animationSettings); var animations = aseFile.GetAnimations(); if (animations.Length <= 0) { return; } if (animationSettings != null) { RemoveUnusedAnimationSettings(animSettings, animations); } int index = 0; foreach (var animation in animations) { AnimationClip animationClip = new AnimationClip(); animationClip.name = name + "_" + animation.TagName; animationClip.frameRate = 25; AseFileAnimationSettings importSettings = GetAnimationSettingFor(animSettings, animation); importSettings.about = GetAnimationAbout(animation); EditorCurveBinding editorBinding = new EditorCurveBinding(); editorBinding.path = ""; editorBinding.propertyName = "m_Sprite"; switch (bindType) { case AseEditorBindType.SpriteRenderer: editorBinding.type = typeof(SpriteRenderer); break; case AseEditorBindType.UIImage: editorBinding.type = typeof(Image); break; } int length = animation.FrameTo - animation.FrameFrom + 1; ObjectReferenceKeyframe[] spriteKeyFrames = new ObjectReferenceKeyframe[length + 1]; // plus last frame to keep the duration Dictionary <string, AnimationCurve> transformCurveX = new Dictionary <string, AnimationCurve>(), transformCurveY = new Dictionary <string, AnimationCurve>(); float time = 0; int from = (animation.Animation != LoopAnimation.Reverse) ? animation.FrameFrom : animation.FrameTo; int step = (animation.Animation != LoopAnimation.Reverse) ? 1 : -1; int keyIndex = from; for (int i = 0; i < length; i++) { if (i >= length) { keyIndex = from; } ObjectReferenceKeyframe frame = new ObjectReferenceKeyframe(); frame.time = time; frame.value = sprites[keyIndex]; time += aseFile.Frames[keyIndex].FrameDuration / 1000f; spriteKeyFrames[i] = frame; foreach (var metadata in metadatas) { if (metadata.Type == MetaDataType.TRANSFORM && metadata.Transforms.ContainsKey(keyIndex)) { var childTransform = metadata.Args[0]; if (!transformCurveX.ContainsKey(childTransform)) { transformCurveX[childTransform] = new AnimationCurve(); transformCurveY[childTransform] = new AnimationCurve(); } var pos = metadata.Transforms[keyIndex]; transformCurveX[childTransform].AddKey(i, pos.x); transformCurveY[childTransform].AddKey(i, pos.y); } } keyIndex += step; } float frameTime = 1f / animationClip.frameRate; ObjectReferenceKeyframe lastFrame = new ObjectReferenceKeyframe(); lastFrame.time = time - frameTime; lastFrame.value = sprites[keyIndex - step]; spriteKeyFrames[spriteKeyFrames.Length - 1] = lastFrame; foreach (var metadata in metadatas) { if (metadata.Type == MetaDataType.TRANSFORM && metadata.Transforms.ContainsKey(keyIndex - step)) { var childTransform = metadata.Args[0]; var pos = metadata.Transforms[keyIndex - step]; transformCurveX[childTransform].AddKey(spriteKeyFrames.Length - 1, pos.x); transformCurveY[childTransform].AddKey(spriteKeyFrames.Length - 1, pos.y); } } AnimationUtility.SetObjectReferenceCurve(animationClip, editorBinding, spriteKeyFrames); foreach (var childTransform in transformCurveX.Keys) { EditorCurveBinding bindingX = new EditorCurveBinding { path = childTransform, type = typeof(Transform), propertyName = "m_LocalPosition.x" }, bindingY = new EditorCurveBinding { path = childTransform, type = typeof(Transform), propertyName = "m_LocalPosition.y" }; MakeConstant(transformCurveX[childTransform]); AnimationUtility.SetEditorCurve(animationClip, bindingX, transformCurveX[childTransform]); MakeConstant(transformCurveY[childTransform]); AnimationUtility.SetEditorCurve(animationClip, bindingY, transformCurveY[childTransform]); } AnimationClipSettings settings = AnimationUtility.GetAnimationClipSettings(animationClip); switch (animation.Animation) { case LoopAnimation.Forward: animationClip.wrapMode = WrapMode.Loop; settings.loopTime = true; break; case LoopAnimation.Reverse: animationClip.wrapMode = WrapMode.Loop; settings.loopTime = true; break; case LoopAnimation.PingPong: animationClip.wrapMode = WrapMode.PingPong; settings.loopTime = true; break; } if (!importSettings.loopTime) { animationClip.wrapMode = WrapMode.Once; settings.loopTime = false; } AnimationUtility.SetAnimationClipSettings(animationClip, settings); ctx.AddObjectToAsset(animation.TagName, animationClip); index++; } animationSettings = animSettings.ToArray(); }