This is a thorough set of questions. Let me work through each one based on my knowledge of spine-unity 4.3.
1. Separator Slots / Enable Separation — Off
Correct to leave Off. Separation is only needed when you need to interleave other Unity renderers between parts of the skeleton. No separator slots defined means no benefit, and leaving it Off avoids the overhead of generating multiple sub-meshes for separation purposes.
2. Use Clipping — Off
Safe to leave Off if no clipping attachments are used. The downside if a clipping attachment is later added is exactly what you described: it will be silently ignored and the clipping region will not be applied. There is no crash or corruption, just missing visual effect. It is worth making it a pipeline rule to turn it On if clipping attachments are introduced.
3. PMA Vertex Colors — Off with PMA textures and CanvasGroup Compatible
Yes, this is the correct and intended combination. The breakdown is:
- PMA texture (
Straight Alpha Texture = 0 on the material): the texture data itself is premultiplied at pack time.
- PMA Vertex Colors = Off (straight vertex colors): vertex alpha is kept in the 0–1 straight range so the CanvasGroup alpha value can be multiplied into it by the shader correctly.
- CanvasGroup Compatible shader: reads the straight vertex alpha and applies the CanvasGroup alpha through it.
What you lose is correct: only single-pass additive blend mode slots cannot be batched in the same draw call as normal slots, because additive blending requires a separate material. With PMA Vertex Colors Off you also lose the ability to use the PMA-specific additive blending trick. For a UI-only project without heavy use of additive slots this is an acceptable tradeoff.
4. CanvasGroup Compatible — On for skeletons inside fading dialogs
Correct. Only skeletons that actually live under a CanvasGroup that changes alpha at runtime need this. If some skeletons are never under a fading CanvasGroup you can leave it Off on those to save the shader cost, but having it On universally is not harmful.
5. Sharing one material across 70 skeletons
For SkeletonGraphic in Multiple CanvasRenderers mode, the actual texture is sourced from the atlas pages referenced by the skeleton data, not from the material's texture slot. The shared material drives shader keywords and properties (CanvasGroup Compatible, Straight Alpha Texture, etc.). Sharing it is fine and is the standard approach. The batching implication is the usual Unity UI rule: draw calls are broken any time the texture changes between renderers in the same canvas, regardless of material sharing. With 70 different atlas sets you will get per-atlas draw calls, but that is inherent to having separate atlases and not caused by material sharing.
6. Maskable — On, and child CanvasRenderers under RectMask2D
Maskable on the SkeletonGraphic component is required. In Multiple CanvasRenderers mode, spine-unity generates child CanvasRenderer objects and it propagates the maskable state to them. However, dynamically created child renderers may not always pick up RectMask2D culling correctly in all Unity versions if they are created after the mask is already on the hierarchy. It is worth calling skeletonGraphic.UpdateMeshToInvisible() or simply toggling the component if you ever see masking not applying after a late instantiation. There are no deep structural issues with RectMask2D and multiple renderers as long as all child renderers are marked maskable, which the runtime handles.
7. Raycast Target — hit area with Multiple CanvasRenderers
Your assumption is correct. The raycast hit area is the RectTransform rect of the SkeletonGraphic component, not the rendered mesh bounds. Unity's Graphic.Raycast uses the rect, not per-pixel or mesh geometry. If you need tighter hit testing you would need a custom ICanvasRaycastFilter implementation.
8. Update When Invisible — recommended value for UI
For UI skeletons that are scrolled off-screen or hidden behind a mask, Nothing is the most aggressive saving but risks the skeleton being in the wrong pose when it comes back into view. The recommended middle ground for UI is:
- Use
Only Animation State (or the equivalent Only Animation Status wording in your version) if you need queued animations and events to keep firing off-screen, but want to skip the expensive mesh rebuild.
- Use
Everything Except Mesh if physics constraints need to keep stepping (rare in UI).
Regarding RectMask2D culling: RectMask2D does call IClippable.Cull on child graphics, and SkeletonGraphic implements that interface, so culling does fire per-RectMask2D, not only at the Canvas level. This means Update When Invisible will engage when the skeleton is fully outside the mask rect, which is the behavior you want for off-screen scroll lists.
9. Threaded Mesh Generation and Threaded Animation for mobile UI
For 1–5 visible skeletons on mobile, the threading overhead (job scheduling, synchronization) will likely exceed the benefit. Threading pays off when you have many skeletons updating simultaneously. The recommendation for your case is to leave both at Off (or Use Global Setting resolving to Off) and revisit only if profiling shows main-thread mesh generation is a bottleneck. Known caveats if you do enable it:
GetAnimationState() and any direct skeleton/bone manipulation from MonoBehaviour.Update must be moved to after the skeleton has been updated (i.e., use the UpdateLocal, UpdateWorld, or UpdateComplete callbacks rather than raw Update ordering) to avoid race conditions.
- Multiple CanvasRenderers mode has additional synchronization points; there are no fundamental blockers but test on device before shipping.
- CanvasGroup Compatible itself does not interact with the threading path.
10. Layout Scale Mode — Fit In Parent runtime cost
Fit In Parent does recalculate the scale each layout pass to fit the skeleton's bounding box within the RectTransform. [incorrect parts removed]
11. SkeletonAnimation Update Timing — In Update, Unscaled Time Off
In Update with Unscaled Time Off means animations advance with Time.deltaTime (scaled time). If your UI tweens use Time.unscaledDeltaTime (e.g., DOTween with SetUpdate(true) or Unity's unscaled CanvasGroup fades), the Spine animations will pause when Time.timeScale is 0 (e.g., during a pause menu). If that is intentional, the setting is correct. If you want Spine animations to keep playing during a paused game, set Unscaled Time to On.
12. Migration note — Use Clipping and PMA Vertex Colors reset by Upgrade All
[incorrect text removed] Thanks for reporting, we will have a look at it!