- (UE4) Changes meant to support PaperZD or any other external plugins which need to interface directly with the renderer.

- (UE4) Added skeleton animation caching on SkeletonRenderer to avoid
per tick searches which are costly. The skeleton animation component can
be setup externally.
- (UE4) Added bAutoPlays members to AnimationComponent, so the skeleton
doesn't update automatically if its needed.
- (UE4) Added SetPlaybackTime method to AnimationComponent.
This commit is contained in:
Carlos Ibanez 2019-01-14 12:06:59 -03:00
parent e95fca696f
commit b21ecba445
4 changed files with 175 additions and 93 deletions

View File

@ -94,7 +94,7 @@ void USpineSkeletonAnimationComponent::TickComponent(float DeltaTime, ELevelTick
void USpineSkeletonAnimationComponent::InternalTick(float DeltaTime, bool CallDelegates) { void USpineSkeletonAnimationComponent::InternalTick(float DeltaTime, bool CallDelegates) {
CheckState(); CheckState();
if (state) { if (state && bAutoPlaying) {
state->update(DeltaTime); state->update(DeltaTime);
state->apply(*skeleton); state->apply(*skeleton);
if (CallDelegates) BeforeUpdateWorldTransform.Broadcast(this); if (CallDelegates) BeforeUpdateWorldTransform.Broadcast(this);
@ -144,6 +144,36 @@ void USpineSkeletonAnimationComponent::FinishDestroy () {
Super::FinishDestroy(); Super::FinishDestroy();
} }
void USpineSkeletonAnimationComponent::SetAutoPlay(bool bInAutoPlays)
{
bAutoPlaying = bInAutoPlays;
}
void USpineSkeletonAnimationComponent::SetPlaybackTime(float InPlaybackTime, bool bCallDelegates)
{
CheckState();
if (state && state->getCurrent(0)) {
spine::Animation* CurrentAnimation = state->getCurrent(0)->getAnimation();
const float CurrentTime = state->getCurrent(0)->getTrackTime();
InPlaybackTime = FMath::Clamp(InPlaybackTime, 0.0f, CurrentAnimation->getDuration());
const float DeltaTime = InPlaybackTime - CurrentTime;
state->update(DeltaTime);
state->apply(*skeleton);
//Call delegates and perform the world transform
if (bCallDelegates)
{
BeforeUpdateWorldTransform.Broadcast(this);
}
skeleton->updateWorldTransform();
if (bCallDelegates)
{
AfterUpdateWorldTransform.Broadcast(this);
}
}
}
void USpineSkeletonAnimationComponent::SetTimeScale(float timeScale) { void USpineSkeletonAnimationComponent::SetTimeScale(float timeScale) {
CheckState(); CheckState();
if (state) state->setTimeScale(timeScale); if (state) state->setTimeScale(timeScale);

View File

@ -68,14 +68,36 @@ void USpineSkeletonRendererComponent::BeginPlay () {
Super::BeginPlay(); Super::BeginPlay();
} }
USpineSkeletonComponent* USpineSkeletonRendererComponent::GetSkeleton() const
{
return CachedSkeleton.IsValid() ? CachedSkeleton.Get() : nullptr;
}
void USpineSkeletonRendererComponent::SetSkeleton(USpineSkeletonComponent* InSkeleton)
{
CachedSkeleton = InSkeleton;
}
void USpineSkeletonRendererComponent::TickComponent (float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) { void USpineSkeletonRendererComponent::TickComponent (float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) {
Super::TickComponent(DeltaTime, TickType, ThisTickFunction); Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
AActor* owner = GetOwner(); //Check if we need to initialize the skeleton cache, this will help us to avoid excessive Find functions when ticking, thus improving performance
if (owner) { if (!GetSkeleton())
UClass* skeletonClass = USpineSkeletonComponent::StaticClass(); {
USpineSkeletonComponent* skeleton = Cast<USpineSkeletonComponent>(owner->GetComponentByClass(skeletonClass)); USpineSkeletonComponent* FoundSkeletonComponent = GetOwner()->FindComponentByClass<USpineSkeletonComponent>();
if (FoundSkeletonComponent)
{
SetSkeleton(FoundSkeletonComponent);
}
}
//Make sure we update the renderer
UpdateRenderer();
}
void USpineSkeletonRendererComponent::UpdateRenderer()
{
USpineSkeletonComponent* skeleton = GetSkeleton();
if (skeleton && !skeleton->IsBeingDestroyed() && skeleton->GetSkeleton() && skeleton->Atlas) { if (skeleton && !skeleton->IsBeingDestroyed() && skeleton->GetSkeleton() && skeleton->Atlas) {
skeleton->GetSkeleton()->getColor().set(Color.R, Color.G, Color.B, Color.A); skeleton->GetSkeleton()->getColor().set(Color.R, Color.G, Color.B, Color.A);
@ -92,27 +114,28 @@ void USpineSkeletonRendererComponent::TickComponent (float DeltaTime, ELevelTick
for (int i = 0; i < skeleton->Atlas->atlasPages.Num(); i++) { for (int i = 0; i < skeleton->Atlas->atlasPages.Num(); i++) {
AtlasPage* currPage = skeleton->Atlas->GetAtlas(false)->getPages()[i]; AtlasPage* currPage = skeleton->Atlas->GetAtlas(false)->getPages()[i];
UMaterialInstanceDynamic* material = UMaterialInstanceDynamic::Create(NormalBlendMaterial, owner); UMaterialInstanceDynamic* material = UMaterialInstanceDynamic::Create(NormalBlendMaterial, this);
material->SetTextureParameterValue(TextureParameterName, skeleton->Atlas->atlasPages[i]); material->SetTextureParameterValue(TextureParameterName, skeleton->Atlas->atlasPages[i]);
atlasNormalBlendMaterials.Add(material); atlasNormalBlendMaterials.Add(material);
pageToNormalBlendMaterial.Add(currPage, material); pageToNormalBlendMaterial.Add(currPage, material);
material = UMaterialInstanceDynamic::Create(AdditiveBlendMaterial, owner); material = UMaterialInstanceDynamic::Create(AdditiveBlendMaterial, this);
material->SetTextureParameterValue(TextureParameterName, skeleton->Atlas->atlasPages[i]); material->SetTextureParameterValue(TextureParameterName, skeleton->Atlas->atlasPages[i]);
atlasAdditiveBlendMaterials.Add(material); atlasAdditiveBlendMaterials.Add(material);
pageToAdditiveBlendMaterial.Add(currPage, material); pageToAdditiveBlendMaterial.Add(currPage, material);
material = UMaterialInstanceDynamic::Create(MultiplyBlendMaterial, owner); material = UMaterialInstanceDynamic::Create(MultiplyBlendMaterial, this);
material->SetTextureParameterValue(TextureParameterName, skeleton->Atlas->atlasPages[i]); material->SetTextureParameterValue(TextureParameterName, skeleton->Atlas->atlasPages[i]);
atlasMultiplyBlendMaterials.Add(material); atlasMultiplyBlendMaterials.Add(material);
pageToMultiplyBlendMaterial.Add(currPage, material); pageToMultiplyBlendMaterial.Add(currPage, material);
material = UMaterialInstanceDynamic::Create(ScreenBlendMaterial, owner); material = UMaterialInstanceDynamic::Create(ScreenBlendMaterial, this);
material->SetTextureParameterValue(TextureParameterName, skeleton->Atlas->atlasPages[i]); material->SetTextureParameterValue(TextureParameterName, skeleton->Atlas->atlasPages[i]);
atlasScreenBlendMaterials.Add(material); atlasScreenBlendMaterials.Add(material);
pageToScreenBlendMaterial.Add(currPage, material); pageToScreenBlendMaterial.Add(currPage, material);
} }
} else { }
else {
pageToNormalBlendMaterial.Empty(); pageToNormalBlendMaterial.Empty();
pageToAdditiveBlendMaterial.Empty(); pageToAdditiveBlendMaterial.Empty();
pageToMultiplyBlendMaterial.Empty(); pageToMultiplyBlendMaterial.Empty();
@ -126,7 +149,7 @@ void USpineSkeletonRendererComponent::TickComponent (float DeltaTime, ELevelTick
UMaterialInstanceDynamic* current = atlasNormalBlendMaterials[i]; UMaterialInstanceDynamic* current = atlasNormalBlendMaterials[i];
if (!current || !current->GetTextureParameterValue(TextureParameterName, oldTexture) || oldTexture != texture) { if (!current || !current->GetTextureParameterValue(TextureParameterName, oldTexture) || oldTexture != texture) {
UMaterialInstanceDynamic* material = UMaterialInstanceDynamic::Create(NormalBlendMaterial, owner); UMaterialInstanceDynamic* material = UMaterialInstanceDynamic::Create(NormalBlendMaterial, this);
material->SetTextureParameterValue(TextureParameterName, texture); material->SetTextureParameterValue(TextureParameterName, texture);
atlasNormalBlendMaterials[i] = material; atlasNormalBlendMaterials[i] = material;
} }
@ -134,7 +157,7 @@ void USpineSkeletonRendererComponent::TickComponent (float DeltaTime, ELevelTick
current = atlasAdditiveBlendMaterials[i]; current = atlasAdditiveBlendMaterials[i];
if (!current || !current->GetTextureParameterValue(TextureParameterName, oldTexture) || oldTexture != texture) { if (!current || !current->GetTextureParameterValue(TextureParameterName, oldTexture) || oldTexture != texture) {
UMaterialInstanceDynamic* material = UMaterialInstanceDynamic::Create(AdditiveBlendMaterial, owner); UMaterialInstanceDynamic* material = UMaterialInstanceDynamic::Create(AdditiveBlendMaterial, this);
material->SetTextureParameterValue(TextureParameterName, texture); material->SetTextureParameterValue(TextureParameterName, texture);
atlasAdditiveBlendMaterials[i] = material; atlasAdditiveBlendMaterials[i] = material;
} }
@ -142,7 +165,7 @@ void USpineSkeletonRendererComponent::TickComponent (float DeltaTime, ELevelTick
current = atlasMultiplyBlendMaterials[i]; current = atlasMultiplyBlendMaterials[i];
if (!current || !current->GetTextureParameterValue(TextureParameterName, oldTexture) || oldTexture != texture) { if (!current || !current->GetTextureParameterValue(TextureParameterName, oldTexture) || oldTexture != texture) {
UMaterialInstanceDynamic* material = UMaterialInstanceDynamic::Create(MultiplyBlendMaterial, owner); UMaterialInstanceDynamic* material = UMaterialInstanceDynamic::Create(MultiplyBlendMaterial, this);
material->SetTextureParameterValue(TextureParameterName, texture); material->SetTextureParameterValue(TextureParameterName, texture);
atlasMultiplyBlendMaterials[i] = material; atlasMultiplyBlendMaterials[i] = material;
} }
@ -150,7 +173,7 @@ void USpineSkeletonRendererComponent::TickComponent (float DeltaTime, ELevelTick
current = atlasScreenBlendMaterials[i]; current = atlasScreenBlendMaterials[i];
if (!current || !current->GetTextureParameterValue(TextureParameterName, oldTexture) || oldTexture != texture) { if (!current || !current->GetTextureParameterValue(TextureParameterName, oldTexture) || oldTexture != texture) {
UMaterialInstanceDynamic* material = UMaterialInstanceDynamic::Create(ScreenBlendMaterial, owner); UMaterialInstanceDynamic* material = UMaterialInstanceDynamic::Create(ScreenBlendMaterial, this);
material->SetTextureParameterValue(TextureParameterName, texture); material->SetTextureParameterValue(TextureParameterName, texture);
atlasScreenBlendMaterials[i] = material; atlasScreenBlendMaterials[i] = material;
} }
@ -158,9 +181,9 @@ void USpineSkeletonRendererComponent::TickComponent (float DeltaTime, ELevelTick
} }
} }
UpdateMesh(skeleton->GetSkeleton()); UpdateMesh(skeleton->GetSkeleton());
} else {
ClearAllMeshSections();
} }
else {
ClearAllMeshSections();
} }
} }

View File

@ -195,6 +195,16 @@ public:
virtual void FinishDestroy () override; virtual void FinishDestroy () override;
//Added functions for manual configuration
/* Manages if this skeleton should update automatically or is paused. */
UFUNCTION(BlueprintCallable, Category="Components|Spine|Animation")
void SetAutoPlay(bool bInAutoPlays);
/* Directly set the time of the current animation, will clamp to animation range. */
UFUNCTION(BlueprintCallable, Category = "Components|Spine|Animation")
void SetPlaybackTime(float InPlaybackTime, bool bCallDelegates = true);
// Blueprint functions // Blueprint functions
UFUNCTION(BlueprintCallable, Category="Components|Spine|Animation") UFUNCTION(BlueprintCallable, Category="Components|Spine|Animation")
void SetTimeScale(float timeScale); void SetTimeScale(float timeScale);
@ -255,4 +265,9 @@ protected:
// in transit within a blueprint // in transit within a blueprint
UPROPERTY() UPROPERTY()
TSet<UTrackEntry*> trackEntries; TSet<UTrackEntry*> trackEntries;
private:
/* If the animation should update automatically. */
UPROPERTY()
bool bAutoPlaying;
}; };

View File

@ -90,6 +90,16 @@ public:
UPROPERTY(Category = Spine, EditAnywhere, BlueprintReadWrite) UPROPERTY(Category = Spine, EditAnywhere, BlueprintReadWrite)
bool bCreateCollision; bool bCreateCollision;
/* Updates this renderer with the lastest skeleton info. */
void UpdateRenderer();
/* Obtains the cached SkeletonComponent */
USpineSkeletonComponent* GetSkeleton() const;
/* Sets the cached SkeletonComponent */
void SetSkeleton(USpineSkeletonComponent* InSkeleton);
/* Called when the component is destroyed */
virtual void FinishDestroy() override; virtual void FinishDestroy() override;
protected: protected:
@ -99,4 +109,8 @@ protected:
spine::Vector<float> worldVertices; spine::Vector<float> worldVertices;
spine::SkeletonClipping clipper; spine::SkeletonClipping clipper;
private:
/* Cached skeleton to use to avoid Find functions on TICK */
TWeakObjectPtr<USpineSkeletonComponent> CachedSkeleton;
}; };