Trying to create a dynamic terrain from a matrix dataset

I’m trying to create a dynamic terrain from an array that I’ll load in. All of the examples are meshes that are created from math, not loaded. I can’t figure out a format that will work?

My marix is 20 X 20 X 20, the process that I’m using to create the matrix will be like this

Even if I do, What do I set the following values:

const mapSubX = 500;
const mapSubZ = 300;
const terrainSub = 100;

As the demos are all created from math, the formula uses those to generate the array. What would I set those to if I had pre-made the terrain?

I originally tried the hightmap.jpg, however I didn’t want to have the extra baggage of storing an image file in static for each new map created. The array isn’t going to be very large, so I’d just like to load it into as part of the scene data.

EDIT: After I solved the problem, I figured out the format. It’s in the docs, but difficult to describe.

[x,y,z,x,y,z,x,y,z,x,y,z,x,y,z,x,y,z,x,y,z,x,y,z]

It’s a flat array of xyz values, so you divide the matrix by three, then you devide by mapSubX.

terrainSub is the same as the number of rows (assuming a square) that you will slice the triplets in the list. So array/terrainSub/3.

Final pattern that does this:

ground_dimensions = 5000
ground_subdivisions = 19  // number of rows in my 2x2 square matrix

const ground = BABYLON.MeshBuilder.CreateGround("ground", {height: ground_dimensions, width: ground_dimensions, subdivisions: ground_subdivisions, updatable: true})
var ground_arr = ground.getVerticesData(BABYLON.VertexBuffer.PositionKind);
var altiudes = JSON.parse(data['biome'][0]['grid']) //my input data form ajax
for (let i=0;i<altiudes.length;i++){ground_arr[(i*3)+1] = altiudes[i]*10}  // 10 is an arbitrary bump in altitude, depends on size of your map

console.log("altiudes: ",altiudes)
console.log('positions:', ground_arr)
ground.updateVerticesData(BABYLON.VertexBuffer.PositionKind, ground_arr);

Did you try to create a ground like this:

And then update the vertex position with your data using that:

1 Like

May be this example can help:

test | Babylon.js Playground (babylonjs.com)

2 Likes

Thanks for the response, but I don’t want to create and store a hightmap in static files for each terrain. Because of my backend requirements I’d rather store a list of heights, rather than a file. In my use case I want to keep the backend as light as possible as the application will generate many heightmaps.

Also your solution generates the array from math, which isn’t what I’m looking for:

var mapData = new Float32Array(nbPoints * nbPoints * 3); 

I want to take an array that I already have, not generate a new one. I need to know what shape that array will have.

I think this is what I’m looking for,

sphere.updateVerticesData(BABYLON.VertexBuffer.PositionKind, positions);

that’s great. But I’m still fuzzy as to the shape of the positions array. Even in this example, the array is generated from Math. I don’t understand how, if I brought my own array, would I convert it to the format of the positions array.

image
Looking in the inspector, this array is confusing.

If I have a matrix like this,


How do I convert it to that format? What format does it need to be. The given examples are generated from math so the location of the height on the 2x2 grid is irrelevant.

Just to test this out, I put the console of the “flat ground” into the console.


It has a set shape (before updating)

 [-10, 0, 10, 10, 0, 10, -10, 0, -10, 10, 0, -10]

but if I want to update that, what should the output shape look like?

the data in the position array of the mesh geometry is x,y,z coordinates.
is it what you have in your array?

1 Like

Appreciate the help!,

Here’s another pass at trying to demonstrate what I’m trying to do:

Let’s say I want a ground that is a 20X20 grid of this data:

