Refactor OceanLOD to ProjectedOcean; update grid generation and shader integration for improved horizon projection and clipping
This commit is contained in:
90
src/main.ts
90
src/main.ts
@@ -1,6 +1,6 @@
|
||||
import { vec3, mat4 } from 'gl-matrix';
|
||||
import { vec3, vec4, mat4 } from 'gl-matrix';
|
||||
import { Camera } from './Camera';
|
||||
import { OceanLOD } from './OceanLOD';
|
||||
import { ProjectedOcean } from './OceanLOD';
|
||||
import { Skybox } from './Skybox';
|
||||
import { createProgram } from './Shader';
|
||||
import * as Config from './constants';
|
||||
@@ -134,14 +134,13 @@ var lastTime = new Date().getTime();
|
||||
var counter = 0.0;
|
||||
var fps = 0;
|
||||
var fpsDisplay: HTMLElement | null = null;
|
||||
var lodStatsTimer = 0;
|
||||
/** Input states*/
|
||||
var mouseXVel = 0;
|
||||
var mouseYVel = 0;
|
||||
var keysPressed: Set<string> = new Set();
|
||||
/** Objects and states*/
|
||||
var camera: Camera;
|
||||
var oceanLOD: OceanLOD;
|
||||
var projectedOcean: ProjectedOcean;
|
||||
var skybox: Skybox;
|
||||
var wireframeMode = false;
|
||||
/** Camera movement speed */
|
||||
@@ -157,7 +156,6 @@ function drawScene() {
|
||||
let now = new Date();
|
||||
let delta = now.getTime() - lastTime;
|
||||
timeSpent += delta;
|
||||
lodStatsTimer += delta;
|
||||
|
||||
if ((counter += delta) >= Config.FPS_UPDATE_INTERVAL) {
|
||||
counter = 0;
|
||||
@@ -166,13 +164,6 @@ function drawScene() {
|
||||
}
|
||||
fps = 0;
|
||||
}
|
||||
|
||||
// Log LOD stats every 5 seconds
|
||||
if (lodStatsTimer >= 5000) {
|
||||
lodStatsTimer = 0;
|
||||
const stats = oceanLOD.getLODStats();
|
||||
console.log(`LOD Stats - High:${stats[0]} Med:${stats[1]} Low:${stats[2]} VeryLow:${stats[3]}`);
|
||||
}
|
||||
lastTime = now.getTime();
|
||||
|
||||
// Sun direction (matches the one in ocean shader)
|
||||
@@ -216,20 +207,18 @@ function drawScene() {
|
||||
gl.enable(gl.DEPTH_TEST);
|
||||
gl.depthMask(true);
|
||||
|
||||
// Update LOD based on camera position and view direction
|
||||
oceanLOD.updateLOD(gl, camera.pos, camera.target);
|
||||
|
||||
var model = mat4.create();
|
||||
mat4.identity(model);
|
||||
// No centering needed - grids are already positioned correctly in world space
|
||||
// Update projected ocean's projector matrices
|
||||
projectedOcean.updateProjector(camera.pos, camera.forward, view, projection);
|
||||
|
||||
gl.useProgram(defaultProgram);
|
||||
let view_loc = gl.getUniformLocation(<WebGLProgram>defaultProgram, "view");
|
||||
gl.uniformMatrix4fv(view_loc, false, view);
|
||||
let model_loc = gl.getUniformLocation(<WebGLProgram>defaultProgram, "model");
|
||||
gl.uniformMatrix4fv(model_loc, false, model);
|
||||
let projection_loc = gl.getUniformLocation(<WebGLProgram>defaultProgram, "projection");
|
||||
gl.uniformMatrix4fv(projection_loc, false, projection);
|
||||
let projectorMatrix_loc = gl.getUniformLocation(<WebGLProgram>defaultProgram, "uProjectorMatrix");
|
||||
gl.uniformMatrix4fv(projectorMatrix_loc, false, projectedOcean.projectorMatrix);
|
||||
let rangeMatrix_loc = gl.getUniformLocation(<WebGLProgram>defaultProgram, "uRangeMatrix");
|
||||
gl.uniformMatrix4fv(rangeMatrix_loc, false, projectedOcean.rangeMatrix);
|
||||
let eye_loc = gl.getUniformLocation(<WebGLProgram>defaultProgram, "eyePos");
|
||||
gl.uniform3fv(eye_loc, camera.pos);
|
||||
let uTime_loc = gl.getUniformLocation(<WebGLProgram>defaultProgram, "uTime");
|
||||
@@ -245,7 +234,60 @@ function drawScene() {
|
||||
let uGlitterIntensity_loc = gl.getUniformLocation(<WebGLProgram>defaultProgram, "uGlitterIntensity");
|
||||
gl.uniform1f(uGlitterIntensity_loc, glitterIntensity);
|
||||
|
||||
oceanLOD.draw(gl, wireframeMode);
|
||||
// Calculate horizon Y in clip space
|
||||
// The skybox horizon is where rayDir.z = 0 (horizontal ray from camera)
|
||||
// This is a point at infinity in a horizontal direction from the camera
|
||||
// We need to find where this projects to in clip space
|
||||
|
||||
// Get a horizontal direction (camera forward projected onto XY plane)
|
||||
const horizonDir = vec3.fromValues(camera.forward[0], camera.forward[1], 0);
|
||||
if (vec3.length(horizonDir) > 0.001) {
|
||||
vec3.normalize(horizonDir, horizonDir);
|
||||
} else {
|
||||
vec3.set(horizonDir, 1, 0, 0);
|
||||
}
|
||||
|
||||
// Transform a direction vector (not a point) to clip space
|
||||
// For a point at infinity in direction D, its clip space position is:
|
||||
// lim(t->inf) ViewProj * (eye + t*D) / w
|
||||
// Which equals ViewProj * D (as a vec4 with w=0), then we look at x/w, y/w
|
||||
// But since w would be 0 for a direction, we use the view matrix only
|
||||
|
||||
// The horizon is where view-space Y = 0 for an infinite point
|
||||
// In our Z-up system, the horizon is where the ray is horizontal (z=0 in world)
|
||||
// Transform a horizontal direction through view matrix
|
||||
const horizonDirView = vec4.fromValues(horizonDir[0], horizonDir[1], 0, 0);
|
||||
vec4.transformMat4(horizonDirView, horizonDirView, view);
|
||||
|
||||
// The Y in clip space where this direction points is based on the view-space direction
|
||||
// projected through the projection matrix
|
||||
// For perspective: clipY/clipW = viewY/(-viewZ) * projectionScaleY
|
||||
// For a horizontal ray at infinity, we can compute where it ends up
|
||||
|
||||
// Simpler approach: transform a point very far away in horizon direction
|
||||
const farDist = 1000000.0;
|
||||
const horizonPoint = vec4.fromValues(
|
||||
camera.pos[0] + horizonDir[0] * farDist,
|
||||
camera.pos[1] + horizonDir[1] * farDist,
|
||||
camera.pos[2], // Same height as camera - this is the horizon!
|
||||
1
|
||||
);
|
||||
const viewProj = mat4.create();
|
||||
mat4.multiply(viewProj, projection, view);
|
||||
vec4.transformMat4(horizonPoint, horizonPoint, viewProj);
|
||||
const horizonClipY = horizonPoint[3] !== 0 ? horizonPoint[1] / horizonPoint[3] : 0;
|
||||
|
||||
let uHorizonClipY_loc = gl.getUniformLocation(<WebGLProgram>defaultProgram, "uHorizonClipY");
|
||||
gl.uniform1f(uHorizonClipY_loc, horizonClipY);
|
||||
|
||||
// Enable backface culling so ocean isn't visible from below
|
||||
gl.enable(gl.CULL_FACE);
|
||||
gl.cullFace(gl.BACK);
|
||||
gl.frontFace(gl.CCW);
|
||||
|
||||
projectedOcean.draw(gl, wireframeMode);
|
||||
|
||||
gl.disable(gl.CULL_FACE);
|
||||
}
|
||||
requestAnimationFrame(drawScene);
|
||||
}
|
||||
@@ -380,9 +422,9 @@ function main() {
|
||||
initGeometry();
|
||||
initFBO();
|
||||
|
||||
oceanLOD = new OceanLOD();
|
||||
oceanLOD.initVAO(gl);
|
||||
console.log(`Ocean LOD initialized with ${oceanLOD.getGridCount()} patches`);
|
||||
projectedOcean = new ProjectedOcean();
|
||||
projectedOcean.initVAO(gl);
|
||||
console.log(`Projected ocean initialized with ${projectedOcean.getIndexCount()} indices`);
|
||||
|
||||
skybox = new Skybox();
|
||||
skybox.initVAO(gl);
|
||||
|
||||
Reference in New Issue
Block a user