Hi, in our game, players can change the skin for 3 different parts of the character: head, body and arms. However, if we set a different animation to play, the skin in the body and arms resets to the default one, only the head remains with the correct skin. It used to work in 4.0 before upgrading to 4.2. Do you guys have any idea what could have caused it to break? Thank you.
Skin changes when playing an animation
gustavo_shoelace Are you resetting the skeleton slots to their setup poses in the implementation part of the code involved in playing back the animation? It would help us to determine the cause if you could show us the code in the part of the code that is involved in the playback of the animation.
- Editado
Misaki sorry for the delay, i had to do some digging into the code as this game was developed by another team and we are maintaining it now.
I don't think we are resetting the slots. We are just setting the animation when using it. Also, it seems the skins are being used on a weird way where the texture is replaced by another texture on the fly. (see example attached)
Here is the code to set the skin:
public void SetTextures(Texture textDown, Texture textUp, bool head)
{
if (head)
{
headDown.GetComponent<MeshRenderer>().material.mainTexture = textDown;
headUp.GetComponent<MeshRenderer>().material.mainTexture = textUp;
}
else
{
try
{
Debug.Log($"Setting up {textUp} / down {textDown}");
bodyUp.GetComponent<MeshRenderer>().material.mainTexture = textUp;
armUp.GetComponent<MeshRenderer>().material.mainTexture = textUp;
bodyDown.GetComponent<MeshRenderer>().material.mainTexture = textDown;
armDown.GetComponent<MeshRenderer>().material.mainTexture = textDown;
}
catch (Exception e)
{
Debug.LogException(e);
throw;
}
}
}
Here is the code to set the animation:
public void SetCorrectAttackAnimation()
{
if (this._baseItem.fullTroopData.alignAnimations)
{
this._baseItem.SpineRenderer.disableAutoUpdateAnimation = true;
this._baseItem.state = Common.State.ATTACK;
this._baseItem.SpineRenderer.SetAnimation("attack", false, this._baseItem.fullItemData.defenseConfig.attackTimeScale);
this._baseItem.LookAt(this._currentTarget);
}
else
{
this._baseItem.SetState(Common.State.ATTACK);
this._baseItem.LookAt(this._currentTarget);
}
}
This is the base texture
This is a skin in the game that is loaded in the fly and replaces the base avatar texture
@gustavo_shoelace Thanks for the additional info. The code that you've shared replaces textures at the first material of each MeshRenderer
. Calling an atlas texture a skin was a bit misleading, as a skin in Spine terminology is a set of attachments and comes with special functionality, see the documentation here. Note that the runtime skin API allows to recombine different body-part skins at runtime.
Are headDown
, headUp
, bodyUp
, etc all separate SkeletonAnimation GameObjects, each with their own MeshRenderer
? If they are all separate SkeletonAnimation GameObjects, please note that this is a rather inefficient setup, as normally combine Spine skins at a single Skeleton.
Regarding potential issues with your code:
- Modifying
MeshRenderer.material
creates a material copy and modifies the copy. The materials might be overwritten with the original AtlasAsset materials at any time bySkeletonRenderer.LateUpdate()
when assigning materials according to currently visible attachments. See the documentation here. If you want to replace materials per instance, see the documentation section here. - Also, your code would only work if each Skeleton only has a single atlas page texture, as it will only replace the first Material's texture. If more than one atlas page is used, subsequent materials are not updated.
If possible, I would recommend to reconsider your basic skeleton setup and potentially use Spine skins instead of splitting a skeleton into parts for each skin to be changed. If I misunderstood your setup, please do let me know.
Harald thanks for your reply.
We will definitely consider to fix it by using Spine skins but it might take some time so we will need to stay on 4.0 for longer than we expected. We were willing to upgrade to 4.2 so we can make use of UITK+Spine. So with this in mind i have a few questions:
- By looking at our current setup, do you have an idea why it stop to work when we upgraded from 4.0 to 4.2?
- Will Spine 4.0 work on Unity 6?
- Any chance 4.0 will receive UITK support in the future?
Thank you,
Gustavo
gustavo_shoelace Will Spine 4.0 work on Unity 6?
Any chance 4.0 will receive UITK support in the future?
Only the 4.2 runtime supports Unity 6 officially, 4.0 never received or will receive bugfixes for Unity 6. As a consequence 4.0 might be broken in some parts.
UITK is also only supported on Unity 6 due to some API extensions which are missing on earlier versions.
By looking at our current setup, do you have an idea why it stop to work when we upgraded from 4.0 to 4.2?
It might be that spine-unity 4.0 didn't update the materials array at the MeshRenderer every frame if the materials haven't changed. You might want to look into that. You could utilize the SkeletonAnimation.OnMeshAndMaterialsUpdated
callback to re-assign the desired material yourself (i.e. create a copy of the material only once and then re-assign the modified copy). See the documentation here:
https://esotericsoftware.com/spine-unity-main-components#Life-cycle
https://esotericsoftware.com/spine-unity-rendering#Changing-Materials-Per-Instance
i was trying your suggestion but noticed that some animations still works. Doing a quick investigation on the animations, we identified that the ones that stop working on 4.2 are the ones that have scales applied in the bones.
Here you can see the current skin in the body was working but breaks when i set an animation with a scale in one of the bones
Here i apply a different skin, it breaks but i force it again and it breaks at the end of the animation
And this is an example of a scale applied to the bone (we have some animations with this applied to one or more bones)
Any guidance on this would be much appreciated.
Thank you,
Gustavo
Harald tagging you just in case.
gustavo_shoelace Doing a quick investigation on the animations, we identified that the ones that stop working on 4.2 are the ones that have scales applied in the bones.
This is likely just a coincidence and has no relation to your issue, at least if the problem that you're experiencing is that your material textures unexpectedly reset to the default one as you've described earlier:
gustavo_shoelace However, if we set a different animation to play, the skin in the body and arms resets to the default one, only the head remains with the correct skin.
Is this still the problem that you're facing?
I've explained the potential issue and what to do about it in my postings above:
Harald Regarding potential issues with your code:
- Modifying MeshRenderer.material creates a material copy and modifies the copy. The materials might be overwritten with the original AtlasAsset materials at any time by SkeletonRenderer.LateUpdate() when assigning materials according to currently visible attachments. See the documentation here. If you want to replace materials per instance, see the documentation section here.
- Also, your code would only work if each Skeleton only has a single atlas page texture, as it will only replace the first Material's texture. If more than one atlas page is used, subsequent materials are not updated.
Harald It might be that spine-unity 4.0 didn't update the materials array at the MeshRenderer every frame if the materials haven't changed. You might want to look into that. You could utilize the SkeletonAnimation.OnMeshAndMaterialsUpdated callback to re-assign the desired material yourself (i.e. create a copy of the material only once and then re-assign the modified copy). See the documentation here:
https://esotericsoftware.com/spine-unity-main-components#Life-cycle
https://esotericsoftware.com/spine-unity-rendering#Changing-Materials-Per-Instance
Did you try what I suggested in the last section?