본문 바로가기

프로그래밍/Unreal

[UE4] 이미지 파일 동적으로 로드하기

참고 : https://wiki.unrealengine.com/Asynchronous_Image_Loading_from_Disk


이미지 동적 로딩관련해서 위 위키에 잘 정리되어 있다. 

동일한 내용이지만 관련 내용을 순서에 따라 정리해본다.




모듈

이미지를 동적으로 불러오기 위해서는 ImageWrapper, RenderCore 모듈이 필요한데,

RenderCore에는 버텍스, 텍스처, 버퍼, 렌더링 관련 기능을 제공하고, ImageWrapper는 이미지의 포맷과 raw 데이터 관련 인터페이스를 제공한다.


프로젝트의 .Build.cs 에 모듈을 추가한다.


PrivateDependencyModuleNames.AddRange(new string[] { "ImageWrapper", "RenderCore"});




관련헤더

Runtime/Core/Public/PixelFormat.h

Runtime/Core/public/Misc/FileHelper.h

Runtime/ImageWrapper/Public/IImageWrapper.h

Runtime/RenderCore/Public/RenderUtils.h

Runtime/Engine/Classes/Engine/Texture2D.h




헤더설정

UCLASS(BlueprintType)

class MY_MODULE_API UImageLoader : public UObject

{

GENERATED_BODY()


public:

위키에서는 static 메써드로 구성되어 있고, 기본 UObject* 입력인 outer는 self로 지정되어 있다. 

비동기 처리를 위한 메쏘드와 일반 로딩메쏘드로 구성.


UFUNCTION(BlueprintCallable, Category = ImageLoader, meta=(HidePin="Outer",DefaultToSelf="Outer"))

static UImageLoader* LoadImageFromDiskAsync( UObject* Outer, const FString& ImagePath );


UFUNCTION(BlueprintCallable, Category = ImageLoader, meta=(HidePin="Outer",DefaultToSelf="Outer"))

static UTexture2D* LoadImageFromDisk( UObject* Outer, const FString& ImagePath );



public:

결과를 저장할 멤버 : Async

TFuture<UTexture2D*> Future;


비동기 작업 처리 메쏘드

void LoadImageTask( UObject* Outer, const FString& ImagePath );

}




LoadImageFromDiskAsync 메쏘드에서는 NewObject 를 통해 UImageLoader 객체를 생성하고, LoadImageTask 를 호출해 준다.

LoadImageTask 에서는 Async 로 LoadImageFromDisk 메쏘드를 호출해 실제 이미지를 로드해 텍스처로 변환.

이후 별도 딜리게이트 등으로 Future->Get() 값을 전달하면 된다.



모듈 인터페이스 얻기

IImageWrapperModule& ImageWrapperModule = FModuleManager::LoadModuleChecked<IImageWrapperModule>(TEXT("ImageWrapper"));




파일 읽기

FString ImagePath;  

TArray<uint8> FileData;



if( FPaths::FileExists( ImagePath ) )

{


}


if( FFileHelper::LoadFileToArray( FileData, *ImagePath) )

{


}




이미지 포맷

EImageFormat::Type ImageFormat = ImageWrapperModule.DetectImageFormat( FileData.GetData(), FileData.Num());




이미지 래퍼

IImageWrapperPtr ImageWrapper = ImageWrapperModule.CreateImageWrapper( ImageFormat );




이미지 디코딩

const TArray<uint8>* RawData = nullptr;

ImageWrapper->SetCompressed( FileData.GetData(), FileData.Num());

ImageWrapper->GetRaw(ERGBFormat::BGRA, 8, RawData);





텍스처 생성


NewObject 로 생성

FString TexturFileName = TEXT("T_") + FPath::GetBaseFileName( ImagePath );

FName BaseName = FName(*TexturFileName );

FName TextureName = MakeUniqueObjectName( Outer, UTexture2D::StaticClass(), BaseName);

UTexture2D* NewTexture = NewObject<UTexture2D>(Outer, TextureName, RF_Transient);


NewTexture->PlatformData = new FTexturePlatformData();

NewTexture->PlatformData->SizeX = ImageWrapper->GetWidth();

NewTexture->PlatformData->SizeY =  ImageWrapper->GetHeight();

NewTexture->PlatformData->PixelFormat = EPixelFormat::PF_B8G8R8A8;




UTexture2D::CreateTransient 를 사용해 생성

UTexture2D* NewTexture = UTexture2D::CreateTransient

ImageWrapper->GetWidth(),

ImageWrapper->GetHeight(),

 EPixelFormat::PF_B8G8R8A8 );




MipMap 데이터 복사

// mipmap을 위한 블럭 사이즈를 설정한다.

int32 NumBlocksX = ImageWrapper->GetWidth() / GPixelFormats[EPixelFormat::PF_B8G8R8A8].BlockSizeX;

int32 NumBlocksY = ImageWrapper->GetHeight() / GPixelFormats[EPixelFormat::PF_B8G8R8A8].BlockSizeY;



// MipMap 배열 생성

FTexture2DMipMap* Mip = new(NewTexture->PlatformData->Mips) FTexture2DMipMap();

Mip->SizeX = ImageWrapper->GetWidth();

Mip->SizeY = ImageWrapper->GetHeight();


// minmap을 lock 하고, 실제 블럭 사이즈에 맞게 재할당

Mip->BulkData.Lock(LOCK_READ_WRITE);

void* TextureData = Mip->BulkData.Realloc( 

NumBlocksX * NumBlocksY * GPixelFormats[EPixelFormat::PF_B8G8R8A8].BlockBytes);


// 복사

FMemory::Memcpy(TextureData, (*RawData).GetData(), (*RawData).Num());


Mip->BulkData.Unlock();




단일 MipMap을 사용하는 경우

FTexture2DMipMap *Mip = &NewTexture->PlatformData->Mips[0];

void* TextureData = Mip->BulkData.Lock(LOCK_READ_WRITE);

FMemory::Memcpy(TextureData, (*RawData).GetData(), (*RawData).Num());

Mip->BulkData.Unlock();





업데이트


NewTexture->UpdateResource();







'프로그래밍 > Unreal' 카테고리의 다른 글

[UE4] 언리얼 엔진 빌드  (1) 2018.06.01
[UE4] Dedicated Server  (0) 2018.05.31
[UE4] Using Static Library  (0) 2018.03.16
[UE4] VR 컨트롤러 IK  (0) 2018.01.24
[UE4] 관람자 화면  (0) 2018.01.04
[UE4] 동적 텍스처  (0) 2017.12.18
[UE4] 디버그 로그 출력  (0) 2017.11.13
[UE4] 유리 매터리얼  (0) 2017.10.15
[UE4] 레벨 스트리밍  (0) 2017.10.15
[UE4] UI 관련 내용  (0) 2017.09.26