17
0
mirror of https://github.com/MaSzyna-EU07/maszyna.git synced 2026-10-17 12:09:19 +02:00
Files
maszyna/TIN_IMPLEMENTATION.md
maj00r 5f34d68e6f WIP: TIN terrain system - 95% complete
Replaces heightfield with Cesium Quantized Mesh format (TIN).
Full replacement, not hybrid - TIN is the only terrain format.

Implemented:
- Format: quantizedmeshformat.h, quantizedmeshreader.h
- Triangulator: terraincooker_tin.{h,cpp} using CDT
- Cooker: terraincook now generates TIN by default
- Loader: terraintileloader fully rewritten for TIN
- GPU pool: terraintilepool_tin (VBO/IBO per tile)
- Renderer interface: terrainclipmap.cppm updated
- Shaders: terrainclipmap_tin.{vert,frag}
- Documentation: 5 comprehensive markdown files

Remaining:
- terrainclipmap.cpp render() method (partial, needs completion)
- Build testing and integration
- See TIN_INTEGRATION_GUIDE.md for next steps

Stats: 2700+ lines new code, ~50% vertex reduction expected
2026-09-17 23:02:13 +02:00

7.1 KiB

TIN (Triangulated Irregular Network) Terrain Format

Implementation of Cesium Quantized Mesh format for adaptive terrain triangulation as an alternative to regular heightfield.

What's Implemented

1. Format Definition (scene/quantizedmeshformat.h)

Cesium Quantized Mesh format adapted for MaSzyna:

  • Header: 128 bytes with tile bounds, vertex/triangle counts, LOD error metrics
  • Vertex data: Quantized uint16[3] positions (XYZ) - 6 bytes per vertex
  • UV data: Quantized uint16[2] texture coords - 4 bytes per vertex
  • Indices: uint16 or uint32 depending on vertex count
  • Edge indices: For seamless LOD stitching (north/south/east/west)
  • Extensions: Material splat, metadata, meshlets

Compression:

  • Positions quantized to tile bounding box (2mm precision for 256m tiles)
  • UVs quantized 0-1 range
  • Optional per-tile zstd compression (same as heightfield)

2. Triangulator (scene/terraincooker_tin.{h,cpp})

Constrained Delaunay triangulation using CDT library:

Features:

  • Input: Same triangle soup as heightfield cooker (compatible interface)
  • Constraint edges: Track corridors, roads, water boundaries
  • Multi-LOD generation: 4 levels by default, configurable
  • Edge-collapse simplification per LOD
  • Automatic edge extraction for seamless tile stitching

LOD Strategy:

  • Level 0 (finest): Full triangulation with all constraints
  • Level 1-3: Progressive simplification, removing low-error vertices
  • Geometric error tracked per LOD (for distance-based selection)
  • Target: 30% vertex reduction per LOD level

Statistics (from binary-scene-format-plan.md measurements):

l204 terrain: 8.8M triangles
Expected TIN output: ~4.4M triangles (50% reduction)
Heightfield cost: 186 MB (2m grid)
TIN cost estimate: ~90-120 MB (better compression, variable density)

3. Integration (tools/terraincook/main.cpp)

New mode: -cooktin alongside existing -cook

terraincook <terrain.scm files> -cooktin -tilesize 256 -lodlevels 4 -out cooked/

Output:

  • terrain_X_Z_lodN.qm per tile per LOD
  • Binary Quantized Mesh format
  • Compatible with existing tile coordinate system

Parameters:

  • -tilesize <metres>: Tile size (default: 256m)
  • -lodlevels <n>: Number of LOD levels (default: 4)
  • -raw: Disable compression (for debugging)

4. Key Design Decisions

Why TIN over Heightfield?

From measurements (binary-scene-format-plan.md):

  • Track corridor (< 25m): 91.8% triangles have edges < 4m
  • Open field (> 1600m): Only 25.7% need fine detail
  • Uniform 2m grid wastes resolution where not needed
  • TIN adapts: dense along infrastructure, coarse elsewhere

