Dynamic terrain splatting

I’m trying to change my terrain splatting dynamically. My code uses a single alpha map to encode the splat texture. I have generated code that can modify and save changes to a PNG file, but I’m not sure how to reload the file at runtime.
I would greatly appreciate any help.
I’m building my code up from the TerrainTestModifyHeight example.

I would like to add a function like this, that loads a new alpha map file “alphamap2.png” (at runtime).
private void UpdateTerrainTextureSplatting_atRuntime()
{
// terrain and matTerrain are global
matTerrain.setTexture(“AlphaMap”, assetManager.loadTexture(“Textures/Terrain/splat/alphamap2.png”));
terrain.updateModelBound();
}
Thanks.

I thinks that is pretty much all necessary, does it not work?

I suggesting to manipulate the already existing alphamap however if possible, as png loading is relativly slow comapred

Yeah, get the alpha map texture. Get the Image out of it. Wrap it in ImageRaster. Modify it as necessary.

Thanks. Got it working now!!!

In my update function I was saving the modified content to a file and using the same filename each time. It seems…

matTerrain.setTexture(“AlphaMap”, assetManager.loadTexture(“Textures/Terrain/splat/alphamap2.png”));

will not update the terrain unless the filename has changed. When i change the filename on each update (toggle between 2 filenames), the new splat loads, each time.

You can also clear the cache which will let it reload every time.

…but really, can you see that changing an image, writing a file, and reloading the file again is going to be WAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY slower than simply modifying the image?

Thanks pspeed.

Trying to impement this, but I seem to be missing something:

I create the global:
Texture AlphaTexture;

and use it to set the alpha texture at start up:
AlphaTexture = assetManager.loadTexture(“Textures/AlphaMap.png”);
matTerrain.setTexture(“AlphaMap”, AlphaTexture);

Then in my update function I get the image from AlphaTexture and wrap it in an ImageRaster:
ImageRaster imageRaster = ImageRaster.create(AlphaTexture.getImage());

I then try to chagne some pixels. The code runs without errors, but nothing changes on the actual render:

 for(int i=10 ; i<=100 ; i++)
   {
       for ( int j=10 ; j<=100 ; j++)
       {
            imageRaster.setPixel(i, j, ColorRGBA.Cyan);
       }
   }

I can’t remember the magic incantations off the top of my head… maybe mipmaps are on and need to be regenerated.

You could try calling setImage() on the texture again just to make things try to update. Maybe someone else remembers the proper magic. It must have been near-obvious when I did this before because I can’t remember. :slight_smile: So there is hope…

Its probably only updating the top mipmap level … I made in change in master that hopefully should address this.

Momoko_Fan, very much appreciate you looking into this. The code above now updates my terrrain.

Thanks again pspeed. As you said, this approach is MUCH faster.

For other that might find this post in the future, here’s a summary of what I’m doing:

  1. I’m modifying the TerrainTestModifyHeight test example.

  2. declare a global Texture object

public class TerrainTestModifyHeight extends SimpleApplication {

Texture AlphaTexture;
  1. create alpha texture object and load into AlphaTexture, then set alpha material to AlphaTexture
    private void createTerrain() {

     // some other code, then:
    
     AlphaTexture = assetManager.loadTexture("Textures/AlphaMap.png");
     matTerrain.setTexture("AlphaMap", AlphaTexture);
    
  2. in my update function, get image from AlphaTexture, wrap the image in a Raster, then use setPixel to dynamicly modify the terrain splatting.

    private void adjustHeight(Vector3f loc, float radius, float height) {

    ImageRaster imageRaster = ImageRaster.create(AlphaTexture.getImage());
    
    for(int i=10 ; i<=100 ; i++)
    {
        for ( int j=10 ; j<=100 ; j++)
        {
             imageRaster.setPixel(i, j, ColorRGBA.Green);
        }
    }
    

}

1 Like