[SOLVED] Heatmap vertex color problem

I’m trying to create a heatmap based on coordinates i get from a database. The poinst are displayed as mountains, but I have a problem with the vertex color gradient.

I’m facing the problem that my terrain is being split in four pieces and the gradient is only being displayed in those quarters. Thus leades me to this forum.

Help would be appreciated.

Here is a screenshot of what i have.

1 Like

Can you post some code that constructs this output?

Here us where i set my colors

    terrain = new TerrainQuad("my terrain", 65, 257, null);
    Material mat = new Material(assetManager,
            "Common/MatDefs/Misc/Unshaded.j3md");
    ArrayList<TerrainPatch> holder = new ArrayList<>();
    mat.setBoolean("VertexColor", true);
    terrain.getAllTerrainPatches(holder);

    for (int i = 0; i < cords.size(); i++) {
        Vector2f f = new Vector2f(cords.get(i).getX(), cords.get(i).getZ());
        terrain.setHeight(f, cords.get(i).getY());
    }

    for (int j = 0; j < holder.size(); j++) {
        float[] colorArray = new float[holder.get(j).getMesh().getVertexCount() * 4];
        for (int i = 0; i < holder.get(j).getMesh().getVertexCount(); i++) {
            colorArray[colorIndex++] = 0f + (0.0002f * i);
            colorArray[colorIndex++] = 0f;
            colorArray[colorIndex++] = 0f;
            colorArray[colorIndex++] = 1.0f;
        }
        colorIndex = 0;
        holder.get(j).getMesh().setBuffer(Type.Color, 4, colorArray);
    }

A terrainQuad takes a float[] heightmap or an image as a height. You shouldn’t edit the vertices directly like that.

int tileSize = 65;
int blockSize = 129;
float height = 32;
float[] data = ...
TerrainQuad terrainQuad = new TerrainQuad("name", tileSize, blockSize, data);
terrainQuad.setLocalScale(new Vector3f(1f, height, 1f));

I dont really understand what you mean by that.
Why should this change anything on my heatmap?

A terrain quad is not a traditional mesh. It is a collection of meshes that are affected by a LOD control over distance. So as the camera moves toward and away (if the LODControl was added) it will change to a simpler or complex mesh - some of the vertices are sometimes not displayed.

You are treating the mesh as a grid of vertices and that’s not what it is.

Take a look at this contribution from the lemur plugin. It creates a box of x slices. You can omit axis. You probably just want a single plane sliced up x times. Then you can continue with the code you posted above and it should work as you expect.

Thanks, for your help, but isnt there an easier way to solve this.
How fast can i read in to the lemur plugin?
Im new to this whole Jmonkey thing, so i would appreciate an easy solution.

You can literally just copy that class into your project.

Mesh mesh = new MBox(32, 0, 0, 10, 0, 0);

Which will create a mesh along the X axis of length 32, sliced 10 times.

I have adjusted my code, but it still doesn’t work. Am I missing something?
Because nothing is being displayed.

    terrain = new TerrainQuad("my terrain", 65, 257, null);
    ArrayList<TerrainPatch> holder = new ArrayList<>();
   
    Mesh mesh = new MBox(32, 0, 0, 10, 0, 0);

    Material mat = new Material(assetManager,
            "Common/MatDefs/Misc/Unshaded.j3md");

    mat.setBoolean("VertexColor", true);
    
    for (int i = 0; i < cords.size(); i++) {
        Vector2f f = new Vector2f(cords.get(i).getX(), cords.get(i).getZ());
        terrain.setHeight(f, cords.get(i).getY());
    }

    for (int j = 0; j < mesh.getVertexCount(); j++) {
        float[] colorArray = new float[mesh.getVertexCount() * 4];
        colorArray[colorIndex++] = 0.1f - (.0002f * j);
        colorArray[colorIndex++] = 1f;
        colorArray[colorIndex++] = 0f;
        colorArray[colorIndex++] = 1.0f;
        mesh.setBuffer(Type.Color, 4, colorArray);
    }

Don’t use terrain anymore.


