diff --git a/src/OceanLOD.ts b/src/OceanLOD.ts index a6118e6..c352ba7 100644 --- a/src/OceanLOD.ts +++ b/src/OceanLOD.ts @@ -13,18 +13,22 @@ export class OceanLOD { }> = []; private readonly LOD_LEVELS = [ - { distance: 5.0, gridSize: 128 }, // Closest - highest detail - { distance: 15.0, gridSize: 64 }, // Medium distance - { distance: 40.0, gridSize: 32 }, // Far distance - { distance: 80.0, gridSize: 16 }, // Very far - { distance: 150.0, gridSize: 8 }, // Horizon - minimal detail - { distance: Infinity, gridSize: 4 },// Beyond horizon - lowest detail + { distance: 3.0, gridSize: 256 }, // Very close - ultra detail + { distance: 8.0, gridSize: 128 }, // Close - high detail + { distance: 20.0, gridSize: 64 }, // Medium distance + { distance: 40.0, gridSize: 16 }, // Far - low detail + { distance: 80.0, gridSize: 8 }, // Very far - minimal + { distance: Infinity, gridSize: 4 },// Horizon - lowest (will be stretched anyway) ]; - private readonly PATCH_SIZE = 8.0; // World size of each patch (larger for horizon coverage) - private readonly PATCHES_PER_SIDE = 51; // 51x51 = 2601 patches (covers ~200 units in each direction) + private readonly PATCH_SIZE = 10.0; // Larger patches = fewer needed + private readonly PATCHES_PER_SIDE = 21; // 21x21 = 441 patches (covers ~200 units) private readonly VIEW_CONE_COS = Math.cos(Math.PI * 0.45); // ~81 degree half-angle (wider than typical FOV) + // Track the grid origin to re-center when camera moves + private gridOriginX: number = 0; + private gridOriginY: number = 0; + constructor() { this.createGridPatches(); } @@ -34,8 +38,8 @@ export class OceanLOD { for (let y = -halfPatches; y <= halfPatches; y++) { for (let x = -halfPatches; x <= halfPatches; x++) { - const centerX = x * this.PATCH_SIZE; - const centerY = y * this.PATCH_SIZE; + const centerX = x * this.PATCH_SIZE + this.gridOriginX; + const centerY = y * this.PATCH_SIZE + this.gridOriginY; // Start with lowest detail - will be updated based on camera const grid = new Grid( @@ -57,6 +61,32 @@ export class OceanLOD { } } + /** Re-center the grid around a new origin */ + private recenterGrid(gl: WebGL2RenderingContext, newOriginX: number, newOriginY: number): void { + this.gridOriginX = newOriginX; + this.gridOriginY = newOriginY; + + const halfPatches = Math.floor(this.PATCHES_PER_SIDE / 2); + let i = 0; + + for (let y = -halfPatches; y <= halfPatches; y++) { + for (let x = -halfPatches; x <= halfPatches; x++) { + const patch = this.grids[i]; + const newCenterX = x * this.PATCH_SIZE + this.gridOriginX; + const newCenterY = y * this.PATCH_SIZE + this.gridOriginY; + + // Only update if patch position changed + if (patch.centerX !== newCenterX || patch.centerY !== newCenterY) { + patch.centerX = newCenterX; + patch.centerY = newCenterY; + // Force LOD recalculation + patch.lodLevel = -1; + } + i++; + } + } + } + /** Update LOD based on camera position and view direction */ updateLOD(gl: WebGL2RenderingContext, cameraPos: vec3, cameraTarget: vec3): void { // Calculate view direction (normalized) @@ -64,6 +94,14 @@ export class OceanLOD { vec3.subtract(viewDir, cameraTarget, cameraPos); vec3.normalize(viewDir, viewDir); + // Check if we need to recenter the grid (camera moved more than one patch size from origin) + const cameraGridX = Math.floor(cameraPos[0] / this.PATCH_SIZE) * this.PATCH_SIZE; + const cameraGridY = Math.floor(cameraPos[1] / this.PATCH_SIZE) * this.PATCH_SIZE; + + if (cameraGridX !== this.gridOriginX || cameraGridY !== this.gridOriginY) { + this.recenterGrid(gl, cameraGridX, cameraGridY); + } + for (const patch of this.grids) { // Calculate vector from camera to patch center (on XY plane, Z=0 for ocean surface) const toPatch = vec3.fromValues(