Rendering tiling hex texture on top of mesh


I’m hoping to get a few ideas on how I might be able to solve my challenge. I’ve been tinkering around with trying to render a hex-grid tiling texture, on top of a mesh, to be able to ‘fake’ a rendered grid, but while saving resources.

The goal would be to be able to render very large grids (100.000+ tiles) without having too many vertices, so having a tiling texture came to mind. The issue I’m having is that the texture tiling seems to have a ‘wave’ effect, where it correctly tiles in some areas, but then it offsets in others.


I’ve put together a small playground which does the following:

  • generates a logical hex grid using an external library
  • using a LineSystem, renders the lines for each hex. As you can imagine, a lot of vertices/faces can come up here.
  • creating a simple Cylinder mesh (with tesselation=6 to make it a hexagon)
  • load & apply a hex grid texture on top
  • try to guess the correct uScale/vScale for the texture so that it correctly matches the scale of the rendered grid through lines


  • the logical grid will be used as a template for pointer actions (find which tile you’ve clicked)
  • the grid lines are missing some lines at the edges, not an issue for this scenario (the line system is only used to showcase the desired result)

I’ve tried other types of hex textures with different tiles, but I always seem to get the ‘wave’ tiling effect. Any ideas what might cause this effect, and how to get around it?


Will the top of the mesh be flat like plane or it will have complex geometry?

Oh, I seem to have fixed the issue by playing a bit more with the vScale of the texture. Setting a value of 17.3 (the actual hex-width) instead of 15 managed to give a perfect tiling.

Updated PG:

Very good question, I have both scenarios - the flat one is definitely more simple to fix, but the other one I don’t have an idea how to approach yet.

Maybe it’s a good time to learn shader coding? I guess that might be an approach… :slight_smile:

I believe your texture solution is the simplest and most effective for flat and curved surfaces.
Also, for flat surfaces you may try to use thin instances but, considering that the grid size is quite big, also use Dynamic Terrain to render only the desired part of the grid at the given moment.
How you are going to make pointer actions?

For translating coordinates, the 3rd party library has a useful method grid.pointToHex() which translates world coordinates to the logical equivalent of tile coordinates, given the tile size (GitHub - flauwekeul/honeycomb: Create hex grids easily, in node or the browser.).

For finding the world coordinates, I’m planning on using scene.pick() method if I have a mesh to pick (e.g. a terrain). One of my scenes also has an invisible plane instead of terrain (think, empty space in a solar system), which won’t trigger the scene.pick() action. For that scenario I plan on creating a flat plane on the XZ axis (i.e. Plane.FromPositionAndNormal(Vector3.Zero(), Vector3.Up());) and intersect the picker ray of the scene with that plane. Then, the resulting point will be translated in tile coordinates using the method above.

So far, using the scene.pick() on a dynamic mesh (terrain) has given accurate results, I’ll have to test the accuracy of the plane interesection.

1 Like

Well, it seems reasonable and I have nothing to add for this :slight_smile:

1 Like

After a bit of implementation, and a LOT of fiddling around with UV coordinates based on grid size & tile alignment, I think you were right to mention that using the texture on curved or dynamic surfaces won’t work too well.

I’m thinking to fallback to line systems in those scenarios - any idea if there’s a way to use the line system as Instances? I’d like to avoid having to calculate each vertex when moving the grid, and using instances (or SPS) could potentially help by repeating one hex muliple times (and setting it’s Y coordinate only, maybe rotate around the terrain normal).

I’ve tried adding a LineMesh to SPS, but it fails since it doesn’t contain any geometry.

In this case I believe thin instances are a good way - Thin Instances | Babylon.js Documentation
You’ll have the same number of drawcalls to draw any number of thin instances.
There were some threads which could help; I’ll try to find them later.
I remember @douglasg14b had some great examples with hexes and thin instances.