var mapData = new Float32Array([ 1.,  2.,  1.,  2.,  2.,  1.,  1.,  1.,  2.,  0.,  2.,  2.,  0.,
        1.,  5.,  1.,  8.,  0.,  1.,  0.,  3.,  1.,  1.,  2.,  0.,  1.,
        3.,  1.,  1.,  2.,  1.,  1.,  0.,  1.,  5., 12.,  2.,  0.,  1.,
        2.,  0.,  1.,  2.,  0.,  1.,  1.,  1.,  0.,  1.,  3.,  0.,  1.,
        2.,  7.,  1.,  0.,  1.,  2.,  2.,  2.,  1.,  2.,  6.,  3., 11.,
        0.,  2.,  6.,  7.,  0.,  2.,  0.,  5.,  1.,  2.,  1.,  1.,  0.,
        3.,  2.,  1.,  2.,  0., 17.,  1.,  6.,  1., 11.,  0.,  0.,  1.,
        6.,  2.,  3.,  1.,  1.,  6.,  7.,  1.,  1.,  1.,  2.,  6., 11.,
        0.,  3.,  0.,  5.,  1.,  1.,  0.,  1.,  3.,  0.,  1.,  5., 11.,
        6.,  1.,  1.,  1.,  0.,  6.,  1.,  0.,  1.,  1., 12., 11.,  1.,
        0.,  0.,  1.,  1.,  1.,  1.,  5.,  0.,  1.,  1.,  2., 12.,  1.,
        1.,  0.,  0.,  0.,  1.,  1.,  2.,  3.,  1.,  1.,  3.,  0.,  0.,
       15.,  5.,  2.,  1.,  8.,  1.,  1.,  0.,  0.,  2.,  2.,  1.,  6.,
        6.,  2.,  0.,  0.,  2.,  2.,  0.,  5.,  6.,  6.,  2.,  1.,  1.,
        1.,  3.,  1.,  0.,  1.,  2.,  6.,  2.,  0.,  0.,  2.,  0.,  2.,
        1.,  1.,  6.,  2.,  3.,  0.,  3.,  5.,  0.,  1.,  1.,  2.,  6.,
        0.,  0.,  1.,  1.,  3.,  2.,  0.,  0.,  1.,  2.,  1.,  1.,  0.,
        0., 12.,  7.,  2.,  2., 12., 12.,  2.,  1.,  2.,  2.,  3.,  3.,
        1.,  0.,  2.,  1.,  3.,  2.,  1.,  2.,  7.,  3.,  0.,  1.,  1.,
        2.,  1.,  3.,  0.,  0.,  1.,  0.,  0.,  2.,  1.,  2.,  7., 22.,
        0.,  1.,  1.,  1.,  3.,  1.,  0.,  0.,  1.,  2.,  3.,  2.,  1.,
        0.,  0.,  1.,  0.,  0.,  6., 12.,  0.,  2.,  0.,  1.,  1.,  0.,
        0.,  2.,  2.,  0.,  0.,  1.,  1.,  1.,  1.,  2.,  1.,  1.,  1.,
        2.,  1.,  1.,  1.,  1.,  0.,  1.,  2.,  1.,  1.,  1.,  1.,  2.,
        5.,  1.,  3.,  2.,  2.,  3.,  0.,  1.,  1.,  1.,  3.,  3.,  2.,
        2.,  1.,  0.,  2.,  0.,  0.,  2.,  0., 21.,  1.,  0.,  0.,  1.,
        1.,  2.,  3.,  0.,  0.,  1.,  3.,  3.,  0.,  1.,  2.,  1.,  1.,
        1.,  2.,  7.,  0.,  0.,  0.,  1.,  0.,  2.,  2.,  1.,  0.,  0.,
        2.,  1.,  3.,  1.,  2.,  0.,  0.,  6., 10.,  1.,  1.,  2.,  0.,
        1.,  0.,  0.,  1.,  1.,  1.,  0.,  2.,  1.,  2.,  0.,  2.,  0.,
        6.,  7., 12.,  7.,  2.,  2.,  0.,  2.,  0.,  2.])

Let’s say that that is the hight (y) of my map at that x,z location.

what would be the correct mapSubX, mapSubZ, terrainSub for my grid? I had assumed 20,20, but that seems to return nothing.

Here’s another example:

In this I’ve parsed out the values into a long list of x,y,z but still blank.
because my grid is 20 X20, per the picture above, I should be able to divide? What am I seeing wrong?

@Cedric , thanks for the pointer. I think I finally got it worked out.

How I eventually worked it out was just describing an array and looking at it in the console to learn the shape.

Another way to think about it is that your flat array, per the docs, needs to be shaped like this:

[x,y,z,x,y,z,x,y,z,x,y,z,x,y,z,x,y,z,x,y,z,x,y,z]

So you need to convert it in the backend.

So if you have a 2x2 grid you just need to munge it out so that it’s flat.

Then the params for your array should be:

{
  height: <how big you want it to be, not relevant to the size of the list>,
  width: <how big you want it to be, not relevant to the size of the list>, 
  subdivisions: <the number of rows in your matrix (if square) - 1>
}

Height and width just stretch out, so they aren’t dependent on the shape of the array.

subdivisions needs to be set to the size of your grid. For some reason it’s -1 but I can’t figure out why.

That’s the part that is relevant to your xyz array. That shows how many times the matrix will be chopped up, which needs to be relevant to the number of cells in your matrix.

1 Like

u should edit your post instead of reposting, since as you have now learned, you’re limited to three in a row:) haha

keeyahh unblocked

2 cool things i noticed. ground.updateVerticesData i guess redoes the indexes automatically? also works in webgpu, where i think the buffer needs to always be a stride of 4 if im not mistaken.

1 Like

Yeah, it would be cool if you could, say, `updateVerticesData(ground, newData, ). You want to keep your array light, so don’t send the x,z coordinates if they don’t change.

That’s why the doc examples have

mapData[3 * (l * mapSubX + w) + 1] = y;

Where the 3 and +1 is the place in the array where they are updating the value. So you have to pipe the values in with matrix math, which is fine.