From 77f1a19310bc78fd11610661087dc9425744d6ae Mon Sep 17 00:00:00 2001 From: Victor Giers Date: Thu, 21 May 2026 07:59:27 +0200 Subject: [PATCH] auto-git: [change] src/geometry/terrain-mesh.ts [change] tests/geometry/terrain-mesh.test.ts --- src/geometry/terrain-mesh.ts | 72 ++++++++++++++--------------- tests/geometry/terrain-mesh.test.ts | 61 +++++++++--------------- 2 files changed, 55 insertions(+), 78 deletions(-) diff --git a/src/geometry/terrain-mesh.ts b/src/geometry/terrain-mesh.ts index 5d9ade3b..e4c6b5e5 100644 --- a/src/geometry/terrain-mesh.ts +++ b/src/geometry/terrain-mesh.ts @@ -37,11 +37,7 @@ export interface DerivedTerrainMeshData { export const TERRAIN_LOD_CHUNK_SIZE_CELLS = 64; export const TERRAIN_LOD_STRIDES = [1, 2, 4, 8, 16] as const; export const TERRAIN_LOD_DEBUG_COLORS = [ - 0xff4d4d, - 0xffa53d, - 0xffe66d, - 0x4ee06f, - 0x4ba3ff + 0xff4d4d, 0xffa53d, 0xffe66d, 0x4ee06f, 0x4ba3ff ] as const; const TERRAIN_LOD_DISTANCE_MULTIPLIERS = [0.75, 1.5, 3, 6] as const; const TERRAIN_LOD_HYSTERESIS_RATIO = 0.16; @@ -232,7 +228,9 @@ export function buildTerrainDerivedMeshData( const vertexCount = terrain.sampleCountX * terrain.sampleCountZ; const positions = new Float32Array(vertexCount * 3); const uvs = new Float32Array(vertexCount * 2); - const layerWeights = new Float32Array(vertexCount * TERRAIN_SHADER_LAYER_COUNT); + const layerWeights = new Float32Array( + vertexCount * TERRAIN_SHADER_LAYER_COUNT + ); const foliageMaskWeights = new Float32Array(vertexCount); const foliageMask = options.foliageMaskLayerId === undefined || @@ -289,11 +287,7 @@ export function buildTerrainDerivedMeshData( ) : foliageMask === null ? 0 - : getTerrainFoliageMaskValueAtSample( - foliageMask, - sampleX, - sampleZ - ); + : getTerrainFoliageMaskValueAtSample(foliageMask, sampleX, sampleZ); foliageMaskWeightOffset += 1; } } @@ -494,7 +488,11 @@ function sampleTerrainLayerWeightsAtSamplePosition( ): number[] { const layerWeights = new Array(terrain.layers.length).fill(0); - for (let layerIndex = 0; layerIndex < terrain.layers.length; layerIndex += 1) { + for ( + let layerIndex = 0; + layerIndex < terrain.layers.length; + layerIndex += 1 + ) { layerWeights[layerIndex] = sampleTerrainScalarAtSamplePosition( terrain, sampleX, @@ -550,13 +548,22 @@ function pushTerrainLodNormal( sampleZ: number, normals: number[] ) { - const leftSampleX = clampSampleCoordinate(sampleX - 1, terrain.sampleCountX - 1); - const rightSampleX = clampSampleCoordinate(sampleX + 1, terrain.sampleCountX - 1); + const leftSampleX = clampSampleCoordinate( + sampleX - 1, + terrain.sampleCountX - 1 + ); + const rightSampleX = clampSampleCoordinate( + sampleX + 1, + terrain.sampleCountX - 1 + ); const bottomSampleZ = clampSampleCoordinate( sampleZ - 1, terrain.sampleCountZ - 1 ); - const topSampleZ = clampSampleCoordinate(sampleZ + 1, terrain.sampleCountZ - 1); + const topSampleZ = clampSampleCoordinate( + sampleZ + 1, + terrain.sampleCountZ - 1 + ); const dxDenominator = Math.max( (rightSampleX - leftSampleX) * terrain.cellSize, Number.EPSILON @@ -752,7 +759,10 @@ function pushTerrainLodBoundaryPoint( ) { const previous = points[points.length - 1]; - if (previous !== undefined && areTerrainLodSamplePointsEqual(previous, point)) { + if ( + previous !== undefined && + areTerrainLodSamplePointsEqual(previous, point) + ) { return; } @@ -844,16 +854,8 @@ function buildTerrainLodLevelMeshData( stride: number, options: TerrainMeshBuildOptions ): TerrainLodLevelMeshData { - const sampleXs = createLodSampleCoordinates( - startSampleX, - endSampleX, - stride - ); - const sampleZs = createLodSampleCoordinates( - startSampleZ, - endSampleZ, - stride - ); + const sampleXs = createLodSampleCoordinates(startSampleX, endSampleX, stride); + const sampleZs = createLodSampleCoordinates(startSampleZ, endSampleZ, stride); const positions: number[] = []; const uvs: number[] = []; const layerWeights: number[] = []; @@ -1307,29 +1309,23 @@ export function resolveTerrainLodLevelIndexWithHysteresis(options: { const lowerBoundary = activeLevelIndex <= 0 ? Number.NEGATIVE_INFINITY - : TERRAIN_LOD_DISTANCE_MULTIPLIERS[activeLevelIndex - 1] ?? + : (TERRAIN_LOD_DISTANCE_MULTIPLIERS[activeLevelIndex - 1] ?? TERRAIN_LOD_DISTANCE_MULTIPLIERS[ TERRAIN_LOD_DISTANCE_MULTIPLIERS.length - 1 - ]!; + ]!); const upperBoundary = activeLevelIndex >= options.levelCount - 1 ? Number.POSITIVE_INFINITY - : TERRAIN_LOD_DISTANCE_MULTIPLIERS[activeLevelIndex] ?? + : (TERRAIN_LOD_DISTANCE_MULTIPLIERS[activeLevelIndex] ?? TERRAIN_LOD_DISTANCE_MULTIPLIERS[ TERRAIN_LOD_DISTANCE_MULTIPLIERS.length - 1 - ]!; + ]!); - if ( - normalizedDistance > - upperBoundary * (1 + TERRAIN_LOD_HYSTERESIS_RATIO) - ) { + if (normalizedDistance > upperBoundary * (1 + TERRAIN_LOD_HYSTERESIS_RATIO)) { return Math.min(activeLevelIndex + 1, options.levelCount - 1); } - if ( - normalizedDistance < - lowerBoundary * (1 - TERRAIN_LOD_HYSTERESIS_RATIO) - ) { + if (normalizedDistance < lowerBoundary * (1 - TERRAIN_LOD_HYSTERESIS_RATIO)) { return Math.max(activeLevelIndex - 1, 0); } diff --git a/tests/geometry/terrain-mesh.test.ts b/tests/geometry/terrain-mesh.test.ts index b7200bb1..89033e7c 100644 --- a/tests/geometry/terrain-mesh.test.ts +++ b/tests/geometry/terrain-mesh.test.ts @@ -14,7 +14,10 @@ import { resolveTerrainLodLevelIndexWithHysteresis } from "../../src/geometry/terrain-mesh"; -function createJaggedTerrainHeights(sampleCountX: number, sampleCountZ: number) { +function createJaggedTerrainHeights( + sampleCountX: number, + sampleCountZ: number +) { return Array.from({ length: sampleCountX * sampleCountZ }, (_, index) => { const sampleX = index % sampleCountX; const sampleZ = Math.floor(index / sampleCountX); @@ -62,13 +65,9 @@ function collectTopEdgeKeys(options: { } const sampleX = - options.axis === "x" - ? options.sampleCoordinate - : roundedVaryingSample; + options.axis === "x" ? options.sampleCoordinate : roundedVaryingSample; const sampleZ = - options.axis === "x" - ? roundedVaryingSample - : options.sampleCoordinate; + options.axis === "x" ? roundedVaryingSample : options.sampleCoordinate; const expectedHeight = getTerrainHeightAtSample( options.terrain, sampleX, @@ -83,7 +82,9 @@ function collectTopEdgeKeys(options: { keys.add(`${roundedVaryingSample}:${height.toFixed(6)}`); } - return [...keys].sort((left, right) => Number(left.split(":")[0]) - Number(right.split(":")[0])); + return [...keys].sort( + (left, right) => Number(left.split(":")[0]) - Number(right.split(":")[0]) + ); } function collectLoweredEdgeVertexCount(options: { @@ -123,18 +124,17 @@ function collectLoweredEdgeVertexCount(options: { continue; } - if (roundedVaryingSample === 0 || roundedVaryingSample === maxVaryingSample) { + if ( + roundedVaryingSample === 0 || + roundedVaryingSample === maxVaryingSample + ) { continue; } const sampleX = - options.axis === "x" - ? options.sampleCoordinate - : roundedVaryingSample; + options.axis === "x" ? options.sampleCoordinate : roundedVaryingSample; const sampleZ = - options.axis === "x" - ? roundedVaryingSample - : options.sampleCoordinate; + options.axis === "x" ? roundedVaryingSample : options.sampleCoordinate; const expectedHeight = getTerrainHeightAtSample( options.terrain, sampleX, @@ -201,27 +201,16 @@ describe("terrain mesh generation", () => { }); const derivedMesh = buildTerrainDerivedMeshData(terrain); - expect(Array.from(derivedMesh.uvs)).toEqual([10, -6, 12, -6, 10, -4, 12, -4]); + expect(Array.from(derivedMesh.uvs)).toEqual([ + 10, -6, 12, -6, 10, -4, 12, -4 + ]); }); it("derives full per-vertex layer weights from the compact terrain paint data", () => { const terrain = createTerrain({ sampleCountX: 2, sampleCountZ: 2, - paintWeights: [ - 0.2, - 0.3, - 0.1, - 0, - 0.5, - 0, - 0.1, - 0.1, - 0.1, - 0.25, - 0.25, - 0.25 - ] + paintWeights: [0.2, 0.3, 0.1, 0, 0.5, 0, 0.1, 0.1, 0.1, 0.25, 0.25, 0.25] }); const derivedMesh = buildTerrainDerivedMeshData(terrain); @@ -318,11 +307,7 @@ describe("terrain mesh generation", () => { expect(chunk).toBeDefined(); expect(chunk!.levels.map((level) => level.stride)).toEqual([ - 1, - 2, - 4, - 8, - 16 + 1, 2, 4, 8, 16 ]); const vertexCounts = chunk!.levels.map( @@ -362,11 +347,7 @@ describe("terrain mesh generation", () => { const [chunk] = buildTerrainLodMeshData(terrain).chunks; const [level] = chunk!.levels; - for ( - let offset = 0; - offset < level!.layerWeights.length; - offset += 8 - ) { + for (let offset = 0; offset < level!.layerWeights.length; offset += 8) { const sum = level!.layerWeights[offset]! + level!.layerWeights[offset + 1]! +