• Editor
  • Pivot data for exported frame sequence

Related Discussions
...

Hi, programmer here

We have a small problem regarding the export of frame sequence animation in our game. When we export these animations, the resulting texture atlases don't have any information about the original pivot that the artists have set in the Spine editor. I've tried to look for a solution from your forums and other sources, but seems like this has not been implemented in any way. I found these threads:
http://esotericsoftware.com/forum/Pivot-points-in-Frame-Atlas-9795
http://esotericsoftware.com/forum/Sprite-Sheet-Grid-Export-problem-10403
http://esotericsoftware.com/forum/Pivot-Problem-On-Export-Sequence-Anim-5585

Adding this kind of a transparent rectangle adds a lot of unnecessary space in to the atlas and bloats it. It also forces us to use other tools to get rid of said wasted space, and doesn't solve the actual problem of not having the pivot data in the resulting atlas data file. If we could get the pivot data to the atlas, we could write an automatic sprite animation creation tool to suit our purposes, but without it we need to do a lot of manual labour to get it working. So would it be possible to add this data to the export tool so we can take full advantage of your tool?
As a reference, this is an example how our exported atlas data looks like:

character-main.png
size: 2036,780
format: RGBA8888
filter: Linear,Linear
repeat: none
character-main-Attack_00
rotate: false
xy: 836, 194
size: 107, 140
orig: 177, 212
offset: 25, 1
index: -1
character-main-Attack_01
rotate: false
xy: 139, 247
size: 103, 167
orig: 177, 212
offset: 25, 1
index: -1
and I'd want it to also contain the pivot (x,y) of the original sprite, for example 836,194 and 139,247 respectively.
To me it seems like it should be fairly trivial to add the pivot data from the root/editor origin. Seeing that this has been requested multiple times over the years, is there some technical restrictions that prevent you from doing this or could this possibly be added in a near future update?

Thank you in advance!

There are a few kinds of "pivots" in Spine, though it is more accurate to call them "origins" because it's not just used for rotation but also scale (and shear for bones).

The obvious one is bones: when a bone is rotated, scaled, or sheared all descendants are affected and the bone's position is the origin.

Another kind of origin is for region attachments. When a region attachment is positioned or scaled, the origin is the center of the rectangular image. Spine doesn't require or allow a different origin to be specified because this would be tedious to set manually. Using the center of the image defines the origin without requiring needing to set it manually. Note the region attachment position is relative to the parent bone.

For mesh attachments, they don't have a single position, instead they are made up of a list of vertices (also relative to the parent bone). The values shown in the editor for the attachment's position are for convenience and are the mesh hull's centroid. Since the hull vertices can be manipulated via deform keys, vertex weights, or scale of ancestor bones, the centroid can vary as the mesh is manipulated. The origin for rotation and scale defaults to the centroid but can be anywhere: in Spine, hover over the little + until a circle appears around it, then you can drag the origin elsewhere.

If you want to attach an image of a different size in the same place, you'll need to define how you want to calculate the "same place".

If you have another image, possible of a different size, how will you know where to place it? You need to know some reference point on that image that matches up to something on your skeleton, such as a bone position or the origin (center) of an existing region attachment. If you want to define that position manually, then in Spine you can just create an attachment from the image and then position it where you like. However, that is a manual solution and unreasonable to attach hundreds or thousands of images. For that you want an automated solution, you do not want to manually define the reference point.

As you found mentioned elsewhere on this forum, one easy solution is to use images with extra whitespace. That way the center of the images is the same, giving you a reference point, and so you can use just replace the old image with the new one without any calculations. Note that the extra whitespace does not bloat the atlas at all when using whitespace stripping. That is a feature Spine's texture packing supports, so other tools are not required.

If you are exporting data from Photoshop, the JSON data contains the positions of the region attachments. Since each position is the image center, that data tells you exactly where to place the images. These positions in the JSON from Photoshop are in world coordinates (unless you use [bone] tags in Photoshop layer tags). You can convert them to bone local positions using Bone worldToLocal.

It's uncommon to need to position a mesh of a different size at the same position. This is because you likely create the new mesh in Spine, so you have already positioned it where you want. For meshes it is much more common to use the same mesh but replace the image it uses. Linked meshes are used to do that.

Hi Nate and thank you for answering so quickly.
I was specifically asking about the frame animation export option you have in place, maybe that was a bit unclear. I'll post a few images if that helps to clarify the situation a bit more.


The first image shows how we have our character set up, with the root bone selected. This root bone is always located at the editor origin and is also the origin for the character, we use it as the pivot for our skeleton animation characters. But for smaller characters like this one, we want to export it as PNG atlas to save CPU on our game.


In the PNG export settings, I noticed that we can use "Maximum bounds" setting to have all the resulting images to have the same size. I assume this is the solution you have provided as an option after the feedback in the threads that I mentioned, and it works very well. I can use the whitespace stripping to pack the frames more tightly and still have the information of the original sizes in the atlas.


