Heleor :the skeletonData comes from the skeletonJson, which is created using the custom atlas. If I reuse the skeletonData, wouldn't that result in reusing the atlas information as well? (Losing all of the texture changes from the specific instance of the skeleton)
We don't generally recommend swapping textures to change how attachments look. You generally want as much on a single texture as possible because changing textures breaks batching.
Instead you could have an attachment in Spine for each variation (hat red, hat purple, etc). Then when you pack your atlas, all the images can be packed together tightly.
If a variation has multiple images (eg shirt arm left, arm right, and torso) you can use a skin to group the attachments in Spine. At runtime you can combine many skins representing various "items" (shirt, pants, sword, etc) into the skin the skeleton uses.
Heleor :You're right for that specific belt, but there are belts that do use the extra space (sashes, fancy shirts). Since the actual rig needs to contain pieces for all possible belts, we chose to expand the actual attachment larger (so that we do not have to keep modifying the rig whenever we want to go slightly outside the current bounds).
This is fine to organize your art, but it is worth finding ways to not have all that whitespace eat up space in your atlas textures. With the setup described above, each image can be packed with whitespace stripping or using the polygons
packing mode. When an image is drawn at runtime, it is offset so it is drawn as if it still had the whitespace.
Heleor :The purpose of the individual textures is so that artists can create new skins without having to use the spine editor (which has proven to be too complex for most 2D artists that we have contracted).
...
We currently have over 1000 unique images and we intend to have 10-100x more than that in the final game. Would you recommend a spine rig with 100,000 skins?
The Spine editor can likely handle that many attachments, but you're right that it is not recommended because it requires too much tedious work that can be avoided in other ways. You approach to use whitespace in the attachment images is good, you just don't want that whitespace in your atlas.
This is going to get a bit long from here because you want everything: 1) to render any of many variations, and 2) to render many of those all at once.
What you can do is rig one set of attachments in Spine that use an image with enough whitespace to fit any of your images for that attachment. These attachments are your "template". Artists can now go off and create any number of attachments images using the template images, as long as their images are the same size. You do not rig any of these images in Spine, your skeleton only contains only the template images.
You can create an image that shows all the bones using Spine's PSD export, so your artists know where the bone origins are located. This lets them position their images based on where the bones rotate.
Now what to do at runtime? You could pack all the images into an atlas (you can exclude the template images) using whitespace stripping (you can use polygon packing too, but let's not complicate things any further for now). When you load your skeleton at runtime, you can provide an AttachmentLoader to control how the texture region for an attachment is found.
There's a few ways to go from here, depending on your needs. When the AttachmentLoader is asked to create the attachment for template-shirt-left-arm
you could create the attachment and instead provide the texture region you want, say red-shirt-left-arm
. The resulting SkeletonData has attachments configured with texture regions for the variations you want. However, the skeleton data and attachments are shared across Skeleton instances, which may not be what you want.
Instead, you could have your AttachmentLoader create the attachment but not configure it with any texture region. Then you can create multiple skeleton instances from the resulting skeleton data. Before you render a skeleton instance, you need to set the texture region for each attachment. Attachments are shared across skeleton instances, so you want to first copy the attachment (Attachment copy
), set the texture region on the attachment, and replace the attachment on the skeleton with the copy.
Alternatively, you could avoid making attachment copies by customizing the skeleton rendering. When you go to render an attachment, instead of getting the texture region from the attachment, you'd decide which texture region to use (based on your application state) and use that instead.
This is all great, no? Your artists can create thousands of new images without any rigging in Spine. You can load the skeleton data once and render multiple skeletons with different variations. At this point you may have the issue that your 100k images makes for an atlas that is huge, even when packed with whitespace stripping. When rendering a skeleton it's likely each image will be on a different texture, resulting in a texture switch and batch flush for each attachment -> poor performance.
To solve this you'll need the attachment images that will be drawn subsequently to be on the same atlas page. One solution to this is to package your game with individual images (or download them as needed) rather than an atlas with ALL the images. Once you know exactly how to outfit a skeleton, you would pack only those images to a texture at runtime. You could even look at the animations you plan to play to find any attachment keys, so those images can be packed too.
You could try to fit multiple skeletons in one texture, or maybe one texture per skeleton is good enough. This runtime packing is a bit of work to implement. Some game toolkits provide ways of doing it, such as Unity or libgdx.
Note if you happen to know the variations at build time, you can put thier images in subfolders so they are grouped together on a single atlas page, pack them with Spine's texture packer, and then at runtime only load the atlas pages you need.
Now you can finally render any skeleton variations with good performance! There are other ways you could make this even more complicated 😉, such as storing your individual attachments as SVG, then rendering the SVG at runtime (usually quite difficult, but probably not too bad using a browser) to create your skeleton's packed texture.
As an alternative solution to runtime packing, or to augment runtime packing when using one texture per skeleton, you could customize rendering to use a texture array and pass the desired texture as a vertex attribute. This avoids flushing the batch when the texture changes. More information and an implementation is available here:
https://www.youtube.com/watch?v=bw6JsLnx5Jg
https://github.com/libgdx/libgdx/issues/5907
We did it this way to allow the shirt to be tinted separately from the pants or the cape. Is there a separate Skeleton.color on each skin?
When you need to tint only some slots, setting the color for just those slots is the way to go.