• Unity
  • Problem upgrading to 3.7

I just upgraded Spine from 3.6 to 3.7 and found that all my units are not rendering.

They all use RenderSeparator to separate character shadow and the character itself.
If I enable the main MechRenderer, it will show but of course with incorrect render order.

Below is the components setup that was working in 3.6 and not working after upgrade.

I was thinking if it is caused by using the old SkeletonAnimation class instead of SeletonMecaim class.
But than I have a few questions about changing the code to use SeletonMecaim.

  1. the new create instance method now accept a T and I am not sure if I am doing it right.
mSpineSkeleton = SkeletonAnimation.NewSkeletonAnimationGameObject(dataAsset);  // 3.6
mSpineSkeleton =  SkeletonMecanim.NewSpineGameObject<SkeletonMecanim>(dataAsset); // like this?
  1. the SkeletonAnimation has a AnimationState member that I can get and use it to control animations. e.g. SetAniamtion(), etc. Now it is gone. I don't know what to do about it.
mAnimState = mSpineSkeleton.AnimationState; // 3.6

I searched the code and found this from the runtime:

var animationStateComponent = (animator.GetComponent(typeof(IAnimationStateComponent))) as IAnimationStateComponent;
         state = animationStateComponent.AnimationState;

I tried the following but with null error.

var animationStateComponent = (mSpineSkeleton.GetComponent(typeof(IAnimationStateComponent))) as IAnimationStateComponent;
            mAnimState = animationStateComponent.AnimationState; // animationStateComponent is null

Also, is it normal to not seeing the character even in Editor (non-playing) state? I tested the separator renderer by hand and with separator renderers turned on and default renderer turned off, it doesn't show anything. Was it working before the upgrade? (3.6)

Related Discussions
...

Thanks for the feedback.

No, SkeletonMecanim is not a replacement for SkeletonAnimation. It's just a renamed version of SkeletonAnimator.
If you were using SkeletonAnimation in 3.6, it should still be SkeletonAnimation in 3.7
(one reason why we switched the name is because SkeletonAnimator and SkeletonAnimation are too similar, both to human eyes and to IDE autocomplete)
Anyway, you should not use SkeletonMecanim.

What version of Unity are you using? I'll try to get a simple project with this setup and try upgrading to 3.7 and see if it breaks. But if I can't get it to break similarly and find out what went wrong, I may need more details. Stay tuned in the meantime.


I copied your component setup in 3.6, then upgraded the runtime to 3.7. It didn't seem to break. It was rendering correctly as expected.
I'm not quite sure what might have gone wrong.
But make sure you enter and exit play mode. (also check play mode if the behavior is correct).
Somtimes, SkeletonRenderSeparator does not update in edit mode automatically, especially during assembly reloads.

Both editor and play mode is not rendering.

I guess the issue maybe related to how I compose the spine game object by code which no longer work in 3.7.
I need to dynamically create the game object and add the components to make things more flexible and dynamic.

Here is part of the code how I add the Separator Renderer:


// SlotBlendModes
{
    var sbm = mSpineSkeleton.gameObject.AddComponent<SlotBlendModes>();
    sbm.multiplyMaterialSource = multiplyMaterialSource;
    sbm.screenMaterialSource = screenMaterialSource;
}

#region [ ========== SkeletonRenderSeparator ========== ]
{
    var srs = mSpineSkeleton.PrepareRenderSeparator();
    if (srs != null)
    {
        if (mSpineSkeleton.separatorSlots.Count == 1)
        {
            // shadow + unit
            srs.CreateSkeletonPartRenderer("shadow", -999);
            var spr = srs.CreateSkeletonPartRenderer("unit");
            mUnitRenderer = spr.GetComponent<Renderer>();
        }
        else if (mSpineSkeleton.separatorSlots.Count == 2)
        {
            // shadow + unit + effect
            srs.CreateSkeletonPartRenderer("shadow", -999);
            var spr = srs.CreateSkeletonPartRenderer("unit");
            mUnitRenderer = spr.GetComponent<Renderer>();
            srs.CreateSkeletonPartRenderer("effect", 999);
        }

    var mainRenderer = mSpineSkeleton.GetComponent<MeshRenderer>();
    mainRenderer.enabled = false;

    srs.enabled = true;
}
else
{
    Debug.LogWarningFormat(this, "Unit-{0} does not have layers separated.", unitID);
}
}
#endregion [ ========== SkeletonRenderSeparator (End) ========== ]

