Jamez0r

1) My game is a 2D top-down sort of SNES Zelda style.

The ground-floor (grass/dirt/etc) is made of Unity Sprites, all on one Sprite Atlas and rendered together.

The layer that has all of the characters, trees, rocks, and all other things that you can go "behind" and "in front of" (using y-order sorting from top to bottom) is currently ALL Spine animations. Even things that aren't animated (that I would usually use a Unity Sprite for) like rocks, are simply a SkeletonAnimation with just a root bone and the image of the rock. I'm doing this to avoid a material/shader/texture swap every time I would have been going from rendering a Unity Sprite to rendering a SkeletonAnimation and vice-versa. So I guess the real question #1 is - does this make sense to do? Or is there some way that I could render Sprites and SkeletonAnimations back-and-forth a bunch of times, who share the same spine-generated TextureAtlas, and while sharing the same Material (which would need to be a URP-lit shader with normal map... just to make things more complicated haha)? If what I'm asking doesn't make sense let me know and I'll explain it better :D

So assuming that I do need to make a SkeletonAnimation for each of these things like rocks, etc, my question is this:
If I make a prefab that has a SkeletonAnimation in the parent gameobject, the thumbnail of the prefab is a preview of the SkeletonAnimation. However, if the SkeletonAnimation is in a child gameobject in the prefab, the prefab thumbnail is just the default blue-box. Is there a way to force the prefab to show a specific thing (the SkeletonAnimation preview) as the thumbnail? This would reaaaaally save time for us since we are talking about having a prefab for every single rock/fence/plant/etc in the game, haha. And each of the prefabs are essentially a SortingGroup on the parent gameobject, and then the SkeletonAnimation gameobject as a child. I tried googling for a while and couldn't find any information on setting the thumbnail image at all :grinfake

2) I'm using URP with the 2D-renderer, with lights and normal maps. The lights are rendered "per Sorting Layer", meaning having a lot of Sorting Layers will slow things down significantly. We had been using like 25 Sorting Layers to keep things organized, and then found out about this afterward haha. So I'm now making an Editor Window that will give me a lot of organization control by setting the Order-In-Layer instead of using a bunch of separate Sorting Layers. So now that you know my life's story, lets get down to the question: When I select a gameobject with a SkeletonAnimation, and click a button in my custom Editor Window to change the "sortingOrder" of the Mesh Renderer of that SkeletonAnimation, it doesn't update the value in the Inspector. I have to "re-select" the gameobject with the SkeletonAnimation, and then it will update.

I had a similar issue with the SortingGroup component, and was able to get it to update instantly in the Inspector by calling this after I set it to the new "sortingOrder":
EditorUtility.SetDirty(sortingGroup);
I tried that with the skeletonAnimation, but it still doesn't update until you re-select it. Is there a function that I could call that would force it to refresh that value in the Inspector?

---

Looking into this for question 1 potentially: https://docs.unity3d.com/ScriptReference/AssetPreview.html
Avatar
Jamez0r
  • Postovi: 356

Harald