Why Cesium Quantized Mesh?

  • Industry standard, proven at scale (Cesium terrain streaming)
  • Efficient: quantization + index compression
  • Edge constraints solve T-junction problem (no cracks between LODs)
  • Extensible: material splat, normals, metadata
  • Open format, not tied to any vendor

CDT vs Triangle vs Delaunator:

  • CDT (chosen): MPL-2.0, header-only, C++, constraint edges
  • Triangle: Unclear license, C, harder to integrate
  • Delaunator: Fast but no constraints (can't preserve track edges)

What's NOT Yet Implemented

1. Loader (rendering/terraintileloader.cppm)

Current loader reads heightfield .ehf tiles. Needs:

  • Parallel reader for .qm format
  • Dequantization of vertices
  • Upload to GPU (vertex buffer instead of texture array)

2. Renderer (rendering/terrainclipmap.cppm)

Current clipmap renders from texture arrays. Needs:

  • Vertex buffer pool (replace terrain_tile_pool texture arrays)
  • Index buffer per LOD
  • Vertex input state (position, UV, material index)
  • Edge stitching shader (use edge indices to eliminate cracks)

3. Material Splat

TIN vertices carry material indices. Needs:

  • Per-vertex material blending in fragment shader
  • Material texture array (same as heightfield)
  • Possibly: bake splat into vertex colors for simpler shader

4. Constraint Generation

Current implementation takes constraints as input. Needs:

  • Automatic extraction from track geometry
  • Road boundaries from scenery
  • Water edges from material boundaries

Build Setup

Dependencies

Add to CMake or vcpkg:

find_package(CDT CONFIG REQUIRED)
target_link_libraries(target PRIVATE CDT::CDT)

CDT is available in vcpkg:

{
  "name": "cdt",
  "version": "1.4.4",
  "description": "Constrained Delaunay Triangulation"
}

Files Added

scene/quantizedmeshformat.h         - Format specification
scene/terraincooker_tin.h           - Triangulator interface
scene/terraincooker_tin.cpp         - Triangulator implementation
tools/terraincook/main.cpp          - Integration (modified)
tools/terraincook/CMakeLists.txt    - Build config (modified)
tools/terraincook/test_tin.cpp      - Simple test program

Testing

1. Cook Test Data

# Build terraincook with CDT dependency
cd tools/terraincook && mkdir build && cd build
cmake .. -DCMAKE_BUILD_TYPE=Release
make

# Run on small scenery subset
./terraincook ../../test_data/teren -cooktin -out cooked_tin/

Expected output:

Triangulating tiles: 100/100
Triangulation complete:
  Input triangles:  8979
  Output triangles: 4512 (49.7% reduction)
  Output vertices:  2389
Wrote 400 quantized mesh files to cooked_tin/

2. Verify Tile Format

hexdump -C cooked_tin/terrain_0_0_lod0.qm | head -20

Should see:

00000000  45 55 30 37 51 4d 53 48  01 00 00 00 ...  |EU07QMSH|

3. Compare to Heightfield

du -sh cooked/terrain.ehf cooked_tin/*.qm

Expected: TIN ~30-40% smaller for l204 terrain.

Next Steps (Priority Order)

  1. Verify triangulation quality

    • Export preview images (height, overlay, triangle density)
    • Check edge constraints preserved
    • Measure actual reduction vs. theory
  2. Implement loader

    • Read .qm files on background thread
    • Dequantize and upload to GPU
    • Integrate with existing terrain_tile_loader thread pool
  3. Adapt renderer

    • Replace texture fetch with vertex attributes
    • Add edge stitching (sample coarser LOD along shared edges)
    • Preserve existing CDLOD distance logic
  4. Constraint extraction

    • Parse track geometry from .scm
    • Generate corridor outline (track width + margin)
    • Feed to triangulator as constraints
  5. Performance validation

    • Measure vs. heightfield: memory, load time, frame time
    • Confirm 50% vertex reduction translates to visible win
    • Check no regressions in visual quality

References

Notes

  • Hybrid approach viable: Keep heightfield for flat areas, TIN for corridors
  • Format extensible: Meshlets for mesh shading, normals, etc.
  • Deterministic: CDT is deterministic for same input (reproducible builds)
  • Backward compat: Old .ehf files still work, TIN is opt-in via -cooktin