• Runtimes
  • Spine-Unity Staggered Update

Related Discussions
...

Hey Nate!
When you get to updating the runtimes, I have a request for Spine-Unity. This post is kinda long but I swear, it's less work implementing than reading this post. I just wanted to share my thoughts. XD

The two main chunks of update work seem to be
1) Animation.Apply(skeleton) (done by AnimationState.Apply via SkeletonAnimation.UpdateSkeleton(delta) ) and
2) "Rendering"/building the mesh ( currently done directly by SkeletonComponent.Update )

I understand you made Update and UpdateSkeleton overridable methods for the purposes of extensibility/customization, but the current setup seems to be a bit confusing because SkeletonComponent's SkeletonComponent.Update calls UpdateSkeleton but SkeletonComponent.Update also does the rendering.

This doesn't make it possible for a few fairly common useful uses (implied by the overridability) by just making a new class, regardless of whether you're extending SkeletonComponent or SkeletonAnimation :
1) Custom delta for slowmo/timewarp or game-time-independent animations like pause menu animations - Can't pass a custom delta time to UpdateSkeleton because the base class SkeletonComponent automatically calls UpdateSkeleton and passes a delta itself in Update. Update is automatically called by Unity. Overriding Update will override rendering.

2) Staggered update/frameskip - Can't skip rebuilding the mesh or applying the Spine.Animation to the skeleton every other frame or two, whether for the purposes of staggering update work for performance (great for making large numbers of skeletons lighter) or for aesthetically making things look low-framerate or like stop-motion (ala Tearaway's special effects).

And maybe the not so common
3) External update control - Related to staggering updates, the current setup doesn't allow a separate entity to handle the timing and limiting of Animation.Applys and mesh rebuilds. I mean, right now, we could freely Apply Animations to the Skeleton held by SkeletonComponent, but SkeletonComponent would still proceed to burn away cycles updating the mesh naively/uselessly most of the time.

I know all this amounts to is some simple method call juggling but, personally, I'd rather the refactor from official Spine.

My recommendation is:
1) Move rendering code out of SkeletonComponent.Update into its own separate method. UpdateMesh?
2) Don't give SkeletonComponent an Update method. (It doesn't need to update itself and rebuild the mesh if the skeleton it holds isn't moving. If ever something updates its skeleton, that thing could/should call a rebuild of the mesh whenever it needs to.)
3) Give an Update method to SkeletonAnimation. Make that call a mesh rebuild every time after Animation.Apply (via AnimationState.Apply).

I think that'd allow these and other less-standard functionality to be built by simple extension of classes.

But I'm sure you built this with some architecture in mind so maybe you have a better idea for how to accommodate this.
The other reason I brought up Skeleton.time in the other thread is because that seemed to be the only thing SkeletonComponent.UpdateSkeleton did. I was wondering if it did something important.

It may be a good time for some refactoring. How about this:

SkeleteonComponent becomes SkeletonMesh. It has a Mesh and Skeleton and knows how to update the Mesh.

SkeletonAnimation no longer extends SkeletonComponent. SkeletonAnimation instead requires a separate SkeletonMesh component on the GameObject. SkeletonAnimation simply poses the SkeletonComponent's Skeleton using AnimationState.

SkeletonAnimation could be renamed AnimationStateComponent. This is kind of long, but descriptive. I guess it is too long.

It is common to pose with AnimationState, then do other stuff, then do skeleton.UpdateWorldTransform() and update the Mesh. How does Unity control the order components are update? I would want to add a script component and have the update order be: SkeletonAnimation, script, then SkeletonMesh.

If SkeletonAnimation tells SkeletonMesh to update the Mesh after posing with AnimationState, then you'd need to be able to insert code between AnimationState#apply(...) and updating the Mesh, which sucks. Maybe SkeletonMesh has a dirty flag instead, so AnimationState only sets the flag. Then SkeletonMesh#LateUpdate() would both call skeleton.UpdateWorldTransform() and update the mesh if the flag is set.

