# Hex Tile Terrain Anti-Repetition Method

This method hides obvious repeating patterns when a seamless ground texture is tiled across a large terrain. It is based on the local demo `hex-tile-terrain-example-made-by-fable-5.html`.

## Goal

Naive UV tiling repeats the same texture square in a visible grid. The hex-tile method samples the same seamless texture multiple times with randomized offsets, then blends those samples in a triangle/hex lattice. The result keeps the texture detail but breaks the obvious repetition.

## Core Steps

1. Convert world position to terrain UVs:

```glsl
vec2 uv = worldPosition.xz / tileSize;
```

2. Build a triangle grid over UV space. Each fragment finds the three nearest lattice vertices and their barycentric weights.

3. Hash each lattice vertex to a stable random `vec2` offset.

4. Sample the same seamless texture three times:

```glsl
vec3 c1 = sampleTexture(uv + hash(v1));
vec3 c2 = sampleTexture(uv + hash(v2));
vec3 c3 = sampleTexture(uv + hash(v3));
```

5. Sharpen and normalize the barycentric weights:

```glsl
vec3 w = pow(vec3(w1, w2, w3), vec3(blendSharpness));
w /= (w.x + w.y + w.z);
```

6. Blend the samples:

```glsl
vec3 blended = w.x * c1 + w.y * c2 + w.z * c3;
```

7. Restore contrast. Linear blending reduces variance, so pull the result away from the texture mean:

```glsl
float corr = inversesqrt(max(dot(w, w), 1e-5));
vec3 result = textureMean + (blended - textureMean) * mix(1.0, corr, 0.85);
```

8. Use `textureGrad` when available so every randomized sample uses gradients from the continuous base UV:

```glsl
vec2 gx = dFdx(uv);
vec2 gy = dFdy(uv);
vec3 c = textureGrad(map, uv + offset, gx, gy).rgb;
```

This keeps mip selection stable and reduces seams at cell borders.

## Extra Quality Passes

Distance re-scale blend:

- In the mid/far field, mix in a coarser texture sample, such as `uv * 0.125`.
- Fade it in with distance, for example `smoothstep(60.0, 320.0, distanceToCamera)`.
- This reduces shimmer and large-scale repetition.

Macro variation:

- Use low-frequency world-space noise.
- Drift brightness and tint slowly over the terrain.
- Keep this subtle; the demo uses a strength around `0.65`.

Texture mean:

- Precompute the albedo texture's average color in linear space.
- Send it as a uniform, often named `uMean`.
- Use it only for contrast restoration, not as a visible tint by itself.

## Suggested Defaults

```txt
tileSize: 3.0 meters
hexDensity: 1.0
blendSharpness: 6.0
macroVariation: 0.4 to 0.7
distanceBlend: enabled
```

## Implementation Notes

- Start with the albedo map. Extend the same UV offset method to normal, roughness, AO, and height maps only if the engine shader can afford the extra texture reads.
- For normal maps, blend normals in a tangent-safe way if possible. A simple normalized blend is acceptable for prototypes.
- Keep source textures seamless. The method hides repetition, but it does not fix hard seams inside the source image.
- Use world-space `xz` coordinates for terrain so UVs do not depend on mesh layout.
- For WebGL 1, fall back to normal texture sampling if `textureGrad` is unavailable, but expect possible mip seams.

## Minimal GLSL Snippet

```glsl
vec2 hash22(vec2 p) {
  vec3 p3 = fract(vec3(p.xyx) * vec3(0.1031, 0.1030, 0.0973));
  p3 += dot(p3, p3.yzx + 33.33);
  return fract((p3.xx + p3.yz) * p3.zy);
}

void triGrid(vec2 st, out float w1, out float w2, out float w3,
             out vec2 v1, out vec2 v2, out vec2 v3) {
  vec2 skewed = mat2(1.0, 0.0, -0.57735027, 1.15470054) * (st * 3.4641016);
  vec2 base = floor(skewed);
  vec3 t = vec3(fract(skewed), 0.0);
  t.z = 1.0 - t.x - t.y;

  if (t.z > 0.0) {
    w1 = t.z; w2 = t.y; w3 = t.x;
    v1 = base;
    v2 = base + vec2(0.0, 1.0);
    v3 = base + vec2(1.0, 0.0);
  } else {
    w1 = -t.z; w2 = 1.0 - t.y; w3 = 1.0 - t.x;
    v1 = base + vec2(1.0, 1.0);
    v2 = base + vec2(1.0, 0.0);
    v3 = base + vec2(0.0, 1.0);
  }
}
```

The original demo also includes a side-by-side comparison mode, procedural seamless texture generation, and a fly camera. Keep the production shader focused on the sampling method above.