The only problem is, that the root bone that the artists have setup in the editor is not recorded anywhere. I know that with the original size data I could easily set the origin in my use case at the center/corner of each frame, but I can not exactly rotate them or draw something at their feet, since I don't have the data where the feet are located. For this I'd want the exporter to record the root bone position in a frame, so I could easily set the frame origin at the feet of a character. Since it is already possible to make every frame the same size based on the maximum bounds, I'd assume it would also be possible to record the the origin position inside those bounds and save it to the atlas json?

With this data I could easily automate our whole asset flow and reduce the possibility of human error when we create new assets for our game. Hopefully this clarifies our situation a bit and you can point me to the right direction!

Ah, no worries. Due to "automatic sprite animation creation tool" I thought you were wanting to attach images at runtime without having first attached them in Spine, so I went off into the weeds a bit.

For exporting frames, it's true we don't export where world 0,0 is in the resulting images. The best you can do is export as you've shown, then determine the offset manually. When you export all animations at once and they all have the (whitespace stripped) bounds, then the same offset will be used for all frames. This means at least you only need to do this manual process once after exporting. Unfortunately if you add new animations that change the maximum bounds, you'll need to determine the offset again.

I agree we should improve this. I've created an issue, you can subscribe to get notified when the status changes:
Provide world 0,0 offset for exported frames ยท #539 ยท EsotericSoftware/spine-editor

You can see all issues on our roadmap here:
Spine Roadmap

3 months later

Ok, I wasn't sure if I had just missed some setting or if there was something wrong with our setup regarding this ๐Ÿ™‚ I guess I'll have to deal with the manual offsetting for now and hope that you can get this feature done in the future.

Thank you Nate!


Hi,

It's been a few months, so any updates on this?

Sorry, there hasn't been progress on this yet. We've been bogged down with getting the 64-bit launcher and curve editor finished. ๐Ÿ™

3 months later
Nate wrote

Sorry, there hasn't been progress on this yet. We've been bogged down with getting the 64-bit launcher and curve editor finished. ๐Ÿ™

Any progress on exporting pivot in sequence animation png atlas export?
I'm using Unity to play the exported sequence but the pivot in a animation could not be determined. There an offset between different animation.
Looking forward the furthur information about the pivot export in atlas export.
Thanks a lot~

3 months later

Hi,

It's been 6 months now, any news if this is going to get implemented at some point? Looks like it would help other developers also ๐Ÿ™‚

Sorry it's taking so long. We are finally wrapping up v4.0 but we might be able to fit this in.

I wonder if adding fields to the atlas is the best way to go. The origin for all the images from the same animation is the same value and adding entries to the atlas limits the kind of values we can write. For example, it could be useful to write the position of a few bones per frame. This could be used for particle effects, spawning projectiles, etc. Lastly, changing the atlas file format may surprise some parsers.

We could write a separate file containing the origin for each animation. Maybe during export you can choose which bones you care about and it writes the positions of those bones for every frame in every animation. It could also write the rotation.

Any other ideas?

5 days later

Hi Nate,

Sorry for late reply, seems like I didn't receive any notification from your response.

So just to clarify, I'm still talking about the frame animation export, where the resulting atlas and .png files have no data related to the bones anymore. The atlas only holds the frame data for the animations. Since nothing requires you to have every frame to be the same size, I think it would be necessary to have that pivot data as "per frame" data since otherwise people can use it wrong ๐Ÿ™‚ Also to note here, I think the using of "maximum bounds" when you export all animations to one sheet would require only one pivot point data, as you could tie it to the size of the original frame size, which is the same for all of the frames (example data in my first post).

I think I've failed to mention that we use Unity also and you are right, adding data to the atlas might break some parsers. I would honestly just be happy to get those pivot datas out in another file ๐Ÿ™‚ I could then read that data from the file when your Unity import scripts do their things and then combine them together to have all the animations with proper pivots, without the need to manually set those for every frame.

Hope I'm making sense, let me know if I can clarify this further ๐Ÿ™‚ Btw, are you using your own texture packer or a third party solution?

Best,

Sampsa

We've been working on this! We decided to store extra data in the atlas file itself. Since Spine's atlas format is based on libgdx which is FOSS, we have gone through the process to make the changes there. You can follow along here:
https://github.com/libgdx/libgdx/pull/6316

After that is merged (likely tomorrow) we'll add support to Spine. We may not add support to output bone locations in 4.0, but likely will write the origin for each frame of image exports.

Using "maximal bounds" means you can't export just a single animation, you have to export them all and that could be time consuming. Storing the origin per frame is redundant but still pretty OK.

sampsao wrote

Btw, are you using your own texture packer or a third party solution?

Spine's texture packer is based on the FOSS one in libgdx (of which I am the author). We've forked it though to add features like polygon packing.

