Jump to content

Updating Albedo/Height of the new Terrain


photo

Recommended Posts

Are there any examples or documentation on using the LandscapeImages class (or the LandscapeTextures class?) to update the albedo texture of a terrain object?

I have an active ObjectLandscapeTerrain which i have added a layer i have created using the LandscapeMapFileCreator, and this all works fine. Now i want to update the albedo of the main layer with Images that are being streamed from a server, but it doesn't seem to have any effect.

The code i have is somewhat similiar to below:

 

// sizeX and sizeY are the same as what was set in LandscapeLayermap::setSize()
landscapeImages = LandscapeImages::create((ivec2(sizeX, sizeY)));

// ...
int updateThing(int x, int y, const ImagePtr& image) 
{
  ImagePtr height = landscapeImages->getHeight();
  ImagePtr albedo = landscapeImages->getAlbedo();

  height->copy(image, x, y, 0, 0, image->getWidth(), image->getHeight());
  albedo->copy(image, x, y, 0, 0, image->getWidth(), image->getHeight());
}

 

Link to comment

Hi Paul,

Terrain modification can be performed in asynchronous mode on GPU side by calling the asyncTextureDraw method of the Landscape class, that commences a drawing operation. The operation itself is to be implemented inside a callback handler.

The workflow here is as follows:

  1. Implement your GPU-based terrain modification logic in a callback function.
  2. Set this callback function to be fired when a Texture Draw (GPU-based terrain modification) operation is performed by calling the addTextureDrawCallback() method.
  3. Commence a GPU drawing operation by calling the asyncTextureDraw() method. Here you should specify the GUID of an .lmap file landscape layer map to be modified, the coordinates of the upper-left corner and the resolution of the segment of data to be modified, you should also define which data layers are to be affected (heights, albedo, masks) via a set of flags.

The example for the docs is on the way (will be added soon), meanwhile you can use the following:

// images to be used for terrain modification
Unigine::ImagePtr custom_albedo_image;
Unigine::ImagePtr custom_height_image;

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
// 												(1)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 

// callback to be fired on commencing a texture draw operation
void my_texture_draw(UGUID guid, int id, LandscapeTexturesPtr buffer, ivec2 coord, int data_mask)
{
	// resize albedo and height images to fit the area to be modified
	custom_albedo_image->resize(buffer->getResolution().x, buffer->getResolution().y);
	custom_height_image->resize(buffer->getResolution().x, buffer->getResolution().y);

	// setting our custom image to the albedo buffer
	buffer->getAlbedo()->setImage(custom_albedo_image);

	// setting our custom image to the height buffer
	buffer->getHeight()->setImage(custom_height_image);

}

// ...

// somewhere in your code (e.g. in the AppWorldLogic::init() method)

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
// 												(2)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 

// add a callback to be fired on a Texture Draw operation
Landscape::addTextureDrawCallback(MakeCallback(my_texture_draw));

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
// 												(3)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 

// preparing images for terrain modification 
// create a new image to load a custom albedo map to
custom_albedo_image = Image::create("custom_albedo.png");
// set the format required for the albedo map - RGBA8
custom_albedo_image->convertToFormat(Image::FORMAT_RGBA8);
// create a new image to load a custom height map to
custom_height_image = Image::create("custom_height.png");
// set the format required for the heightmap - R32F
custom_height_image->convertToFormat(Image::FORMAT_R32F);


// getting the first layermap that we're going to modify
LandscapeLayerMapPtr lmap = checked_ptr_cast<LandscapeLayerMap>(terrain->getChild(0));

// generating a new ID for the draw operation
int id = Landscape::generateOperationID();

// commencing a Texture Draw operation for the selected landscape map at (10, 10) with the size of [512 x 512]
Landscape::asyncTextureDraw(id, lmap->getGUID(), ivec2(10, 10), ivec2(512, 512), (int)(Landscape::FLAGS_DATA_HEIGHT | Landscape::FLAGS_DATA_ALBEDO));

// ...

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Don't forget to clear the list of callbacks on shutdown
int AppWorldLogic::shutdown()
{
	// clearing the list of TextureDraw Callbacks
	Landscape::clearTextureDrawCallbacks();
  
	return 1;
}

Hope this helps!

Thanks!

Link to comment

That does help, thankyou! I managed to use similar code to update the albedo, but there seems to be a few issues, or maybe i'm using this feature incorrectly. 

Just a quick overview, my terrain is 1x1 tiles, and 16k by 16k in size and i am trying to change the texture of the terrain to another texture which is 4x by 4k. The problem i am having is:

  • Starting a  asyncTextureDraw() with a 16k by 16k size (to update the entire terrain) causes the application to allocate about 60 gigabytes, then it crashes.
  • Updating a smaller region works ok by using asyncTextureDraw() with 4k by 4k size; but only a portion of the terrain is updated. It still allocates a large amount of memory, about 4GB

Perhaps this feature is not supposed to be used for changing the entire terrain albedo texture. If not, is there any way of changing the entire texture of a terrain? Or perhaps I have to create multiple layers and turn them on/off?

Thanks for the help again! 

Link to comment

Glad to be helpful, Paul!

Well, such GPU-based modification is rather intended for local changes (such as brush editing, digging, things like that). You didn't describe your situation in detail (what sort of changes do you want to implement and when), but I guess in your case it would be much better to use non-destructive modification via landscape layer maps. It works pretty fast and enables you to switch your modification on and off quickly.

Thanks!

Link to comment

Yep, thought so.

So say i had a terrain that is currently using albedo texture "albedo_1.dds" that i created using the LandscapeMapFile creator, and i want to change the terrain albedo texture to use "albedo_2.dds" would i have to:

  • Use the LandscapeMapFile class to create a new lmap file that uses "albedo_2.dds"
  • Create a new LandscapeLayerMap using the newly created lmap file
  • Disable the layer with "albedo_1.dds" with setEnabled() 

Is that more or less correct?

 

Link to comment

Cool, that seems to be working! Thanks :)

I noticed that when creating a new layermap it seems to apply it over the top of the existing layer automatically? I assume that is by design? Also, there sometimes seems to be some tiles that aren't updated for a long long time (they stay black) - even if i move the camera. Eventually they redraw, it just takes awhile; It might be worth noting at this point im using the OpenGL renderer.

Link to comment

You're welcome!

By default layer maps use Alpha Blending mode, but you can change it if you wish. Different modes for albedo and height maps are available, you can also change rendering order for your layer maps. To learn more please refer to this article

DirectX is the recommended graphic API for projects that use the Landscape Terrain system, so such things with streaming and so on for OpenGL are rather normal. You can try tweaking some of these settings to improve the situation, but that surely won't make it the same level as for DirectX.

Thanks!

Link to comment
×
×
  • Create New...