• Unity
  • Replace body part via code

Hello!

On the previous engine we used, Haxe based, I hacked my way in and did it, but I was wondering if there's a proper solution for Unity.

In our game, we have characters which gets damaged. I need them to change body parts, but since these parts are a lot and there's lots of characters, I need to do that via code.

Sprite dimensions won't change. Is just a sprite replacement. Is there a way to grab a sprite from "resources/" folder and use that one, for the damaged head instead? Thanks in advance. 8)

Related Discussions
...
  • تم التحرير

Yes, there is a proper built-in solution available in spine-unity. Please check out the example scenes Spine Examples/Other Examples/Mix and Match and Mix and Match Equip that come with the spine-unity package. These show how you can switch out attachments with Unity Sprites.

You can also have a look at the Runtime Repacking section in the spine-unity documentation pages here, which is also used in the above example scenes:
spine-unity Runtime Documentation: Combining Skins

Hey, thanks a lot for the answer. I followed your information and managed to do what I wanted.

However, I bumped into a scale issue:

The circled one, uses the very same image as the source, but for some reason, is smaller. What would be the cause for this? Thanks a lot for your time and for helping so much 8)

I have been trying to do the same thing and encountered the same problem. In my case some are getting bigger and some are getting smaller. Did you get any solution to that?

I have been trying to do the same thing and encountered the same problem. In my case some are getting bigger and some are getting smaller. Did you get any solution to that?

Same issues here and sadly, no solution that I could find. I would be editing this post if I find something.

We are sorry for the troubles! Could you please create a minimal Unity package that still shows the problem, and send it as a zip package to contact@esotericsoftware.com, then we can have a look at what's going wrong.

Edit: @parth16parikh @SysOp After sending a zip package, please post here on the forum, so that only one of you two needs to create and send a reproduction package.

Remark: The discussion from this thread will be continued here.

Done, sent to that address 🙂

Click on the button to replace it:

There's no custom code, uses scripts from Mix and Match examples.

Thanks for the amazing support :love:

Hi @Harald,

I have also sent email to the email which you said.

You can just open the Test scene and hit play. As you click on the play button, green character will turn blue. You will be able to notice problem in that.

Just for further updates, Are you going to update me on this thread or you will be updating me on email?

Thank you for the quick support.

Thanks! Harald will check it out as soon as he can. We normally keep the discussion on the forum when possible and respond to the email only to say we've replied on the forum.

@[محذوف]
Thanks for sending the reproduction package. Unfortunately after loading the unitypackage there is a missing script on the Main Camera GameObject, and nothing happens when clicking the buttons. In general we prefer zip packages of the project (without the Library dir) to unitypackages as this saves us some time. Anyway, since Parikh also sent us a package there is no need to send an updated package.

@[محذوف]
Thanks for sending the reproduction package, we received everything and can see the issue occurring in your project.
We will get back to you here on the forum once we've figured out what's going wrong.


@[محذوف]
After having a detailed look at your reproduction project, the problem turned out to be different sizes of the image (so not a bug in spine-unity):

The blue foot is of size 231 x 207 (tightly clipped without borders) while the green one is larger, size 263 x 263 with a transparent border around it. At least Spine shows this size at the green one in the atlas.txt file and upon atlas-unpacking, the resulting image is of this size. As you are saying they are of equal size: did you clamp them somewhere along your workflow perhaps?


@[محذوف]
I just had a detailled look at your reproduction project. The problem is as follows: Your atlas has been exported with Strip Whitespace X/Y set to a non-zero border (see the documentation here). Now in the EquipSystemExample class, templateAttachment.GetRemappedClone() is called with default parameter useOriginalRegionSize = false here. So you need to call GetRemappedClone() with the parameter useOriginalRegionSize explicitly specified as true as follows:

attachment = templateAttachment.GetRemappedClone(asset.sprite, sourceMaterial, premultiplyAlpha: this.applyPMA, useOriginalRegionSize : true);