mSpineSkeleton.Initialize(false);


Here is the two extension function I used to the code above.


public static SkeletonRenderSeparator PrepareRenderSeparator(this SkeletonAnimation sa)
{
    var slots = sa.Skeleton.Data.Slots;

var detectedSeparators = new List<Spine.SlotData>();
foreach (var slot in slots)
{
    if (slot.Name.StartsWith("==="))    // all separator slot start with '==='
    {
        detectedSeparators.Add(slot);
    }
}

if (detectedSeparators.Count <= 0)
    return null;

var srs = sa.gameObject.AddComponent<SkeletonRenderSeparator>();
srs.SkeletonRenderer = sa;

sa.separatorSlots.Clear();
sa.separatorSlotNames = new string[detectedSeparators.Count];
int i = 0;
foreach (var slot in detectedSeparators)
{
    sa.separatorSlotNames[i] = slot.Name;
    sa.separatorSlots.Add(sa.skeleton.FindSlot(slot.Name));
    i++;
}
return srs;
}

public static SkeletonPartsRenderer CreateSkeletonPartRenderer(
                                this SkeletonRenderSeparator srs,
                                string name, int sortingOrder = 0)
{
    var go = new GameObject(name, typeof(MeshFilter), typeof(MeshRenderer));
    var spr = go.AddComponent<SkeletonPartsRenderer>();

go.transform.SetParent(srs.transform, false);


// Mesh 
{
    var meshFilter0 = srs.GetComponent<MeshFilter>();
    var meshFilter1 = go.GetComponent<MeshFilter>();
    meshFilter1.mesh = meshFilter0.mesh;
}

// Material
{
    var mr0 = srs.GetComponent<MeshRenderer>();
    var mr1 = go.GetComponent<MeshRenderer>();
    mr1.material = mr0.material;
}

spr.SetSortingOrder(sortingOrder);

srs.partsRenderers.Add(spr);

return spr;
}


Note that I changed the separatorSlotNames back to public to have the code compile because it is private in 3.7. But I guess some other changes in 3.7 make the code above not working anymore.

Thanks for the details, I'll take a look at these in a little bit.
Some of these extensions may be unnecessary in 3.7. The rest may be a good addition into the code if they don't do anything unusual.


Is this method meant to run in the editor or only at runtime?


I'm applying some changes and fixes to the runtime to make this workflow better. You will need to update your unitypackage. Stay tuned for the updated version.


  1. SlotBlendModes are no longer necessary in this case in 3.7.
    If your skeleton always needs it (eg, the shadow will always need multiply), go to your Skeleton's SkeletonDataAsset inspector, then unfold the "Skeleton Data Modifiers" inspector field right below where you have "Skeleton JSON" and "Scale".
    Then in your Project panel, search for the "Default BlendModeMaterials" asset and drag it to that field.


This will cause all attachments in screen and multiply slots to be loaded with the correct material when the skeleton is loaded.

  1. I've just updated the unitypackage.
    Spine Unity Download

Your new code should look something like this now:

skeletonAnimation.Initialize(false);
#region [ ========== SkeletonRenderSeparator ========== ]
{
   var srs = skeletonAnimation.PrepareRenderSeparator();
   bool foundSeparators = skeletonAnimation.separatorSlots.Count > 0;

   if (foundSeparators) {
      if (skeletonAnimation.separatorSlots.Count == 1) {
         // shadow + unit
         srs.CreateSkeletonPartRenderer("shadow", -999);
         var spr = srs.CreateSkeletonPartRenderer("unit");
         mUnitRenderer = spr.GetComponent<Renderer>();
      } else if (skeletonAnimation.separatorSlots.Count == 2) {
         // shadow + unit + effect
         srs.CreateSkeletonPartRenderer("shadow", -999);
         var spr = srs.CreateSkeletonPartRenderer("unit");
         mUnitRenderer = spr.GetComponent<Renderer>();
         srs.CreateSkeletonPartRenderer("effect", 999);
      }
   } else {
      Debug.LogWarningFormat(this, "Unit-{0} does not have layers separated.", unitID);
   }
}
#endregion [ ========== SkeletonRenderSeparator (End) ========== ]