Alright, this is great news! That is probably the best way to go. For our use case, we really want to use the maximum bounds to export all the animations to one file because that allows us (with this new data) to recreate the frame animations straight from the data you provide. Currently if we have wanted to put these animations to one atlas, for better performance, we have had to use Unity's own tools which aren't that great to be honest... So very glad you decided to do this ๐Ÿ™‚

Nate wrote

After that is merged (likely tomorrow) we'll add support to Spine

So can we expect this in some minor release during Q1?

Ah, I guess you do need to export everything at once so the atlas data will contain all the origin information. You could export all animations to a folder and re-export individual animations there, then run the texture packer separately to have a single atlas, but it wouldn't contain origin information. Hmm, you could export and pack animations individually, then concatenate the atlas files to make a single atlas that has all the origin information.

It should make it into one of the next few beta releases.


The new feature is in 4.0.46-beta, available now!

An example has been added to spine-libgdx. When exporting an image sequence and packing, the world origin is written to the atlas file for each frame:
https://github.com/EsotericSoftware/spine-runtimes/blob/4.0-beta/spine-libgdx/spine-libgdx-tests/assets/spineboy/frame-by-frame.atlas
That is the new atlas format with "pretty print" turned off. Unrecognized values, like origin, in the atlas file are available at runtime. This is how you get the origin for a region and adjust the drawing position:
https://github.com/EsotericSoftware/spine-runtimes/blob/4.0-beta/spine-libgdx/spine-libgdx-tests/src/com/esotericsoftware/spine/FrameByFrameTest.java#L78-L81
The origin is the amount to add to the lower left corner of the region to get the position of the world 0,0 position in the Spine editor. That code makes the drawing position (x and y in the code) correspond to the world 0,0 position, which is the same way skeletons are positioned when using the Spine Runtimes.

Note you will need to read the new texture atlas file format. Currently the only Spine Runtimes that can do that are spine-libgdx, spine-csharp, spine-unity, and spine-xna. The other runtimes will be updated with support for the new format soon.

14 days later

Hi Nate,

Thanks for the quick implementation! I just wonder if I did something wrong when I tried this out: having the same kind of setup as in the original screenshots, it seemed like the origin information didn't get written for every frame, like few animations lost the information. This shouldn't be a problem in my use case though as I should be able to work around it since I use the maximum bounds option. Implementing everything in our workflow will take some time from me so I can not yet comment on how everything works in a real life situation.

I did try to make a new clean Unity project with the latest Unity runtime and Spine examples. I then added the the test data you provided above to try out how it looks, but I failed to get the automated sprite slicing working. I setup the texture import settings to be multiple sprites but when I clicked the "Apply Regions as Texture Sprite Slices" - button, it only sliced one sprite out of the data. I just wonder if I downloaded the wrong runtime, but that was the most recent beta release that I could find from your website and Git. Would love to get this kind of an isolated test working before I move on to implementing it into our project ๐Ÿ™‚

And the data seems quite different from the old version we have used (3.X, legacy data format) previously. Am I correct assuming that the new data is presented in this way:
bounds - x and y positions, height and width of the frame in the resulting atlas
offsets - x and y offset in pixels compared to the original frame, original width and original height of the frame
origin - the origin of the frame in relation to the original size

Yep, that's how the new data looks.

sampsao wrote

it seemed like the origin information didn't get written for every frame

Can you please post your atlas file? There should be an origin entry for every region in the atlas.

Re: Unity, the latest in the 4.0-beta branch should be able to parse the new format. I don't believe it does anything with the origin data though.

Hi Nate,

I'll attach an example atlas test data from my export. As you can see, some frames have no origin data and some do. For my use case where I use the "maximum bounds" - setting, this is no problem as I can use the same origin for every single frame. Just wondered if this might cause trouble for people using different setup, where every frame would have a varying size.

Thanks for clarifying the version, I'll get the files straight from Git to make sure I have the latest ones and try them out!


Adding a small update: so with my own data, the importing and applying the regions as texture sprite slices everything seemed to work just fine. I noticed that your example data used indexing for the frames. I made another test with my own data where I also used the indexes and seems like your Unity importer/tool doesn't know how to apply the texture regions when the indexes are used. Not sure if this is only a problem in the beta, but just so you know.

That said, the feature seems to be already good enough for my use case at least, so again, thank you for the quick implementation! I'll now look into making sure that the origin data works properly and report back if I encounter any problems with it. At a glance it looks to be correct though ๐Ÿ™‚


Something more I discovered. Tried reading the new data and first failed miserably. I then noticed I had the texture packer setting to scale the resulting atlas at 0.5. I guess this option should mostly be used if you want to export different quality versions of your assets (hs/sd). However, the new origin data does not respect this setting but rather saves the origin data always using the 1.0 scale. For the smaller scaled one, this makes it impossible to use the origin properly as other data is affected by the scale. And now I specifically mean the scaling variant setting in the texture packing settings, the general scale in the general png export setting seems to work properly with the origin data.

The general scaling should be more than enough for my use case though, but maybe this is something you want to fix before rolling it out in a final release ๐Ÿ™‚