Hi there,
I'm looking to modify my characters item related attachments at runtime.
The aim is to have these attachments update when the players inventory changes.
For example... the item attachment positioned in the characters hand should update at runtime to show the equipped weapon sprite.
My preferred method is to use the "GetRemappedClone" method, and this works great.
(FYI, I've tried bone followers, but this isn't desirable for my use case. Long story short - My game is 2.5d and I'm using custom shaders which distort the vertices of the mesh, so ideally i don't want to have seperate mesh renderers for all of my items)
However, when using the GetRemappedClone method, my sprites lose their secondary textures. To be more precise, their _EmissionMap.
As a quick example, i have two Texture2Ds
weapons-albedo and weapons-emissive.
The weapons-albedo looks like this.
It has several weapon sprites inside it.
It also has a reference to the _EmissionMap secondary texture (weapons-emissive)

and 'weapons-emissive' looks like the following.

Ideally, I want my sprites to have both albedo and emissive.
(For example purposes)

But what I actually get is just the albedo

What is the optimal way to achieve something like this?
I can't really get my head around it.
Any help would be greatly appreciated. Thanks.
[RequireComponent(typeof(SkeletonAnimation))]
public class AttachmentSetter : MonoBehaviour
{
[SpineSlot]
[SerializeField]
private string slotName;
[Tooltip("Material whose Main Texture is set to the generated Texture2D of the atlas")]
[SerializeField]
private Material spriteMaterial;
[Tooltip("The settings to apply to your new attachment when cloning from the template.")]
[SerializeField]
private AttachmentCloneSettings attachmentCloneSettings;
private readonly Dictionary<string, Attachment> _attachmentCache = new();
private SkeletonAnimation _skeletonAnimation;
private RegionAttachment _originalAttachment;
// Modify the Awake method to store the original attachment
private void Awake() {
_skeletonAnimation = GetComponent<SkeletonAnimation>();
// Store the original attachment.
Skeleton skeleton = _skeletonAnimation.Skeleton;
Slot slot = skeleton.FindSlot(slotName);
_originalAttachment = slot.Attachment as RegionAttachment;
}
public void SetSprite(string id, Sprite newSprite)
{
if (!newSprite || string.IsNullOrEmpty(id))
{
ResetAttachment();
return;
}
// Locate the Spine slot and its current RegionAttachment as a template.
Skeleton skeleton = _skeletonAnimation.Skeleton;
Slot slot = skeleton.FindSlot(slotName);
RegionAttachment template = slot.Attachment as RegionAttachment;
if (template == null) {
Log.Error($"'{slotName}' slot has no RegionAttachment to use as a template.");
return;
}
// Get or create a remapped clone that swaps in newSprite.
if (!_attachmentCache.TryGetValue(id, out Attachment attachment))
{
// First create the remapped clone
attachment = template.GetRemappedClone(
newSprite,
spriteMaterial,
premultiplyAlpha: attachmentCloneSettings.premultiplyAlpha,
cloneMeshAsLinked: attachmentCloneSettings.cloneMeshAsLinked,
useOriginalRegionSize: attachmentCloneSettings.useOriginalRegionSize,
pivotShiftsMeshUVCoords: attachmentCloneSettings.pivotShiftsMeshUVCoords,
useOriginalRegionScale: attachmentCloneSettings.useOriginalRegionScale
);
_attachmentCache[id] = attachment;
}
slot.Attachment = attachment;
}
public void ResetAttachment()
{
Skeleton skeleton = _skeletonAnimation.Skeleton;
Slot slot = skeleton.FindSlot(slotName);
if (_originalAttachment != null)
{
slot.Attachment = _originalAttachment;
}
else
{
Log.Warn("Original attachment was not stored properly.");
}
}