2024.08.02
깃허브! | 풀리퀘! |
---|---|
★ https://github.com/ChangJin-Lee/Project-Lena | ★ https://github.com/ChangJin-Lee/Project-Lena/pull/16 |
이번 포스팅에서는 아이템 캡처 이미지 저장 및 충돌 처리와 관련된 문제를 해결하는 과정을 다룹니다. SceneCaptureComponent2D를 활용한 이미지 캡처 방법, 다중 충돌 처리, 그리고 히트 결과를 효과적으로 필터링하는 방법을 설명합니다.
상호작용 관련 Class 상속 관계도 |
인벤토리 관련 Class 상속 관계도 |
SceneCaptureComponent2D와 RenderTarget을 설정하고, 캡처한 이미지를 렌더 타깃으로 내보내기 위해 다음과 같은 작업을 수행했습니다.
먼저, SceneCaptureComponent2D
를 설정하여 특정 메시 컴포넌트만 캡처하고, 이를 RenderTarget에 저장하는 코드를 작성합니다.
void ABase_Item::BeginPlay()
{
Super::BeginPlay();
// SceneCaptureComponent2D 설정
SceneCaptureComponent2D->TextureTarget = RenderTarget;
SceneCaptureComponent2D->ShowOnlyComponent(MeshComponent); // 특정 메시 컴포넌트만 캡처
SceneCaptureComponent2D->CaptureScene();
}
Create Material
옵션을 선택합니다.User Interface
로 설정하고, 블렌드 모드를 Translucent
로 변경합니다.Base Color
에, 알파 값을 Opacity
에 연결합니다.SceneCaptureComponent2D로 캡처한 이미지를 RenderTarget에 저장하고, 이를 Material로 변환하여 UI에서 사용할 수 있도록 합니다. 이를 통해 동적으로 캡처한 이미지를 게임 내 UI에 표시할 수 있습니다.
void ABase_Item::CaptureSceneAndSaveImage()
{
if (SceneCaptureComponent2D && RenderTarget)
{
// Capture the scene
SceneCaptureComponent2D->CaptureScene();
// Save the RenderTarget as a Texture
FString Directory = FPaths::ProjectContentDir() / TEXT("RenderTargets");
FString FileName = TEXT("CapturedImage");
IPlatformFile& PlatformFile = FPlatformFileManager::Get().GetPlatformFile();
if (!PlatformFile.DirectoryExists(*Directory))
{
PlatformFile.CreateDirectoryTree(*Directory);
}
FString AbsoluteFilePath = Directory / (FileName + TEXT(".png"));
FTextureRenderTargetResource* RenderTargetResource = RenderTarget->GameThread_GetRenderTargetResource();
TArray<FColor> OutBMP;
FReadSurfaceDataFlags ReadPixelFlags(RCM_UNorm);
ReadPixelFlags.SetLinearToGamma(false);
RenderTargetResource->ReadPixels(OutBMP, ReadPixelFlags);
// Compress image array to PNG format using PNGCompressImageArray
TArray64<uint8> CompressedPNG;
FImageUtils::PNGCompressImageArray(RenderTarget->SizeX, RenderTarget->SizeY, OutBMP, CompressedPNG);
if (FFileHelper::SaveArrayToFile(CompressedPNG, *AbsoluteFilePath))
{
UE_LOG(LogTemp, Log, TEXT("Successfully saved screenshot to %s"), *AbsoluteFilePath);
}
else
{
UE_LOG(LogTemp, Error, TEXT("Failed to save screenshot to %s"), *AbsoluteFilePath);
}
}
}
위 코드를 통해 SceneCaptureComponent2D로 캡처한 이미지를 RenderTarget에 저장하고, 이를 Material로 변환하여 UI에 표시할 수 있습니다.
아이템이 스폰될 때, 동일한 액터 내의 여러 메시 컴포넌트로 인해 다중 충돌이 발생하는 문제를 해결하기 위해 TSet을 사용하여 중복된 충돌 결과를 필터링했습니다.
void AShooterPlayerController::CheckPickUpItemSweep()
{
ACharacter* Character_ = UGameplayStatics::GetPlayerCharacter(GetWorld(), 0);
FVector Start = Character_->GetActorLocation();
FVector End = Character_->GetActorLocation();
TArray<FHitResult> HitResults;
FCollisionQueryParams Params;
float Radius = 130.0f;
if (GetWorld()->SweepMultiByChannel(HitResults, Start, End, FQuat::Identity, ECC_Visibility, FCollisionShape::MakeSphere(Radius), Params))
{
Base_Character->GroundItemsComponent->Items.Empty();
for (FHitResult HitResult : HitResults)
{
AActor* HitActor = HitResult.GetActor();
if (HitActor)
{
ABase_Item* Item = Cast<ABase_Item>(HitActor);
if (Item)
{
UE_LOG(LogTemp, Warning, TEXT("HitResults.Num() : %s"), *Item->GetName());
if (Base_Character)
{
Base_Character->CheckGroundItem(Item);
}
}
}
}
}
}
void AShooterPlayerController::CheckPickUpItemSweep()
{
ACharacter* Character_ = UGameplayStatics::GetPlayerCharacter(GetWorld(), 0);
FVector Start = Character_->GetActorLocation();
FVector End = Character_->GetActorLocation();
TArray<FHitResult> HitResults;
FCollisionQueryParams Params;
float Radius = 130.0f;
if (GetWorld()->SweepMultiByChannel(HitResults, Start, End, FQuat::Identity, ECC_Visibility, FCollisionShape::MakeSphere(Radius), Params))
{
TSet<AActor*> ProcessedActors;
Base_Character->GroundItemsComponent->Items.Empty();
for (FHitResult HitResult : HitResults)
{
AActor* HitActor = HitResult.GetActor();
if (HitActor && !ProcessedActors.Contains(HitActor))
{
ProcessedActors.Add(HitActor);
ABase_Item* Item = Cast<ABase_Item>(HitActor);
if (Item)
{
UE_LOG(LogTemp, Warning, TEXT("HitResults.Num() : %s"), *Item->GetName());
if (Base_Character)
{
Base_Character->CheckGroundItem(Item);
}
}
}
}
}
}
이 개선된 코드에서는 TSet
을 사용하여 중복된 히트 결과를 제거하고, 각 액터에 대해 한 번만 처리되도록 했습니다.
SceneCaptureComponent2D로 캡처한 이미지를 UI에 표시하기 위해 다음과 같은 작업을 수행했습니다. 캡처한 이미지를 Material로 만들고, 이 Material을 UI에 표시했습니다. UI에서는 아이템에 해당하는 메테리얼이 Valid한지 체크하고 이를 반환하여 이미지에서 보여주도록 만들었습니다.
Make Brush from Matatial, Texture로 이미지를 반환하는 부분 |
아이템 이름에 해당하는 메테리얼을 반환하는 부분 |
이번 작업을 통해 SceneCaptureComponent2D를 활용한 아이템 이미지 캡처 및 저장 기능을 구현하고, 다중 충돌 결과를 효과적으로 필터링하는 방법을 배웠습니다.