The Download Image node returns a UTexture2DDynamic but this plugin function that I use requires a UTexture2D. How do I convert between the two?
An answer in Blueprint or C++ will suffice.
The Download Image node returns a UTexture2DDynamic but this plugin function that I use requires a UTexture2D. How do I convert between the two?
An answer in Blueprint or C++ will suffice.
Hi DanimalsOnParade
Since UTexture2D and UTexture2DDynamic are different stuff with UTexture as base, you cannot convert directly or cast, you have 2 options here!,
1.- Make a new node to transform between UTexture2DDynamic to UTexture2D as follows:
UTexture2D* Texture2DDynamicToTexture2D(UTexture2DDynamic* Texture)
{
UTexture2D* ResultTexture;
ENQUEUE_UNIQUE_RENDER_COMMAND_TWOPARAMETER(
FConvertTextures,
FTexture2DDynamicResource*, TextureResource, static_cast<FTexture2DDynamicResource*>(Texture->Resource),
UTexture2D*, ResultTexture, ResultTexture,
{
FTexture2DRHIParamRef TextureRHI = TextureResource->GetTexture2DRHI();
int32 Width = TextureRHI->GetSizeX();
int32 Height = TextureRHI->GetSizeY();
uint32 DestStride = 0;
uint8* ReadData = reinterpret_cast<uint8*>(RHILockTexture2D(TextureRHI, 0, RLM_ReadOnly, DestStride, false, false));
ResultTexture = UTexture2D::CreateTransient(Width, Height);
FTexture2DMipMap& Mip = ResultTexture->PlatformData->Mips[0];
uint8* Data = (uint8*)Mip.BulkData.Lock(LOCK_READ_WRITE);
FMemory::Memcpy(Data, ReadData, Width * Height * 4);
Mip.BulkData.Unlock();
ResultTexture->UpdateResource();
});
return ResultTexture;
}
Summary
The problem with the first approach is very obvious you are duplicating textures in memory for a moment which is not bad if you dont mind, I would like the second method to be honest, is cleaner, only that memory and that is all
Hope helps
Cheers!
Hi ZkarmaKun thank you for your reply!
I tried your C++ code but it resulted in errors during the linking stage:
BasePlayerController.h
#pragma once
#include "CoreMinimal.h"
#include "Engine/Texture2D.h"
#include "Engine/Texture2DDynamic.h"
#include "GameFramework/PlayerController.h"
#include "BasePlayerController.generated.h"
/**
*
*/
UCLASS()
class UNIFORM_API ABasePlayerController : public APlayerController
{
GENERATED_BODY()
public:
UFUNCTION(BlueprintCallable, Category = "BasePlayerController")
UTexture2D* Texture2DDynamicToTexture2D(UTexture2DDynamic* Texture);
};
BasePlayerController.cpp
#include "BasePlayerController.h"
#include "Runtime/RHI/Public/RHI.h"
UTexture2D* ABasePlayerController::Texture2DDynamicToTexture2D(UTexture2DDynamic* Texture)
{
UTexture2D* ResultTexture;
ENQUEUE_UNIQUE_RENDER_COMMAND_TWOPARAMETER(
FConvertTextures,
FTexture2DDynamicResource*, TextureResource, static_cast<FTexture2DDynamicResource*>(Texture->Resource),
UTexture2D*, ResultTexture, ResultTexture,
{
FTexture2DRHIParamRef TextureRHI = TextureResource->GetTexture2DRHI();
int32 Width = TextureRHI->GetSizeX();
int32 Height = TextureRHI->GetSizeY();
uint32 DestStride = 0;
uint8* ReadData = reinterpret_cast<uint8*>(RHILockTexture2D(TextureRHI, 0, RLM_ReadOnly, DestStride, false, false));
ResultTexture = UTexture2D::CreateTransient(Width, Height);
FTexture2DMipMap& Mip = ResultTexture->PlatformData->Mips[0];
uint8* Data = (uint8*)Mip.BulkData.Lock(LOCK_READ_WRITE);
FMemory::Memcpy(Data, ReadData, Width * Height * 4);
Mip.BulkData.Unlock();
ResultTexture->UpdateResource();
});
return ResultTexture;
}
Any ideas?
I solved those errors by added “RHI”, “RenderCore” to the PublicDependencyModuleNames, but the code isn’t working. How am I supposed to use it? Should it be in an Async blueprint like the Download Image node? The compiler complains that ResultTexture may not be initialized so whatever I initialize it to is what is sent to the plugin which makes me think I need it to be async or something.
I got it to work! The problem was in your code ResultTexture wasn’t instantiated so I instantiated it but the pointer was again changed in the render command. Marking this as accepted answer. Thank you!!
Final function for me for anyone else:
UTexture2D * ABasePlayerController::ConvertImage(UTexture2DDynamic * DynTex)
{
int32 Width = DynTex->SizeX;
int32 Height = DynTex->SizeY;
UTexture2D* ResultTexture = UTexture2D::CreateTransient(Width, Height);
ENQUEUE_UNIQUE_RENDER_COMMAND_TWOPARAMETER(
FConvertTextures,
FTexture2DDynamicResource*, TextureResource, static_cast<FTexture2DDynamicResource*>(DynTex->Resource),
UTexture2D*, ResultTexture, ResultTexture,
{
FTexture2DRHIParamRef TextureRHI = TextureResource->GetTexture2DRHI();
int32 Width = TextureRHI->GetSizeX();
int32 Height = TextureRHI->GetSizeY();
uint32 DestStride = 0;
uint8* ReadData = reinterpret_cast<uint8*>(RHILockTexture2D(TextureRHI, 0, RLM_ReadOnly, DestStride, false, false));
FTexture2DMipMap& Mip = ResultTexture->PlatformData->Mips[0];
uint8* Data = (uint8*)Mip.BulkData.Lock(LOCK_READ_WRITE);
FMemory::Memcpy(Data, ReadData, Width * Height * 4);
Mip.BulkData.Unlock();
ResultTexture->UpdateResource();
});
return ResultTexture;
}
Hi!
Does it work properly with any kind of texture? I’m experiencing problems with a downloaded texture, it distorts completely the image to the point of unrecognition. I was wondering if this method stopped working in a newer version of the engine.
Could someone confirm? Thank you!
Hello, i´m trying to implement your code in ue4.26 but when compiling the code visual tells
the function takes too many arguments, I change the macro ENQUEUE_UNIQUE_RENDER_COMMAND_TWOPARAMETER with ENQUEUE_RENDER_COMMAND because in 4.26 it seems not to exit. Do you know why I can´t compile.
thanks