[UE4] AnimNotifiy의 Play Particle Effect 부하를 UE4 표준 Object Pool 기능으로 줄이자!
17991 단어 위 4UnrealEngineUnrealEngine4
소개
UE4의 애니메이션 알림(AnimNotify) 기능 중 하나인 Play Particle Effect( UAnimNotify_PlayParticleEffect
)를 사용하여 캐릭터의 움직임에 맞게 효과를 재생하도록 하는 것이 일반적일까 생각합니다. 예를 들어 달리고있는 캐릭터의 다리가 땅에 도착했을 때 모래 연기를 내거나 공격 모션 중에 불꽃과 궤적을 내거나 ...
htps : // / cs. 그래, 응. 코 m/쟈/엔기네/아니마치온/세쿠엔세 s/의 치후에에 s/그리고 x. html # p ぁ y ぱ rc ぇ 에후 ぇ ct
그러나, 대량의 캐릭터가 돌아다니는 콘텐츠의 경우, 대량의 이펙트가 동시에 생성·재생되는 것에 의한 처리 부하가 문제가 되는 경우가 많습니다…
따라서이 기사에서는 이전에 소개 한 Spawn Emitter~
노드의 Pooling Method를 사용하여 부하를 개선하는 방법에 대해 설명합니다.
Spawn Emitter ~ 노드의 Pooling Method 란 무엇입니까?
Pooling Method 유효판의 Play Particle Effect를 Blueprint로 만들자!
주식회사 히스토리아님의 기술 블로그 [UE4] 독자적인 Animation Notify 구현 방법 에서 설명한 대로, Blueprint를 사용해 독자적인 AnimNotify/AnimNotifyState를 만들 수 있습니다. 이 기능을 사용하여 Pooling Method를 활성화한 UAnimNotify_PlayParticleEffect
를 만들면 이번 목표를 달성할 수 있습니다! 이것만 들으면 어렵게 느낄지도 모릅니다만, UAnimNotify_PlayParticleEffect
는 내부에서 SpawnEmitter~
처리를 호출하고 있을 뿐이므로 간단합니다!
AnimNotify_PlayPArticleEffect.cppUParticleSystemComponent* UAnimNotify_PlayParticleEffect::SpawnParticleSystem(class USkeletalMeshComponent* MeshComp, class UAnimSequenceBase* Animation)
{
UParticleSystemComponent* ReturnComp = nullptr;
if (PSTemplate)
{
if (PSTemplate->IsLooping())
{
UE_LOG(LogParticles, Warning, TEXT("Particle Notify: Anim '%s' tried to spawn infinitely looping particle system '%s'. Spawning suppressed."), *GetNameSafe(Animation), *GetNameSafe(PSTemplate));
return ReturnComp;
}
if (Attached)
{
ReturnComp = UGameplayStatics::SpawnEmitterAttached(PSTemplate, MeshComp, SocketName, LocationOffset, RotationOffset, Scale);
}
else
{
const FTransform MeshTransform = MeshComp->GetSocketTransform(SocketName);
FTransform SpawnTransform;
SpawnTransform.SetLocation(MeshTransform.TransformPosition(LocationOffset));
SpawnTransform.SetRotation(MeshTransform.GetRotation() * RotationOffsetQuat);
SpawnTransform.SetScale3D(Scale);
ReturnComp = UGameplayStatics::SpawnEmitterAtLocation(MeshComp->GetWorld(), PSTemplate, SpawnTransform);
}
}
else
{
UE_LOG(LogParticles, Warning, TEXT("Particle Notify: Particle system is null for particle notify '%s' in anim: '%s'"), *GetNotifyName(), *GetPathNameSafe(Animation));
}
return ReturnComp;
}
라고 하는 것으로, 참고 기사로 해설되고 있는 대로 「Notify 클래스를 계승한 BP를 작성」하고, 「Received_Notify」에 상기의 코드와 같은 구현을 BP로 써 갑니다.
갸리코리… 카리카리…
… 할 수 있었습니다!
Before
After
초엄밀한 비교라고 하는 것은 아니지만, Spawn Emitter ~ 노드의 Pooling Method 란 무엇입니까? 에서 설명한 대로, Pooling Method를 활용하는 것으로 일부 처리를 생략할 수 있었던 것으로 부하가 개선하고 있습니다. 이번 프로필 환경은 적당히 좋은 PC + 심플한 이펙트라고 하는 것으로 12 μs 라고 하는 약간의 개선이었습니다만 환경·조건에 따라서는 무시할 수 없을 정도의 개선이 되는 경우도 있습니다 (예:저스펙인 모바일 단말상에서 움직인다 , 수십체 이상의 캐릭터가 동시에 몇개의 이펙트를 자주 내는 컨텐츠).
프로파일링했을 때 UAnimNotify_PlayParticleEffect
의 부하가 눈에 띄는 때는 꼭 Pooling Method를 활용하는 방법으로의 전환을 검토해 보세요!
덤 : 이번에 설명한 자작 AnimNotify의 과제 「Socket Name의 예측이 나오지 않는다」에 대해
UAnimNotify_PlayParticleEffect
의 속성인 Socket Name
, 문자를 입력하면 예측을 해줍니다. 편리합니다.
한편, 이번 자작한 AnimNotify는...내주지 않습니다! 「아이에에에! 같은 프로퍼티명・같은 Name형인데 난데!?」라고 생각했기 때문에 조사해 보았습니다.
AnimNotifyDetails.cppbool FAnimNotifyDetails::CustomizeProperty(IDetailCategoryBuilder& CategoryBuilder, UObject* Notify, TSharedPtr<IPropertyHandle> Property)
{
if(Notify && Notify->GetClass() && Property->IsValidHandle())
{
FString ClassName = Notify->GetClass()->GetName();
FString PropertyName = Property->GetProperty()->GetName();
bool bIsBoneName = Property->GetBoolMetaData(TEXT("AnimNotifyBoneName"));
if(ClassName.Find(TEXT("AnimNotify_PlayParticleEffect")) != INDEX_NONE && PropertyName == TEXT("SocketName"))
{
AddBoneNameProperty(CategoryBuilder, Notify, Property);
return true;
}
else if(ClassName.Find(TEXT("AnimNotifyState_TimedParticleEffect")) != INDEX_NONE && PropertyName == TEXT("SocketName"))
{
AddBoneNameProperty(CategoryBuilder, Notify, Property);
return true;
}
else if(ClassName.Find(TEXT("AnimNotify_PlaySound")) != INDEX_NONE && PropertyName == TEXT("AttachName"))
{
AddBoneNameProperty(CategoryBuilder, Notify, Property);
return true;
}
else if (ClassName.Find(TEXT("AnimNotifyState_Trail")) != INDEX_NONE)
{
if(PropertyName == TEXT("FirstSocketName") || PropertyName == TEXT("SecondSocketName"))
{
AddBoneNameProperty(CategoryBuilder, Notify, Property);
return true;
}
else if(PropertyName == TEXT("WidthScaleCurve"))
{
AddCurveNameProperty(CategoryBuilder, Notify, Property);
return true;
}
}
else if (bIsBoneName)
{
AddBoneNameProperty(CategoryBuilder, Notify, Property);
return true;
}
}
return false;
}
특정의 클래스가 특정의 이름의 프로퍼티를 가지거나 UPROPERTY의 meta로 AnimNotifyBoneName가 유효하게 되어 있는 경우는 본 소켓명의 예측이 나오게 된다고 하는 사양이었습니다. 따라서 위의 코드에 없는 클래스에서 예측을 실행하려면 다음과 같이 AnimNotifyBoneName을 활성화해야 합니다.
UPROPERTY(EditAnywhere, meta = (AnimNotifyBoneName = "true"))
BP의 경우는 ... 죄송합니다 ... 할 수 없어야합니다 ....
라고 하는 것으로, Pooling Method 유효판의 UAnimNotify_PlayParticleEffect
를 진심으로 만드는 경우는 UAnimNotify_PlayParticleEffect
를 개조, 또는 계승한 클래스에서 Pooling Method를 AnimNotify의 상세 패널로부터 설정할 수 있는 형태로 하는 것이 좋을까 생각합니다.
오시마
Reference
이 문제에 관하여([UE4] AnimNotifiy의 Play Particle Effect 부하를 UE4 표준 Object Pool 기능으로 줄이자!), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다
https://qiita.com/EGJ-Kaz_Okada/items/c9408aea9c0984f92849
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념
(Collection and Share based on the CC Protocol.)
주식회사 히스토리아님의 기술 블로그 [UE4] 독자적인 Animation Notify 구현 방법 에서 설명한 대로, Blueprint를 사용해 독자적인 AnimNotify/AnimNotifyState를 만들 수 있습니다. 이 기능을 사용하여 Pooling Method를 활성화한
UAnimNotify_PlayParticleEffect
를 만들면 이번 목표를 달성할 수 있습니다! 이것만 들으면 어렵게 느낄지도 모릅니다만, UAnimNotify_PlayParticleEffect
는 내부에서 SpawnEmitter~
처리를 호출하고 있을 뿐이므로 간단합니다!AnimNotify_PlayPArticleEffect.cpp
UParticleSystemComponent* UAnimNotify_PlayParticleEffect::SpawnParticleSystem(class USkeletalMeshComponent* MeshComp, class UAnimSequenceBase* Animation)
{
UParticleSystemComponent* ReturnComp = nullptr;
if (PSTemplate)
{
if (PSTemplate->IsLooping())
{
UE_LOG(LogParticles, Warning, TEXT("Particle Notify: Anim '%s' tried to spawn infinitely looping particle system '%s'. Spawning suppressed."), *GetNameSafe(Animation), *GetNameSafe(PSTemplate));
return ReturnComp;
}
if (Attached)
{
ReturnComp = UGameplayStatics::SpawnEmitterAttached(PSTemplate, MeshComp, SocketName, LocationOffset, RotationOffset, Scale);
}
else
{
const FTransform MeshTransform = MeshComp->GetSocketTransform(SocketName);
FTransform SpawnTransform;
SpawnTransform.SetLocation(MeshTransform.TransformPosition(LocationOffset));
SpawnTransform.SetRotation(MeshTransform.GetRotation() * RotationOffsetQuat);
SpawnTransform.SetScale3D(Scale);
ReturnComp = UGameplayStatics::SpawnEmitterAtLocation(MeshComp->GetWorld(), PSTemplate, SpawnTransform);
}
}
else
{
UE_LOG(LogParticles, Warning, TEXT("Particle Notify: Particle system is null for particle notify '%s' in anim: '%s'"), *GetNotifyName(), *GetPathNameSafe(Animation));
}
return ReturnComp;
}
라고 하는 것으로, 참고 기사로 해설되고 있는 대로 「Notify 클래스를 계승한 BP를 작성」하고, 「Received_Notify」에 상기의 코드와 같은 구현을 BP로 써 갑니다.
갸리코리… 카리카리…
… 할 수 있었습니다!
Before
After
초엄밀한 비교라고 하는 것은 아니지만, Spawn Emitter ~ 노드의 Pooling Method 란 무엇입니까? 에서 설명한 대로, Pooling Method를 활용하는 것으로 일부 처리를 생략할 수 있었던 것으로 부하가 개선하고 있습니다. 이번 프로필 환경은 적당히 좋은 PC + 심플한 이펙트라고 하는 것으로 12 μs 라고 하는 약간의 개선이었습니다만 환경·조건에 따라서는 무시할 수 없을 정도의 개선이 되는 경우도 있습니다 (예:저스펙인 모바일 단말상에서 움직인다 , 수십체 이상의 캐릭터가 동시에 몇개의 이펙트를 자주 내는 컨텐츠).
프로파일링했을 때
UAnimNotify_PlayParticleEffect
의 부하가 눈에 띄는 때는 꼭 Pooling Method를 활용하는 방법으로의 전환을 검토해 보세요!덤 : 이번에 설명한 자작 AnimNotify의 과제 「Socket Name의 예측이 나오지 않는다」에 대해
UAnimNotify_PlayParticleEffect
의 속성인 Socket Name
, 문자를 입력하면 예측을 해줍니다. 편리합니다.
한편, 이번 자작한 AnimNotify는...내주지 않습니다! 「아이에에에! 같은 프로퍼티명・같은 Name형인데 난데!?」라고 생각했기 때문에 조사해 보았습니다.
AnimNotifyDetails.cppbool FAnimNotifyDetails::CustomizeProperty(IDetailCategoryBuilder& CategoryBuilder, UObject* Notify, TSharedPtr<IPropertyHandle> Property)
{
if(Notify && Notify->GetClass() && Property->IsValidHandle())
{
FString ClassName = Notify->GetClass()->GetName();
FString PropertyName = Property->GetProperty()->GetName();
bool bIsBoneName = Property->GetBoolMetaData(TEXT("AnimNotifyBoneName"));
if(ClassName.Find(TEXT("AnimNotify_PlayParticleEffect")) != INDEX_NONE && PropertyName == TEXT("SocketName"))
{
AddBoneNameProperty(CategoryBuilder, Notify, Property);
return true;
}
else if(ClassName.Find(TEXT("AnimNotifyState_TimedParticleEffect")) != INDEX_NONE && PropertyName == TEXT("SocketName"))
{
AddBoneNameProperty(CategoryBuilder, Notify, Property);
return true;
}
else if(ClassName.Find(TEXT("AnimNotify_PlaySound")) != INDEX_NONE && PropertyName == TEXT("AttachName"))
{
AddBoneNameProperty(CategoryBuilder, Notify, Property);
return true;
}
else if (ClassName.Find(TEXT("AnimNotifyState_Trail")) != INDEX_NONE)
{
if(PropertyName == TEXT("FirstSocketName") || PropertyName == TEXT("SecondSocketName"))
{
AddBoneNameProperty(CategoryBuilder, Notify, Property);
return true;
}
else if(PropertyName == TEXT("WidthScaleCurve"))
{
AddCurveNameProperty(CategoryBuilder, Notify, Property);
return true;
}
}
else if (bIsBoneName)
{
AddBoneNameProperty(CategoryBuilder, Notify, Property);
return true;
}
}
return false;
}
특정의 클래스가 특정의 이름의 프로퍼티를 가지거나 UPROPERTY의 meta로 AnimNotifyBoneName가 유효하게 되어 있는 경우는 본 소켓명의 예측이 나오게 된다고 하는 사양이었습니다. 따라서 위의 코드에 없는 클래스에서 예측을 실행하려면 다음과 같이 AnimNotifyBoneName을 활성화해야 합니다.
UPROPERTY(EditAnywhere, meta = (AnimNotifyBoneName = "true"))
BP의 경우는 ... 죄송합니다 ... 할 수 없어야합니다 ....
라고 하는 것으로, Pooling Method 유효판의 UAnimNotify_PlayParticleEffect
를 진심으로 만드는 경우는 UAnimNotify_PlayParticleEffect
를 개조, 또는 계승한 클래스에서 Pooling Method를 AnimNotify의 상세 패널로부터 설정할 수 있는 형태로 하는 것이 좋을까 생각합니다.
오시마
Reference
이 문제에 관하여([UE4] AnimNotifiy의 Play Particle Effect 부하를 UE4 표준 Object Pool 기능으로 줄이자!), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다
https://qiita.com/EGJ-Kaz_Okada/items/c9408aea9c0984f92849
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념
(Collection and Share based on the CC Protocol.)
bool FAnimNotifyDetails::CustomizeProperty(IDetailCategoryBuilder& CategoryBuilder, UObject* Notify, TSharedPtr<IPropertyHandle> Property)
{
if(Notify && Notify->GetClass() && Property->IsValidHandle())
{
FString ClassName = Notify->GetClass()->GetName();
FString PropertyName = Property->GetProperty()->GetName();
bool bIsBoneName = Property->GetBoolMetaData(TEXT("AnimNotifyBoneName"));
if(ClassName.Find(TEXT("AnimNotify_PlayParticleEffect")) != INDEX_NONE && PropertyName == TEXT("SocketName"))
{
AddBoneNameProperty(CategoryBuilder, Notify, Property);
return true;
}
else if(ClassName.Find(TEXT("AnimNotifyState_TimedParticleEffect")) != INDEX_NONE && PropertyName == TEXT("SocketName"))
{
AddBoneNameProperty(CategoryBuilder, Notify, Property);
return true;
}
else if(ClassName.Find(TEXT("AnimNotify_PlaySound")) != INDEX_NONE && PropertyName == TEXT("AttachName"))
{
AddBoneNameProperty(CategoryBuilder, Notify, Property);
return true;
}
else if (ClassName.Find(TEXT("AnimNotifyState_Trail")) != INDEX_NONE)
{
if(PropertyName == TEXT("FirstSocketName") || PropertyName == TEXT("SecondSocketName"))
{
AddBoneNameProperty(CategoryBuilder, Notify, Property);
return true;
}
else if(PropertyName == TEXT("WidthScaleCurve"))
{
AddCurveNameProperty(CategoryBuilder, Notify, Property);
return true;
}
}
else if (bIsBoneName)
{
AddBoneNameProperty(CategoryBuilder, Notify, Property);
return true;
}
}
return false;
}
UPROPERTY(EditAnywhere, meta = (AnimNotifyBoneName = "true"))
Reference
이 문제에 관하여([UE4] AnimNotifiy의 Play Particle Effect 부하를 UE4 표준 Object Pool 기능으로 줄이자!), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://qiita.com/EGJ-Kaz_Okada/items/c9408aea9c0984f92849텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)