Well I said vector4 since that seems to be how texture data is presented. Basically, I want to be able to get the pixel values of a texture map in a blueprint. For instance, I would like to use a texture map to control placement of actors in a level. As far as I can tell, there’s no way to do that currently. Am I wrong?
Hi , I’ve been using the Load Image node and it’s now a vital part of my software! - As you’re looking into the node again for asset placement thing have you thought of an async loader? I’m loading about 20 2k images into an array and the whole engine locks for about 8 secs while happens. There’s a similar node in the 4.8 which loads URL’s async - I’ve experimented with to load my images but they arrive out of order so I gave up on it. Also - if you take a look at the source of that node - there’s a flag somewhere in it which forces no mipmaps - it might be worth a look to see if you can flag compression or other import options. I of course have no idea with the c++ side as you know so email is as much as I can contribute.
After 4.8 happens things will be easier, for now just add an empty Actor class to your project via File->Add Code to project or using the 4.7 way of adding code.
Then my plugin will get compiled when your game gets packaged!
Thanks for suggestion John!
I will write down to do
Yes I am working on my Load Image node right now actually!
Async = great idea!
option for no mip maps = great idea!
Right now I am trying to get the pixels
I can multi thread the loading of the image, the will be how your BP code will be told properly when the loading process has finished
I will probably need an UImageLoader component to organize and you can ping Victory Image Loader to to ask it if it has finished loading everything.
component could be added to any actor / a new actor that gets spawned on level start
Hey ! Think you could bang out a node for making a Victory Key? Like we feed a string in the format your Key as String into node and it gives us the Key struct back? We need to store our Keybindings in a database and storing them as strings would be best. We’d really appreciate it! Your BP nodes are the best!
As requested I’ve made a node that let’s you load an image from file, and get the pixel data from the image for use in Blueprints!
Very conveniently, the pixel data comes in the Linear Color format so you can directly plug your pixels into Print string nodes or any other node that wants a color in UE4 Blueprints!!
** node is live as of April 17th, 2015 5:43am version!**
**Bonus Just For You ~ Get Pixel by Coordinate!**
And as a bonus, just for you Community members, I've added a node that let's you specify a pixel coordinate and retrieves that value from the pixel data array!
Picture explanation
In the top picture I am loading an image at runtime, and then using print string to display the color values of different pixels within the image, notice how they match correctly in a 5 x 5 image! (it blurs cause of how textures work)
Please note that in the image that is 5 x 5, the lower right corner is 4,4 because picture indices start at 0,0 not 1,1.
**PNG Format**
Please make sure to use .png format for small images if you are wanting to use the pixel data to proceduraly generate world, jpg has compression quality loss that destroys pixel-level precision, especially for small files.
Plugin Download ( Tiny file, about 0.5 MB )
**Latest Download From the UE4 Wiki Site **
**My C++ Code For You**
Here's the C++ code for my new node!
```
UTexture2D* UVictoryBPFunctionLibrary::Victory_LoadTexture2D_FromFile_Pixels(const FString& FullFilePath,EJoyImageFormats ImageFormat,bool& IsValid, int32& Width, int32& Height, TArray<FLinearColor>& OutPixels)
{
//Clear any previous data
OutPixels.Empty();
IsValid = false;
UTexture2D* LoadedT2D = NULL;
IImageWrapperModule& ImageWrapperModule = FModuleManager::LoadModuleChecked<IImageWrapperModule>(FName("ImageWrapper"));
// Note: PNG format. Other formats are supported
IImageWrapperPtr ImageWrapper = ImageWrapperModule.CreateImageWrapper(GetJoyImageFormat(ImageFormat));
//Load From File
TArray<uint8> RawFileData;
if (!FFileHelper::LoadFileToArray(RawFileData, *FullFilePath)) return NULL;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//Create T2D!
if (ImageWrapper.IsValid() && ImageWrapper->SetCompressed(RawFileData.GetData(), RawFileData.Num()))
{
const TArray<uint8>* UncompressedBGRA = NULL;
if (ImageWrapper->GetRaw(ERGBFormat::BGRA, 8, UncompressedBGRA))
{
LoadedT2D = UTexture2D::CreateTransient(ImageWrapper->GetWidth(), ImageWrapper->GetHeight(), PF_B8G8R8A8);
//Valid?
if(!LoadedT2D) return NULL;
//~~~~~~~~~~~~~~
//Out!
Width = ImageWrapper->GetWidth();
Height = ImageWrapper->GetHeight();
const TArray<uint8>& ByteArray = *UncompressedBGRA;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
for(int32 v = 0; v < ByteArray.Num(); v+=4)
{
if(!ByteArray.IsValidIndex(v+3))
{
break;
}
const uint8& B = ByteArray[v];
const uint8& G = ByteArray[v+1];
const uint8& R = ByteArray[v+2];
const uint8& A = ByteArray[v+3];
OutPixels.Add(FLinearColor(R,G,B,A));
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//Copy!
void* TextureData = LoadedT2D->PlatformData->Mips[0].BulkData.Lock(LOCK_READ_WRITE);
FMemory::Memcpy(TextureData, UncompressedBGRA->GetData(), UncompressedBGRA->Num());
LoadedT2D->PlatformData->Mips[0].BulkData.Unlock();
//Update!
LoadedT2D->UpdateResource();
}
}
// Success!
IsValid = true;
return LoadedT2D;
}
```
C++ Pixel Core
Here’s the core of my C++ code above where I turn the loaded byte array into Linear Color Pixel data!
Note how the provided format is BGRA so I have to re-arrange the values when I send them out to the FLinearColor constructor!
const TArray<uint8>& ByteArray = *UncompressedBGRA;
for(int32 v = 0; v < ByteArray.Num(); v+=4)
{
if(!ByteArray.IsValidIndex(v+3))
{
break;
}
const uint8& B = ByteArray[v];
const uint8& G = ByteArray[v+1];
const uint8& R = ByteArray[v+2];
const uint8& A = ByteArray[v+3];
OutPixels.Add(FLinearColor(R,G,B,A));
}
Wait hold on a few minutes!, wait about 2-5 minutes and then get my latest version!
I just made the code more efficient by getting the byte data by const reference!
**C++ Pixel Core**
Here's the core of my C++ code above where I turn the loaded byte array into Linear Color Pixel data!
**Note how the provided format is BGRA** so I have to re-arrange the values when I send them out to the FLinearColor constructor!
```
const TArray<uint8>& ByteArray = *UncompressedBGRA;
for(int32 v = 0; v < ByteArray.Num(); v+=4)
{
if(!ByteArray.IsValidIndex(v+3))
{
break;
}
const uint8& B = ByteArray[v];
const uint8& G = ByteArray[v+1];
const uint8& R = ByteArray[v+2];
const uint8& A = ByteArray[v+3];
OutPixels.Add(FLinearColor(R,G,B,A));
}
```
Your question got me thinking, so I fixed the code and made it even more efficient! I am now loading the Texture2D in RGBA format, which is PF_R8G8B8A8.
**My C++ Code, Even More Faster Now!**
Notice how now I am not even storing the const references, **I am plugging directly into the FLinearColor constructor!**
```
UTexture2D* UVictoryBPFunctionLibrary::Victory_LoadTexture2D_FromFile_Pixels(const FString& FullFilePath,EJoyImageFormats ImageFormat,bool& IsValid, int32& Width, int32& Height, TArray<FLinearColor>& OutPixels)
{
//Clear any previous data
OutPixels.Empty();
IsValid = false;
UTexture2D* LoadedT2D = NULL;
IImageWrapperModule& ImageWrapperModule = FModuleManager::LoadModuleChecked<IImageWrapperModule>(FName("ImageWrapper"));
IImageWrapperPtr ImageWrapper = ImageWrapperModule.CreateImageWrapper(GetJoyImageFormat(ImageFormat));
//Load From File
TArray<uint8> RawFileData;
if (!FFileHelper::LoadFileToArray(RawFileData, *FullFilePath)) return NULL;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//Create T2D!
if (ImageWrapper.IsValid() && ImageWrapper->SetCompressed(RawFileData.GetData(), RawFileData.Num()))
{
const TArray<uint8>* UncompressedRGBA = NULL;
if (ImageWrapper->GetRaw(**ERGBFormat::RGBA**, 8, UncompressedRGBA))
{
LoadedT2D = UTexture2D::CreateTransient(ImageWrapper->GetWidth(), ImageWrapper->GetHeight(), ****PF_R8G8B8A8****);
//Valid?
if(!LoadedT2D) return NULL;
//~~~~~~~~~~~~~~
//Out!
Width = ImageWrapper->GetWidth();
Height = ImageWrapper->GetHeight();
const TArray<uint8>& ByteArray = *UncompressedRGBA;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
for(int32 v = 0; v < ByteArray.Num(); v+=4)
{
if(!ByteArray.IsValidIndex(v+3))
{
break;
}
**OutPixels.Add(
FLinearColor(
ByteArray[v], //R
ByteArray[v+1], //G
ByteArray[v+2], //B
ByteArray[v+3] //A
)
);**
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//Copy!
void* TextureData = LoadedT2D->PlatformData->Mips[0].BulkData.Lock(LOCK_READ_WRITE);
FMemory::Memcpy(TextureData, UncompressedRGBA->GetData(), UncompressedRGBA->Num());
LoadedT2D->PlatformData->Mips[0].BulkData.Unlock();
//Update!
LoadedT2D->UpdateResource();
}
}
// Success!
IsValid = true;
return LoadedT2D;
}
```
Load Image From File and Get Pixel Data!
New Node Release Post is here!
**Plugin Download** ( Tiny file, about 0.5 MB )
It's ready now, top-most link, April 17th!
**Latest Download From the UE4 Wiki Site **
https://wiki.unrealengine.com/File:VictoryPlugin.zip
♥
I am going to have to see if I can get an Earth map generated using new node!
Just going to need specifically sized earth textures for each of the data types(Topology, Temperature, Precipitation, etc). Will post here if I make any progress.