Another solution would be to disable whitespace stripping upon atlas texture export.

I will investigate (most likely tomorrow) whether behaviour of GetRemappedClone() with useOriginalRegionSize set to false should behave differently than it does right now. I will get back to you once I've come up with an answer.

That, indeed, solves it!

I suspected it had something to do with white space stripping as I had same issue on previous engine, I even tested that out, but perhaps got myself confused.

Thanks a lot for checking this out, customization, here we go! :heart:

Thanks for your kind words, very glad it helped! 🙂

Harald wrote

I will investigate (most likely tomorrow) whether behaviour of GetRemappedClone() with useOriginalRegionSize set to false should behave differently than it does right now. I will get back to you once I've come up with an answer.

I will have a look at this right now and will let you know if we can provide an improvement in this regard as well.

Hi @Harald,

Yea size of the image in atlas is 263 x 263. So we tried to increase the size of the blue foot image to 263x263. When we did that we get this error "negative source coordinates".

Actual size of the green foot in the spine software is 231x207. When we export it from spine, then it will show 263x263 in atlas file. That is the reason why blue foot size is 231x207.

Also one more update, when we added one pixel black line in 231x207 size blue foot image then it worked properly. I dont know where exactly the problems is. Let me know if you have any explanation.

parth16parikh wrote

Yea size of the image in atlas is 263 x 263. So we tried to increase the size of the blue foot image to 263x263. When we did that we get this error "negative source coordinates".

Could you please describe exactly what you did, and where this exception or error occurred? Could you share some screenshots of the Texture and Sprite import settings?

A side note: I noticed that your foot attachment is a MeshAttachment and not a RegionAttachment. MeshAttachments are more limited in regard to remapping, so a working setup for RegionAttachments may produce incorrect results on MeshAttachments. This is mostly due to the Mesh vertex positions, which cannot be expanded or contracted as RegionAttachments vertices. Mesh vertices need to stay as they are, only uv coords are modified to map the texture differently.

parth16parikh wrote

Actual size of the green foot in the spine software is 231x207. When we export it from spine, then it will show 263x263 in atlas file. That is the reason why blue foot size is 231x207.

It is strange that the output image in the atlas is larger than the input image. Could you please send us your Spine project files, so that we can have a look at it? Could you please also post a screenshot of your Texture Packer Settings used when exporting the atlas from Spine?

parth16parikh wrote

Also one more update, when we added one pixel black line in 231x207 size blue foot image then it worked properly. I dont know where exactly the problems is. Let me know if you have any explanation.

Most likely the problem is that the Sprite Mesh Type import setting is set to Tight instead of Full Rect, which will additionally clamp transparent borders. Unfortunately tight packing is not yet fully supported in spine-unity. Please try setting it to Full Rect for now.

I have created an issue ticket here to cover Mesh Type Tight:
https://github.com/EsotericSoftware/spine-runtimes/issues/1884
Unfortunately it will most likely take some time until we get to implement this issue ticket, due to many higher priority tasks.


Harald wrote

I will investigate (most likely tomorrow) whether behaviour of GetRemappedClone() with useOriginalRegionSize set to false should behave differently than it does right now. I will get back to you once I've come up with an answer.

@[محذوف]
The main problem with the Sprite attachment being too small was due to the implicitly used scale not being equal to the original attachment scale, since it uses the Sprite's Pixels per Unit value (set to the default value of 100, which leads to a scale of 0.01).

We have just released some improvements regarding the behaviour when useOriginalRegionSize is set to false:

Changelog.md wrote

Attachment.GetRemappedClone(Sprite) method now provides an additional optional parameter useOriginalRegionScale. When set to true, the replaced attachment's scale is used instead of the Sprite's Pixel per Unity setting, allowing for more consistent scaling. Note: When remapping Sprites, be sure to set the Sprite's Mesh Type to Full Rect and not Tight, otherwise the scale will be wrong.

