Heightfield from external

Hi Folks,

I’m looking to create a PhysicsShapeHeightField from an mesh that’s imported into a scene. I’ve created a playground to demonstrate how far I’ve got with this so far: https://playground.babylonjs.com/#849YCW#16 (it will take about a minute or so to render due to the ray casting explained below).

This imports an external model for a race track, which is not finished yet, but has enough features that you get the idea. The external model includes a ground mesh and a track mesh (well, they have multiple materials in each case so come in with the _primitive suffix, but I merge them into two meshes).

I then have a function that creates a grid 1200 wide with an interval of 20, and casts rays at x, z positions from (-600, -600) to (600, 600) intercepting the ground or track mesh. It does this to get the height at that point, and then I put that into a Float32Array for use with PhysicsShapeHeightField. I log the values to the console to confirm they seem correct (as far as I understand it). I then create a PhysicsViewer for the heightfield I’ve created. This won’t cover the entire ground mesh, which is 9913 wide and high, but covers the area of the ground mesh I’m concerned with in this case.

What I’m hoping to achieve is that the heightfield would match the existing terrain (with fidelity up to the interval I use for the grid of rays that I cast). But it seems I’m not quite constructing the heightfield correctly, as it doesn’t match the underlying terrain.

Can anyone point me in the right direction in terms of what I’m missing to construct the heightfield so that it matches the underlying terrain? I have tried just creating a heightfield of the ground mesh directly but this seems to give “stuttering” results when moving an object over its surface, presumably due to the non-uniform vertices underneath (which is why I’m trying this approach above).

Once I work out how to construct the heightfield correctly I’ll only cast the rays once and store the resulting Float32Array for subsequent visits.

Thanks, Tom

To compute a Heightfield from a mesh, I’d use this : Babylon.js docs

and use float values. Then write texel as mesh height (with appropriate camera placement) and read back texels using .

There are threads on this forum doing the same : How to access depth of RenderTargetTexture?

This said, for physics, I’d try first use physics mesh shape for static colliders.

Sorry, this is a bit beyond my understanding - can you explain what’s happening in principle (or are there some docs on this?) so that I can try to follow along? The linked playground doesn’t seem to work anymore as the external resources aren’t accessible.

I have tried just using the ground and track mesh shapes for static colliders and this seems to give “stuttering” results when moving an object over its surface, presumably due to the non-uniform vertices underneath (which is why I’m trying the approach above).

The idea to use a render target is to render the meshes and have each rendered pixel to have the height.
Just like making as many raycasts as pixels. But faster because it runs on the GPU.

Ok, that certainly sounds like it could be a good approach. I’ll see if I can find some other playground examples that show this and see if I can follow along this even though it’s not currently working.

1 Like

I’ve figured out what I was doing wrong with my initial (naive) solution. I was calculating the heightBuffer incorrectly. This is what I should have been doing:

    var planeSize = 1200;
    const subdivisions = 20;
    const stepSize = planeSize / subdivisions;
    const midPlane = Math.floor((planeSize / 2));
    var heightBuffer = new Float32Array((subdivisions + 1) * (subdivisions + 1));
    for (var x = 0; x <= subdivisions; x++){
        for (var z = 0; z <= subdivisions; z++){
            var xCoord = (x * stepSize) - midPlane;
            var zCoord = -1 * ((z * stepSize) - midPlane);
            var height = getHeightAtCoordinates(xCoord, zCoord);
            var index = z * (subdivisions+1) + x;
            heightBuffer[index] = height;
        }
    }
    var shape = new BABYLON.PhysicsShapeHeightField(
        planeSize,
        planeSize,
        subdivisions + 1,
        subdivisions + 1,
        heightBuffer,
    scene); 

That works fine. Now I understand what I’m trying to construct it should make it a bit easier to get it working with RenderTargetTexture instead. I’ll mark this as “solved” for now, but will add an update here when I figure out that approach.

1 Like