방법
1. 액터를 하나 만든다.
2. 컴포넌트에 PoseableMesh를 추가하고, 설정 값을 바꾼다.
3. 이벤트가 들어오면 2번에서 만들었던 액터를 생성한다. (잔상이니까 내 위치에 생성.)
4. 생성하고 난 뒤, 애니메이션도 복제하도록 설정한다.
5. 잔상에 적용할 머터리얼을 생성한다.
이 때 설정 체크를 해줘야한다.
이걸 체크 안 하면, 오류 뜸.
아마 SkinnedRenderer만 체크하면 대부분 될 것 같다.
나는 캐릭터가 걸치는 망토가 Cloth라서 Clothing도 체크해주었다. (Clothing 체크 안하니까 저렇게 혼종이...)
6. 잔상에 존재하는 머터리얼 개수만큼 생성해서 세팅해준다.
이 머터리얼은 이후에 쓸 것이므로 변수에 저장해둔다.
머터리얼 변수는 Material Instance Dynamic 자료형으로 만들어서 저장해야한다.
이 자료형이여야지 머터리얼 내부의 파라미터 값을 변경할 수 있다.
7. 일정 시간 있다가 사라져야하므로, 머터리얼에 Opacity를 제어할 파라미터를 만든다.
타임라인 노드로 Opacity 값을 바꿔준다.
6번의 머터리얼 세팅이 끝나면 투명화를 시키는 타임라인 노드를 실행시켜준다.
타임라인 노드는 따로 불러서 사용할 수도 있다.
Opacity가 0이 되면, (= 타임라인 노드가 끝나면)
잔상 액터가 사라지도록 만든다.
끝!
사용하고 싶은 곳에 이벤트를 발생시키면 된다.
나는 구르기 애니메이션에 노티파이로 적용했다.
C++로도 구현해보았다.
빠르게 사라지니까 더 멋있는 듯?
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "CPP_GhostTail.generated.h"
class UPoseableMeshComponent;
class UMaterialInstance;
class UMaterialInstanceDynamic;
class USkeletalMeshComponent;
UCLASS()
class PRACTICE_CPP_API ACPP_GhostTail : public AActor
{
GENERATED_BODY()
public:
ACPP_GhostTail();
virtual void Tick(float DeltaTime) override;
public:
void Init(USkeletalMeshComponent* Pawn);
private:
UPoseableMeshComponent* PoseableMesh;
UMaterialInstance* GhostMaterial;
TArray<UMaterialInstanceDynamic*> Materials;
bool IsSpawned = false;
float FadeCountDown;
float FadeOutTime = 0.5f;
};
#include "CPP_GhostTail.h"
#include "Components/PoseableMeshComponent.h"
#include "Kismet/KismetMaterialLibrary.h"
ACPP_GhostTail::ACPP_GhostTail()
{
// Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = true;
PoseableMesh = CreateDefaultSubobject<UPoseableMeshComponent>(TEXT("POSEABLEMESH"));
RootComponent = PoseableMesh;
ConstructorHelpers::FObjectFinder<USkeletalMesh> SK_PoseMesh(TEXT("SkeletalMesh'/Game/PP801_P3/Meshes/Characters/Combines/SK_PP801P3_G.SK_PP801P3_G'"));
if (SK_PoseMesh.Succeeded())
{
PoseableMesh->SetSkeletalMesh(SK_PoseMesh.Object);
}
ConstructorHelpers::FObjectFinder<UMaterialInstance> M_GhostTail(TEXT("MaterialInstanceConstant'/Game/Blueprints/Player/MI_GhostTail.MI_GhostTail'"));
if (M_GhostTail.Succeeded())
{
GhostMaterial = M_GhostTail.Object;
}
}
void ACPP_GhostTail::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
if (IsSpawned)
{
FadeCountDown -= DeltaTime;
for (int i = 0; i < Materials.Num(); i++)
{
Materials[i]->SetScalarParameterValue("Opacity", FadeCountDown/FadeOutTime);
}
if (FadeCountDown < 0)
{
Destroy();
}
}
}
void ACPP_GhostTail::Init(USkeletalMeshComponent* Pawn)
{
PoseableMesh->CopyPoseFromSkeletalComponent(Pawn);
TArray<UMaterialInterface*> Mats = PoseableMesh->GetMaterials();
for (int i = 0; i < Mats.Num(); i++)
{
Materials.Add(UKismetMaterialLibrary::CreateDynamicMaterialInstance(GetWorld(), GhostMaterial));
PoseableMesh->SetMaterial(i, Materials[i]);
}
FadeCountDown = FadeOutTime;
IsSpawned = true;
}
'Unreal' 카테고리의 다른 글
[Unreal BP & C++] 애니메이션 노티파이 (5) | 2021.04.08 |
---|---|
[Unreal BP & C++] Trace로 탐색하기 (0) | 2021.04.01 |
[Unreal C++] CPP 파일 생성/삭제/경로 변경하기 (0) | 2021.03.25 |
[Unreal Error] CPP 컴파일할 때마다 Crash 오류 (2) | 2021.03.24 |
[Material] 디퓨즈 구현하기 (램버트/하프램버트/툰) (0) | 2021.03.22 |