And your extensions will look like this:

public static SkeletonRenderSeparator PrepareRenderSeparator (this SkeletonAnimation sa) {
   sa.Initialize(false);
   const string SeparatorStartsWith = "===";
   var srs = SkeletonRenderSeparator.AddToSkeletonRenderer(sa, addMinimumPartsRenderers: false);
   sa.FindAndApplySeparatorSlots(SeparatorStartsWith, clearExistingSeparators: true, updateStringArray: true);
   return srs;
}

public static SkeletonPartsRenderer CreateSkeletonPartRenderer (this SkeletonRenderSeparator srs, string name, int sortingOrder = 0) {
   var spr = srs.AddPartsRenderer(name: name);
   spr.MeshRenderer.sortingOrder = sortingOrder;
   return spr;
}

Thank you!
The characters are all visible in play mode now.
In the Scene panel it still not showing the character but I can see them in Game panel so it isn't a big issue.

I found another problem. One of my character doesn't have all the parts rendered.
Two parts of her hair is not rendering. I notice that those parts are all using "path". (Already re-exported from latest Spine 3.7 beta version)


Btw, you mentioned that SlotBlendMode is no longer needed. When blending like multiply is needed, can config the SkeletonDataAsset. Can this process be done automatically? e.g. detect if multiply or other blend mode used in skeleton and auto assign the data modifier?

My concern is, it is now requiring more actions to perform. In the original workflow, I only need to export the character to the project folder. The code and the SlotBlendMode will take care of the everything. I don't need to do anything to make it work which is very smooth in comparison.

I'm not sure why those parts aren't showing up. If you could send this exported project to us, we could try to debug it. unity@esotericsoftware.com

As for SlotBlendMode not needed. Yes, you can automate adding the Default BlendModeMaterials to any SkeletonDataAsset in your project.
That field is just a public List<SkeletonDataModifierAsset>. The "Default BlendModeMaterials" asset is an instance of a BlendModeMaterialsAsset which is a type of SkeletonDataModifierAsset.


I've received your repro file. Thanks.

I see the attachment rendered but it looks like there might be something wrong with PathConstraint. The bones on it are at the wrong positions. We'll check it out.


I'm having trouble finding the source of the problem in our PathConstraint code.
I've showed the others in the team though. No luck finding it yet. But this is the first time we've seen this happen.

4 dias depois

Any updates on this?

Have you try to delete irrelevant bones leaving only the affected parts to test? That would help make tracing code much simpler.
Can also run both new/old functions in parallel at the same time and compare result systematically from code to test which function is having different output.

5 dias depois

The issue has been resolved and commited to 3.7-beta branch.

I'll be uploading the updated unitypackage in a bit. Thanks so much for the hard work, Harald and Nate!

And thanks again for reporting this problem, fantasyz.

Looking good!

Tried the new runtime, the previous issue is fixed.
Thanks

However, for this particular character, I found that the tint black is not work correctly. Other units are doing fine without rainbow color. They share the same code for loading. My initial guess is that there are setting or data differences.

According to http://esotericsoftware.com/spine-unity-tintblack :

In the Unity Editor, the changes may not all be applied together so you may need to enter and exit play mode to force a new mesh to be generated according to the settings.

When the setup is incorrect, instead of the color you want, the mesh may look rainbow-colored, as in the case where Tint Black was not enabled on the component. In this case, make sure the setup is correct and you try to enter and exit play mode to refresh the meshes.

I double checked the material and the Tint Black (!) option under "advance".
The config should be correct. Enter/Exit play mode doesn't fix the rainbow issue.
(You can see the Tint Black checked before I press the play button the 1st time. )
You can test it with the existing grayscale export.

This stuff just gets weirder and weirder. I'm sure I can handle this one this time though. XD


Looks like some helpful errors were logged. And it's another case where your skeleton exhibits it but ours don't.
I have some good leads of the source of the error though.


The latest update should fix it.
Spine Unity Download

Dated today (2018 Dec 18)