Creating the UTexture2D object.
Let’s say we have generated a UTexture2D from C++ within the editor. It could be interesting to save it in order to use later. Let’s have a look on how to do this.
The first step is to create a UTexture2D object. Here, we cannot create a transient texture using UTexture2D::CreateTransient, because if we did so, we would be unable to save the texture (transient objects can’t be saved).
So, we will create a package, and then store a new texture in this package.
FString PackageName = TEXT("/Game/ProceduralTextures/");
PackageName += TextureName;
UPackage* Package = CreatePackage(NULL, *PackageName);
Package->FullyLoad();
UTexture2D* NewTexture = NewObject<UTexture2D>(Package, *TextureName, RF_Public | RF_Standalone | RF_MarkAsRootSet);
Here, we are creating a package “/Game/ProceduralTextures/” and adding a texture named TextureName in this package when calling NewObject<Texture2D>.
Filling the texture with our data.
Once we have our texture, we can initialize it and fill it with our data.
NewTexture->AddToRoot(); // This line prevents garbage collection of the texture
NewTexture->PlatformData = new FTexturePlatformData(); // Then we initialize the PlatformData
NewTexture->PlatformData->SizeX = TextureWidth;
NewTexture->PlatformData->SizeY = TextureHeight;
NewTexture->PlatformData->NumSlices = 1;
NewTexture->PlatformData->PixelFormat = EPixelFormat::PF_B8G8R8A8;
So far, it’s pretty similar to what we do when creating a transient texture: we fill the PlatformData object with the parameters of our texture (width, height, pixel format). Here we are chosing PF_B8G8R8A8 as pixel format, but we could choose any pixel format, as long as we fill the data accordingly after.
Then, it’s time to fill the texture.
uint8* Pixels = new uint8[TextureWidth * TextureHeight * 4];
for (int32 y = 0; y < TextureHeight; y++)
{
for (int32 x = 0; x < TextureWidth; x++)
{
int32 curPixelIndex = ((y * TextureWidth) + x);
Pixels[4 * curPixelIndex] = B;
Pixels[4 * curPixelIndex + 1] = G;
Pixels[4 * curPixelIndex + 2] = R;
Pixels[4 * curPixelIndex + 3] = A;
}
}
There are different ways to fill the texture. In this small code snippet, we’re just creating a pixel array and defining a color for each one. The array size is the Width x Height x Bytes per pixel. As the pixel format is BGRA, there are four bytes per pixel. We may note that the pixels are filled in the order BGRA to match the previously selected pixel format.
Then, we need to populate the texture with the data in the pixel array:
// Allocate first mipmap.
FTexture2DMipMap* Mip = new(NewTexture->PlatformData->Mips) FTexture2DMipMap();
Mip->SizeX = TextureWidth;
Mip->SizeY = TextureHeight;
// Lock the texture so it can be modified
Mip->BulkData.Lock(LOCK_READ_WRITE);
uint8* TextureData = (uint8*) Mip->BulkData.Realloc(TextureWidth * TextureHeight * 4);
FMemory::Memcpy(TextureData, Pixels, sizeof(uint8) * TextureHeight * TextureWidth * 4);
Mip->BulkData.Unlock();
At this point we have generated texture. Now, we want to save it as a new asset.
Saving the texture.
So far, we have only set data in the PlatformData. However, PlatformData is sort of transient and cannot be saved on the disk. To initialize the data in a non-transient field of the texture, we will refer to the Source field.
NewTexture->Source.Init(TextureWidth, TextureHeight, 1, 1, ETextureSourceFormat::TSF_BGRA8, Pixels);
The call to this function will initialize the Source object, setting its width, its height, its pixel format and also the data from the Pixels array.
Finally, we will call SavePackage to save the newly created asset:
NewTexture->UpdateResource();
Package->MarkPackageDirty();
FAssetRegistryModule::AssetCreated(NewTexture);
FString PackageFileName = FPackageName::LongPackageNameToFilename(PackageName, FPackageName::GetAssetPackageExtension());
bool bSaved = UPackage::SavePackage(Package, NewTexture, EObjectFlags::RF_Public | EObjectFlags::RF_Standalone, *PackageFileName, GError, nullptr, true, true, SAVE_NoError);
delete[] Pixels; // Don't forget to free the memory here
Im getting a crash on UpdateResource() command, can’t figure out why… Any ideas?
OH, my problem was the size I assigned to the texture. It was crashing in the TextureCompressorModule because its width and height were not power of 2.
Thank you so much! I had exactly the same problem and you saved me a lot of debugging.
I get same error in the TextureCompressorModule ,but I had set the width and height to be power of 2, is it rigtht?
saviour
I have been using this code for some time, thank you. Lately i have migrated to 4.22 version and I have got deprecation warning on line:
FTexture2DMipMap* Mip = new(NewTexture->PlatformData->Mips) FTexture2DMipMap();
warning C4996: ‘operator new’: Placement new on TIndirectArray has been deprecated – users should call Add() passing a pointer to an object created with new. Please update your code to the new API before upgrading to the next release, otherwise your project will no longer compile.
I cant see how to rewrite it. Any idea??
FTexture2DMipMap* Mip = new FTexture2DMipMap();
NewTexture->PlatformData->Mips.Add(Mip);
Mip->SizeX = TextureWidth;
Mip->SizeY = TextureHeight;
Great tutorial. Do you happen to know where UTexture2D.PlatformData is getting destroyed? I can seem to find this in the engine anywhere but not sure if i’m misunderstanding something as my pointer knowledge is a little rusty…
For anyone that got stuck like me trying to make a HDR texture package out of a Linear Color array – you need to first convert to FFloat16Color and use Pixel Format PF_FloatRGBA.
Heres my example code.
TArray colors;
colors.SetNum(_data.Num());
for (int32 i = 0; i PlatformData = new FTexturePlatformData();
_tex->PlatformData->SizeX = _width;
_tex->PlatformData->SizeY = _height;
_tex->PlatformData->PixelFormat = PF_FloatRGBA;
_tex->CompressionSettings = TextureCompressionSettings::TC_HDR;
_tex->MipGenSettings = TextureMipGenSettings::TMGS_NoMipmaps;
_tex->SRGB = false;
// Allocate first mipmap.
int32 NumBlocksX = _width / GPixelFormats[PF_FloatRGBA].BlockSizeX;
int32 NumBlocksY = _height / GPixelFormats[PF_FloatRGBA].BlockSizeY;
FTexture2DMipMap* Mip = new FTexture2DMipMap();
_tex->PlatformData->Mips.Add(Mip);
Mip->SizeX = _width;
Mip->SizeY = _height;
Mip->BulkData.Lock(LOCK_READ_WRITE);
void* Data = Mip->BulkData.Realloc(NumBlocksX * NumBlocksY * GPixelFormats[PF_FloatRGBA].BlockBytes);
FMemory::Memcpy(Data, colors.GetData(), _width * _height * GPixelFormats[PF_FloatRGBA].BlockBytes);
Mip->BulkData.Unlock();
_tex->Source.Init(_width, _height, 1, 1, ETextureSourceFormat::TSF_RGBA16F, (uint8*)colors.GetData());
_tex->AddToRoot();
_tex->UpdateResource();
Sorry Copy Paste Error – It cropped out my for loop
TArray colors;
colors.SetNum(_data.Num());
for (int32 i = 0; i PlatformData = new FTexturePlatformData();
_tex->PlatformData->SizeX = _width;
_tex->PlatformData->SizeY = _height;
_tex->PlatformData->PixelFormat = PF_FloatRGBA;
_tex->CompressionSettings = TextureCompressionSettings::TC_HDR;
_tex->MipGenSettings = TextureMipGenSettings::TMGS_NoMipmaps;
_tex->SRGB = false;
// Allocate first mipmap.
int32 NumBlocksX = _width / GPixelFormats[PF_FloatRGBA].BlockSizeX;
int32 NumBlocksY = _height / GPixelFormats[PF_FloatRGBA].BlockSizeY;
FTexture2DMipMap* Mip = new FTexture2DMipMap();
_tex->PlatformData->Mips.Add(Mip);
Mip->SizeX = _width;
Mip->SizeY = _height;
Mip->BulkData.Lock(LOCK_READ_WRITE);
void* Data = Mip->BulkData.Realloc(NumBlocksX * NumBlocksY * GPixelFormats[PF_FloatRGBA].BlockBytes);
FMemory::Memcpy(Data, colors.GetData(), _width * _height * GPixelFormats[PF_FloatRGBA].BlockBytes);
Mip->BulkData.Unlock();
_tex->Source.Init(_width, _height, 1, 1, ETextureSourceFormat::TSF_RGBA16F, (uint8*)colors.GetData());
_tex->AddToRoot();
_tex->UpdateResource();
This approach to create a texture only seems to work if the texture w x h is is in power of two. What needs to be done if it isnt?
Sorry if I’m not understanding this correctly, but how would you go about saving a texture with float color data, for more accuracy? As an example if I wanted all pixels to be RGBA(0.145, 0.543, 0.223, 1.0), how would I save this to a texture when it requires the data to be passed as a uint8* ?
Alright, so I stumbled on df999 the other day. Looks promising. Good odds? Fast payouts? Let me know your experience with df999 before I deposit!
Just checking if anyone has used f168n before? I’m looking for a new place to drop some bets.
Just signed up with 99okwin, and so far, so good! The interface is clean, and I’m already eyeing a few games. Hoping for some big wins! Definitely checking out 99okwin.
Heard about 8xx07 and decided to give it a whirl. Not bad! Decent payouts and a cool interface. Worth checking out in my book. 8xx07
Thanks for sharing. I read many of your blog posts, cool, your blog is very good. https://accounts.binance.com/da-DK/register-person?ref=V3MG69RO
Every weekend i used to go to see this web site, because i
want enjoyment, as this this site conations really fastidious funny data too.
My web blog … bclub cm
I’d like to thank you for the efforts you have put in penning this blog.
I really hope to check out the same high-grade blog posts from you later on as well.
In truth, your creative writing abilities has inspired me to get my own blog now 😉
my site: prozone cc
Thanks for one’s marvelous posting! I quite enjoyed reading it,
you may be a great author. I will remember to bookmark your blog and definitely
will come back very soon. I want to encourage one to continue your great writing, have a nice evening!
Here is my blog jerrys login
Hi, yup this piece of writing is actually pleasant and I have learned lot of
things from it regarding blogging. thanks.
Here is my blog :: blackbet
Every weekend i used to visit this web page, for the reason that i wish for
enjoyment, since this this website conations genuinely pleasant
funny information too.
Here is my blog post: findsome.ru
I blog often and I seriously appreciate your information. This great article has really peaked my interest.
I will bookmark your website and keep checking for new information about once
per week. I opted in for your Feed too.
Here is my web blog – castrocvv login
Hey there! This post could not be written any better!
Reading this post reminds me of my old room mate!
He always kept talking about this. I will forward this page to him.
Fairly certain he will have a good read. Thanks for sharing!
Also visit my page :: luxchecker
Hey I know this is off topic but I was wondering if you knew of any widgets I could add
to my blog that automatically tweet my newest twitter updates.
I’ve been looking for a plug-in like this for quite some
time and was hoping maybe you would have
some experience with something like this. Please let me know if
you run into anything. I truly enjoy reading your blog and I look forward
to your new updates.
Also visit my website; 4check
Hmm is anyone else experiencing problems with the pictures on this blog loading?
I’m trying to figure out if its a problem on my end or if it’s the blog.
Any feed-back would be greatly appreciated.
my web-site :: black pass
Attractive component to content. I just stumbled upon your web site and in accession capital to assert
that I get in fact enjoyed account your blog posts. Any way I will be subscribing to
your feeds and even I success you get right of entry
to constantly fast.
my blog post: ssn24
Hi it’s me, I am also visiting this site regularly,
this web site is in fact fastidious and the people are truly
sharing nice thoughts.
Also visit my homepage: findsome cc
What a data of un-ambiguity and preserveness of valuable familiarity regarding unexpected feelings.
Check out my page russianmarket
Very nice post. I just stumbled upon your blog and wanted to
say that I have truly enjoyed browsing your blog posts.
After all I’ll be subscribing to your feed and I hope you write again very soon!
Here is my web page … luxchecker pm
I would like to thank you for the efforts you have put in penning this site.
I am hoping to check out the same high-grade blog posts by you in the future as well.
In fact, your creative writing abilities has inspired me to get my
own, personal blog now 😉
My web page … basetools login
It’s amazing designed for me to have a web site, which is useful for my knowledge.
thanks admin
Here is my website; donald cc
Pretty great post. I just stumbled upon your
weblog and wished to mention that I have truly loved surfing around
your weblog posts. In any case I’ll be subscribing for your feed and I’m
hoping you write again soon!
Take a look at my web-site – tox23
I love your blog.. very nice colors & theme. Did you make this website yourself or did
you hire someone to do it for you? Plz answer back as I’m
looking to construct my own blog and would like to know where
u got this from. thanks
My web page … wizardshop cc
Asking questions are actually pleasant thing if you are not understanding something totally, but this paragraph provides fastidious understanding even.
My web page – xleet shop
I was extremely pleased to uncover this website.
I want to to thank you for your time for this wonderful read!!
I definitely appreciated every part of it and i also have you bookmarked to see new stuff on your website.
My page :: ultimateshop login
When I initially commented I clicked the “Notify me when new comments are added” checkbox and now each time a
comment is added I get four e-mails with the same comment. Is there any way you can remove people from that service?
Appreciate it!
Here is my web page … castrocvv
It’s actually a nice and helpful piece of info. I am satisfied that you simply shared this useful information with us.
Please stay us up to date like this. Thank you for sharing.
My blog :: xleet shop
I am regular reader, how are you everybody? This post posted at this site is really nice.
my website bankom
Hi there to every single one, it’s actually a nice for me to pay a quick visit this web page, it consists of valuable Information.
Also visit my webpage … ultimateshop vc
Great blog here! Also your site loads up very fast!
What host are you using? Can I get your affiliate link to
your host? I wish my website loaded up as quickly as yours lol
my site … just kill
Hello! I simply would like to offer you a big thumbs up for your excellent info you have right here on this post.
I am returning to your website for more soon.
Visit my website: infodig
It’s going to be finish of mine day, however before end I am reading this
enormous post to increase my know-how.
Visit my webpage; savastan0