Jamez0r je napisao/la:Even things that aren't animated (that I would usually use a Unity Sprite for) like rocks, are simply a SkeletonAnimation with just a root bone and the image of the rock.
When things are static, it is sufficient to use the SkeletonRenderer component instead of SkeletonAnimation (it's a base class but not abstract), this saves the AnimationState overhead. This is also shown in the SpineGauge example scene, on the health bar GameObject Spine GameObject (gauge). You can also disable the SkeletonRenderer component to prevent any updates after Awake, as you don't want the mesh to be updated later at all.
Jamez0r je napisao/la:And each of the prefabs are essentially a SortingGroup on the parent gameobject, and then the SkeletonAnimation gameobject as a child.
Please note that you can attach the SortingGroup component directly at the SkeletonAnimation or MeshRenderer, it does not need to be a parent GameObject. Don't know if you have other reasons why you need the parent though.

I will have a look at how the thumbnail image is created for child GameObjects in other circumstances (normal meshes), however it might be out of our control.
I have to "re-select" the gameobject with the SkeletonAnimation, and then it will update.
You can ping a GameObject if you want to perform code as if it were just selected (without changing selection):
https://docs.unity3d.com/ScriptReference/EditorGUIUtility.PingObject.html
Avatar
Harald

Harri
  • Postovi: 3914

Jamez0r

When things are static, it is sufficient to use the SkeletonRenderer component instead of SkeletonAnimation (it's a base class but not abstract), this saves the AnimationState overhead. This is also shown in the SpineGauge example scene, on the health bar GameObject Spine GameObject (gauge). You can also disable the SkeletonRenderer component to prevent any updates after Awake, as you don't want the mesh to be updated later at all.
Ooh, thats nice. I'll give the SkeletonRenderer a try!
Please note that you can attach the SortingGroup component directly at the SkeletonAnimation or MeshRenderer, it does not need to be a parent GameObject. Don't know if you have other reasons why you need the parent though.
My game is a top down SNES Legend of Zelda viewing angle -> the default y-axis sort-point for a spine mesh is its center, so I have to put the Spine gameobject as a child of another gameobject with a SortingGroup and then position them as-needed so that the sort-point (from the SortingGroup gameobject) is at the location where the spine animation is touching the ground. The configuration works great, but not being able to see the thumbnail image sucks when you have like 20+ plants/etc and are trying to find the correct one :confused:
I will have a look at how the thumbnail image is created for child GameObjects in other circumstances (normal meshes), however it might be out of our control.
Thanks! I'm going to keep looking too and see if I can figure it out - was hoping it would have been a quick thing (like drag and drop or something haha), but there seems to be very little info.
You can ping a GameObject if you want to perform code as if it were just selected (without changing selection):
https://docs.unity3d.com/ScriptReference/EditorGUIUtility.PingObject.html
Worked perfectly. Thanks! :grinteeth:

---

Well I just spent an hour googling and couldn't find any way to set the Prefab's thumbnail. Maybe instead of setting the thumbnail, I could instead place the SkeletonAnimation on the parent gameObject of the prefab, and then on Awake() do some re-parenting? :think:

---

Whoops, just realized that I was incorrectly thinking that having the SkeletonAnimation in the parent of the prefab would set the thumbnail, but that doesn't seem to work. Looks like the Mesh doesn't get saved or something :think: I guess thats what you were talking about haha

---

Sorry for the reply-spam :p

I'm new to this area of Unity (editor/asset stuff) so bear with me if this stuff is already obvious. Seems like the goal with the thumbnail would be to get the same Preview as is shown for the SkeletonData asset, but to have it shown on a prefab that contains the SkeletonAnimation.

I was able to get/display the preview image in an Editor Window using this:
texture = AssetPreview.GetAssetPreview(my_skeletonData.asset);
or possibly more specifically for the thumbnail (EDIT: this returns the little grey/red Spine icon, not the Skeleton's preview, so use GetAssetPreview):
texture = AssetPreview.GetMiniThumbnail(my_skeletonData.asset);
This post seems to be asking a similar question, but I wasn't able to figure out too much from it: https://answers.unity.com/questions/1276359/how-can-i-create-a-custom-assetpreview-for-a-prefa.html

Going to keep looking around - even if its sort of hacky with an Editor Window or something.

Looking at this: https://docs.unity3d.com/ScriptReference/EditorApplication.ProjectWindowItemCallback.html

Here is a post using that callback where they are drawing on top of the default icon: https://forum.unity.com/threads/editor-changing-an-items-icon-in-the-project-window.272061/

Gonna try that out and see if I can get anywhere :)

---

Woohoo! Got a working configuration! :grinteeth:

These are all prefabs with SkeletonRenderers in them (can be anywhere within the prefab with this setup).



It's definitely sort of hacky the way I did it, I added this code to an Editor Window that I made. Basically it hooks into the EditorApplication.ProjectWindowItemCallback, checks if the name of the item ends in .prefab, then searches that prefab asset for a SkeletonRenderer. If it finds it, it gets the texture with Texture2D prefabIcon = AssetPreview.GetAssetPreview(skeletonRenderer.SkeletonDataAsset); and then it draws the icon texture on top of the "default prefab blue square" icon.

Here is the relevant code in case anyone else wants to give it a try. Note that this is calling Texture2D prefabIcon = AssetPreview.GetAssetPreview(skeletonRenderer.SkeletonDataAsset); every frame for each of the icons, which may not be the most efficient (I'm not sure if its making a copy of it or not). I didn't notice any lag/slowdown in the editor when enabling this. Also, the OnAfterAssemblyReload() doesn't seem to be getting called, so I have to press the "Enable" button again after a recompile. And just to clarify something I mentioned earlier - AssetPreview.GetMiniThumbnail() returns the tiny "spine" icon (little gray icon with red spine), and not the actual Skeleton preview.
//Prefab Icons
public bool prefabIconsEnabled = true;


private void Awake() {
AssemblyReloadEvents.afterAssemblyReload += OnAfterAssemblyReload;
EnablePrefabIcons();
}

private void OnGUI() {
//draw whatever other stuff you want in the editor window...
DrawPrefabIconOverride();
}

public void DrawPrefabIconOverride() {
if (GUILayout.Button("Enable")) { EnablePrefabIcons(); }
if (GUILayout.Button("Disable")) { DisableIcons(); }
}

public void OnAfterAssemblyReload() {
Debug.Log("assembly reloaded");
if (prefabIconsEnabled == true) { EnablePrefabIcons(); }
}

public void EnablePrefabIcons() {
prefabIconsEnabled = true;
EditorApplication.projectWindowItemOnGUI -= WindowItemOnGuiCallback();
EditorApplication.projectWindowItemOnGUI += WindowItemOnGuiCallback();
}

public void DisableIcons() {
prefabIconsEnabled = false;
EditorApplication.projectWindowItemOnGUI -= WindowItemOnGuiCallback();
}

public EditorApplication.ProjectWindowItemCallback WindowItemOnGuiCallback() {
EditorApplication.ProjectWindowItemCallback myCallback = new EditorApplication.ProjectWindowItemCallback(IconGUI);
return myCallback;
}

public void IconGUI(string s, Rect r) {

string fileName = AssetDatabase.GUIDToAssetPath(s);

if (fileName.Contains(".prefab")) {
if(r.height > 30) { //Prevents the icon from being drawn if the "icon size slider" (bottom right corner) is all the way to the left
GameObject prefabObject = AssetDatabase.LoadAssetAtPath<GameObject>(fileName);
SkeletonRenderer skeletonRenderer = prefabObject.GetComponentInChildren<SkeletonRenderer>(true);
if (skeletonRenderer) {
Texture2D prefabIcon = AssetPreview.GetMiniThumbnail(skeletonRenderer.SkeletonDataAsset);
Rect smallerRect = new Rect(r);
smallerRect.height = smallerRect.height * 0.85f;
GUI.DrawTexture(smallerRect, prefabIcon);
}
}
}
}
Avatar
Jamez0r
  • Postovi: 356

Harald

Thanks so much for your hard work Jamez0r! I just noticed that they were not displayed at the parent as well, my fault. As this should definitely be supported, I have just added an issue ticket here:
https://github.com/EsotericSoftware/spine-runtimes/issues/1722
Avatar
Harald

Harri
  • Postovi: 3914

vhristov

I am resurrecting this thread as I just pushed an initial draft PR in github ( https://github.com/EsotericSoftware/spine-runtimes/pull/1931 ) for supporting this feature. It's not yet perfect (neither completed yet :) ) but I'd like to ask for some help from the unity and spine masters in this forum on how to proceed further in order to complete it (or to completely scratch the idea of it is total crap)
vhristov
  • Postovi: 36

Harald

Thanks very much for your efforts! OnPostprocessPrefab is indeed a great addition (added rather recently, in Unity 2020.2) which we might also consider using for the prefab override issue ticket.

We are currently working on this prefab override ticket and have one unfortunately non-perfect solution ready, we will consider using OnPostProcessPrefab on newer Unity versions.

Regarding your questions:
vhristov je napisao/la:Verify this mesh is really not included in build (any idea how to do that?)
In general this can be done via component's or object's hideFlags, e.g. meshFilter.hideFlags = HideFlags.HideAndDontSave or DontSaveInEditor / DontSaveInBuild. Some special rules apply here as we recently found out, as Mesh.hideFlags is ignored, but MeshFilter.hideFlags is respected. This might however again break the preview (untested though) or the prefab always listing overrides.
vhristov je napisao/la:Split mesh and multiple atlas support (what is this actually?)
Could you please describe what you mean by split mesh, where you have this term from or where you see problems? Do you mean the SkeletonRenderSeparator and parts renderers? Or multiple submeshes in general?
vhristov je napisao/la:Skeleton Graphics support (is it even possible to have prefab preview for canvas?)
Admittedly I don't know how the prefab system behaves here: it would require a Canvas parent, which could perhaps be saved with special hide flags in order to not include it in the build or upon saving. Again I'm not sure about the effect on the above prefab override issue.
vhristov je napisao/la:Check unity compatibility (and possibly hide everything behind a define)
This is easily resolved by preprocessor #if branches, yes.
#if UNITY_2020_2_OR_NEWER
#define HAS_ON_POSTPROCESS_PREFAB
#endif

#if HAS_ON_POSTPROCESS_PREFAB
...
#endif
In general: thanks again, any work or shared insights in this area is very much appreciated! We keep you updated of course in case we find out anything relevant as well.
Avatar
Harald

Harri
  • Postovi: 3914

vhristov

Harald je napisao/la:meshFilter.hideFlags = HideFlags.HideAndDontSave or DontSaveInEditor / DontSaveInBuild. Some special rules apply here as we recently found out, as Mesh.hideFlags is ignored, but MeshFilter.hideFlags is respected. This might however again break the preview (untested though) or the prefab always listing overrides.
Doing some more tests today it turns out I have broken the build. Having mesh.hideFlags = HideFlags.DontSaveInBuild turns out is throwing an error and preventing the build from happening if the mesh is referenced from another asset which shall be included. I have completely misunderstood the meaning of this flags... And I have no idea how I have tested with a successful build (I suspect I might have some dirty changes with HideFlags.None)...
Harald je napisao/la:We are currently working on this prefab override ticket and have one unfortunately non-perfect solution ready, we will consider using OnPostProcessPrefab on newer Unity verisons.
What is the plan for this? I just cannot see how the prefab post process might help here.
But based on how you handle this issue I guess two outcomes might happen:
1. Break my attempt to handle the preview (which is already broken as explained above)
2. Fix the thumbnail generation

Do you have any ETA when it will be done, so I can postpone my activities until it is done?
Harald je napisao/la:Could you please describe what you mean by split mesh, where you have this term from or where you see problems? Do you mean the SkeletonRenderSeparator and parts renderers? Or multiple submeshes in general?
I tried to make a new collective term for all the possible scenarios as I don't completely understand some of them :)
I have a local change that enables SkeletonRenderSeparator in the generation path, but as I understand it so far it uses mesh override and two (or more?) separate mesh renderers in children and not submeshes (which I still have no idea what this is). I haven't yet published this as there are some issues with it, which might be related to the mesh hide flags.
Harald je napisao/la:Admittedly I don't know how the prefab system behaves here: it would require a Canvas parent, which could perhaps be saved with special hide flags in order to not include it in the build or upon saving. Again I'm not sure about the effect on the above prefab override issue.
I am not sure either. I just observe that non of my canvas prefabs (read as either canvas itself or game object child of canvas) have any preview thumbnail generated by unity
Harald je napisao/la:#if UNITY_2020_2_OR_NEWER
Thanks.

P.S. and as a side note I just found out one new issue with my change - when doing a reinport on a prefab unity shows a warning that the prefab is inconsistent. I suspect it expect the result to be the same, but the new mesh generated every time messes with this logic.
vhristov
  • Postovi: 36

Harald

vhristov je napisao/la:And I have no idea how I have tested with a successful build (I suspect I might have some dirty changes with HideFlags.None)...
Such editor scripting changes can unfortunately be really cumbersome to test, as any affected previously serialized assets might already have state saved from a previous set of code-changes. So most of the time you need to re-create the prefab to test the current code's behaviour.
vhristov je napisao/la:What is the plan for this? I just cannot see how the prefab post process might help here.
It might be a better alternative with more control to clear or setup the Mesh or MeshFilter at one concise point and only for Prefab serialization. I'm not completely sure whether this single point of change really improves the situation (e.g. by avoiding triggering side-effects), but it could at least make the code more readable than having if (isPrefab) branches scattered across normal update code.
vhristov je napisao/la:But based on how you handle this issue I guess two outcomes might happen:
1. Break my attempt to handle the preview (which is already broken as explained above)
2. Fix the thumbnail generation
This might both happen, yes :).
vhristov je napisao/la:Do you have any ETA when it will be done, so I can postpone my activities until it is done?
If nothing gets in the way, it would perhaps be done next week. However we can never give guarantees for that, as such changes must not be rushed and questions and bugreports on the forum might create more or less workload.
vhristov je napisao/la:I tried to make a new collective term for all the possible scenarios as I don't completely understand some of them :)
I have a local change that enables SkeletonRenderSeparator in the generation path, but as I understand it so far it uses mesh override and two (or more?) separate mesh renderers in children and not submeshes (which I still have no idea what this is).
Yes, your observations are correct, SkeletonRenderSeparator uses separate MeshRenderers for each part. For an explanation of submeshes see here. Basically SkeletonRenderer will produce additional submeshes at a single MeshRenderer.mesh whenever the atlas texture page (an thus the material) changes, leading to additional draw calls.
vhristov je napisao/la:P.S. and as a side note I just found out one new issue with my change - when doing a reinport on a prefab unity shows a warning that the prefab is inconsistent. I suspect it expect the result to be the same, but the new mesh generated every time messes with this logic.
Thanks for the info. I remember getting such warning messages when class member vars of serialized objects were only included in the Editor (via #if UNITY_EDITOR preprocessor branches) and not in the build, but this is no longer reported in recent Unity versions. I wonder what conditions triggers such warnings currently.
Avatar
Harald

Harri
  • Postovi: 3914

vhristov

Harald je napisao/la:So most of the time you need to re-create the prefab to test the current code's behaviour.
At least I will try to be more careful next time I test this :)
Harald je napisao/la:It might be a better alternative with more control to clear or setup the Mesh or MeshFilter at one concise point and only for Prefab serialization. I'm not completely sure whether this single point of change really improves the situation (e.g. by avoiding triggering side-effects), but it could at least make the code more readable than having if (isPrefab) branches scattered across normal update code.
Ok. I got it, sounds reasonable. BTW be careful if you are using AssetDatabase methods inside the prefab postprocress callback, I managed to crash unity a few times while trying to modify the asset that was being post processed (before seeing the manual that it states I shall use "this.context")
Harald je napisao/la:If nothing gets in the way, it would perhaps be done next week.
Thanks, I will wait for it to happen and then continue with my struggles with the preview thumbnails.
Harald je napisao/la:However we can never give guarantees for that, as such changes must not be rushed and questions and bugreports on the forum might create more or less workload.
That is perfectly understandable. Your answer was more than I was hoping to get (I was thinking I will get "soon" vs "not-so-soon") :)
Even though I was wishing for prefab preview for a long time it was not until recently I got some free time and will to check on them. If I had to choose priorities I would place them in this order: Bugs > some other useful feature > prefab override & thumbnails. So a week or two or even more is more than acceptable.
Harald je napisao/la:Yes, your observations are correct, SkeletonRenderSeparator uses separate MeshRenderers for each part. For an explanation of submeshes see here. Basically SkeletonRenderer will produce additional submeshes at a single MeshRenderer.mesh whenever the atlas texture page (an thus the material) changes, leading to additional draw calls.
Oh I understand now. Thanks for explanation. I was under the wrong impression this is more of a spine feature not related with multiple atlases/textures in any way.
Harald je napisao/la:I remember getting such warning messages when class member vars of serialized objects were only included in the Editor (via #if UNITY_EDITOR preprocessor branches) and not in the build, but this is no longer reported in recent Unity versions. I wonder what conditions triggers such warnings currently.
In my case I am pretty confident it is the mesh update (having a new Mesh() every time sounds as an inconsistency to me), but I hit a deadend trying to figure what exactly can cause this warning and most of the results I found on unity forums were related to unity bugs.
vhristov
  • Postovi: 36

Harald

vhristov je napisao/la: BTW be careful if you are using AssetDatabase methods inside the prefab postprocress callback, I managed to crash unity a few times while trying to modify the asset that was being post processed (before seeing the manual that it states I shall use "this.context")
Thanks for the warning, will keep that in mind!
vhristov je napisao/la:At least I will try to be more careful next time I test this
I think no-one ever did this right the first time before running into such an error at least once :).

---

The two issue tickets have just been implemented:

  • Prefabs containing SkeletonRenderer, SkeletonAnimation and SkeletonMecanim now provide a proper Editor preview, including the preview thumbnail.
  • SkeletonRenderer (and subclassesSkeletonAnimation and SkeletonMecanim) now provide a property Advanced - Fix Prefab Override MeshFilter, which when enabled fixes the prefab always being marked as changed. It sets the MeshFilter's hide flags to DontSaveInEditor. Unfortunately this comes at the cost of references to the MeshFilter by other components being lost, therefore this parameter defaults to false to keep the safe existing behaviour.

The prefab override bug was resolved via a bool parameter which has to be enabled, as otherwise existing references to the MeshFilter would be lost. Fortunately the preview shows a proper thumbnail regardless of the parameter being enabled or disabled, so your hint of using OnPostProcessPrefab turned out to be very helpful indeed. The RequireComponent(typeof(MeshFilter)) part has been removed from SkeletonRenderer and replaced by generating the MeshFilter manually, which avoids some annoying warnings.

A new 4.0 unitypackage is available for download here as usual:
Spine Unity Download

Thanks again for reporting, hope it works for your use cases too! Please let us know if you encounter any problems.
Avatar
Harald

Harri
  • Postovi: 3914

vhristov

Thanks Harald!
It is nice and sweet, unfortunately there is still one case where the player build is failing :(

I have sent you a small reproduction project by e-mail, but here are the details.

When there is a direct reference to the prefab asset the build fails with the following error:
An asset is marked with HideFlags.DontSave but is included in the build:
Asset: 'Assets/Prefabs/SpineBoyPrefab.prefab'
Asset name: Skeleton Prefab Mesh "SpineBoyPrefab"
(You are probably referencing internal Unity data in your build.)
UnityEngine.GUIUtility:ProcessEvent (int,intptr,bool&)
It seems like that the reference to the Mesh from the MeshFilter saved in the prefab is still trying to get in the build...

I tried 2 things in the prefab post process:
1. Setting the mesh itself's hide flags to none:
mesh.hideFlags = HideFlags.None;
Unfortunately this will have the side effect of including every spine prefab's mesh inside the build, which could potentially have a noticeable impact on game size in some cases.

2. After saving the mesh asset clear the shared mesh with:
meshFilter.sharedMesh = null
This way the prefab thumbnail is not presented again and I don't see the point in saving the mesh to the asset at all.

It doesn't matter if fixPrefabOverrideViaMeshFilter is true or false. Which confuses me further as the mesh filter is definitely not in the prefab when is being edited, but is in the prefab when is being built...

The code I used for reproduction:
using UnityEngine;
using Spine;
using Spine.Unity;

public class DynamicSpinePrefabInstance : MonoBehaviour
{
public GameObject prefab;

private SkeletonAnimation instance;
void Start()
{
var go = GameObject.Instantiate(prefab, transform.position, transform.rotation, transform);
instance = go.GetComponent<SkeletonAnimation>();
instance.AnimationState.SetAnimation(0, "idle", true);
}
}
With the above script attached to game object, I just set a reference to the prefab of spine-boy that I created.
vhristov
  • Postovi: 36

Harald

Oh dear, thanks for reporting and sending the reproduction package! While I did tests with references to the MeshFilter, the test didn't cover references to the prefab (which is somewhat stupid that this is causing problems). I will have a look right away!

---

An updated unitypackage has just been released fixing the build error:
Spine Unity Download: Download
For now it sets all prefab meshes to DontSaveInEditor which prevents the build from being broken. I will have a look at how the mesh can be best cleared before building the player, it might be OnPreprocessBuild.
Avatar
Harald

Harri
  • Postovi: 3914

vhristov

Harald je napisao/la: While I did tests with references to the MeshFilter,
I was sure you tested it! That's how I managed to narrow it down to what is actually failing. With my previous attempts to do the thumbnails, it never popped up in my head it could be related to the prefab references.
Harald je napisao/la:I will have a look at how the mesh can be best cleared before building the player, it might be OnPreprocessBuild.
I managed to get it working on the reproduction project I sent you earlier, but it still doesn't work on my project...
public int callbackOrder {
get { return -1000; }
}
public void OnPreprocessBuild(BuildReport report)
{
var assets = AssetDatabase.FindAssets("t:Prefab");
foreach(var asset in assets) {
CleanPrefab(AssetDatabase.GUIDToAssetPath(asset));
}
AssetDatabase.SaveAssets();
}
private void CleanPrefab(string path)
{
var g = AssetDatabase.LoadAssetAtPath<GameObject>(path);
var skeletonRenderers = g.GetComponentsInChildren<SkeletonRenderer>(true);
foreach (SkeletonRenderer renderer in skeletonRenderers) {
var meshFilter = renderer.GetComponent<MeshFilter>();
if (meshFilter != null) {
meshFilter.sharedMesh = null;
}
}
}
(I haven't taken the hide flag change, so I haven't reverted it)
The following is happening:
1. The build is successful
2. Prefab icons are not broken after the build. This I cannot understand at all why is happening. Isn't it supposed to disappear after reseting the mesh?
3. There is at least one other corner case or the code above is not working properly...
Any idea what to look for?


---
Update:
I believe I found the issue(s):
1. There was a race condition between prefab postprocess and build preprocess, where the prefab post process could get triggered during the build and attach the mesh back to the skeleton -> and then later cause the build error
2. I have been playing back and forth with fixPrefabOverrideViaMeshFilter and if it the meshFilter was with a HideFlag.DontSaveInEditor it seems it didn't preserve the modification of the meshFilter.sharedMesh = null.

I'll do some more testing (and clean up my test code a bit) and will send a pull request later today if it proves to work stable.

Update2:
Pull request is here: https://github.com/EsotericSoftware/spine-runtimes/pull/1937
vhristov
  • Postovi: 36

Harald

You're the best! Thanks very much for implementing the solution already! :nerd:

I have tested it and only noticed a minor problem with your pull request so far:
When a prefab created with fixPrefabOverrideViaMeshFilter == false is reimported, it issues a warning:
Importer(PrefabImporter) generated inconsistent result for asset(guid:..)
This can be fixed by setting mesh.hideFlags = HideFlags.None; at the end of SetupSpinePrefabMesh. I will merge your pull request and add this minor bugfix and another one reported reported by another user (a missing null check that was reported by foriero via email).

Thanks again for your hard work! 8)

---

The two bugfixes have just been committed and a new 4.0 unitypackage has been released:
Spine Unity Download
As always, please let us know if you notice any issues after the latest update.
Avatar
Harald

Harri
  • Postovi: 3914

vhristov

Thank you very much Harald!
Harald je napisao/la:When a prefab created with fixPrefabOverrideViaMeshFilter == false is reimported, it issues a warning:
Ooops, I missed that.. anyway glad you catched it.
vhristov
  • Postovi: 36

Harald

Strangely I also encountered this warning again today at the current code status after editing code and then reverting the change :rolleyes: . I will check where this is coming from now.

---

Update: It turned out that the current status should be good (not issuing a warning upon re-importing a prefab), it must have been those intermediate code changes that affected the prefabs in a bad persistent way.
Avatar
Harald

Harri
  • Postovi: 3914

gouzhen1

Thank you @vhristov !! I ran into the exact build errors. Updated runtime which included your PR and works perfectly now!!
gouzhen1
  • Postovi: 1

bklooster

Sorry for the bump, but we updated our 4.0 runtime and I think this fix is causing us some problems. While I think our artists appreciate the prefab preview and other fixes there are two problems generating these mesh assets for the prefabs.

One is that the mesh name that is outputted is not unique and is generating a lot of warnings because of duplicated skeletons that are nested in other prefabs. "Identifier uniqueness violation: 'Name:Skeleton Prefab Mesh X" Multiple Objects with the same name/type are generated by this importer" (see attachment) Also these assets are showing up in the asset hierarchy which isn't very nice.
SpineMeshUniquenessError.png


The other problem is that we have hundreds of spine skeletons dispersed around the prefabs. These prefabs when you modify them prebuild and post build require the asset to be checked out in version control (perforce) which individually is really slow, but on top of that it requires a reimport of the assets which is thrashing the asset database pretty hard. These changes have hurt our build times by a factor of 2-3x due to the reimports and checkouts.

I'm willing to explore alternatives, but there are definitely problems with this solution on some setups.
Nemaš dopuštenje za pregledavanje privit(a)ka dodan(og)ih postu.
bklooster
  • Postovi: 10

Harald

bklooster je napisao/la:One is that the mesh name that is outputted is not unique and is generating a lot of warnings because of duplicated skeletons that are nested in other prefabs. "Identifier uniqueness violation: 'Name:Skeleton Prefab Mesh X" Multiple Objects with the same name/type are generated by this importer" (see attachment) Also these assets are showing up in the asset hierarchy which isn't very nice.
SpineMeshUniquenessError.png
Are you using the latest spine-unity 4.0 unitypackage? This issue should already have been fixed since Nov. 8:
https://github.com/EsotericSoftware/spine-runtimes/issues/1973
bklooster je napisao/la:The other problem is that we have hundreds of spine skeletons dispersed around the prefabs. These prefabs when you modify them prebuild and post build require the asset to be checked out in version control (perforce) which individually is really slow, but on top of that it requires a reimport of the assets which is thrashing the asset database pretty hard. These changes have hurt our build times by a factor of 2-3x due to the reimports and checkouts.
Do you mean that if you enable the Advanced - Fix Prefab Overr. MeshFilter option at your prefabs, that these prefabs are constantly modified and checked out in Perforce? Or do you see these problems arise when you have the option disabled at your prefabs?

In any way if I understood your description correctly, it could be a solution to not use an exclusive-lock workflow on your prefab assets and only commit these assets upon actual modification (they should not change when the same prefab mesh is regenerated and stored again). Anyway, perhaps updating the spine-unity unitypackage resolves this issue as well.
Avatar
Harald

Harri
  • Postovi: 3914

bklooster

Thanks for the quick response Harald.

The first problem was fixed by the runtime update (thanks).

Even with the latest runtime, I tested the builds with and without the fix box checked, but didn't matter the files would still be reimported and checked out in perforce when making a build. My understanding of the problem is that you're doing a preprocess build (to destroy this preview mesh) which causes the asset to import through the asset database, and postprocess (to reset them). This the the problem that is causing the reimport of these assets and Unity to checkout these assets during this process. Perforce doesn't exclusively lock the files, but does visibly show the file is checkout by others. The users need to monitor these checkouts to monitor who else is modifying and notify them.

I think my solution right now is to disable this HAS_ON_POSTPROCESS_PREFAB define and have our artists endure the lack of prefab previews. While not great, I checked with the artists and they OK with losing to prefab preview to fix these checkout issues. Ideally, I'd think there'd be a HideFlag config somewhere that could fix this? I did try with DontSave | HideInInspector combination, but yeah ran into errors being thrown when included in the build as others mentioned. Maybe we could have a runtime scriptable object lookup mesh cache library that could be created? Regardless, I'll move forward with this disabled and our use case maybe is just an outlier. I wanted to check with you first to see if there was maybe something else we could try to work around our problem. I'd rather have time be spent on other things if there's not an easy solution (like multithreading :yuno: ;) )
bklooster
  • Postovi: 10

Harald

bklooster je napisao/la:The first problem was fixed by the runtime update (thanks).
Glad to hear, thanks for checking.

Regarding the second issue: sorry to hear that it still persists after the update. It's unfortunate that the Unity Perforce integration checks out the prefab file, just to write the same file content to it. Perhaps your could add a "Revert if unchanged" call automatically afterwards?

After reading your original posting again, I noticed that your problem was just with the build automation (during pre- and post build steps) and not with normal workflow. If you only need to prevent this problem, you could theoretically get away with "best of both worlds" at the cost of increased build-size by just disabling HAS_ON_POSTPROCESS_PREFAB in the SpineBuildProcessor.cs file. This way you should still get previews, it's just that the generated meshes are added to your build size, which could be OK for intermediate test builds.
Avatar
Harald

Harri
  • Postovi: 3914


Natrag na Unity