Dynamic Terrain Instance Support

Some months ago, the support solid particles management has been added to the Dynamic Terrain in order to render objects on a map : Adding Objects to a Dynamic Terrain - Babylon.js Documentation

At this time, the custom instance buffers weren’t available in the current BJS version. Now they are.
So the DynamicTerrain can now also manage instances , exactly like it does with solid particles.
Both can even work together.

Usage :

  • As usual create a map to depict the relief and the landscape mapData : successive ground coordinates in a large array.
  • Create also a map of objects beside. This map can hold different object types. This map can be as large as wanted and can contain hundred thousands or millions objects.

var instanceMapData = [ [], [], [] ]; // this object map can hold data for 3 object types
// type 0
instanceMapData[0] = [posx1, posy1, posz1, rotx1, roty1, rotz1, sclx1, scly1, sclz1, posx2, posxy2, ...];
// type 1
instanceMapData[1] = [posx1, posy1, posz1, rotx1, roty1, rotz1, sclx1, scly1, sclz1, posx2, posxy2, ...];
// type 2
instanceMapData[2] = [posx1, posy1, posz1, rotx1, roty1, rotz1, sclx1, scly1, sclz1, posx2, posxy2, ...];
  • Then create (or import) one mesh per object type, store it in an array sourceMeshes and create a pool of instances for this mesh.
// assuming mesh1, mesh2 and mesh3 are created
// create the wanted pools of instances of each one, say 1000 per type here
for (var i = 0; i < 1000; i++) {
    mesh1.createInstance("mesh1" + i);
    mesh2.createInstance("mesh2" + i);
    mesh3.createInstance("mesh3" + i);
}
var sourceMeshes = [mesh1, mesh2, mesh3]; 
// mesh1 will be the object type 0, mesh2 the object type1 and mesh3 the object type2

The order of the meshes in the sourceMeshes array is the object type order in the object map.

  • At last, just create your terrain with the parameters instanceMapData and sourceMeshes this time
        var terrainSub = 100;        // terrain subdivisions
        var terrainOptions = {
            terrainSub: terrainSub, 
            mapData: mapData, mapSubX: mapSubX, mapSubZ: mapSubZ, 
            instanceMapData: instanceMapData,
            sourceMeshes: meshes
        };
        var terrain = new BABYLON.DynamicTerrain("dt", terrainOptions, scene);

That’s all.
Now the terrain will recycle the instances from each pool and use them to render the objects from the map.

Note that you can also use colors like with the solid particles.
Just create an extra array to hold the instance colors (r, g, b, a floats) per type :

var instanceColorData = [[], [], []];
instanceColorData[0] =  [r1, g1, b1, a1, r2, g2, b2, a2...];
instanceColorData[1] =  [r1, g1, b1, a1, r2, g2, b2, a2...];
instanceColorData[2] =  [r1, g1, b1, a1, r2, g2, b2, a2...];

and pass it to the terrain constructor with the parameter instanceColorData :

        var terrainSub = 100;        // terrain subdivisions
        var terrainOptions = {
            terrainSub: terrainSub, 
            mapData: mapData, mapSubX: mapSubX, mapSubZ: mapSubZ, 
            mapColors: mapColors, 
            instanceMapData: instanceMapData,
            instanceColorData: instanceColorData,
            sourceMeshes: meshes
        };
        var terrain = new BABYLON.DynamicTerrain("dt", terrainOptions, scene);
4 Likes

Why use the instances more than the SPS ? or the contrary ?

The SPS performance depends on the global number of vertices, not on the number of particles.
Unless you use MultiMaterials, the SPS will render particles from different geometries, colors and textures in a single draw call.
So if the objects need many different geometries, colors, textures and don’t have such a big number of vertices, the SPS may be the right choice.

The performance of instances depends more on the global instance number. There’ll be one draw call per instance type and each type will share the same geometry (position, rotation, scaling can vary though) and the same texture. They aren’t really sped down by the number of vertices.
So if the objects are high poly, numerous but with the same geometries and textures, instances should be preferred.

As both have quite the same declarations in the terrain constructor (only parameter names differ), it’s pertinent for you to test in your actual case to check what fits best with your needs.

example of both : Trees On Dynamic Terrain

Feature merged and documented : Extensions/dynamicTerrainDocumentation.md at master · BabylonJS/Extensions · GitHub
PG examples to come soon

[EDIT] PG example links added in the documentation.

1 Like

This is an excellent topic! thanks a ton for that

1 Like

Is there a way to those instances after terrain is created?