Would this refactoring satisfy all the use cases you listed above?

Re: order of updates
MonoBehaviour Updates are called based on the order scripts are loaded, "which is arbitrarily", unless you specify them manually in Script Execution Order in the editor.

I have the impression that people generally don't want to touch Script Execution Order unless they really have to.
It makes it a bit messier/error prone to add the Spine runtime into a project or work in groups.

There's a page describing a bunch of other automatically called MonoBehaviour Event Functions but I dunno if anything fits the bill. LateUpdate is there though, and the method execution order, in case you're curious.

Re: doing something after AnimationState.Apply and before Skeleton.UpdateWorldTransform
I think the current setup where there's an UpdateBones delegate called right between these calls works well.
It could probably be renamed something more generic though.

It being a delegate type is pretty handy. You can subscribe and unsubscribe, and you can reorder the invocation list.

Did you have a problem with this?

Re: a dirty flag so SkeletonMesh can determine when to update itself
Unity tutorials have always recommended not to have "empty Update methods".
But I'm not actually sure how badly it impacts performance to many objects that have Update methods that do nothing.

But considering the dirty flag is precisely to save on performance of updating hundreds of skeletons...
I lean more towards SkeletonMesh not having an Update.

If only to heed Unity tech's ominous warnings. : p

On the other hand, what's your motivation for separating SkeletonMesh and SkeletonAnimation?

Re: the applications
Yeah. I think it'd work well.

1) If I wanted a Spine animation setup to be "immune" to the game pausing, slowing down or speeding up, I'd extend SkeletonAnimationthat overrides the Update method so it passes a delta time source that's different from Unity's Time.deltaTime. Then make SkeletonMesh update.

2) If I wanted something to update only every other frame, I'd extend SkeletonAnimation and override its Update so it does nothing every few frames, tracks its own deltatime to pass to AnimationState.Update(time) and then make SkeletonMesh update only when it updates.

1 and 2 both assume Update is still overridable.

3) For external update control, I'd make my own version of SkeletonAnimation that does the AnimationState stuff and update the SkeletonMesh but not automatically on Update. Instead, another class can call a method to do that stuff.
To stagger the update, I'd store a bunch of SkeletonAnimations in an array in a separate class, then traverse and update its elements with an i + 2 or i + 3 or something, with a different starting index each update.

And there's more than one way to do these things cleanly now without jumbling up Spine's runtime code (and making it harder to update when the runtime updates).

Re: limiting updates for the SkeletonMesh and SkeletonAnimation
There's a thing that UnityEngine.Animation does that has an option to stop playing animations when the mesh exits the camera's view.
This enum kinda describes it concisely.

If you're gonna refactor to allow customization of when/how often updates happen, might as well make sure this animation culling optimization can be done by the user, even if you don't build it into the runtime officially.

A Unity user can easily detect when the renderer enters and exits view through OnBecameInvisible and OnBecameVisible or the MeshRenderer's boolean Renderer.isVisible.

Re: the name of the posing and updating component with the AnimationState
Why don't you keep it as SkeletonAnimation?
or SkeletonAnimator
SpineAnimationState?

I'm not sure how this naming will affect the other runtimes and documentation.
I'm partial to SpineMesh and SpineAnimator.

Pharan wrote

MonoBehaviour Updates are called based on the order scripts are loaded, "which is arbitrarily", unless you specify them manually in Script Execution Order in the editor.

That sucks. 🙁

Re: doing something after AnimationState.Apply and before Skeleton.UpdateWorldTransform
I think the current setup where there's an UpdateBones delegate called right between these calls works well.
Did you have a problem with this?

The delegate is ok, but it is not as nice as being able to control when components on a GameObject are updated, which IMO is a basic necessity for a system like Unity. Having Update and LateUpdate is pretty terrible and leads to stupid things like LaterUpdate, LaterererUpdate, EarlyUpdate and EarlierUpdate... :no:

Re: a dirty flag so SkeletonMesh can determine when to update itself
Unity tutorials have always recommended not to have "empty Update methods".

Mysterious advice without reason? :puke:

On the other hand, what's your motivation for separating SkeletonMesh and SkeletonAnimation?

Say you have a SkeletonMesh and you want to manipulate it. You could use a SkeletonAnimation component for easy access to the AnimationState and add some scripts as needed.

Another reason is we may have multiple implementations of SkeletonMesh if meshes or FFD would negatively affect rendering for skeletons that don't use those features. Eg SkeletonMesh, SkeletonSkinnedMesh, etc. There could also be a SkeletonMesh that improves performance when using only a single atlas page, if that proves true.

It seems like separating them doesn't help if the order the components are update can't be controlled.

What if SkeletonMesh used OnWillRenderObject to check a flag and update the mesh if needed? This also means the mesh won't be update when off-screen.

1) If I wanted a Spine animation setup to be "immune" to the game pausing, slowing down or speeding up

You can do this now with AnimationState#timeScale.

There's a thing that UnityEngine.Animation does that has an option to stop playing animations when the mesh exits the camera's view.
This enum kinda describes it concisely.

If you're gonna refactor to allow customization of when/how often updates happen, might as well make sure this animation culling optimization can be done by the user, even if you don't build it into the runtime officially.

SkeletonAnimation is hardly any code, it mostly exists just so it can be controlled by the Inspector. It isn't hard to write your own class that applies an AnimationState if you need added control.

Another reason is we may have multiple implementations of SkeletonMesh if meshes or FFD would negatively affect rendering for skeletons that don't use those features. Eg SkeletonMesh, SkeletonSkinnedMesh, etc. There could also be a SkeletonMesh that improves performance when using only a single atlas page, if that proves true.

Makes perfect sense. I like it.

The delegate is ok, but it is not as nice as being able to control when components on a GameObject are updated, which IMO is a basic necessity for a system like Unity. Having Update and LateUpdate is pretty terrible and leads to stupid things like LaterUpdate, LaterererUpdate, EarlyUpdate and EarlierUpdate... :no:

lol. LaterererUpdate.
I'm going to include that in code someday.

I suspect, behind the scenes, these components are added to an array per Component type and just iterated through, instead of in any specific order per object.
Because prefetchers.
And hence you can reorder Script Execution Order globally but not per object.
But we may never know the workings of closed-source things... mysterious hands

It's not a huge bother to reorder. And you can. But it's just one more place where you can get user-side errors. So people avoid it.

But really, with the new structure of SkeletonMesh and SkeletonAnimation you described, and since as you said, SkeletonAnimation really isn't much code, it won't be difficult to make a different implementation (via a subclass or just a different class outside the hierarchy) of SkeletonAnimation that makes stuff happen between the AnimationState Update&Apply and skeleton.UpdateWorldTransform. I totally think the delegate is a great way to go though.

For all the basic functionality, we'll have vanilla SkeletonMesh and SkeletonAnimation.

You can do this now with AnimationState#timeScale.

SkeletonAnimation uses AnimationState.Update(UnityEngine.Time.deltaTime * timeScale).
That won't work for pause menus, in a paused-game or timestop situations (ie, where UnityEngine.Time.timeScale == 0f. Time would just keep giving AnimationState zero deltaTimes).
Plus it'd involve having to slide every AnimationState's timeScale you want to 'immunize" by the reciprocal of UnityEngine.Time.timeScale.
More manageable to centralize their deltaTime source with a customized timer and make the immune SkeletonAnimations use deltas from that.

SkeletonAnimation is hardly any code, it mostly exists just so it can be controlled by the Inspector. It isn't hard to write your own class that applies an AnimationState if you need added control.

True. But in its relationship with SkeletonComponent, you can't. SkeletonComponent Updates every frame, and causes SkeletonAnimation's AnimationState to update and apply every frame, then builds the mesh.
I think this really isn't an issue with the new structure you mentioned. It's just an additional perk, I guess, because it'll be totally doable.
It is doable now but I just needed to point out that the current resulting call stack doesn't allow it. Just needs minor adjustment for which method calls who.

What if SkeletonMesh used OnWillRenderObject to check a flag and update the mesh if needed? This also means the mesh won't be update when off-screen.

This is one way to implement the animation culling thing (and in Spine's case, the rebuild-mesh-culling thing). But I think the there should still be the option for the thing that poses the skeleton to determine when to make SkeletonMesh rebuild the mesh.

But if you really want official SkeletonMesh to be self-updating, I guess this passiveness could be a different implementation of SkeletonMesh.

Pharan wrote

What if SkeletonMesh used OnWillRenderObject to check a flag and update the mesh if needed? This also means the mesh won't be update when off-screen.

This is one way to implement the animation culling thing (and in Spine's case, the rebuild-mesh-culling thing). But I think the there should still be the option for the thing that poses the skeleton to determine when to make SkeletonMesh rebuild the mesh.

That would be the flag I mentioned. If you want SkeletonMesh to update the mesh, you set a flag and it happens in the next OnWillRenderObject.

Oh, you mean OnWillRenderObject will check the flag.
That'd fix the LatererererUpdate predicament too, I guess. Plus it's descriptive and in the right place in execution order.


Ohh. and this separation is cool 'cause it'll easily support an alternate version of SkeletonMesh that uses multiple GameObjects as its "rendering" method, which will be easier to ragdoll and attach things to and influence with physics.

Aye, I think it's a good plan. I've spent today working on spine-csharp and getting spine-xna to render it for testing, so spine-unity and friends will see some love soon. :love:


FUBAR...

What I want is to do some setup in Awake, but if some configuration is missing, abort. I don't want to litter checks throughout my code to handle if something isn't configured (eg, a SkeletonData asset isn't set).

I guess there is no way around it. I'll have a boolean named valid. Initialization and communication between scripts seems like it would be a lot of pain when writing a game in Unity.


spine-unity and spine-tk2d are committed. I ended up not having multiple renderers and SkeletonAnimation still extends the SkeletonRenderer class (formerly SkeletonComponent). It was too awkward since SkeletonRenderer also provides the skeleton, so things like BoneComponent want a reference to it which wouldn't work out if there were multiple SkeletonRenderers.

SkeletonRenderer sets new triangle indices every frame, even for region attachments. If not using meshes maybe it could be optimized slightly. When using meshes it has to be done.

Does this setup satisfy all your use cases? Any other feedback on the API? Now is a good time to make changes.

Sorry! I was out for the day. I'll be out again tomorrow.

(1)
The one I made also assigned new triangle indices every frame because it's unpredictable where the meshes insert themselves especially with draw order animations, or when they swap to other meshes with a different number of vertices.

I also added a public bool alwaysUpdateTriangles so I could easily optimize and switch this behavior on and off for specific skeleton setups.
I'll actually just readd it to my project whether you put it in there officially or not, 'cause I kinda need it for our crowd setup. :p

I'd be modding it either way to darken the vertex colors it pushes 'cause we're using a modified version of the Skeleton shader that allows it to overbrighten the texture way past RGBA(1,1,1,1)— because flashing skeletons make good game feedback!

In Spine-C#, I also cached vertexCount in the attachments themselves in SetMesh so I could avoid the array property access and int divisions in SkeletonRenderer:line 130, 135, 326, 330.

(2)
I expected the awkwardness of having SkeletonMesh and SkeletonAnimation both needing to hold a reference to the same skeleton.
And it would also be a bit weird to require and to not require SkeletonAnimation to have a SkeletonMesh component to be attached to the same GameObject, considering the point of the separation was to allow SkeletonMesh to have a different implementation.
And I was averse to the separation at first because it'd mean that it'd break the setups of everyone already using Spine.

But I think the separation would still be useful as an option for people who need to mix and match.
I guess it's not that hard to implement though. Anyone who ventures into that territory of modifying Spine will know how to be careful with the separation.
I think extending SkeletonAnimation will do for most cases.

The ragdoll-friendly individual-gameobject setup will be interesting to make. And we can put them side by side with the single mesh version and see who wins in performance. But that's for another day and for when we have more time. 😃

(3)
BoneComponent currently has some problems that I wanted to fix but didn't really get around to just yet, like it doesn't follow the bone properly when the skeleton flips because it doesn't know of flipX and flipY at all.
I thought it could be a bit agnostic and not really need SkeletonRenderer or SkeletonAnimation, but I guess it really does need that reference to their Skeleton object at the very least to know the state of flipX and flipY.
The caching logic also needs some accounting for cases when things aren't assigned or the BoneComponent is added at runtime through code. That's my bad, really for adding it the way I did. I'll fix it, I'll fix it!

(4)
API:
I like how UpdateBones now passes the SkeletonAnimation to the subscriber. Though one would expect the subscriber to have already had the reference to that SkeletonAnimation at the point of subscription. But I guess this removes the necessity of one centralized object having to store references to a hundred SkeletonAnimations if it needed to do UpdateBones for all of them. Can't imagine why you'd pattern code that way though.

If I wanted to change the conditions that cause a mesh rebuild, would I override OnWillRenderObject and go

if(conditions) {
     base.OnWillRenderObject()
}

?
That'll do, right?
And if I need another class to determine when to repose the skeleton and rebuild the mesh, the condition can just be a dirty flag.

(4) addSubmesh needs to be AddSubmesh. 😃


Just attempting to update to the new runtime.

So Initialize is now Reset?

I don't think Reset is safe to call now.
The point of the original Initialize method was so scripts that ran their Awake before SkeletonComponent's Awake could force SkeletonComponent to do its thing (particularly initialize its skeleton) so it could do things like get references to slots and bones and the skeleton itself.

Without the check, it would create and orphan instances of Skeleton (in SkeletonRenderer) and AnimationState (in SkeletonAnimation) with each call to Initialize (or Reset).


There's a bug in SkeletonJSON in C#. The JSON scale isn't being applied to the meshes.
line 223 should be

float[] vertices = GetFloatArray(map, "vertices", Scale);

I'm having strange bugs. Some of my skinned meshes are being drawn upside down.


Some other meshes have UVs that are just plain messed up.
This isn't a rotation problem. These were atlases packed before meshes and skinnedmeshes supported rotated regions so they were exported with rotation disabled.


My bad, it's not just meshes.
Specific entire skeletons have region attachments that are mapped all wrong.
But others are fine.
It can't be an atlas problem. I have several skeletons sharing the same atlas. Some skeletons have ALL attachments that have messed up uv-mapping. Some of them are completely fine.
Some of the ones that are messed up use meshes, some of them don't. Likewise for the skeletons that are fine.

Pharan wrote

I also added a public bool alwaysUpdateTriangles so I could easily optimize and switch this behavior on and off for specific skeleton setups.
I'll actually just readd it to my project whether you put it in there officially or not, 'cause I kinda need it for our crowd setup. :p

It was an optimization so I smoked it until someone complained. I added a renderMeshes field which is more efficient if a skeleton doesn't use meshes.

In Spine-C#, I also cached vertexCount in the attachments themselves in SetMesh so I could avoid the array property access and int divisions in SkeletonRenderer:line 130, 135, 326, 330.

I changed them to a shift, it's unlikely to be a bottleneck.

The ragdoll-friendly individual-gameobject setup will be interesting to make. And we can put them side by side with the single mesh version and see who wins in performance. But that's for another day and for when we have more time. 😃

Indeed. 🙂 It's a pain keeping GameObjects in sync with the skeleton.

BoneComponent ... I'll fix it, I'll fix it!

Sweet! 8)

If I wanted to change the conditions that cause a mesh rebuild, would I override OnWillRenderObject and go if(conditions) {

Yep. Though there is some issue with using OnWillRenderObject. It is called when the object is on screen, but this check is determined using the mesh bounds. Since the mesh vertices are only populated in OnWillRenderObject we have a chicken and egg problem. I'd say maybe we use OnPreCull, but this never seems to be called (wtf...). I guess LateUpdate is the way to go. Avoiding updating the mesh is via culling is problematic when the mesh changes size dramatically.

So Initialize is now Reset?

I don't think Reset is safe to call now.
The point of the original Initialize method was so scripts that ran their Awake before SkeletonComponent's Awake could force SkeletonComponent to do its thing (particularly initialize its skeleton) so it could do things like get references to slots and bones and the skeleton itself.

Things outside of SkeletonMesh shouldn't have to worry that the SkeletonMesh is not initialized. Scripts should use Start to communicate with other components, not Awake:
http://docs.unity3d.com/Documentation/S ... Awake.html

Each GameObject's Awake is called in a random order between objects. Because of this, you should use Awake to set up references between scripts, and use Start to pass any information back and forth.

Of course they mean arbitrary order, not random. :nerd:

There's a bug in SkeletonJSON in C#. The JSON scale isn't being applied to the meshes.

I had to leave you some bugs to find. 😉

Specific entire skeletons have region attachments that are mapped all wrong.
But others are fine.
It can't be an atlas problem. I have several skeletons sharing the same atlas. Some skeletons have ALL attachments that have messed up uv-mapping. Some of them are completely fine.

Ehm, that is odd. I don't see this. Can you try with the latest and send a project that shows the problem if it still happens?

Things outside of SkeletonMesh shouldn't have to worry that the SkeletonMesh is not initialized. Scripts should use Start to communicate with other components, not Awake:

This is the LaterererUpdate all over again. Some scripts need to do this on Awake so other scripts can start in Start. The scripts that could be doing this may very well be lower-level systems just on top of Spine but below everything else.

How about this:
Add Skeleton and State getter properties that forces initialization when it hasn't initialized yet and just returns the skeleton and state if it already has them ready.
That way, other scripts don't have to worry about SkeletonMesh or SkeletonAnimation not being initialized to get to the skeleton and the AnimationState.

One thing I find weird though: I don't see what use replacing the existing skeleton reference with a new one would be except in Unity Editor.

I don't see any changes that would've fixed the problem with the weird uvs.
And it didn't fix the problem. 😃

I'm still readding the alwaysUpdateTriangles bool to mine 'cause that still allowed meshes to be used as long as they didn't change order or swap to other meshes, which can be pretty common for enviro stuff. (ie, didn't require the triangles indexes to be updated after the first time.)


Re-exporting doesn't fix the problem. At least that rules that one out. My primary suspect is SkeletonJSON.
I'm trying to figure out how to get examples to you.

If it's any clue, the UV maps are messed up but consistently mapped at 180º rotated boxes with incorrect coordinates. Though the coordinates seem to have some sense since the mapping isn't skewed or stretched. Just at the wrong place and rotated 180º.


(There's 2 SkeletonDataAsset fields in the inspector for SkeletonAnimation.)


I think the UV thing is related to Unity's (u, 1-v) coordinate system for UVs.
Addressing it flips which ones get broken and which ones are okay.
It doesn't explain why it's ok for entire skeletons of some, for any type of attachment, and everything's flipped for others.

Is it an Atlas thing? Is FlipV being called for some but not for others? But since it's shared, shouldn't it apply to all skeletons trying to use the same atlas?


See SkeletonDataAsset.cs : line 76

In this situation where the atlas is shared by different SkeletonDataAssets;
for each SkeletonDataAsset gets initialized by GetSkeletonData, the shared atlas gets flipped by line 76.

Fixed the atlas flipping problem. Oops. 🙂

Pharan wrote

Things outside of SkeletonMesh shouldn't have to worry that the SkeletonMesh is not initialized. Scripts should use Start to communicate with other components, not Awake:

This is the LaterererUpdate all over again. Some scripts need to do this on Awake so other scripts can start in Start. The scripts that could be doing this may very well be lower-level systems just on top of Spine but below everything else.

Awake gets and stores the SkeletonRenderer/SkeletonAnimation reference but doesn't use it. Start uses it. SkeletonRenderer/SkeletonAnimation don't have Start, so there is no problem with a script's Start happening first. Is that right? What is a scenario where Awake and Start won't work? Unity forces public fields so to use a property we'd have to renamed skeleton to _skeleton.

One thing I find weird though: I don't see what use replacing the existing skeleton reference with a new one would be except in Unity Editor.

Not sure what you mean. At runtime Reset will only be called once.

I'm still readding the alwaysUpdateTriangles bool to mine 'cause that still allowed meshes to be used as long as they didn't change order or swap to other meshes, which can be pretty common for enviro stuff. (ie, didn't require the triangles indexes to be updated after the first time.)

I suppose that is a good optimization, though a little scary since it can completely break things if used on the wrong skeleton. I'll add something.

Woo! That flipping thing was funny while it lasted. :rofl:

Awake gets and stores the SkeletonRenderer/SkeletonAnimation reference but doesn't use it. Start uses it. SkeletonRenderer/SkeletonAnimation don't have Start, so there is no problem with a script's Start happening first. Is that right? What is a scenario where Awake and Start won't work?

Scenario:
In a separate low-level component type (Let's call it SpineCharacterAnimator), Awake would need references to Skeleton and AnimationState to find bones and animation references and make the animation autoreset and other things, so that the higher-level scripts can use Start or do a safe initialize to do their things with the lower-level components.

This is under the assumption that the best way to use SkeletonRenderer/SkeletonAnimation is not to extend it or make sibling classes for it but to have various other component classes to manage it in different ways depending on the need. (This is at least the option for people who subscribe to component-instead-of-subclassing architecture, plus making making the rendering work in UnityEditor without having to write a new inspector class for each new extension)

Either way, without the safe initialization or a lazy-instantiation getter, you'd be taking away the user's ability to use Awake cleanly or chain a bunch of initializations safely for their own purposes in all other scripts related to SkeletonAnimation.

Unity forces public fields so to use a property we'd have to renamed skeleton to _skeleton.

I'm not sure what you mean by "forces". You mean Unity forces fields to be public? That's not true.
Does this have something to do with things being visible in the inspector and compatibility with playmaker or something?

Not sure what you mean. At runtime Reset will only be called once.

Ah, you're right.

I'm still readding the alwaysUpdateTriangles bool to mine 'cause that still allowed meshes to be used as long as they didn't change order or swap to other meshes, which can be pretty common for enviro stuff. (ie, didn't require the triangles indexes to be updated after the first time.)

I suppose that is a good optimization, though a little scary since it can completely break things if used on the wrong skeleton. I'll add something.

What I did was make this field default to true so we could turn it off to opt-in for optimization. And I didn't add it to the inspector script so whoever uses it is forced to enable Debug mode for the inspector panel to get to its serialization, and also to make it a bit more clear that it's something to be careful with.

Pharan wrote

Scenario:
In a separate low-level component type (Let's call it SpineCharacterAnimator), Awake would need references to Skeleton and AnimationState to find bones and animation references and make the animation autoreset and other things, so that the higher-level scripts can use Start or do a safe initialize to do their things with the lower-level components.

Unity says you aren't supposed to do this. You shouldn't access other components in Awake. If you do, it leads to needing to initialize the other components manually, and then those components have to know they are already initialized when their Awake is called later... it's nasty. Components should be given a chance to initialize before they are used by other things and that is what Awake is for.

If you have a script that accesses bones or animations, it can look them up in Start. If you have two scripts, one provides access to bones or animations and you have the problem that the wrong script's Start might run first, then you have the standard Unity script dependency problem. You could: 1) have each script look up the bones or animations themselves, 2) provide a way to manage initialization (eg your own initialize method), 3) use script execution order.

We could have some initialize method in SkeletonRenderer (and the code that manages if it has really been initialized, should be re-initialized because something changed in the inspector, etc), but I don't that is the right way to do it in Unity. I expect Unity developers are used to the Unity script dependency problem.

Unity forces public fields so to use a property we'd have to renamed skeleton to _skeleton.

I'm not sure what you mean by "forces". You mean Unity forces fields to be public? That's not true.
Does this have something to do with things being visible in the inspector and compatibility with playmaker or something?

Unity serializes public fields. I found an annotation that lets private fields be used, so that helps. I wish Unity's documentation wasn't complete ass. 🙁

What I did was make this field default to true so we could turn it off to opt-in for optimization. And I didn't add it to the inspector script so whoever uses it is forced to enable Debug mode for the inspector panel to get to its serialization, and also to make it a bit more clear that it's something to be careful with.

For your alwaysUpdateTriangles, when true it always updates the triangles. When false, it does the firstVertex checks to try to avoid updating the triangles (which is only valid if not using meshes!).

I added immutableTriangles, when true it only updates the triangles the first time. Don't use this if your skeleon ever changes attachments!

Ah well. In the end, I guess people do need use Script Execution Order for this. Or just do things in Start.

I'm still gonna give them an Initialize method. Reviewing my code, I remember I got weird stuff when I instantiated prefabs with SkeletonAnimations in them too.
Something about either OnEnable or Awake not being called immediately. I can't recall.

Oh, Unity automatically serializes public fields if they're primitives like bool and float. It also serializes strings and enums but not structs.
It doesn't serialize public fields if they're reference types, unless the class of the object referenced is marked [System.Serializable] and the public reference field is marked [UnityEngine.SerializeField].
But yeah [System.NonSerialized] is the way to go for public primitives you don't want to serialize. Either that or make it a property, which doesn't serialize and only shows up in the inspector if you code it in the custom inspector class.

When you disabled alwaysUpdateTriangles, it broke when you had meshes that swapped or changed draw order, but it worked for when RegionAttachments changed draw order and increased and decreased in number.
I guess immutableTriangles and renderMeshes does the same with better control. So cool!

I'm just not sure we should go against how Unity is supposed to work by suggesting people do things in Awake and after using an initialize method. If it is painful enough to do other ways maybe we should.

Hmm.. okay. I'll review some stuff and do some digging. :wonder:
Seems like rather ambiguous ground in places. AnimationState kinda has what you'd expect as the API of a MonoBehaviour so I would think the ideal of storing references to scripts in Awake kinda apply to it.
If things were different, SkeletonAnimation would be the thing you'd tell to SetAnimation and subscribe to for events and stuff like that.

I guess for the official thing, it'll be fine to leave it as is.
I haven't really gone through my code that thoroughly yet either.
I'll let you know about the instantiation thing.

:think:

If I wanted to get Animation references... I really should've been going through SkeletonRenderer.SkeletonDataAsset.GetSkeletonData. That has safe initialization. 😃
Bones and slots and the skeleton flipping interface are a different matter.

I think I'll do a PR sometime to better illustrate recommended arrangement stuff in Unity through an example scene with Spineboy.
And so I'll have a place to check and point to in case I forget.
Maybe mark it "Advanced" so people just trying Spine out don't think it's super-required just to get things running.

We found and fixed the bugs anyway. (I liked the mini-goblin.) So ,yay!


By the way, you removed mesh.RecalculateBounds()?
Its absence was causing meshes to disappear even before it completely left the camera's view.

It's possibly expensive to put in an Update method but we should probably allow it to at least set some good bounds values at some point.

Pharan wrote

By the way, you removed mesh.RecalculateBounds()?
Its absence was causing meshes to disappear even before it completely left the camera's view.

http://docs.unity3d.com/Documentation/S ... ounds.html
Says, "Assigning triangles will automatically Recalculate the bounding volume." Is there a problem with not having it? I wanted to avoid doing work twice. Of course Unity is a black box and doesn't document what exactly happens, for example if the bounds are already calculated. :makeup:


Answer to that:
viewtopic.php?p=12483#p12483