public override void Process(ImportContext ctx, Layer layer) { var eventFrames = new HashSet <int>(); var file = ctx.file; for (int i = 0; i < file.frames.Count; ++i) { bool isEvent = file.frames[i].cels.ContainsKey(layer.index); if (isEvent) { eventFrames.Add(i); } } LayerParamType paramType = layer.GetParamType(1); foreach (var frametag in file.frameTags) { var clip = ctx.generatedClips[frametag]; var events = new List <AnimationEvent>(clip.events); var time = 0.0f; for (int f = frametag.from; f <= frametag.to; ++f) { if (eventFrames.Contains(f)) { var evt = new AnimationEvent { time = time, functionName = layer.GetParamString(0), messageOptions = SendMessageOptions.DontRequireReceiver }; // Debug.Log(paramType + ", " + layer.metaInfo.ParamCount); if (paramType == LayerParamType.String) { evt.stringParameter = layer.GetParamString(1); } else if (paramType == LayerParamType.Number) { var fval = layer.GetParamFloat(1); if (fval == Math.Floor(fval)) { evt.intParameter = (int)fval; } else { evt.floatParameter = fval; } } events.Add(evt); } time += file.frames[f].duration * 1e-3f; } events.Sort((lhs, rhs) => lhs.time.CompareTo(rhs.time)); AnimationUtility.SetAnimationEvents(clip, events.ToArray()); EditorUtility.SetDirty(clip); } }
public override void Process(ImportContext ctx, Layer layer) { var childName = layer.GetParamString(0); EditorCurveBinding bindingX = new EditorCurveBinding { path = childName, type = typeof(Transform), propertyName = "m_LocalPosition.x" }, bindingY = new EditorCurveBinding { path = childName, type = typeof(Transform), propertyName = "m_LocalPosition.y" }; var frames = new Dictionary <int, Vector2> (); var file = ctx.file; for (int i = 0; i < file.frames.Count; ++i) { Vector2 center = Vector2.zero; int pixelCount = 0; Cel cel; file.frames[i].cels.TryGetValue(layer.index, out cel); if (cel == null) { continue; } for (int y = 0; y < cel.height; ++y) { for (int x = 0; x < cel.width; ++x) { int texX = cel.x + x; int texY = -(cel.y + y) + file.height - 1; var col = cel.GetPixelRaw(x, y); if (col.a > 0.1f) { center += new Vector2(texX, texY); pixelCount++; } } } if (pixelCount > 0) { center /= pixelCount; var pivot = Vector2.Scale(ctx.settings.PivotRelativePos, new Vector2(file.width, file.height)); var posWorld = (center - pivot) / ctx.settings.ppu; frames.Add(i, posWorld); } } foreach (var frameTag in file.frameTags) { var clip = ctx.generatedClips[frameTag]; AnimationCurve curveX = new AnimationCurve(), curveY = new AnimationCurve(); float t = 0; for (int f = frameTag.from; f <= frameTag.to + 1; ++f) { if (f == frameTag.to + 1) { if (frames.ContainsKey(frameTag.from)) { t = t - 1.0f / clip.frameRate; var pos = frames[frameTag.from]; curveX.AddKey(t, pos.x); curveY.AddKey(t, pos.y); } break; } if (frames.ContainsKey(f)) { var pos = frames[f]; curveX.AddKey(t, pos.x); curveY.AddKey(t, pos.y); } t += file.frames[f].duration * 1e-3f; } if (curveX.length > 0) { MakeConstant(curveX); MakeConstant(curveY); AnimationUtility.SetEditorCurve(clip, bindingX, curveX); AnimationUtility.SetEditorCurve(clip, bindingY, curveY); EditorUtility.SetDirty(clip); } } }
public override void Process(ImportContext ctx, Layer layer) { var animPath = layer.group.path; var frames = new Dictionary <int, Vector2>(); var file = ctx.file; //Change this layer sprites pivot var processor = ASEImporter.getProcessor("pivot"); processor?.Process(ctx, layer); //Read data from cel for (var i = 0; i < file.frames.Count; ++i) { var center = Vector2.zero; var pixelCount = 0; file.frames[i].cels.TryGetValue(layer.layerIndex, out var cel); if (cel == null) { continue; } for (var y = 0; y < cel.height; ++y) { for (var x = 0; x < cel.width; ++x) { var texX = cel.x + x; var texY = -(cel.y + y) + file.height - 1; var col = cel.GetPixelRaw(x, y); if (col.a > 0.1f) { center += new Vector2(texX, texY); pixelCount++; } } } if (pixelCount > 0) { center /= pixelCount; var pivot = Vector2.Scale(ctx.settings.pivotRelativePos, new Vector2(file.width, file.height)); var posWorld = (center - pivot) / ctx.settings.ppu; frames.Add(i, posWorld); } } //Change animation clips foreach (var frameTag in file.frameTags) { var clip = ctx.generatedClips[frameTag]; AnimationCurve curveX = new AnimationCurve(), curveY = new AnimationCurve(); float t = 0; var firstFramePos = frames[frameTag.from]; for (var f = frameTag.from; f <= frameTag.to; ++f) { if (frames.ContainsKey(f)) { var pos = frames[f]; var currentGroup = layer.group.parent; while (currentGroup != null) { var path = currentGroup.path; var bindings = AnimationUtility.GetCurveBindings(clip); var xb = bindings.Where(it => it.path == path && it.propertyName == "m_LocalPosition.x") .ToList(); var yb = bindings.Where(it => it.path == path && it.propertyName == "m_LocalPosition.y") .ToList(); if (!(xb.IsNullOrEmpty() || yb.IsNullOrEmpty())) { var x = AnimationUtility.GetEditorCurve(clip, xb[0]).keys .First(it => Mathf.Approximately(it.time, t)).value; var y = AnimationUtility.GetEditorCurve(clip, yb[0]).keys .First(it => Mathf.Approximately(it.time, t)).value; pos -= new Vector2(x, y); } currentGroup = currentGroup.parent; } if (f == frameTag.from) { firstFramePos = pos; } curveX.AddKey(t, pos.x); curveY.AddKey(t, pos.y); } t += file.frames[f].duration * 1e-3f; } //Completing the end frame for the loop //t -= 1.0f / clip.frameRate; curveX.AddKey(t, firstFramePos.x); curveY.AddKey(t, firstFramePos.y); if (curveX.length <= 0) { continue; } MakeConstant(curveX); MakeConstant(curveY); EditorCurveBinding bindingX = new EditorCurveBinding { path = animPath, type = typeof(Transform), propertyName = "m_LocalPosition.x" }, bindingY = new EditorCurveBinding { path = animPath, type = typeof(Transform), propertyName = "m_LocalPosition.y" }; AnimationUtility.SetEditorCurve(clip, bindingX, curveX); AnimationUtility.SetEditorCurve(clip, bindingY, curveY); EditorUtility.SetDirty(clip); } if (ctx.settings.generatePrefab) { var layerTransform = ctx.name2GameObject[layer.group.name].transform; var position = frames[0]; var transform = layerTransform.parent; while (transform.gameObject != ctx.rootGameObject) { position -= (Vector2)transform.localPosition; transform = transform.parent; } layerTransform.transform.localPosition = position; } }
static void ImportStage(ImportContext ctx, Stage stage) { EditorUtility.DisplayProgressBar("Importing " + ctx.fileName, stage.GetDisplayString(), stage.GetProgress()); }
static void ImportEnd(ImportContext ctx) { EditorUtility.ClearProgressBar(); }
public static void Import(DefaultAsset defaultAsset, ImportSettings settings) { var path = AssetDatabase.GetAssetPath(defaultAsset); var context = new ImportContext { // file = file, settings = settings, fileDirectory = Path.GetDirectoryName(path), fileName = Path.GetFileName(path), fileNameNoExt = Path.GetFileNameWithoutExtension(path), animData = ScriptableObject.CreateInstance <AnimData>(), }; try { // context.animData.data = new Dictionary<string, Dictionary<string, List<FrameData>>>(); ImportStage(context, Stage.LoadFile); context.file = ASEParser.Parse(File.ReadAllBytes(path)); context.atlasPath = Path.Combine(settings.atlasOutputDirectory, context.fileNameNoExt + ".png"); if (settings.controllerPolicy == AnimControllerOutputPolicy.CreateOrOverride) { context.animControllerPath = settings.animControllerOutputPath + "/" + settings.baseName + ".controller"; } context.animClipDirectory = settings.clipOutputDirectory; context.animDataDirectory = settings.dataOutputDirectory; // Create paths in advance Directory.CreateDirectory(settings.atlasOutputDirectory); Directory.CreateDirectory(context.animClipDirectory); Directory.CreateDirectory(context.animDataDirectory); if (context.animControllerPath != null) { Directory.CreateDirectory(Path.GetDirectoryName(context.animControllerPath)); } ImportStage(context, Stage.GenerateAtlas); context.generatedSprites = AtlasGenerator.GenerateAtlas(context, context.file.layers.Where(it => it.type == LayerType.Content).ToList(), context.atlasPath); ImportStage(context, Stage.GenerateClips); GenerateAnimClips(context); ImportStage(context, Stage.GenerateController); GenerateAnimController(context); ImportStage(context, Stage.InvokeMetaLayerProcessor); context.file.layers .Where(layer => layer.type == LayerType.Meta) .Select(layer => { MetaLayerProcessor processor; layerProcessors.TryGetValue(layer.actionName, out processor); return(new LayerAndProcessor { layer = layer, processor = processor }); }) .OrderBy(it => it.processor != null ? it.processor.executionOrder : 0) .ToList() .ForEach(it => { var layer = it.layer; var processor = it.processor; if (processor != null) { processor.Process(context, layer); } else { Debug.LogWarning(string.Format("No processor for meta layer {0}", layer.layerName)); } }); // calc num frames for each animation, save to animData foreach (var tag in context.file.frameTags) { string animName = tag.name; int numFrames = tag.to - tag.from + 1; if (context.animData.animDict.ContainsKey(animName)) { context.animData.animDict[animName].numFrames = numFrames; } else { context.animData.animDict.Add(animName, new AnimList { numFrames = numFrames, frameDict = new FrameDictionary(), }); } } // save each frame's pivot and dimensions in animData foreach (var tag in context.file.frameTags) { string animName = tag.name; var pivotDataList = new FrameDataList { frames = new List <FrameData>() }; var dimsDataList = new FrameDataList { frames = new List <FrameData>() }; for (int i = tag.from, j = 0; i <= tag.to; i++, j++) { pivotDataList.frames.Add(new FrameData { frame = j, coords = new List <Vector2> { context.spritePivots[i] } }); dimsDataList.frames.Add(new FrameData { frame = j, coords = new List <Vector2> { context.spriteDimensions[i] } }); } context.animData.animDict[animName].frameDict.Add("pivot", pivotDataList); context.animData.animDict[animName].frameDict.Add("dims", dimsDataList); } /* * var importer = AssetImporter.GetAtPath(context.atlasPath) as TextureImporter; * var spriteSheet = importer.spritesheet; * Debug.Log("== SPRITESHEET =="); * Debug.Log($"{spriteSheet[0].rect}"); * Debug.Log($"{spriteSheet[0].pivot}"); * Debug.Log(ObjectDumper.Dump(context.spriteDimensions)); * Debug.Log(ObjectDumper.Dump(context.spritePivots)); */ ImportStage(context, Stage.SaveAnimData); var filePath = context.animDataDirectory + "/" + context.settings.baseName + " data.asset"; AnimData asset = (AnimData)AssetDatabase.LoadAssetAtPath(filePath, typeof(AnimData)); if (!asset) { asset = ScriptableObject.CreateInstance <AnimData>(); asset = context.animData; asset.ppu = context.settings.ppu; asset.pixelOrigin = context.settings.pixelOrigin.ToString(); AssetDatabase.CreateAsset(asset, filePath); } else { asset.ppu = context.settings.ppu; asset.pixelOrigin = context.settings.pixelOrigin.ToString(); // merge any new animations with old (and overwrite matching old) foreach (KeyValuePair <string, AnimList> item in context.animData.animDict) { asset.animDict[item.Key] = item.Value; } EditorUtility.SetDirty(asset); AssetDatabase.SaveAssets(); } } catch (Exception e) { Debug.LogException(e); } ImportEnd(context); }
public static void Import(string path, ImportSettings settings) { // var path = AssetDatabase.GetAssetPath(defaultAsset); var context = new ImportContext { // file = file, settings = settings, fileDirectory = Path.GetDirectoryName(path), fileName = Path.GetFileName(path), fileNameNoExt = Path.GetFileNameWithoutExtension(path) }; try { ImportStage(context, Stage.LoadFile); context.file = ASEParser.Parse(File.ReadAllBytes(path)); context.atlasPath = Path.Combine(settings.atlasOutputDirectory, context.fileNameNoExt + ".png"); if (settings.controllerPolicy == AnimControllerOutputPolicy.CreateOrOverride) { context.animControllerPath = settings.animControllerOutputPath + "/" + settings.baseName + ".controller"; } context.animClipDirectory = settings.clipOutputDirectory; // Create paths in advance Directory.CreateDirectory(settings.atlasOutputDirectory); Directory.CreateDirectory(context.animClipDirectory); if (context.animControllerPath != null) { Directory.CreateDirectory(Path.GetDirectoryName(context.animControllerPath)); } // ImportStage(context, Stage.GenerateAtlas); context.generatedSprites = AtlasGenerator.GenerateAtlas(context, context.file.layers.Where(it => it.type == LayerType.Content).ToList(), context.atlasPath); ImportStage(context, Stage.GenerateClips); GenerateAnimClips(context); ImportStage(context, Stage.GenerateController); GenerateAnimController(context); ImportStage(context, Stage.InvokeMetaLayerProcessor); context.file.layers .Where(layer => layer.type == LayerType.Meta) .Select(layer => { MetaLayerProcessor processor; layerProcessors.TryGetValue(layer.actionName, out processor); return(new LayerAndProcessor { layer = layer, processor = processor }); }) .OrderBy(it => it.processor != null ? it.processor.executionOrder : 0) .ToList() .ForEach(it => { var layer = it.layer; var processor = it.processor; if (processor != null) { processor.Process(context, layer); } else { Debug.LogWarning(string.Format("No processor for meta layer {0}", layer.layerName)); } }); } catch (Exception e) { Debug.LogException(e); } ImportEnd(context); }
public override void Process(ImportContext ctx, Layer layer) { var pivots = new List <PivotFrame>(); var file = ctx.file; var importer = AssetImporter.GetAtPath(ctx.atlasPath) as TextureImporter; var spriteSheet = importer.spritesheet; for (int i = 0; i < file.frames.Count; ++i) { Cel cel; file.frames[i].cels.TryGetValue(layer.index, out cel); if (cel != null) { Vector2 center = Vector2.zero; int pixelCount = 0; for (int y = 0; y < cel.height; ++y) { for (int x = 0; x < cel.width; ++x) { // tex coords relative to full texture boundaries int texX = cel.x + x; int texY = -(cel.y + y) + file.height - 1; var col = cel.GetPixelRaw(x, y); if (col.a > 0.1f) { center += new Vector2(texX, texY); ++pixelCount; } } } if (pixelCount > 0) { center /= pixelCount; pivots.Add(new PivotFrame { frame = i, pivot = center }); } } } if (pivots.Count == 0) { return; } for (int i = 0; i < spriteSheet.Length; ++i) { int j = 1; while (j < pivots.Count && pivots[j].frame <= i) { ++j; // j = index after found item } Vector2 pivot = pivots[j - 1].pivot; pivot -= ctx.spriteCropPositions[i]; pivot = Vector2.Scale(pivot, new Vector2(1.0f / spriteSheet[i].rect.width, 1.0f / spriteSheet[i].rect.height)); spriteSheet[i].pivot = pivot; } importer.spritesheet = spriteSheet; EditorUtility.SetDirty(importer); importer.SaveAndReimport(); }
public override void Process(ImportContext ctx, Layer layer) { // the name of the data variable should be the first parameter. eg @data("leg l") string dataName = layer.GetParamString(0); var file = ctx.file; var importer = AssetImporter.GetAtPath(ctx.atlasPath) as TextureImporter; var spriteSheet = importer.spritesheet; // each tag represents a different animation. look at each frame of each tag. store coordinates of any visible pixels. // these represent the data points. foreach (var tag in ctx.file.frameTags) { string animName = tag.name; Vector3 distance = Vector3.zero; var frameDataList = new FrameDataList { frames = new List <FrameData>() }; int numFrames = tag.to - tag.from + 1; for (int i = tag.from, j = 0; i <= tag.to; ++i, j++) { var frameData = new FrameData { frame = j, coords = new List <Vector2>() }; Cel cel; file.frames[i].cels.TryGetValue(layer.index, out cel); if (cel != null) { int pixelCount = 0; for (int y = 0; y < cel.height; ++y) { for (int x = 0; x < cel.width; ++x) { // tex coords relative to full texture boundaries int texX = cel.x + x; int texY = -(cel.y + y) + file.height - 1; // store position of any visible pixels var pxl = cel.GetPixelRaw(x, y); if (pxl.a > 0.1f) { // start the coordinate of the pixel on the layer (from bottom left corner) Vector2 coord = new Vector2(texX, texY); // default pixel origin is bottom left. if centered, add half a pixel in x and y directions if (ctx.settings.pixelOrigin == PixelOrigin.Center) { coord += new Vector2(0.5f, 0.5f); } // calculate position in relation to pivot Vector2 pivot = spriteSheet[i].pivot; Vector2 pivotPxl = new Vector2(pivot.x * spriteSheet[i].rect.width, pivot.y * spriteSheet[i].rect.height); // get coordinate relative to pivot coord -= ctx.spriteCropPositions[i]; coord -= pivotPxl; // if calculating "prev pivot" data, and this is first pixel (should only be one), then store its distance if (dataName == "prev pivot" && pixelCount == 0) { // coord is distance from pivot. negate to make positive, and round to get rid of float errors distance += new Vector3(-Mathf.Round(coord.x), -Mathf.Round(coord.y), 0); } // points are all relative to the sprite's bounding rectangle, which is 1 by 1 in both dimensions // regardless of sprite size. So (0.5, 0.5) would be the center of the sprite. // it's ok for points to be outside the bounding rectangle. they'll just be less than 0, or greater than 1. // WHY? so if the sprite is transformed, everything stays relative. You can multiply points by the transforms // to get their position relative to the transform. // NOTE: spriteSheet[i].rect.width/height are in pixels coord = new Vector2(coord.x / spriteSheet[i].rect.width, coord.y / spriteSheet[i].rect.height); frameData.coords.Add(coord); ++pixelCount; } } } if (pixelCount > 0) { frameDataList.frames.Add(frameData); } } } // if we've collected all the data for this animation, save it in appropriate dictionary spot if (frameDataList.frames.Count > 0) { if (ctx.animData.animDict.ContainsKey(animName)) { ctx.animData.animDict[animName].frameDict.Add(dataName, frameDataList); if (dataName == "prev pivot") { ctx.animData.animDict[animName].distance = distance; } } else { ctx.animData.animDict.Add(animName, new AnimList { numFrames = numFrames, distance = distance, frameDict = new FrameDictionary() { { dataName, frameDataList } } }); } // Debug.Log(ctx.animData.data["run e"]); } } // Debug.Log(data); }
static void GenerateAnimClips(ImportContext ctx) { Directory.CreateDirectory(ctx.animClipDirectory); var fileNamePrefix = ctx.animClipDirectory + '/' + ctx.settings.baseName; string childPath = ctx.settings.spriteTarget; // Generate one animation for each tag foreach (var tag in ctx.file.frameTags) { var clipPath = fileNamePrefix + '_' + tag.name + ".anim"; AnimationClip clip = AssetDatabase.LoadAssetAtPath <AnimationClip>(clipPath); if (!clip) { clip = new AnimationClip(); AssetDatabase.CreateAsset(clip, clipPath); } else { AnimationUtility.SetAnimationEvents(clip, new AnimationEvent[0]); } var loop = tag.properties.Contains("loop"); var settings = AnimationUtility.GetAnimationClipSettings(clip); if (loop) { clip.wrapMode = WrapMode.Loop; settings.loopBlend = true; settings.loopTime = true; } else { clip.wrapMode = WrapMode.Clamp; settings.loopBlend = false; settings.loopTime = false; } AnimationUtility.SetAnimationClipSettings(clip, settings); int time = 0; var keyFrames = new ObjectReferenceKeyframe[tag.to - tag.from + 2]; for (int i = tag.from; i <= tag.to; ++i) { var aseFrame = ctx.file.frames[i]; keyFrames[i - tag.from] = new ObjectReferenceKeyframe { time = time * 1e-3f, value = ctx.generatedSprites[aseFrame.frameID] }; time += aseFrame.duration; } keyFrames[keyFrames.Length - 1] = new ObjectReferenceKeyframe { time = time * 1e-3f - 1.0f / clip.frameRate, value = ctx.generatedSprites[tag.to] }; var binding = new EditorCurveBinding { path = childPath, type = typeof(SpriteRenderer), propertyName = "m_Sprite" }; AnimationUtility.SetObjectReferenceCurve(clip, binding, keyFrames); EditorUtility.SetDirty(clip); ctx.generatedClips.Add(tag, clip); } }
public override void Process(ImportContext ctx, Layer layer) { var pivots = new List <PivotFrame>(); var file = ctx.file; //var importer = AssetImporter.GetAtPath(ctx.atlasPath) as TextureImporter; var spriteSheet = ctx.generatedSprites; for (int i = 0; i < file.frames.Count; ++i) { Cel cel; file.frames[i].cels.TryGetValue(layer.index, out cel); if (cel != null) { //Vector2 center = Vector2.Zero; //int pixelCount = 0; //for (int y = 0; y < cel.height; ++y) // for (int x = 0; x < cel.width; ++x) { // // tex coords relative to full texture boundaries // int texX = cel.x + x; // int texY = -(cel.y + y) + file.height - 1; // var col = cel.GetPixelRaw(x, y); // if (col.Af > 0.1f) { // center += new Vector2(texX, texY); // ++pixelCount; // } // } //if (pixelCount > 0) { // center /= pixelCount; // pivots.Add(new PivotFrame { frame = i, pivot = center }); //} pivots.Add(new PivotFrame { frame = i, pivot = CenterOfCel(cel) }); } } if (pivots.Count == 0) { return; } for (int i = 0; i < spriteSheet.Count; ++i) { int j = 1; while (j < pivots.Count && pivots[j].frame <= i) { ++j; // j = index after found item } //Vector2 pivot = pivots[j - 1].pivot; //pivot -= ctx.spriteCropPositions[i]; //pivot = FunctionBoost.Vector2_Scale(pivot, new Vector2(1.0f / spriteSheet[i].rect.Width, 1.0f / spriteSheet[i].rect.Height)); //spriteSheet[i].spritedPivot = new Vector2(pivot.X, pivot.Y); Vector2 pivot = pivots[j - 1].pivot; //pivot -= ctx.spriteCropPositions[i]; //pivot = FunctionBoost.Vector2_Scale(pivot, new Vector2(1.0f / file.width, 1.0f / file.height)); //spriteSheet[i].spritedPivot = new Vector2(pivot.X, pivot.Y); spriteSheet[i].spritedPivot = new Vector2(pivot.X, pivot.Y); } //importer.spritesheet = spriteSheet; //EditorUtility.SetDirty(importer); //importer.SaveAndReimport(); }
public override void Process(ImportContext ctx, Layer layer) { var path = layer.GetParamString(0); EditorCurveBinding bindingOffX = Binding(path, typeof(BoxCollider2D), "m_Offset.x"), bindingOffY = Binding(path, typeof(BoxCollider2D), "m_Offset.y"), bindingSizeX = Binding(path, typeof(BoxCollider2D), "m_Size.x"), bindingSizeY = Binding(path, typeof(BoxCollider2D), "m_Size.y"), bindingEnable = Binding(path, typeof(BoxCollider2D), "m_Enabled"); List <Rect> frameRects = new List <Rect>(); for (int i = 0; i < ctx.file.frames.Count; ++i) { var frame = ctx.file.frames[i]; Cel cel; frame.cels.TryGetValue(layer.index, out cel); if (cel == null) { frameRects.Add(new Rect(0, 0, 0, 0)); } else { int minx = int.MaxValue, miny = int.MaxValue, maxx = int.MinValue, maxy = int.MinValue; for (int y = 0; y < cel.height; ++y) { for (int x = 0; x < cel.width; ++x) { var col = cel.GetPixelRaw(x, y); if (col.a > 0.1f) { int texX = cel.x + x; int texY = ctx.file.height - (cel.y + y) - 1; minx = Mathf.Min(minx, texX); miny = Mathf.Min(miny, texY); maxx = Mathf.Max(maxx, texX); maxy = Mathf.Max(maxy, texY); } } } if (maxx == int.MinValue) { frameRects.Add(new Rect(0, 0, 0, 0)); } else { var texCenter = new Vector2((maxx + minx) / 2.0f, (maxy + miny) / 2.0f); var texSize = new Vector2(maxx - minx, maxy - miny); var pivot = Vector2.Scale(ctx.settings.PivotRelativePos, new Vector2(ctx.file.width, ctx.file.height)); var posWorld = (texCenter - pivot) / ctx.settings.ppu; var sizeWorld = texSize / ctx.settings.ppu; frameRects.Add(new Rect(posWorld, sizeWorld)); } } } foreach (var frameTag in ctx.file.frameTags) { var clip = ctx.generatedClips[frameTag]; AnimationCurve curveOffX = new AnimationCurve(), curveOffY = new AnimationCurve(), curveSizeX = new AnimationCurve(), curveSizeY = new AnimationCurve(), curveEnable = new AnimationCurve(); float t = 0; for (int f = frameTag.from; f <= frameTag.to; ++f) { var rect = frameRects[f]; var enable = rect.size != Vector2.zero; curveEnable.AddKey(new Keyframe(t, enable ? 1 : 0)); if (enable) { curveOffX.AddKey(t, rect.position.x); curveOffY.AddKey(t, rect.position.y); curveSizeX.AddKey(t, rect.size.x); curveSizeY.AddKey(t, rect.size.y); } t += ctx.file.frames[f].duration / 1000.0f; } MakeConstant(curveOffX); MakeConstant(curveOffY); MakeConstant(curveSizeX); MakeConstant(curveSizeY); MakeConstant(curveEnable); AnimationUtility.SetEditorCurve(clip, bindingOffX, curveOffX); AnimationUtility.SetEditorCurve(clip, bindingOffY, curveOffY); AnimationUtility.SetEditorCurve(clip, bindingSizeX, curveSizeX); AnimationUtility.SetEditorCurve(clip, bindingSizeY, curveSizeY); AnimationUtility.SetEditorCurve(clip, bindingEnable, curveEnable); EditorUtility.SetDirty(clip); } }
public abstract void Process(ImportContext ctx, Layer layer);
public override void Process(ImportContext ctx, Layer layer) { var pivots = new List <PivotFrame>(); var file = ctx.file; var path = Path.Combine(ctx.settings.atlasOutputDirectory, ctx.fileNameNoExt + "_" + layer.group.name + ".png"); var importer = AssetImporter.GetAtPath(path) as TextureImporter; if (importer == null) { return; } var spriteSheet = importer.spritesheet; //Read data from cel for (var i = 0; i < file.frames.Count; ++i) { file.frames[i].cels.TryGetValue(layer.layerIndex, out var cel); if (cel == null) { continue; } var center = Vector2.zero; var pixelCount = 0; for (var y = 0; y < cel.height; ++y) { for (var x = 0; x < cel.width; ++x) { // tex coords relative to full texture boundaries var texX = cel.x + x; var texY = -(cel.y + y) + file.height - 1; var col = cel.GetPixelRaw(x, y); if (col.a > 0.1f) { center += new Vector2(texX, texY); ++pixelCount; } } } if (pixelCount > 0) { center /= pixelCount; pivots.Add(new PivotFrame { frame = i, pivot = center }); } } if (pivots.Count == 0) { return; } for (var i = 0; i < spriteSheet.Length; ++i) { var j = 1; while (j < pivots.Count && pivots[j].frame <= i) { ++j; // j = layerIndex after found item } var pivot = pivots[j - 1].pivot; ctx.groupIndex2SpriteCropPositions.TryGetValue(layer.group.groupIndex, out var value); if (value == null) { return; } pivot -= value[i]; pivot = Vector2.Scale(pivot, new Vector2(1.0f / spriteSheet[i].rect.width, 1.0f / spriteSheet[i].rect.height)); spriteSheet[i].pivot = pivot; } importer.spritesheet = spriteSheet; EditorUtility.SetDirty(importer); importer.SaveAndReimport(); }