Implement Ocean LOD management and enhance grid generation with wireframe support
This commit is contained in:
118
src/OceanLOD.ts
Normal file
118
src/OceanLOD.ts
Normal file
@@ -0,0 +1,118 @@
|
||||
import { Grid } from './Grid';
|
||||
import { vec3 } from 'gl-matrix';
|
||||
|
||||
/** Manages multiple ocean grid patches with LOD based on camera distance */
|
||||
export class OceanLOD {
|
||||
private grids: Array<{
|
||||
grid: Grid;
|
||||
centerX: number;
|
||||
centerY: number;
|
||||
size: number;
|
||||
lodLevel: number;
|
||||
}> = [];
|
||||
|
||||
private readonly LOD_LEVELS = [
|
||||
{ distance: 2.0, gridSize: 128 }, // Closest - highest detail
|
||||
{ distance: 5.0, gridSize: 64 }, // Medium distance
|
||||
{ distance: 10.0, gridSize: 32 }, // Far distance
|
||||
{ distance: 20.0, gridSize: 16 }, // Very far - lowest detail
|
||||
];
|
||||
|
||||
private readonly PATCH_SIZE = 2.0; // World size of each patch
|
||||
private readonly PATCHES_PER_SIDE = 7; // 7x7 = 49 patches total
|
||||
|
||||
constructor() {
|
||||
this.createGridPatches();
|
||||
}
|
||||
|
||||
private createGridPatches(): void {
|
||||
const halfPatches = Math.floor(this.PATCHES_PER_SIDE / 2);
|
||||
|
||||
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;
|
||||
|
||||
// Start with lowest detail - will be updated based on camera
|
||||
const grid = new Grid(
|
||||
this.LOD_LEVELS[3].gridSize,
|
||||
centerX,
|
||||
centerY,
|
||||
this.PATCH_SIZE
|
||||
);
|
||||
|
||||
this.grids.push({
|
||||
grid,
|
||||
centerX,
|
||||
centerY,
|
||||
size: this.PATCH_SIZE,
|
||||
lodLevel: 3
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Update LOD based on camera position */
|
||||
updateLOD(gl: WebGL2RenderingContext, cameraPos: vec3): void {
|
||||
for (const patch of this.grids) {
|
||||
// Calculate distance from camera to patch center
|
||||
const dx = patch.centerX - cameraPos[0];
|
||||
const dy = patch.centerY - cameraPos[1];
|
||||
const distance = Math.sqrt(dx * dx + dy * dy);
|
||||
|
||||
// Determine appropriate LOD level
|
||||
let newLodLevel = 3; // Default to lowest detail
|
||||
for (let i = 0; i < this.LOD_LEVELS.length; i++) {
|
||||
if (distance < this.LOD_LEVELS[i].distance) {
|
||||
newLodLevel = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Only recreate grid if LOD level changed
|
||||
if (newLodLevel !== patch.lodLevel) {
|
||||
patch.lodLevel = newLodLevel;
|
||||
patch.grid = new Grid(
|
||||
this.LOD_LEVELS[newLodLevel].gridSize,
|
||||
patch.centerX,
|
||||
patch.centerY,
|
||||
patch.size
|
||||
);
|
||||
patch.grid.initVAO(gl);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
initVAO(gl: WebGL2RenderingContext): void {
|
||||
for (const { grid } of this.grids) {
|
||||
grid.initVAO(gl);
|
||||
}
|
||||
}
|
||||
|
||||
draw(gl: WebGL2RenderingContext, wireframe: boolean = false): void {
|
||||
for (const { grid } of this.grids) {
|
||||
grid.draw(gl, wireframe);
|
||||
}
|
||||
}
|
||||
|
||||
getGridCount(): number {
|
||||
return this.grids.length;
|
||||
}
|
||||
|
||||
getTotalVertexCount(): number {
|
||||
let total = 0;
|
||||
for (const { grid } of this.grids) {
|
||||
total += grid.getIndexCount() / 3;
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
/** Get statistics about current LOD distribution */
|
||||
getLODStats(): { [key: number]: number } {
|
||||
const stats: { [key: number]: number } = { 0: 0, 1: 0, 2: 0, 3: 0 };
|
||||
for (const patch of this.grids) {
|
||||
stats[patch.lodLevel]++;
|
||||
}
|
||||
return stats;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user