I am trying to find a way to set the heightmap of a landscape from a AlevelScripterActor C++ class. I think I have found a way to do this by setting the heightmap in the landscape component.
“landscape->LandscapeComponents[0]->SetHeightmap(test);”
But now I am trying to find a way to create a heightmap using C++. I am planning on combining perlin noise with different frequencies to create fractal noise and use that as the heightmap. Now I know that you can create the images this way but are they the same as UTexture2D (which is what the SetHeightmap is requesting).
In short is there a way to make a UTexture2D from a heightmap. I have tried understanding what UTexture2D is but ue4 is very confusing for me.
Thanks in advance
update
I think i have found a possible way. As I said i want to try and set the heightmap using SetHeightmap. The only problem was i did not know how to make a UTexture2D object to put in it. I have found a way to make it based upon an image using FImageUtils::CreateTexture2D(). I first tryed testing this out with FImageUtils::CreateCheckerboardTexture(FColor(255, 255, 255), FColor(0,0,0),10) is this required less variables. But now the problem is actually setting this as the height map. I have tried doing it for 1 an all components of the landscape and even same update method’s which sound like they would work but nothing. If someone knows any way of setting the heightmap in C++ the correct way then please let me know. I will also add the code that i have so far. I hope it will help someone.
//my input is a landscape object
int ACPP_TestLevel::VeranderLandschap(ALandscape* landscape)
{
//testing out some code to get heightmap
//UTexture2D* heightMap = landscape->LandscapeComponents[0]->GetHeightmap();
//EPixelFormat formatPixel = heightMap->GetPixelFormat();
// figuring out how to make UTexture2D
/*UTexture2D* test = UTexture2D::CreateTransient(90,100, PF_B8G8R8A8);*/
int aantal = landscape->LandscapeComponents.Num();
//first attempt at setting the heightmap
//landscape->LandscapeComponents[0]->SetHeightmap(test);
// testing code to see if this would load the changes
landscape->LandscapeComponents[0]->RequestHeightmapUpdate();
// creating CreateCheckerboardTexture to use as heightmap
//UTexture2D* bob = FImageUtils::CreateTexture2D();
UTexture2D* bob2 = FImageUtils::CreateCheckerboardTexture(FColor(255, 255, 255), FColor(0,0,0),10);
landscape->LandscapeComponents[1]->SetHeightmap(bob2);
landscape->LandscapeComponents[1]->RequestHeightmapUpdate();
// testing if PostLoad would load the changes
landscape->LandscapeComponents[1]->PostLoad();
// updating al the landscape component
for (int i = 0; i < aantal; ++i)
{
landscape->LandscapeComponents[i]->SetHeightmap(bob2);
landscape->LandscapeComponents[i]->RequestHeightmapUpdate();
landscape->LandscapeComponents[i]->PostLoad();
}
// this is code from https://isaratech.com/save-a-procedurally-generated-texture-as-a-new-asset/
// it is about saving textures to a local folder.
// tested this code out to see if i actualy created the texture.
int TextureWidth = 256;
int TextureHeight = 256;
FString TextureName = "testtexture";
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);
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;
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] = 0;
Pixels[4 * curPixelIndex + 1] = 0;
Pixels[4 * curPixelIndex + 2] = 0;
Pixels[4 * curPixelIndex + 3] = 0;
}
}
// 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();
NewTexture->Source.Init(TextureWidth, TextureHeight, 1, 1, ETextureSourceFormat::TSF_BGRA8, Pixels);
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
for (int i = 0; i < aantal; ++i)
{
landscape->LandscapeComponents[i]->SetHeightmap(NewTexture);
landscape->LandscapeComponents[i]->RequestHeightmapUpdate();
landscape->LandscapeComponents[i]->PostLoad();
}
// just a number i return that i desplay in the game to see if things worked.
if (bSaved) aantal = 0;
return aantal;
}