- Uređeno
Textures and resolutions
Hi,
I'm working on a game with Spine (Awesome work by the way!) and I would like to export my animations from the editor but I've got some problems.
My graphic animator work with HD textures in the Spine editor (character's head have a size of 600600 pixels). When I export all the character, I've got 4 textures of 20482048 pixels. Just one image take 16Mo, I'm working on mobile devices, so it's impossible to me to work with this dimensions.
So, I've tried to export the character in a texture of 81928192, Spine didn't compute textures above 20482048. Well, I would like to resize result texture with photoshop to something like 512*512 but in the game, region atlas are wrong.
I've read the forum and I've found that we can resize character with "json->scale = scale;", this action resize the character but not the region position.
How can I do?
Thanks for your time
(Info: I'm working with C runtime)
The scale on the JSON loader scales the images and all the bones. If your head is 600x600 and you want it 100x100, set a scale of 1/6. This means you want to draw your character at 1/6 the size that it was in the editor.
The Spine runtime does not care about the actual size of your texture regions. Based on the size the images were in the editor and the JSON loader scale, the runtime draws the images. If your images are not actually the size drawn, they are stretched up or down. Typically if you use a scale of 1/6 you would also scale your images down 1/6 and then pack them.
1024x1024 is typically the max texture size for mobile. You'll need to decide on a size for your game, then have your artist provide the images sized down. You can use the texture packer on the scaled down images separately from exporting the JSON. Set the JSON loader scale at runtime to the same ratio the images were scaled down.
Hey Nate - sorry to be thick, but how do you do this in objective-c (cocos2D)?
I'm loading my files like this:
CCSkeletonAnimation *animationNode = [CCSkeletonAnimation skeletonWithFile:@"hero03.json" atlasFile:@"hero03.atlas" scale:1];
The scale in this method scales both the skeleton and the texture atlas. How do I scale just the skeleton?
What do you mean it scales the texture atlas?
I'm sorry - I mean it scales the entire character - texture sheet and skeleton. I'm trying to do exactly what the OP wanted - scale just the skeleton in my code, and create separate packed texture sheets to fit:
iPad Retina = scale 1, texture sheet = 2048 x 2048 (create this size)
iPad = scale.5, texture sheet = 1024 x 1024
iPhone Retina = scale .5, texture sheet = 1024 x 1024
iPhone = scale .25, texture sheet = 512 x 512
I'm just not seeing a json or skeleton scale variable using the skeletonWithFile: setup method.
Again: "The Spine runtime does not care about the actual size of your texture regions. Based on the size the images were in the editor and the JSON loader scale, the runtime draws the images. If your images are not actually the size drawn, they are stretched up or down."
Eg, if you use the same resolution images as in the editor and scale of 2, it will stretch the images to be twice as large. If you use images that are twice as large as in the editor and scale of 1, it will shrink the images to be half the size. If you use images that are twice as large as in the editor and scale of 2, it will draw the images at their native size.
collider, I have the same issue, I am not sure the cocos2d (and/or cocos2d-x) asset loading strategy works exactly right with the Spine runtime scaling, see my post here: viewtopic.php?p=5924#p5924
I ended up having to modify the source to get it to work right with my different sized assets. In the end I can use the same atlas file for all sizes of my image, but it requires one additional manual modification, I added the original exported image dimensions, and then in Atlas.cpp the loaded texture scale is determined by these dimensions and all the coordinate values are scaled by this factor.
If cocos2d changed the runtime as described in the thread msm linked, I'm not responsible. Use the runtime from github.
I was unable to figure it out either way, using the github version or the version bundled with cocos2d-x.
Using images of different dimensions than the one exported from the Spine editor with the unmodified atlas file exported from the editor would not work.
I only know how I solved it and that was by modifying the source to account for the different texture scales within the related Atlas code. If anyone is interested this is my diff, it requires adding the original Spine exported image dimensions to your atlas. For example, if the exported image is 2048 x 2048, add this line to your atlas file
skeleton.png
format: RGBA8888
filter: Nearest,Nearest
repeat: none
orig: 2048 x 2048
(add the "orig:" line after "repeat" as shown)
If anyone knows what the proper way of working within cocos2d without modifying the source, I am interested as well.
---
extensions/spine/Atlas.cpp | 38 ++++++++++++++++++++
---
extensions/spine/Atlas.h | 3 +++
extensions/spine/spine-cocos2dx.cpp | 1 +
3 files changed, 25 insertions(+), 17 deletions(-)
diff
---
git a/extensions/spine/Atlas.cpp b/extensions/spine/Atlas.cpp
index 281e214..f27bf4f 100755
---
a/extensions/spine/Atlas.cpp
+++ b/extensions/spine/Atlas.cpp
@@ -213,6 +213,10 @@ Atlas* Atlas_readAtlas (const char* begin, int length, const char* dir) {
page->vWrap = *str.begin == 'x' ? ATLAS_CLAMPTOEDGE : (*str.begin == 'y' ? ATLAS_REPEAT : ATLAS_REPEAT);
}
+ if (readTuple(end, tuple) != 2) return abortAtlas(self);
+ page->origWidth = toInt(tuple);
+ page->origHeight = toInt(tuple + 1);
+
_AtlasPage_createTexture(page, path);
FREE(path);
} else {
@@ -230,12 +234,12 @@ Atlas* Atlas_readAtlas (const char* begin, int length, const char* dir) {
region->rotate = equals(&str, "true");
if (readTuple(end, tuple) != 2) return abortAtlas(self);
- region->x = toInt(tuple);
- region->y = toInt(tuple + 1);
+ region->x = toInt(tuple) * page->textureScale;
+ region->y = toInt(tuple + 1) * page->textureScale;
if (readTuple(end, tuple) != 2) return abortAtlas(self);
- region->width = toInt(tuple);
- region->height = toInt(tuple + 1);
+ region->width = toInt(tuple) * page->textureScale;
+ region->height = toInt(tuple + 1) * page->textureScale;
region->u = region->x / (float)page->width;
region->v = region->y / (float)page->height;
@@ -250,29 +254,29 @@ Atlas* Atlas_readAtlas (const char* begin, int length, const char* dir) {
if (!(count = readTuple(end, tuple))) return abortAtlas(self);
if (count == 4) { /* split is optional */
region->splits = MALLOC(int, 4);
- region->splits[0] = toInt(tuple);
- region->splits[1] = toInt(tuple + 1);
- region->splits[2] = toInt(tuple + 2);
- region->splits[3] = toInt(tuple + 3);
+ region->splits[0] = toInt(tuple) * page->textureScale;
+ region->splits[1] = toInt(tuple + 1) * page->textureScale;
+ region->splits[2] = toInt(tuple + 2) * page->textureScale;
+ region->splits[3] = toInt(tuple + 3) * page->textureScale;
if (!(count = readTuple(end, tuple))) return abortAtlas(self);
if (count == 4) { /* pad is optional, but only present with splits */
region->pads = MALLOC(int, 4);
- region->pads[0] = toInt(tuple);
- region->pads[1] = toInt(tuple + 1);
- region->pads[2] = toInt(tuple + 2);
- region->pads[3] = toInt(tuple + 3);
+ region->pads[0] = toInt(tuple) * page->textureScale;
+ region->pads[1] = toInt(tuple + 1) * page->textureScale;
+ region->pads[2] = toInt(tuple + 2) * page->textureScale;
+ region->pads[3] = toInt(tuple + 3) * page->textureScale;
if (!readTuple(end, tuple)) return abortAtlas(self);
}
}
- region->originalWidth = toInt(tuple);
- region->originalHeight = toInt(tuple + 1);
+ region->originalWidth = toInt(tuple) * page->textureScale;
+ region->originalHeight = toInt(tuple + 1) * page->textureScale;
readTuple(end, tuple);
- region->offsetX = toInt(tuple);
- region->offsetY = toInt(tuple + 1);
+ region->offsetX = toInt(tuple) * page->textureScale;
+ region->offsetY = toInt(tuple + 1) * page->textureScale;
if (!readValue(end, &str)) return abortAtlas(self);
region->index = toInt(&str);
@@ -336,4 +340,4 @@ AtlasRegion* Atlas_findRegion (const Atlas* self, const char* name) {
return 0;
}
-}} // namespace cocos2d { namespace extension {
\ No newline at end of file
+}} // namespace cocos2d { namespace extension {
diff
---
git a/extensions/spine/Atlas.h b/extensions/spine/Atlas.h
index ea5ca9b..bd1ce48 100755
---
a/extensions/spine/Atlas.h
+++ b/extensions/spine/Atlas.h
@@ -52,6 +52,9 @@ struct AtlasPage {
AtlasFormat format;
AtlasFilter minFilter, magFilter;
AtlasWrap uWrap, vWrap;
+ int origWidth;
+ int origHeight;
+ float textureScale;
void* rendererObject;
int width, height;
diff
---
git a/extensions/spine/spine-cocos2dx.cpp b/extensions/spine/spine-cocos2dx.cpp
index aa40693..b71e4c4 100755
---
a/extensions/spine/spine-cocos2dx.cpp
+++ b/extensions/spine/spine-cocos2dx.cpp
@@ -38,6 +38,7 @@ void _AtlasPage_createTexture (AtlasPage* self, const char* path) {
// Using getContentSize to make it supports the strategy of loading resources in cocos2d-x.
self->width = texture->getPixelsWide();
self->height = texture->getPixelsHigh();
+ self->textureScale = 1.0f * self->width / self->origWidth;
//self->width = texture->getContentSize().width;
//self->height = texture->getContentSize().height;
}
---
1.8.2.3
msm wroteUsing images of different dimensions than the one exported from the Spine editor with the unmodified atlas file exported from the editor would not work.
This is a little confusing. If you have images of a different size, you'll need to pack them into an atlas of a different size. You can use the same skeleton file with the different size atlas. Scaling up/down is separate from the size of the images.
I think I am still confused.
I have 3 files that are exported from Spine, skeleton.png, skeleton.atlas, and skeleton.json
I am scaling the exported skeleton.png to different sizes, in cocos2d/cocos2dx this is typically 25%, 50% and 100% scaled images.
I want to use all 3 scaled versions of skeleton.png with the same unmodified skeleton.atlas and skeleton.json files exported from Spine.
Using the runtime skeleton->scale doesn't do that. I was only able to do it with my changes in my previous post.
If that skeleton->scale was never intended to do that, is it possible to export to different scales from the Spine editor, or would I need to create 3 separate skeletons?
I think part of my confusion stems from the documentation, the part that describes Scale in this way:
This can be useful when using different sized images than were used when designing the skeleton in Spine. For example, if using images that are half the size than were used in Spine, a scale of 0.5 can be used. This is commonly used for games that can run with either low or high resolution texture atlases.
I can see now that it only refers to the json skeleton file exported from Spine, and not .atlas file
Personally i had to create different atlas files for each of my 3 resolutions using TexturePacker for my cocos solution. So in summary i have the master json file in my master folder, and a copy of the atlas and png scaled appropriately in each of the SD,HD,HDR folders.
Nice, so the TexturePacker atlas data file is compatible with the Spine runtime?
Sorry for the confusion, msm. Currently the Spine texture packer doesn't pack multiple resolutions. I'd like to add this feature, but haven't got to it yet. You'll need 3 copies of all your images (eg 100%, 50%, 25%) and then run the packer 3 times to get 3 atlases. Use the appropriate atlas and JSON loader scale at runtime. You can use a script (ImageMagick, Photoshop, Java, python, etc) to scale your 100% images down to the other sizes.
An alternative is to use Texture Packer Pro which does have the automatic multi atlas feature, though this is a paid application. Choose the "libgdx" export option for Texture Packer Pro.
I'm also having problems here. I animated in Spine with the hd version of my character. Then exported that. To make the non hd I reduced all images to 50% in photoshop and opened the same spine file. It had all the animations but the images where too small. So I needed to scale those images to 200% inside Spine before export.
I dont think you can just scale the images and be done with it. Your animations would still be made for a higher size images.
Nate wroteSorry for the confusion, msm. Currently the Spine texture packer doesn't pack multiple resolutions. I'd like to add this feature, but haven't got to it yet. You'll need 3 copies of all your images (eg 100%, 50%, 25%) and then run the packer 3 times to get 3 atlases. Use the appropriate atlas and JSON loader scale at runtime. You can use a script (ImageMagick, Photoshop, Java, python, etc) to scale your 100% images down to the other sizes.
An alternative is to use Texture Packer Pro which does have the automatic multi atlas feature, though this is a paid application. Choose the "libgdx" export option for Texture Packer Pro.
No worries Nate, thanks for clearing this up for me.
Erebar wroteI'm also having problems here. I animated in Spine with the hd version of my character. Then exported that. To make the non hd I reduced all images to 50% in photoshop and opened the same spine file. It had all the animations but the images where too small. So I needed to scale those images to 200% inside Spine before export.
I dont think you can just scale the images and be done with it. Your animations would still be made for a higher size images.
Nate can probably correct me, but Erebar, in your case I think this where you want to use the runtime json scale
http://esotericsoftware.com/spine-using ... s/#scaling
msm is correct.
msm wroteNate can probably correct me, but Erebar, in your case I think this where you want to use the runtime json scale
http://esotericsoftware.com/spine-using ... s/#scaling
Yes, thanks msm, that will make things easier.