So calling GetRemappedClone(.., useOriginalRegionScale : true) should improve the situation for many cases where you want to maintain the replaced attachment's scale instead of using a specific Sprite scale.
New 3.8 and 4.0-beta unitypackages are available for download here as usual:
Spine Unity Download
Note that only has an effect on RegionAttachments, not on MeshAttachments. Please let us know if this works for you as well and whether it improves the situation.

Also beware to set all Sprite's Mesh Type to Full Rect and not Tight as described in the changelog, as this causes improper scale when using the head_robot_test: when the Sprite is set to Full Rect it maps correctly, when set to Tight it is incorrectly stretched vertically.

Thanks for the explanation and for the hard work mate. Backing up this project was one of the best decisions I ever made <3

EDIT: When optimizing the skin (by pressing Done), my character looks like this (main texture looks like gray boxes):

And in the console, I get dozens of:

Graphics.CopyTexture can only copy memory with the same size (src=26240 bytes dst=6560 bytes), maybe the size (src=163 * 160 dst=41 * 40) or format (src=RGBA Compressed DXT5 UNorm dst=RGBA8 UNorm) are not compatible

What might be the cause of this?

Thanks for your kind words. 8)

Regarding the issue with repacking:

SysOp wrote

src=RGBA Compressed DXT5 UNorm

Most likely it's the DXT5 compressed source texture which cannot be read, please change the texture import settings (for all target platforms) from Compressed to an uncompressed format.

You can also have a look at the list that reads "Important Note: If repacking fails [..]" in section Runtime Repacking on the spine-unity documentation pages here:
spine-unity Runtime Documentation: Combining Skins

Disabling compression and enabling read/write did the trick! Huge thanks again! <3

EDIT: Deeply sorry to again bring out issues, but after repacking, I'm losing a material.

Here's the ones I use:

After repacking I lose one:

I read the documentation and SpineBoy example uses a single material. I tried to do something like:

int[] additionalTexturePropertyIDsToCopy = new int[] { Shader.PropertyToID("-Additive") };

repackedSkin = repackedSkin.GetRepackedSkin("repacked skin", sourceMaterial, out runtimeMaterial, out runtimeAtlas, additionalTexturePropertyIDsToCopy: additionalTexturePropertyIDsToCopy); // Pack all the items in the skin.
         

... to copy that additive material, but doesn't work. I'm obviously doing something wrong.

SysOp wrote

Disabling compression and enabling read/write did the trick! Huge thanks again! <3

Very glad to hear that! 8)

SysOp wrote

EDIT: Deeply sorry to again bring out issues, but after repacking, I'm losing a material.

No need to apologize. The main purpose of the repacking methods is to reduce drawcalls by using a single texture and material. Unfortunately, packing to two separate output materials is not supported by these methods. I'm afraid you will have to call GetRepackedSkin() or GetRepackedAttachments() once for each material that you want to keep, as either of these methods creates only a single output material. So you could either create two lists of attachments and use GetRepackedAttachments, or create two separate Skins, add the respective attachments to one of the two skins and call GetRepackedSkin() for both skins.

In general you could have a look if you would be saving draw calls at all by repacking to multiple materials. If you would have the same number of submeshes and materials before as after repacking, then you can save the repacking step. You will not benefit much (or at all) if you have two drawcalls with one repacked texture, compared to two drawcalls with two textures.

SysOp wrote
int[] additionalTexturePropertyIDsToCopy = new int[] { Shader.PropertyToID("-Additive") };

The additionalTexturePropertyIDsToCopy parameter is only for additional texture maps at the same material, e.g. when you have a material with diffuse, normal and emissive textures that all shall be repacked the same way in one go.

You will not benefit much (or at all) if you have two drawcalls with one repacked texture, compared to two drawcalls with two textures.

Ah, okay then. Yeah, I'm only using 4 customizable characters max, it won't affect the performance at all. Since this pretty much done, I'm marking this as solved. Thanks again! :heart: