• Runtimes
  • [UE4] Materials and Atlas Slots

New thread because wrong subject and the hot-reload issue is now resolved thanks to the very efficient badlogic, thanks!

Hello! Quite a neat piece of software and we were delighted when we stumbled over it one day. Been making some tests and so on and have been mostly impressed with what we've found.

There are however some questions that arose from playing around. The first one is the fact that the USpineSkeletonRendererComponent creates materials in TickComponent (meaning they do not exist in BeginPlay in C++ yet). While we can redesign a bit to work with this I'd like to know how often these materials get recreated? We have some material properties with effects and would rather not have to set them every frame if the material changes. From the code it looks like it only runs if the atlas pages don't match how many pages the skeleton has, but does this really change during runtime for the same object?

We'd also like to know if there's a way to check which animation is running so we don't try to set it again, i.e. to avoid restarting the running animation every frame. Like you can do in Paper2D here:

	if (GetSprite()->GetFlipbook() != DesiredAnimation)
	{
		GetSprite()->SetFlipbook(DesiredAnimation);
Related Discussions
...
  • Змінено

We need to reassign the materials in TickComponent, as you may change them either in the editor, or at runtime of your game. The check you saw makes sure we only do so if the atlas changed. This means we change materials only when absolutely necessary.

You can check which animations are being played back by getting the AnimationState from SpineSkeletonAnimationComponent spine-runtimes/SpineSkeletonAnimationComponent.h at 3.7-beta-cpp

An animation state has multiple tracks, indexed from 0 onwards. Animation state has multiple methods that return the currently playing TrackEntry instances, see spine-runtimes/AnimationState.h at 3.7-beta-cpp. TrackEntry let's you query the Animation it's playing back spine-runtimes/AnimationState.h at 3.7-beta-cpp.

I would however highly advise not to (try) to set animations every frame. AnimationState is designed to deal with animation blending and managing the, well, animation state for you. Say your character is idling, and the user presses a key to make it move right. Now you want to transition from idle to a looping run animation. All you need to do is set the new animation on AnimationState via a call to AnimationState::addAnimation() and animation state will perform the transition and ensure it keeps playing until you queue new animations or tell it to stop animating.

You can also get notified when an animation has stopped playing by registering listeners either with AnimationState or UTrackEntry (a UE4 wrapper of TrackEntry), see spine-runtimes/SpineSkeletonAnimationComponent.h at 3.7-beta-cpp

I'd also highly recommend checking out the spine-cpp documentation at Spine-cpp Runtime Documentation: Animation state API, the generic runtime documentation at Spine Runtime Documentation, and the spine-ue4 documentation Spine-UE4 Runtime Documentation

I gather that, yes, but I suppose that also means that unless you do change anything at runtime the MaterialInstances never change on their own? In that case it should be possible to edit their properties without much worry that they will be re-instanced at random moments. Was mostly just wondering why it was done there, and not in BeginPlay, but fair enough. Our normal workflow has been to create Instances in BeginPlay from whatever material is assigned to the object, assign the instances to the object and then that material instance is the one that lives for the duration of the object itself with whatever FX settings you change on it. From what you say USpineSkeletonRendererComponent works the same but does its updates on the fly in TickComponent and provided we don't change the material it will not discard the current instances.

I only started digging for this because USpineSkeletonRendererComponent->GetMaterials() is empty in BeginPlay in C++ but worked in BP (which is executed later).

Thank you for the info RE the animations, it's a bit different from Paper yes. I did find the delegates already so working with them. I just needed a way to keep track of which animation is playing and if it's not the right one update it, that was what the whole Tick check was about. In this case it would be to check if i.e. idle has changed to run and if not, add that track which means next frame you can check if it's already added on and don't bother with it.


How do I work around the linker errors produced by accessing anything that is in the spine-cpp section of the UE4 spine plugin? I.e. I can do GetAnimationState() fine, but trying to append getCurrent(0) there gives me an unresolved external for getCurrent. Same for anything else that returns a spine::class.

I.e:

		spine::AnimationState* state = GetAnimator()->GetAnimationState();
		state->getCurrent(0);

The first line compiles OK, but the second gives an unresolved external. GetAnimator is just an inline that returns the USpineSkeletonAnimationComponent pointer.

I have deleted the .vs, Binaries, Intermediate and Saved folders, and regenerated the solution file on both my desktop and laptop just to be sure but both get the same issue. It's almost as if they are not being built in despite having the SPINE_UE4 tag.


Tried in your test project as well by trying to getCurrent, for example, on the ASpineboyCppPawn with the same result.


Aaaah It's me being stupid and invoking the wrong methods, yay 😛 Food first, programming later after reading properly. And reading the wrong tutorials originally.