int size = 32;

Mesh mesh = new MBox(size, 0, 0, 10, 0, 0);

Geometry geometry = new Geometry("name", mesh);
geometry.setMaterial(mat);

Vector3f[] verts = BufferUtils.getVector3Array(mesh.getFloatBuffer(VertexBuffer.Type.Position));
ColorRGBA[] colors = new ColorRGBA[verts.length];

for (int x = 0; x < size; x++) {
    for (int y = 0; y < size; y++) {
        int index = (y * size) + x;
        
        Vector3f vert = verts[index];
        vert.y = heightYouWantToSet;

        colors[index] = new ColorRGBA(red, green, blue, 1.0); // the color of this vertex.
    }
}

// set the positions
FloatBuffer pb = BufferUtils.createFloatBuffer(verts);
mesh.setBuffer(Type.Position, 3, pb);

FloatBuffer cb = BufferUtils.createFloatBuffer(colors);
mesh.setBuffer(Type.Color, 4, cb);
mesh.updateBounds();

Or something like that. I wrote it off the top of my head.

I have tried your code and it worked partly, it created 1 white box in the middle of the screen.
But how could i color just a simple spot based on a coordinate?
With my previous code.

public int getIndex(int x, int y) {
    int index = (y * size) + x;
}

Where x and y are your coordinates.

int index = getIndex(5, 2);
Vector3f vertex = verts[index]; // the position of the coord.
ColorRGBA color = colors[index]; // the color of the coord.

Im facing the same Problem as @M1ztl. I’m trying to display a heatmap.

But my vertex gradiant is only being shown in the quarters is there a way to solve this without using any plugins or anything for that matter.

I’ve tried to get the height based on the coordinates in a mesh but i couldnt figure that out.

Our codes are similar

Is this for a school project?

Indeed

so i understand heightmap from points is not a problem right?

it can be done like:

AbstractHeightMap heightmap = new AbstractHeightMap() {
    @Override
    public boolean load() {
        size = terrainSize;
        // clean up data if needed.
        if (null != heightData) {
            unloadHeightMap();
        }
            heightData = new float[size * size];
            // transfer temporary buffer to final heightmap
            for (int i = 0; i < size; i++) {
                for (int j = 0; j < size; j++) {
                    setHeightAtPoint(GETYOURHEIGHT(j,i), j, i);
                }
            }
            normalizeTerrain(NORMALIZE_RANGE);
        }
        return true;
    }
};
heightmap.load();

about gradient, not sure what you mean by vertex color(do it really need to be made via vertex color?), but i would make it in shader based on ModelSpace or some space of pixel. The more Y the more red or something like that.

in shader i belive it will be using:

wPosition = TransformWorld(modelSpacePos).xyz;

not sure it it were taking vertex, might not, if not then use somethign that take vetrex position.
so in fragment shader(pixel shader) the more y the more r something like:

gl_FragColor.r = wPosition.y / 100; or something similar, just an idea.

because im not sure if you need to make this Via vertex color, or just effect need to be like this.

Here’s what I meant by vertex colors https://wiki.jmonkeyengine.org/jme3/advanced/custom_meshes.html#example-vertex-colors

Doesn’t have to be made with vertex colors, I just thought it might be the easier way to implement a heatmap.

But i can give it a try i guess, thanks for the advice

its always best if you say what you exactly need to do.

if you say it dont need to be made with vertex color and custom mesh, then i suggest using JME Terrain with heightmap like i show above code, and override its material to use one with your shader that print black color + red the higher Y value of pixel/vertex is. (but it require little shader knowledge or some research/play in shader)

ofc, you can still do with custom mesh /vertex color, but if you have problems making it work, i just add another suggestion you can use :slight_smile:

I really appreciate your help on this matter. I’ll try and implement your idea into my programm.

The reason why i went for vertex colors was because there was a thread
this one

which lead me to trying it out with vertex colors, it looks stunning so i thought why not try it. But if you say that i can get the same or somewhat the same result with shaders ill give it a try

Thanks again :slight_smile: