Getting terrain material/layer

Hi there!
I cant seem to find a simple way on the forums or in the docs to get the material/layer that is showing at a specific point on a terrain.
For example at some point x is there grass, dirt or rock textures being displayed?
Any help would be greatly appreciated and sorry if this is posted in the wrong section. :affe:
P.S that smiley is awesome

Each terrain only has one material. You can get the texture blend from the alphamaps however.

1 Like

As @perfecticus said, what texture is displayed where is part of the alpha maps. There are 3 of them, with 4 channels each: R G B A. So your stack of textures would look like this:
R
G
B
A
R
G
B
A
R
G
B
A

You would then take the world coordinate of the point you are interested in and translate that to the percentage along the entire terrain image, and get the pixel that way. The terrain painting tool has some example code to do this: PaintTerrainToolAction.paintTexture()

1 Like

Thanks for explaining that to me i think i’m starting to understand more about how this works.
I think that this thread might be useful to others looking for the same information so for completeness sake ill post my progress.

I looked at the PaintTerrainToolAction class and i tried to simplify things so that i had code that just takes in a point and checks to see how transparent a texture is at that point.
I came up with this so, far I’m looking at the terrain point at the origin I’ve been painting and erasing my two textures in different combinations near the origin using the terrain editor but there’s been no change in the output so obviously i’ve gone terribly wrong somewhere XD

This is what i did(tried to do):

[java]
MatParam matParam = terrain.getMaterial(null).getParam(“AlphaMap”);
Texture tex = (Texture) matParam.getValue();
Image image = tex.getImage();

Vector2f UV = getPointPercentagePosition(terrain, new Vector3f(0,terrain.getHeight(new Vector2f(0,0)),0));
ByteBuffer buf = image.getData(0);
int width = image.getWidth();

int position = (((int)UV.y) * width + ((int)UV.x)) * 4;
ColorRGBA color = new ColorRGBA().set(ColorRGBA.Black);

buf.position( position );
color.set(byte2float(buf.get()), byte2float(buf.get()), byte2float(buf.get()), byte2float(buf.get()));

System.out.println(color);

public Vector2f getPointPercentagePosition(Terrain terrain, Vector3f worldLoc) {
Vector2f uv = new Vector2f(worldLoc.x,-worldLoc.z);
float scale = ((Node)terrain).getLocalScale().x;

    uv.subtractLocal(((Node)terrain).getWorldTranslation().x*scale, ((Node)terrain).getWorldTranslation().z*scale); // center it on 0,0
    float scaledSize = terrain.getTerrainSize()*scale;
    uv.addLocal(scaledSize/2, scaledSize/2); // shift the bottom left corner up to 0,0
    uv.divideLocal(scaledSize); // get the location as a percentage
    
    return uv;
}

private float byte2float(byte b){
    return ((float)(b & 0xFF)) / 255f;
}

[/java]

Changing the textures near the origin always produces,
Color[1.0, 0.0, 0.0, 0.0]
Maybe its not working at all or maybe its getting the alpha value from the wrong place on the terrain i’m not sure maybe someone can shed some light.

Perhaps its worth mentioning that the reason for wanting to know this is so that i can generate grass(cross quads) for the terrain only where there is a certain grass texture visible.

I think i fixed my issues i now have a method to check more or less if only the first texture(in terrain editor) is showing at a specific point on a terrain here it is for completeness sake:
Note TerrainQuad terrain; is defined as a field variable.
[java]
private boolean isGrassLayer(Vector3f pos)
{
MatParam matParam = terrain.getMaterial(null).getParam(“AlphaMap”);
Texture tex = (Texture) matParam.getValue();
Image image = tex.getImage();
Vector2f uv = getPointPercentagePosition(terrain, pos);

    ByteBuffer buf = image.getData(0);
    int width = image.getWidth();
    int height = image.getHeight();

    int x = (int)(uv.x*width);
    int y = (int)(uv.y*height);
  
    int position = (y*width + x) * 4;
    ColorRGBA color = new ColorRGBA().set(ColorRGBA.Black);
    
    buf.position( position );
    color.set(byte2float(buf.get()), byte2float(buf.get()), byte2float(buf.get()), byte2float(buf.get()));
    
    if(color.r==1 && color.b==0 && color.g==0)
    {
        return true;
    }
    else
    {
        return false;
    }
}

[/java]